diff options
author | Ben Murdoch <benm@google.com> | 2011-05-24 11:24:40 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-06-02 09:53:15 +0100 |
commit | 81bc750723a18f21cd17d1b173cd2a4dda9cea6e (patch) | |
tree | 7a9e5ed86ff429fd347a25153107221543909b19 /Source/WebCore/inspector | |
parent | 94088a6d336c1dd80a1e734af51e96abcbb689a7 (diff) | |
download | external_webkit-81bc750723a18f21cd17d1b173cd2a4dda9cea6e.zip external_webkit-81bc750723a18f21cd17d1b173cd2a4dda9cea6e.tar.gz external_webkit-81bc750723a18f21cd17d1b173cd2a4dda9cea6e.tar.bz2 |
Merge WebKit at r80534: Intial merge by Git
Change-Id: Ia7a83357124c9e1cdb1debf55d9661ec0bd09a61
Diffstat (limited to 'Source/WebCore/inspector')
109 files changed, 6897 insertions, 3029 deletions
diff --git a/Source/WebCore/inspector/CodeGeneratorInspector.pm b/Source/WebCore/inspector/CodeGeneratorInspector.pm index e4e19b0..70eb61d 100644 --- a/Source/WebCore/inspector/CodeGeneratorInspector.pm +++ b/Source/WebCore/inspector/CodeGeneratorInspector.pm @@ -55,10 +55,6 @@ $typeTransform{"FileSystem"} = { "header" => "InspectorFileSystemAgent.h", "domainAccessor" => "m_inspectorAgent->fileSystemAgent()", }; -$typeTransform{"InjectedScript"} = { - "forwardHeader" => "InjectedScriptHost.h", - "domainAccessor" => "m_inspectorAgent->injectedScriptAgent()", -}; $typeTransform{"Inspector"} = { "forwardHeader" => "InspectorAgent.h", "domainAccessor" => "m_inspectorAgent", @@ -78,6 +74,11 @@ $typeTransform{"Runtime"} = { "header" => "InspectorRuntimeAgent.h", "domainAccessor" => "m_inspectorAgent->runtimeAgent()", }; +$typeTransform{"Timeline"} = { + "forward" => "InspectorTimelineAgent", + "header" => "InspectorTimelineAgent.h", + "domainAccessor" => "m_inspectorAgent->timelineAgent()", +}; $typeTransform{"Frontend"} = { "forward" => "InspectorFrontend", @@ -97,7 +98,8 @@ $typeTransform{"Object"} = { "forward" => "InspectorObject", "header" => "InspectorValues.h", "JSONType" => "Object", - "JSType" => "object" + "JSType" => "object", + "DocType" => "%s" }; $typeTransform{"Array"} = { "param" => "PassRefPtr<InspectorArray>", @@ -106,7 +108,8 @@ $typeTransform{"Array"} = { "forward" => "InspectorArray", "header" => "InspectorValues.h", "JSONType" => "Array", - "JSType" => "object" + "JSType" => "object", + "DocType" => "array of %s" }; $typeTransform{"Value"} = { "param" => "PassRefPtr<InspectorValue>", @@ -115,7 +118,8 @@ $typeTransform{"Value"} = { "forward" => "InspectorValue", "header" => "InspectorValues.h", "JSONType" => "Value", - "JSType" => "" + "JSType" => "", + "DocType" => "value" }; $typeTransform{"String"} = { "param" => "const String&", @@ -217,12 +221,16 @@ my @backendJSStubs; my $frontendClassName; my %frontendTypes; my @frontendMethods; +my @frontendAgentFields; my @frontendMethodsImpl; my %frontendMethodSignatures; my $frontendConstructor; my @frontendConstantDeclarations; my @frontendConstantDefinitions; -my $frontendFooter; +my @frontendFooter; + +my @documentationToc; +my @documentationLines; # Default constructor sub new @@ -250,20 +258,11 @@ sub GenerateModule $namespace = $dataNode->module; $namespace =~ s/core/WebCore/; -} - -# Params: 'idlDocument' struct -sub GenerateInterface -{ - my $object = shift; - my $interface = shift; - my $defines = shift; - - my $className = $interface->name; $frontendClassName = "InspectorFrontend"; - $frontendConstructor = " ${frontendClassName}(InspectorClient* inspectorClient) : m_inspectorClient(inspectorClient) { }"; - $frontendFooter = " private:\n InspectorClient* m_inspectorClient;"; + $frontendConstructor = " ${frontendClassName}(InspectorClient*);"; + push(@frontendFooter, "private:"); + push(@frontendFooter, " InspectorClient* m_inspectorClient;"); $frontendTypes{"String"} = 1; $frontendTypes{"InspectorClient"} = 1; $frontendTypes{"PassRefPtr"} = 1; @@ -281,22 +280,87 @@ sub GenerateInterface $backendTypes{"InspectorClient"} = 1; $backendTypes{"PassRefPtr"} = 1; $backendTypes{"Object"} = 1; +} + +# Params: 'idlDocument' struct +sub GenerateInterface +{ + my $object = shift; + my $interface = shift; + my $defines = shift; - generateFunctions($interface); + my %agent = ( + methodDeclarations => [], + methodSignatures => {} + ); + generateFunctions($interface, \%agent); + if (@{$agent{methodDeclarations}}) { + generateAgentDeclaration($interface, \%agent); + } +} + +sub generateAgentDeclaration +{ + my $interface = shift; + my $agent = shift; + my $agentName = $interface->name; + push(@frontendMethods, " class ${agentName} {"); + push(@frontendMethods, " public:"); + push(@frontendMethods, " ${agentName}(InspectorClient* inspectorClient) : m_inspectorClient(inspectorClient) { }"); + push(@frontendMethods, @{$agent->{methodDeclarations}}); + push(@frontendMethods, " private:"); + push(@frontendMethods, " InspectorClient* m_inspectorClient;"); + push(@frontendMethods, " };"); + push(@frontendMethods, ""); + + my $getterName = lc($agentName); + push(@frontendMethods, " ${agentName}* ${getterName}() { return &m_${getterName}; }"); + push(@frontendMethods, ""); + + push(@frontendFooter, " ${agentName} m_${getterName};"); + + push(@frontendAgentFields, "m_${getterName}"); +} + +sub generateFrontendConstructorImpl +{ + my @frontendConstructorImpl; + push(@frontendConstructorImpl, "${frontendClassName}::${frontendClassName}(InspectorClient* inspectorClient)"); + push(@frontendConstructorImpl, " : m_inspectorClient(inspectorClient)"); + foreach my $agentField (@frontendAgentFields) { + push(@frontendConstructorImpl, " , ${agentField}(inspectorClient)"); + } + push(@frontendConstructorImpl, "{"); + push(@frontendConstructorImpl, "}"); + return @frontendConstructorImpl; } sub generateFunctions { my $interface = shift; + my $agent = shift; foreach my $function (@{$interface->functions}) { - if ($function->signature->extendedAttributes->{"notify"}) { - generateFrontendFunction($interface, $function); + if ($function->signature->extendedAttributes->{"event"}) { + generateFrontendFunction($interface, $function, $agent); } else { generateBackendFunction($interface, $function); } } + push(@documentationToc, "<li><a href='#" . $interface->name . "'>" . $interface->name . "</a></li>"); + push(@documentationLines, "<h2 id='" . $interface->name . "'><a name=" . $interface->name . "></a>" . $interface->name . "</h2>"); + + push(@documentationLines, "<h3>Events</h3>"); + foreach my $function (grep($_->signature->extendedAttributes->{"event"}, @{$interface->functions}) ) { + generateDocumentationEvent($interface, $function); + } + + push(@documentationLines, "<h3>Commands</h3>"); + foreach my $function (grep(!$_->signature->extendedAttributes->{"event"}, @{$interface->functions})) { + generateDocumentationCommand($interface, $function); + } + collectBackendJSStubFunctions($interface); } @@ -304,37 +368,76 @@ sub generateFrontendFunction { my $interface = shift; my $function = shift; + my $agent = shift; my $functionName = $function->signature->name; my $domain = $interface->name; my @argsFiltered = grep($_->direction eq "out", @{$function->parameters}); # just keep only out parameters for frontend interface. map($frontendTypes{$_->type} = 1, @argsFiltered); # register required types. - my $arguments = join(", ", map($typeTransform{$_->type}->{"param"} . " " . $_->name, @argsFiltered)); # prepare arguments for function signature. + my $arguments = join(", ", map(typeTraits($_->type, "param") . " " . $_->name, @argsFiltered)); # prepare arguments for function signature. - my $signature = " void ${functionName}(${arguments});"; - !$frontendMethodSignatures{${signature}} || die "Duplicate frontend function was detected for signature '$signature'."; - $frontendMethodSignatures{${signature}} = 1; - push(@frontendMethods, $signature); + my $signature = " void ${functionName}(${arguments});"; + !$agent->{methodSignatures}->{$signature} || die "Duplicate frontend function was detected for signature '$signature'."; + $agent->{methodSignatures}->{$signature} = 1; + push(@{$agent->{methodDeclarations}}, $signature); my @function; - push(@function, "void ${frontendClassName}::${functionName}(${arguments})"); + push(@function, "void ${frontendClassName}::${domain}::${functionName}(${arguments})"); push(@function, "{"); push(@function, " RefPtr<InspectorObject> ${functionName}Message = InspectorObject::create();"); push(@function, " ${functionName}Message->setString(\"type\", \"event\");"); push(@function, " ${functionName}Message->setString(\"domain\", \"$domain\");"); push(@function, " ${functionName}Message->setString(\"event\", \"$functionName\");"); - push(@function, " RefPtr<InspectorObject> payloadDataObject = InspectorObject::create();"); - my @pushArguments = map(" payloadDataObject->set" . $typeTransform{$_->type}->{"JSONType"} . "(\"" . $_->name . "\", " . $_->name . ");", @argsFiltered); + push(@function, " RefPtr<InspectorObject> bodyObject = InspectorObject::create();"); + my @pushArguments = map(" bodyObject->set" . typeTraits($_->type, "JSONType") . "(\"" . $_->name . "\", " . $_->name . ");", @argsFiltered); push(@function, @pushArguments); - push(@function, " ${functionName}Message->setObject(\"data\", payloadDataObject);"); + push(@function, " ${functionName}Message->setObject(\"body\", bodyObject);"); push(@function, " m_inspectorClient->sendMessageToFrontend(${functionName}Message->toJSONString());"); - push(@function, "}"); push(@function, ""); push(@frontendMethodsImpl, @function); } +sub generateDocumentationEvent +{ + my $interface = shift; + my $function = shift; + + my $functionName = $function->signature->name; + my $domain = $interface->name; + + my @argsFiltered = grep($_->direction eq "out", @{$function->parameters}); + + my @lines; + push(@lines, "<h4>" . $interface->name . "." . ${functionName} . "</h4>"); + my $doc = $function->signature->extendedAttributes->{"doc"}; + if ($doc) { + push(@lines, $doc); + } + + push(@lines, "<pre style='background: lightGrey; padding: 10px'>"); + push(@lines, "{"); + push(@lines, " seq: <number>,"); + push(@lines, " type: \"event\","); + push(@lines, " domain: \"$domain\","); + if (scalar(@argsFiltered)) { + push(@lines, " event: \"${functionName}\","); + push(@lines, " data: {"); + my @parameters; + foreach my $parameter (@argsFiltered) { + push(@parameters, " " . parameterDocLine($parameter)); + } + push(@lines, join(",\n", @parameters)); + push(@lines, " }"); + } else { + push(@lines, " event: \"${functionName}\""); + } + push(@lines, "}"); + push(@lines, "</pre>"); + push(@documentationLines, @lines); +} + sub camelCase { my $value = shift; @@ -352,12 +455,12 @@ sub generateBackendFunction my $fullQualifiedFunctionName = $interface->name . "_" . $function->signature->name; push(@backendConstantDeclarations, " static const char* ${fullQualifiedFunctionName}Cmd;"); - push(@backendConstantDefinitions, "const char* ${backendClassName}::${fullQualifiedFunctionName}Cmd = \"${functionName}\";"); + push(@backendConstantDefinitions, "const char* ${backendClassName}::${fullQualifiedFunctionName}Cmd = \"${fullQualifiedFunctionName}\";"); map($backendTypes{$_->type} = 1, @{$function->parameters}); # register required types my @inArgs = grep($_->direction eq "in" && !($_->name eq "callId") , @{$function->parameters}); my @outArgs = grep($_->direction eq "out", @{$function->parameters}); - + my $signature = " void ${fullQualifiedFunctionName}(long callId, InspectorObject* requestMessageObject);"; !$backendMethodSignatures{${signature}} || die "Duplicate function was detected for signature '$signature'."; $backendMethodSignatures{${signature}} = "$fullQualifiedFunctionName"; @@ -371,14 +474,14 @@ sub generateBackendFunction push(@function, ""); my $domain = $interface->name; - my $domainAccessor = $typeTransform{$domain}->{"domainAccessor"}; + my $domainAccessor = typeTraits($domain, "domainAccessor"); $backendTypes{$domain} = 1; push(@function, " if (!$domainAccessor)"); push(@function, " protocolErrors->pushString(\"Protocol Error: $domain handler is not available.\");"); push(@function, ""); # declare local variables for out arguments. - push(@function, map(" " . $typeTransform{$_->type}->{"variable"} . " " . $_->name . " = " . $typeTransform{$_->type}->{"defaultValue"} . ";", @outArgs)); + push(@function, map(" " . typeTraits($_->type, "variable") . " " . $_->name . " = " . typeTraits($_->type, "defaultValue") . ";", @outArgs)); my $indent = ""; if (scalar(@inArgs)) { @@ -388,15 +491,18 @@ sub generateBackendFunction my $name = $parameter->name; my $type = $parameter->type; my $typeString = camelCase($parameter->type); - push(@function, " " . $typeTransform{$type}->{"variable"} . " $name = get$typeString(argumentsContainer.get(), \"$name\", protocolErrors.get());"); + push(@function, " " . typeTraits($type, "variable") . " $name = get$typeString(argumentsContainer.get(), \"$name\", protocolErrors.get());"); } push(@function, ""); $indent = " "; } - my $args = join(", ", (map($_->name, @inArgs), map("&" . $_->name, @outArgs))); + push(@function, "$indent ErrorString error;"); + my $args = join(", ", ("&error", map($_->name, @inArgs), map("&" . $_->name, @outArgs))); push(@function, "$indent if (!protocolErrors->length())"); push(@function, "$indent $domainAccessor->$functionName($args);"); + push(@function, "$indent if (error.length())"); + push(@function, "$indent protocolErrors->pushString(error);"); if (scalar(@inArgs)) { push(@function, " } else {"); push(@function, " protocolErrors->pushString(\"Protocol Error: 'arguments' property with type 'object' was not found.\");"); @@ -407,16 +513,14 @@ sub generateBackendFunction push(@function, " if ((callId || protocolErrors->length()) && m_inspectorAgent->hasFrontend()) {"); push(@function, " RefPtr<InspectorObject> responseMessage = InspectorObject::create();"); push(@function, " responseMessage->setNumber(\"seq\", callId);"); - push(@function, " responseMessage->setString(\"domain\", \"$domain\");"); - push(@function, " responseMessage->setBoolean(\"success\", !protocolErrors->length());"); push(@function, ""); push(@function, " if (protocolErrors->length())"); push(@function, " responseMessage->setArray(\"errors\", protocolErrors);"); if (scalar(@outArgs)) { push(@function, " else {"); - push(@function, " RefPtr<InspectorObject> responseData = InspectorObject::create();"); - push(@function, map(" responseData->set" . $typeTransform{$_->type}->{"JSONType"} . "(\"" . $_->name . "\", " . $_->name . ");", @outArgs)); - push(@function, " responseMessage->setObject(\"data\", responseData);"); + push(@function, " RefPtr<InspectorObject> responseBody = InspectorObject::create();"); + push(@function, map(" responseBody->set" . typeTraits($_->type, "JSONType") . "(\"" . $_->name . "\", " . $_->name . ");", @outArgs)); + push(@function, " responseMessage->setObject(\"body\", responseBody);"); push(@function, " }"); } push(@function, " m_inspectorAgent->inspectorClient()->sendMessageToFrontend(responseMessage->toJSONString());"); @@ -428,6 +532,64 @@ sub generateBackendFunction push(@backendMethodsImpl, @function); } +sub generateDocumentationCommand +{ + my $interface = shift; + my $function = shift; + + my $functionName = $function->signature->name; + my $domain = $interface->name; + + my @lines; + + push(@lines, "<h4>" . $interface->name . "." . ${functionName} . "</h4>"); + my $doc = $function->signature->extendedAttributes->{"doc"}; + if ($doc) { + push(@lines, $doc); + } + + my @inArgs = grep($_->direction eq "in" && !($_->name eq "callId") , @{$function->parameters}); + push(@lines, "<pre style='background: lightGrey; padding: 10px'>"); + push(@lines, "request: {"); + push(@lines, " seq: <number>,"); + push(@lines, " type: \"request\","); + push(@lines, " domain: \"" . $interface->name . "\","); + if (scalar(@inArgs)) { + push(@lines, " command: \"${functionName}\","); + push(@lines, " arguments: {"); + my @parameters; + foreach my $parameter (@inArgs) { + push(@parameters, " " . parameterDocLine($parameter)); + } + push(@lines, join(",\n", @parameters)); + push(@lines, " }"); + } else { + push(@lines, " command: \"${functionName}\""); + } + push(@lines, "}"); + + my @outArgs = grep($_->direction eq "out", @{$function->parameters}); + push(@lines, ""); + push(@lines, "response: {"); + push(@lines, " seq: <number>,"); + if (scalar(@outArgs)) { + push(@lines, " type: \"response\","); + push(@lines, " body: {"); + my @parameters; + foreach my $parameter (@outArgs) { + push(@parameters, " " . parameterDocLine($parameter)); + } + push(@lines, join(",\n", @parameters)); + push(@lines, " }"); + } else { + push(@lines, " type: \"response\""); + } + push(@lines, "}"); + push(@lines, "</pre>"); + + push(@documentationLines, @lines); +} + sub generateBackendReportProtocolError { my $reportProtocolError = << "EOF"; @@ -436,7 +598,6 @@ void ${backendClassName}::reportProtocolError(const long callId, const String& e { RefPtr<InspectorObject> message = InspectorObject::create(); message->setNumber("seq", callId); - message->setBoolean("success", false); RefPtr<InspectorArray> errors = InspectorArray::create(); errors->pushString(errorText); message->setArray("errors", errors); @@ -449,10 +610,10 @@ EOF 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 $json = typeTraits($type, "JSONType"); + my $variable = typeTraits($type, "variable"); + my $defaultValue = typeTraits($type, "defaultValue"); + my $return = typeTraits($type, "return") ? typeTraits($type, "return") : typeTraits($type, "param"); my $typeString = camelCase($type); push(@backendConstantDeclarations, " $return get$typeString(InspectorObject* object, const String& name, InspectorArray* protocolErrors);"); @@ -487,6 +648,11 @@ sub generateBackendDispatcher my $mapEntries = join("\n", @mapEntries); my $backendDispatcherBody = << "EOF"; +static String commandName(const String& domain, const String& command) +{ + return makeString(domain, "_", command); +} + void ${backendClassName}::dispatch(const String& message) { typedef void (${backendClassName}::*CallHandler)(long callId, InspectorObject* messageObject); @@ -522,6 +688,18 @@ $mapEntries return; } + RefPtr<InspectorValue> domainValue = messageObject->get("domain"); + if (!domainValue) { + reportProtocolError(callId, "Protocol Error: Invalid message format. 'domain' property wasn't found."); + return; + } + + String domain; + if (!domainValue->asString(&domain)) { + reportProtocolError(callId, "Protocol Error: Invalid message format. The type of 'domain' property should be string."); + return; + } + RefPtr<InspectorValue> callIdValue = messageObject->get("seq"); if (!callIdValue) { reportProtocolError(callId, "Protocol Error: Invalid message format. 'seq' property was not found in the request."); @@ -533,9 +711,9 @@ $mapEntries return; } - HashMap<String, CallHandler>::iterator it = dispatchMap.find(command); + HashMap<String, CallHandler>::iterator it = dispatchMap.find(commandName(domain, command)); if (it == dispatchMap.end()) { - reportProtocolError(callId, makeString("Protocol Error: Invalid command was received. '", command, "' wasn't found.")); + reportProtocolError(callId, makeString("Protocol Error: Invalid command was received. '", command, "' wasn't found in domain ", domain, ".")); return; } @@ -558,11 +736,16 @@ bool ${backendClassName}::getCommandName(const String& message, String* result) if (!object) return false; - RefPtr<InspectorValue> commandValue = object->get("command"); - if (!commandValue) + String domain; + if (!object->getString("domain", &domain)) return false; - return commandValue->asString(result); + String command; + if (!object->getString("command", &command)) + return false; + + *result = commandName(domain, command); + return true; } EOF return split("\n", $messageParserBody); @@ -571,12 +754,12 @@ EOF sub collectBackendJSStubFunctions { my $interface = shift; - my @functions = grep(!$_->signature->extendedAttributes->{"notify"}, @{$interface->functions}); + my @functions = grep(!$_->signature->extendedAttributes->{"event"}, @{$interface->functions}); my $domain = $interface->name; foreach my $function (@functions) { my $name = $function->signature->name; - my $argumentNames = join(",", map("\"" . $_->name . "\": \"" . $typeTransform{$_->type}->{"JSType"} . "\"", grep($_->direction eq "in", @{$function->parameters}))); + my $argumentNames = join(",", map("\"" . $_->name . "\": \"" . typeTraits($_->type, "JSType") . "\"", grep($_->direction eq "in", @{$function->parameters}))); push(@backendJSStubs, " this._registerDelegate('{" . "\"seq\": 0, " . "\"domain\": \"$domain\", " . @@ -595,6 +778,7 @@ $licenseTemplate InspectorBackendStub = function() { this._lastCallbackId = 1; + this._pendingResponsesCount = 0; this._callbacks = {}; this._domainDispatchers = {}; $JSStubs @@ -608,22 +792,13 @@ InspectorBackendStub.prototype = { return callbackId; }, - _processResponse: function(callbackId, args) - { - var callback = this._callbacks[callbackId]; - callback.apply(null, args); - delete this._callbacks[callbackId]; - }, - - _removeResponseCallbackEntry: function(callbackId) - { - delete this._callbacks[callbackId]; - }, - _registerDelegate: function(commandInfo) { var commandObject = JSON.parse(commandInfo); - this[commandObject.command] = this.sendMessageToBackend.bind(this, commandInfo); + var agentName = commandObject.domain + "Agent"; + if (!window[agentName]) + window[agentName] = {}; + window[agentName][commandObject.command] = this.sendMessageToBackend.bind(this, commandInfo); }, sendMessageToBackend: function() @@ -633,29 +808,33 @@ InspectorBackendStub.prototype = { for (var key in request.arguments) { if (args.length === 0) { - console.error("Protocol Error: Invalid number of arguments for 'InspectorBackend.%s' call. It should have the next arguments '%s'.", request.command, JSON.stringify(request.arguments)); + console.error("Protocol Error: Invalid number of arguments for '" + request.domain + "Agent." + request.command + "' call. It should have the next arguments '" + JSON.stringify(request.arguments) + "'."); return; } var value = args.shift(); if (request.arguments[key] && typeof value !== request.arguments[key]) { - console.error("Protocol Error: Invalid type of argument '%s' for 'InspectorBackend.%s' call. It should be '%s' but it is '%s'.", key, request.command, request.arguments[key], typeof value); + console.error("Protocol Error: Invalid type of argument '" + key + "' for '" + request.domain + "Agent." + request.command + "' call. It should be '" + request.arguments[key] + "' but it is '" + typeof value + "'."); return; } request.arguments[key] = value; } + var callback; if (args.length === 1) { if (typeof args[0] !== "function" && typeof args[0] !== "undefined") { - console.error("Protocol Error: Optional callback argument for 'InspectorBackend.%s' call should be a function but its type is '%s'.", request.command, typeof args[0]); + console.error("Protocol Error: Optional callback argument for '" + request.domain + "Agent." + request.command + "' call should be a function but its type is '" + typeof args[0] + "'."); return; } - request.seq = this._wrap(args[0]); + callback = args[0]; } + request.seq = this._wrap(callback || function() {}); if (window.dumpInspectorProtocolMessages) console.log("frontend: " + JSON.stringify(request)); var message = JSON.stringify(request); + + ++this._pendingResponsesCount; InspectorFrontendHost.sendMessageToBackend(message); }, @@ -672,28 +851,33 @@ InspectorBackendStub.prototype = { var messageObject = (typeof message === "string") ? JSON.parse(message) : message; var arguments = []; - if (messageObject.data) - for (var key in messageObject.data) - arguments.push(messageObject.data[key]); + if (messageObject.body) + for (var key in messageObject.body) + arguments.push(messageObject.body[key]); if ("seq" in messageObject) { // just a response for some request - if (messageObject.success) - this._processResponse(messageObject.seq, arguments); - else { - this._removeResponseCallbackEntry(messageObject.seq) + if (!messageObject.errors) + this._callbacks[messageObject.seq].apply(null, arguments); + else this.reportProtocolError(messageObject); - } + + --this._pendingResponsesCount; + delete this._callbacks[messageObject.seq]; + + if (this._scripts && !this._pendingResponsesCount) + this.runAfterPendingDispatches(); + return; } if (messageObject.type === "event") { if (!(messageObject.domain in this._domainDispatchers)) { - console.error("Protocol Error: the message is for non-existing domain '%s'", messageObject.domain); + console.error("Protocol Error: the message is for non-existing domain '" + messageObject.domain + "'"); return; } var dispatcher = this._domainDispatchers[messageObject.domain]; if (!(messageObject.event in dispatcher)) { - console.error("Protocol Error: Attempted to dispatch an unimplemented method '%s.%s'", messageObject.domain, messageObject.event); + console.error("Protocol Error: Attempted to dispatch an unimplemented method '" + messageObject.domain + "." + messageObject.event + "'"); return; } dispatcher[messageObject.event].apply(dispatcher, arguments); @@ -702,10 +886,25 @@ InspectorBackendStub.prototype = { reportProtocolError: function(messageObject) { - console.error("Protocol Error: InspectorBackend request with seq = %d failed.", messageObject.seq); + console.error("Protocol Error: InspectorBackend request with seq = " + messageObject.seq + " failed."); for (var i = 0; i < messageObject.errors.length; ++i) console.error(" " + messageObject.errors[i]); - this._removeResponseCallbackEntry(messageObject.seq); + }, + + runAfterPendingDispatches: function(script) + { + if (!this._scripts) + this._scripts = []; + + if (script) + this._scripts.push(script); + + if (!this._pendingResponsesCount) { + var scripts = this._scripts; + this._scripts = [] + for (var id = 0; id < scripts.length; ++id) + scripts[id].call(this); + } } } @@ -724,8 +923,8 @@ sub generateHeader my $methods = shift; my $footer = shift; - my $forwardHeaders = join("\n", sort(map("#include <" . $typeTransform{$_}->{"forwardHeader"} . ">", grep($typeTransform{$_}->{"forwardHeader"}, keys %{$types})))); - my $forwardDeclarations = join("\n", sort(map("class " . $typeTransform{$_}->{"forward"} . ";", grep($typeTransform{$_}->{"forward"}, keys %{$types})))); + my $forwardHeaders = join("\n", sort(map("#include <" . typeTraits($_, "forwardHeader") . ">", grep(typeTraits($_, "forwardHeader"), keys %{$types})))); + my $forwardDeclarations = join("\n", sort(map("class " . typeTraits($_, "forward") . ";", grep(typeTraits($_, "forward"), keys %{$types})))); my $constantDeclarations = join("\n", @{$constants}); my $methodsDeclarations = join("\n", @{$methods}); @@ -742,6 +941,8 @@ namespace $namespace { $forwardDeclarations +typedef String ErrorString; + class $className { public: $constructor @@ -777,7 +978,7 @@ sub generateSource my %headers; foreach my $type (keys %{$types}) { - $headers{"#include \"" . $typeTransform{$type}->{"header"} . "\""} = 1 if !$typeTransform{$type}->{"header"} eq ""; + $headers{"#include \"" . typeTraits($type, "header") . "\""} = 1 if !typeTraits($type, "header") eq ""; } push(@sourceContent, sort keys %headers); push(@sourceContent, ""); @@ -794,12 +995,50 @@ sub generateSource return @sourceContent; } +sub typeTraits +{ + my $type = shift; + my $trait = shift; + return $typeTransform{$type}->{$trait}; +} + +sub parameterDocType +{ + my $parameter = shift; + my $subtype = $parameter->extendedAttributes->{"type"}; + if ($subtype) { + my $pattern = typeTraits($parameter->type, "DocType"); + return sprintf($pattern, "<$subtype>"); + } + + my $subtypeRef = $parameter->extendedAttributes->{"typeRef"}; + if ($subtypeRef) { + my $pattern = typeTraits($parameter->type, "DocType"); + return sprintf($pattern, "<<a href='#$subtypeRef'>" . $subtypeRef . "</a>>"); + } + + return "<" . typeTraits($parameter->type, "JSType") . ">"; +} + +sub parameterDocLine +{ + my $parameter = shift; + + my $result = $parameter->name . ": " . parameterDocType($parameter); + my $doc = $parameter->extendedAttributes->{"doc"}; + if ($doc) { + $result = $result . " // " . $doc; + } + return $result; +} + sub finish { my $object = shift; push(@backendMethodsImpl, generateBackendDispatcher()); push(@backendMethodsImpl, generateBackendReportProtocolError()); + unshift(@frontendMethodsImpl, generateFrontendConstructorImpl(), ""); open(my $SOURCE, ">$outputDir/$frontendClassName.cpp") || die "Couldn't open file $outputDir/$frontendClassName.cpp"; print $SOURCE join("\n", generateSource($frontendClassName, \%frontendTypes, \@frontendConstantDefinitions, \@frontendMethodsImpl)); @@ -807,7 +1046,7 @@ sub finish undef($SOURCE); open(my $HEADER, ">$outputHeadersDir/$frontendClassName.h") || die "Couldn't open file $outputHeadersDir/$frontendClassName.h"; - print $HEADER generateHeader($frontendClassName, \%frontendTypes, $frontendConstructor, \@frontendConstantDeclarations, \@frontendMethods, $frontendFooter); + print $HEADER generateHeader($frontendClassName, \%frontendTypes, $frontendConstructor, \@frontendConstantDeclarations, \@frontendMethods, join("\n", @frontendFooter)); close($HEADER); undef($HEADER); @@ -816,7 +1055,7 @@ sub finish push(@backendConstantDeclarations, "private:"); foreach my $type (keys %backendTypes) { - if ($typeTransform{$type}{"JSONType"}) { + if (typeTraits($type, "JSONType")) { push(@backendMethodsImpl, generateArgumentGetters($type)); } } @@ -840,6 +1079,14 @@ sub finish print $JS_STUB join("\n", generateBackendStubJS()); close($JS_STUB); undef($JS_STUB); + + open(my $DOCS, ">$outputDir/WebInspectorProtocol.html") || die "Couldn't open file $outputDir/WebInspectorProtocol.html"; + print $DOCS "<ol class='toc' style='list-style: none; padding: 0'>"; + print $DOCS join("\n", @documentationToc); + print $DOCS "</ol>"; + print $DOCS join("\n", @documentationLines); + close($DOCS); + undef($DOCS); } 1; diff --git a/Source/WebCore/inspector/ConsoleMessage.cpp b/Source/WebCore/inspector/ConsoleMessage.cpp index 8d56a5a..63fb020 100644 --- a/Source/WebCore/inspector/ConsoleMessage.cpp +++ b/Source/WebCore/inspector/ConsoleMessage.cpp @@ -86,7 +86,7 @@ ConsoleMessage::~ConsoleMessage() { } -void ConsoleMessage::addToFrontend(InspectorFrontend* frontend, InjectedScriptHost* injectedScriptHost) +void ConsoleMessage::addToFrontend(InspectorFrontend::Console* frontend, InjectedScriptHost* injectedScriptHost) { RefPtr<InspectorObject> jsonObj = InspectorObject::create(); jsonObj->setNumber("source", static_cast<int>(m_source)); @@ -103,7 +103,7 @@ void ConsoleMessage::addToFrontend(InspectorFrontend* frontend, InjectedScriptHo if (!injectedScript.hasNoValue()) { RefPtr<InspectorArray> jsonArgs = InspectorArray::create(); for (unsigned i = 0; i < m_arguments->argumentCount(); ++i) { - RefPtr<InspectorValue> inspectorValue = injectedScript.wrapForConsole(m_arguments->argumentAt(i)); + RefPtr<InspectorValue> inspectorValue = injectedScript.wrapObject(m_arguments->argumentAt(i), "console"); if (!inspectorValue) { ASSERT_NOT_REACHED(); return; @@ -118,7 +118,7 @@ void ConsoleMessage::addToFrontend(InspectorFrontend* frontend, InjectedScriptHo frontend->addConsoleMessage(jsonObj); } -void ConsoleMessage::updateRepeatCountInConsole(InspectorFrontend* frontend) +void ConsoleMessage::updateRepeatCountInConsole(InspectorFrontend::Console* frontend) { frontend->updateConsoleMessageRepeatCount(m_repeatCount); } diff --git a/Source/WebCore/inspector/ConsoleMessage.h b/Source/WebCore/inspector/ConsoleMessage.h index 7c3348b..26e5675 100644 --- a/Source/WebCore/inspector/ConsoleMessage.h +++ b/Source/WebCore/inspector/ConsoleMessage.h @@ -32,6 +32,7 @@ #define ConsoleMessage_h #include "Console.h" +#include "InspectorFrontend.h" #include "ScriptState.h" #include <wtf/Forward.h> @@ -54,8 +55,8 @@ public: ConsoleMessage(MessageSource, MessageType, MessageLevel, const String& m, const String& responseUrl, unsigned long identifier); ~ConsoleMessage(); - void addToFrontend(InspectorFrontend*, InjectedScriptHost*); - void updateRepeatCountInConsole(InspectorFrontend* frontend); + void addToFrontend(InspectorFrontend::Console*, InjectedScriptHost*); + void updateRepeatCountInConsole(InspectorFrontend::Console*); void incrementCount() { ++m_repeatCount; } bool isEqual(ConsoleMessage* msg) const; diff --git a/Source/WebCore/inspector/InjectedScript.cpp b/Source/WebCore/inspector/InjectedScript.cpp index 9fd606b..6c115d0 100644 --- a/Source/WebCore/inspector/InjectedScript.cpp +++ b/Source/WebCore/inspector/InjectedScript.cpp @@ -33,7 +33,10 @@ #if ENABLE(INSPECTOR) +#include "Frame.h" +#include "InjectedScriptHost.h" #include "InspectorValues.h" +#include "Node.h" #include "PlatformString.h" #include "ScriptFunctionCall.h" @@ -53,37 +56,20 @@ void InjectedScript::evaluate(const String& expression, const String& objectGrou makeCall(function, result); } -void InjectedScript::evaluateOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, RefPtr<InspectorValue>* result) -{ - ScriptFunctionCall function(m_injectedScriptObject, "evaluateOnCallFrame"); - function.appendArgument(callFrameId->toJSONString()); - function.appendArgument(expression); - function.appendArgument(objectGroup); - function.appendArgument(includeCommandLineAPI); - makeCall(function, result); -} - -void InjectedScript::evaluateOnSelf(const String& functionBody, PassRefPtr<InspectorArray> argumentsArray, RefPtr<InspectorValue>* result) -{ - ScriptFunctionCall function(m_injectedScriptObject, "evaluateOnSelf"); - function.appendArgument(functionBody); - function.appendArgument(argumentsArray->toJSONString()); - makeCall(function, result); -} - -void InjectedScript::getCompletions(const String& expression, bool includeCommandLineAPI, RefPtr<InspectorValue>* result) +void InjectedScript::evaluateOn(PassRefPtr<InspectorObject> objectId, const String& expression, RefPtr<InspectorValue>* result) { - ScriptFunctionCall function(m_injectedScriptObject, "getCompletions"); + ScriptFunctionCall function(m_injectedScriptObject, "evaluateOn"); + function.appendArgument(objectId->toJSONString()); function.appendArgument(expression); - function.appendArgument(includeCommandLineAPI); makeCall(function, result); } -void InjectedScript::getCompletionsOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, bool includeCommandLineAPI, RefPtr<InspectorValue>* result) +void InjectedScript::evaluateOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, RefPtr<InspectorValue>* result) { - ScriptFunctionCall function(m_injectedScriptObject, "getCompletionsOnCallFrame"); + ScriptFunctionCall function(m_injectedScriptObject, "evaluateOnCallFrame"); function.appendArgument(callFrameId->toJSONString()); function.appendArgument(expression); + function.appendArgument(objectGroup); function.appendArgument(includeCommandLineAPI); makeCall(function, result); } @@ -98,44 +84,45 @@ void InjectedScript::getProperties(PassRefPtr<InspectorObject> objectId, bool ig makeCall(function, result); } -void InjectedScript::pushNodeToFrontend(PassRefPtr<InspectorObject> objectId, RefPtr<InspectorValue>* result) +Node* InjectedScript::nodeForObjectId(PassRefPtr<InspectorObject> objectId) { - ScriptFunctionCall function(m_injectedScriptObject, "pushNodeToFrontend"); + if (hasNoValue() || !canAccessInspectedWindow()) + return 0; + + ScriptFunctionCall function(m_injectedScriptObject, "nodeForObjectId"); function.appendArgument(objectId->toJSONString()); - makeCall(function, result); -} -void InjectedScript::resolveNode(long nodeId, RefPtr<InspectorValue>* result) -{ - ScriptFunctionCall function(m_injectedScriptObject, "resolveNode"); - function.appendArgument(nodeId); - makeCall(function, result); -} + bool hadException = false; + ScriptValue resultValue = function.call(hadException); + ASSERT(!hadException); -void InjectedScript::getNodeProperties(long nodeId, PassRefPtr<InspectorArray> propertiesArray, RefPtr<InspectorValue>* result) -{ - ScriptFunctionCall function(m_injectedScriptObject, "getNodeProperties"); - function.appendArgument(nodeId); - function.appendArgument(propertiesArray->toJSONString()); - makeCall(function, result); + return InjectedScriptHost::scriptValueAsNode(resultValue); } -void InjectedScript::getNodePrototypes(long nodeId, RefPtr<InspectorValue>* result) +void InjectedScript::resolveNode(long nodeId, RefPtr<InspectorValue>* result) { - ScriptFunctionCall function(m_injectedScriptObject, "getNodePrototypes"); + ScriptFunctionCall function(m_injectedScriptObject, "resolveNode"); function.appendArgument(nodeId); makeCall(function, result); } void InjectedScript::setPropertyValue(PassRefPtr<InspectorObject> objectId, const String& propertyName, const String& expression, RefPtr<InspectorValue>* result) { - ScriptFunctionCall function(m_injectedScriptObject, "getNodeProperties"); + ScriptFunctionCall function(m_injectedScriptObject, "setPropertyValue"); function.appendArgument(objectId->toJSONString()); function.appendArgument(propertyName); function.appendArgument(expression); makeCall(function, result); } +void InjectedScript::releaseObject(PassRefPtr<InspectorObject> objectId) +{ + ScriptFunctionCall function(m_injectedScriptObject, "releaseObject"); + function.appendArgument(objectId->toJSONString()); + RefPtr<InspectorValue> result; + makeCall(function, &result); +} + #if ENABLE(JAVASCRIPT_DEBUGGER) PassRefPtr<InspectorValue> InjectedScript::callFrames() { @@ -146,23 +133,41 @@ PassRefPtr<InspectorValue> InjectedScript::callFrames() } #endif -PassRefPtr<InspectorValue> InjectedScript::wrapForConsole(ScriptValue value) +PassRefPtr<InspectorObject> InjectedScript::wrapObject(ScriptValue value, const String& groupName) { ASSERT(!hasNoValue()); - ScriptFunctionCall wrapFunction(m_injectedScriptObject, "wrapObjectForConsole"); + ScriptFunctionCall wrapFunction(m_injectedScriptObject, "wrapObject"); wrapFunction.appendArgument(value); + wrapFunction.appendArgument(groupName); wrapFunction.appendArgument(canAccessInspectedWindow()); bool hadException = false; ScriptValue r = wrapFunction.call(hadException); - if (hadException) - return InspectorString::create("<exception>"); - return r.toInspectorValue(m_injectedScriptObject.scriptState()); + if (hadException) { + RefPtr<InspectorObject> result = InspectorObject::create(); + result->setString("description", "<exception>"); + return result; + } + return r.toInspectorValue(m_injectedScriptObject.scriptState())->asObject(); +} + +PassRefPtr<InspectorObject> InjectedScript::wrapNode(Node* node, const String& groupName) +{ + return wrapObject(nodeAsScriptValue(node), groupName); +} + +void InjectedScript::inspectNode(Node* node) +{ + ASSERT(!hasNoValue()); + ScriptFunctionCall function(m_injectedScriptObject, "inspectNode"); + function.appendArgument(nodeAsScriptValue(node)); + RefPtr<InspectorValue> result; + makeCall(function, &result); } -void InjectedScript::releaseWrapperObjectGroup(const String& objectGroup) +void InjectedScript::releaseObjectGroup(const String& objectGroup) { ASSERT(!hasNoValue()); - ScriptFunctionCall releaseFunction(m_injectedScriptObject, "releaseWrapperObjectGroup"); + ScriptFunctionCall releaseFunction(m_injectedScriptObject, "releaseObjectGroup"); releaseFunction.appendArgument(objectGroup); releaseFunction.call(); } @@ -189,6 +194,11 @@ void InjectedScript::makeCall(ScriptFunctionCall& function, RefPtr<InspectorValu *result = InspectorValue::null(); } +ScriptValue InjectedScript::nodeAsScriptValue(Node* node) +{ + return InjectedScriptHost::nodeAsScriptValue(m_injectedScriptObject.scriptState(), node); +} + } // namespace WebCore #endif // ENABLE(INSPECTOR) diff --git a/Source/WebCore/inspector/InjectedScript.h b/Source/WebCore/inspector/InjectedScript.h index 0dd41ae..33d5411 100644 --- a/Source/WebCore/inspector/InjectedScript.h +++ b/Source/WebCore/inspector/InjectedScript.h @@ -41,6 +41,7 @@ namespace WebCore { class InspectorValue; +class Node; class ScriptFunctionCall; class InjectedScript { @@ -51,31 +52,31 @@ public: bool hasNoValue() const { return m_injectedScriptObject.hasNoValue(); } void evaluate(const String& expression, const String& objectGroup, bool includeCommandLineAPI, RefPtr<InspectorValue>* result); + void evaluateOn(PassRefPtr<InspectorObject> objectId, const String& expression, RefPtr<InspectorValue>* result); void evaluateOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, RefPtr<InspectorValue>* result); - void evaluateOnSelf(const String& functionBody, PassRefPtr<InspectorArray> argumentsArray, RefPtr<InspectorValue>* result); - void getCompletions(const String& expression, bool includeCommandLineAPI, RefPtr<InspectorValue>* result); - void getCompletionsOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, bool includeCommandLineAPI, RefPtr<InspectorValue>* result); void getProperties(PassRefPtr<InspectorObject> objectId, bool ignoreHasOwnProperty, bool abbreviate, RefPtr<InspectorValue>* result); - void pushNodeToFrontend(PassRefPtr<InspectorObject> objectId, RefPtr<InspectorValue>* result); + Node* nodeForObjectId(PassRefPtr<InspectorObject> objectId); void resolveNode(long nodeId, RefPtr<InspectorValue>* result); - void getNodeProperties(long nodeId, PassRefPtr<InspectorArray> propertiesArray, RefPtr<InspectorValue>* result); - void getNodePrototypes(long nodeId, RefPtr<InspectorValue>* result); void setPropertyValue(PassRefPtr<InspectorObject> objectId, const String& propertyName, const String& expression, RefPtr<InspectorValue>* result); - + void releaseObject(PassRefPtr<InspectorObject> objectId); + #if ENABLE(JAVASCRIPT_DEBUGGER) PassRefPtr<InspectorValue> callFrames(); #endif - PassRefPtr<InspectorValue> wrapForConsole(ScriptValue); - void releaseWrapperObjectGroup(const String&); + PassRefPtr<InspectorObject> wrapObject(ScriptValue, const String& groupName); + PassRefPtr<InspectorObject> wrapNode(Node*, const String& groupName); + void inspectNode(Node*); + void releaseObjectGroup(const String&); ScriptState* scriptState() const { return m_injectedScriptObject.scriptState(); } private: friend InjectedScript InjectedScriptHost::injectedScriptFor(ScriptState*); explicit InjectedScript(ScriptObject); - bool canAccessInspectedWindow(); + bool canAccessInspectedWindow(); void makeCall(ScriptFunctionCall&, RefPtr<InspectorValue>* result); + ScriptValue nodeAsScriptValue(Node*); ScriptObject m_injectedScriptObject; }; diff --git a/Source/WebCore/inspector/InjectedScriptHost.cpp b/Source/WebCore/inspector/InjectedScriptHost.cpp index fbb4dbf..ad4df45 100644 --- a/Source/WebCore/inspector/InjectedScriptHost.cpp +++ b/Source/WebCore/inspector/InjectedScriptHost.cpp @@ -42,10 +42,10 @@ #include "InspectorAgent.h" #include "InspectorClient.h" #include "InspectorConsoleAgent.h" -#include "InspectorDOMAgent.h" #include "InspectorDOMStorageAgent.h" #include "InspectorDatabaseAgent.h" #include "InspectorFrontend.h" +#include "InspectorValues.h" #include "Pasteboard.h" #if ENABLE(JAVASCRIPT_DEBUGGER) @@ -80,73 +80,59 @@ InjectedScriptHost::~InjectedScriptHost() { } -void InjectedScriptHost::evaluateOnSelf(const String& functionBody, PassRefPtr<InspectorArray> argumentsArray, RefPtr<InspectorValue>* result) +void InjectedScriptHost::inspectImpl(PassRefPtr<InspectorValue> objectId, PassRefPtr<InspectorValue> hints) { - InjectedScript injectedScript = injectedScriptForMainFrame(); - if (!injectedScript.hasNoValue()) - injectedScript.evaluateOnSelf(functionBody, argumentsArray, result); + if (InspectorFrontend* fe = frontend()) + fe->inspector()->inspect(objectId->asObject(), hints->asObject()); } void InjectedScriptHost::clearConsoleMessages() { - if (m_inspectorAgent) - m_inspectorAgent->consoleAgent()->clearConsoleMessages(); + if (m_inspectorAgent) { + ErrorString error; + m_inspectorAgent->consoleAgent()->clearConsoleMessages(&error); + } } -void InjectedScriptHost::copyText(const String& text) +void InjectedScriptHost::addInspectedNode(Node* node) { - Pasteboard::generalPasteboard()->writePlainText(text); + m_inspectedNodes.prepend(node); + while (m_inspectedNodes.size() > 5) + m_inspectedNodes.removeLast(); } -Node* InjectedScriptHost::nodeForId(long nodeId) +void InjectedScriptHost::clearInspectedNodes() { - if (InspectorDOMAgent* domAgent = inspectorDOMAgent()) - return domAgent->nodeForId(nodeId); - return 0; + m_inspectedNodes.clear(); } -long InjectedScriptHost::pushNodePathToFrontend(Node* node, bool withChildren, bool selectInUI) +void InjectedScriptHost::copyText(const String& text) { - InspectorDOMAgent* domAgent = inspectorDOMAgent(); - if (!domAgent || !frontend()) - return 0; - long id = domAgent->pushNodePathToFrontend(node); - if (withChildren) - domAgent->pushChildNodesToFrontend(id); - if (selectInUI) - frontend()->updateFocusedNode(id); - return id; + Pasteboard::generalPasteboard()->writePlainText(text); } -long InjectedScriptHost::inspectedNode(unsigned long num) +Node* InjectedScriptHost::inspectedNode(unsigned long num) { - InspectorDOMAgent* domAgent = inspectorDOMAgent(); - if (!domAgent) - return 0; - - return domAgent->inspectedNode(num); + if (num < m_inspectedNodes.size()) + return m_inspectedNodes[num].get(); + return 0; } #if ENABLE(DATABASE) -Database* InjectedScriptHost::databaseForId(long databaseId) +long InjectedScriptHost::databaseIdImpl(Database* database) { if (m_inspectorAgent && m_inspectorAgent->databaseAgent()) - return m_inspectorAgent->databaseAgent()->databaseForId(databaseId); + return m_inspectorAgent->databaseAgent()->databaseId(database); return 0; } - -void InjectedScriptHost::selectDatabase(Database* database) -{ - if (m_inspectorAgent && m_inspectorAgent->databaseAgent()) - m_inspectorAgent->databaseAgent()->selectDatabase(database); -} #endif #if ENABLE(DOM_STORAGE) -void InjectedScriptHost::selectDOMStorage(Storage* storage) +long InjectedScriptHost::storageIdImpl(Storage* storage) { if (m_inspectorAgent && m_inspectorAgent->domStorageAgent()) - m_inspectorAgent->domStorageAgent()->selectDOMStorage(storage); + return m_inspectorAgent->domStorageAgent()->storageId(storage); + return 0; } #endif @@ -177,26 +163,19 @@ void InjectedScriptHost::discardInjectedScripts() m_idToInjectedScript.clear(); } -void InjectedScriptHost::releaseWrapperObjectGroup(long injectedScriptId, const String& objectGroup) +void InjectedScriptHost::releaseObjectGroup(long injectedScriptId, const String& objectGroup) { if (injectedScriptId) { InjectedScript injectedScript = m_idToInjectedScript.get(injectedScriptId); if (!injectedScript.hasNoValue()) - injectedScript.releaseWrapperObjectGroup(objectGroup); + injectedScript.releaseObjectGroup(objectGroup); } else { // Iterate over all injected scripts if injectedScriptId is not specified. for (IdToInjectedScriptMap::iterator it = m_idToInjectedScript.begin(); it != m_idToInjectedScript.end(); ++it) - it->second.releaseWrapperObjectGroup(objectGroup); + it->second.releaseObjectGroup(objectGroup); } } -InspectorDOMAgent* InjectedScriptHost::inspectorDOMAgent() -{ - if (!m_inspectorAgent) - return 0; - return m_inspectorAgent->domAgent(); -} - InspectorFrontend* InjectedScriptHost::frontend() { if (!m_inspectorAgent) diff --git a/Source/WebCore/inspector/InjectedScriptHost.h b/Source/WebCore/inspector/InjectedScriptHost.h index f51f8da..cdb1e64 100644 --- a/Source/WebCore/inspector/InjectedScriptHost.h +++ b/Source/WebCore/inspector/InjectedScriptHost.h @@ -37,16 +37,17 @@ #include <wtf/HashMap.h> #include <wtf/RefCounted.h> +#include <wtf/Vector.h> namespace WebCore { class Database; class InjectedScript; -class InspectorDOMAgent; class InspectorFrontend; class InspectorObject; class Node; class ScriptObject; +class ScriptValue; class Storage; class InjectedScriptHost : public RefCounted<InjectedScriptHost> @@ -57,27 +58,28 @@ public: return adoptRef(new InjectedScriptHost(inspectorAgent)); } - ~InjectedScriptHost(); + static Node* scriptValueAsNode(ScriptValue); + static ScriptValue nodeAsScriptValue(ScriptState*, Node*); - // Part of the protocol. - void evaluateOnSelf(const String& functionBody, PassRefPtr<InspectorArray> argumentsArray, RefPtr<InspectorValue>* result); + ~InjectedScriptHost(); InspectorAgent* inspectorAgent() { return m_inspectorAgent; } void disconnectController() { m_inspectorAgent = 0; } + void inspectImpl(PassRefPtr<InspectorValue> objectId, PassRefPtr<InspectorValue> hints); void clearConsoleMessages(); + void addInspectedNode(Node*); + void clearInspectedNodes(); + void copyText(const String& text); - Node* nodeForId(long nodeId); - long pushNodePathToFrontend(Node* node, bool withChildren, bool selectInUI); - long inspectedNode(unsigned long num); + Node* inspectedNode(unsigned long num); #if ENABLE(DATABASE) - Database* databaseForId(long databaseId); - void selectDatabase(Database* database); + long databaseIdImpl(Database*); #endif #if ENABLE(DOM_STORAGE) - void selectDOMStorage(Storage* storage); + long storageIdImpl(Storage*); #endif #if ENABLE(WORKERS) long nextWorkerId(); @@ -91,13 +93,12 @@ public: InjectedScript injectedScriptForObjectId(InspectorObject* objectId); InjectedScript injectedScriptForMainFrame(); void discardInjectedScripts(); - void releaseWrapperObjectGroup(long injectedScriptId, const String& objectGroup); + void releaseObjectGroup(long injectedScriptId, const String& objectGroup); static bool canAccessInspectedWindow(ScriptState*); private: InjectedScriptHost(InspectorAgent*); - InspectorDOMAgent* inspectorDOMAgent(); InspectorFrontend* frontend(); String injectedScriptSource(); ScriptObject createInjectedScript(const String& source, ScriptState* scriptState, long id); @@ -108,6 +109,7 @@ private: long m_lastWorkerId; typedef HashMap<long, InjectedScript> IdToInjectedScriptMap; IdToInjectedScriptMap m_idToInjectedScript; + Vector<RefPtr<Node> > m_inspectedNodes; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/InjectedScriptHost.idl b/Source/WebCore/inspector/InjectedScriptHost.idl index 5fb57b4..0d5c500 100644 --- a/Source/WebCore/inspector/InjectedScriptHost.idl +++ b/Source/WebCore/inspector/InjectedScriptHost.idl @@ -35,22 +35,13 @@ module core { void clearConsoleMessages(); void copyText(in DOMString text); - [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] void inspect(in DOMObject objectId, in DOMObject hints); + [Custom] DOMObject inspectedNode(in unsigned long num); [Custom] DOMObject internalConstructorName(in DOMObject object); -#if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER [Custom] DOMObject currentCallFrame(); -#endif - -#if defined(ENABLE_DATABASE) && ENABLE_DATABASE - [Custom] void selectDatabase(in DOMObject database); -#endif - -#if defined(ENABLE_DOM_STORAGE) && ENABLE_DOM_STORAGE - [Custom] void selectDOMStorage(in DOMObject storage); -#endif + [Custom] long databaseId(in DOMObject database); + [Custom] long storageId(in DOMObject storage); #if defined(ENABLE_WORKERS) && ENABLE_WORKERS void didCreateWorker(in long id, in DOMString url, in boolean isFakeWorker); diff --git a/Source/WebCore/inspector/InjectedScriptSource.js b/Source/WebCore/inspector/InjectedScriptSource.js index c88e8e4..9c662e8 100644 --- a/Source/WebCore/inspector/InjectedScriptSource.js +++ b/Source/WebCore/inspector/InjectedScriptSource.js @@ -50,33 +50,62 @@ var InjectedScript = function() } InjectedScript.prototype = { - wrapObjectForConsole: function(object, canAccessInspectedWindow) + wrapObject: function(object, groupName, canAccessInspectedWindow) { if (canAccessInspectedWindow) - return this._wrapObject(object, "console"); + return this._wrapObject(object, groupName); var result = {}; result.type = typeof object; result.description = this._toString(object); return result; }, + inspectNode: function(object) + { + this._inspect(object); + }, + + _inspect: function(object) + { + if (arguments.length === 0) + return; + + var objectId = this._wrapObject(object, "", false); + var hints = {}; + + switch (injectedScript._describe(object)) { + case "Database": + var databaseId = InjectedScriptHost.databaseId(object) + if (databaseId) + hints.databaseId = databaseId; + break; + case "Storage": + var storageId = InjectedScriptHost.storageId(object) + if (storageId) + hints.domStorageId = storageId; + break; + } + InjectedScriptHost.inspect(objectId, hints); + return object; + }, + _wrapObject: function(object, objectGroupName, abbreviate) { try { - var objectId; if (typeof object === "object" || typeof object === "function" || this._isHTMLAllCollection(object)) { var id = this._lastBoundObjectId++; this._idToWrappedObject[id] = object; + var objectId = { injectedScriptId: injectedScriptId, id: id }; - var group = this._objectGroups[objectGroupName]; - if (!group) { - group = []; - this._objectGroups[objectGroupName] = group; + if (objectGroupName) { + var group = this._objectGroups[objectGroupName]; + if (!group) { + group = []; + this._objectGroups[objectGroupName] = group; + } + group.push(id); + objectId.groupName = objectGroupName; } - group.push(id); - objectId = { injectedScriptId: injectedScriptId, - id: id, - groupName: objectGroupName }; } return InjectedScript.RemoteObject.fromObject(object, objectId, abbreviate); } catch (e) { @@ -89,7 +118,7 @@ InjectedScript.prototype = { return eval("(" + objectId + ")"); }, - releaseWrapperObjectGroup: function(objectGroupName) + releaseObjectGroup: function(objectGroupName) { var group = this._objectGroups[objectGroupName]; if (!group) @@ -181,6 +210,12 @@ InjectedScript.prototype = { } }, + releaseObject: function(objectId) + { + var parsedObjectId = this._parseObjectId(objectId); + delete this._idToWrappedObject[parsedObjectId.id]; + }, + _populatePropertyNames: function(object, resultSet) { for (var o = object; o; o = o.__proto__) { @@ -200,57 +235,23 @@ InjectedScript.prototype = { return Object.keys(propertyNameSet); }, - getCompletions: function(expression, includeCommandLineAPI) + evaluate: function(expression, objectGroup, injectCommandLineAPI) { - var props = {}; - try { - if (!expression) - expression = "this"; - var expressionResult = this._evaluateOn(inspectedWindow.eval, inspectedWindow, expression, false, false); - - if (typeof expressionResult === "object") - this._populatePropertyNames(expressionResult, props); - - if (includeCommandLineAPI) { - for (var prop in CommandLineAPI.members_) - props[CommandLineAPI.members_[prop]] = true; - } - } catch(e) { - } - return props; + return this._evaluateAndWrap(inspectedWindow.eval, inspectedWindow, expression, objectGroup, false, injectCommandLineAPI); }, - getCompletionsOnCallFrame: function(callFrameId, expression, includeCommandLineAPI) + evaluateOn: function(objectId, expression) { - var props = {}; + var parsedObjectId = this._parseObjectId(objectId); + var object = this._objectForId(parsedObjectId); + if (!object) + return false; try { - var callFrame = this._callFrameForId(callFrameId); - if (!callFrame) - return props; - - if (expression) { - var expressionResult = this._evaluateOn(callFrame.evaluate, callFrame, expression, true, false); - if (typeof expressionResult === "object") - this._populatePropertyNames(expressionResult, props); - } else { - // Evaluate into properties in scope of the selected call frame. - var scopeChain = callFrame.scopeChain; - for (var i = 0; i < scopeChain.length; ++i) - this._populatePropertyNames(scopeChain[i], props); - } - - if (includeCommandLineAPI) { - for (var prop in CommandLineAPI.members_) - props[CommandLineAPI.members_[prop]] = true; - } - } catch(e) { + inspectedWindow.console._objectToEvaluateOn = object; + return this._evaluateAndWrap(inspectedWindow.eval, inspectedWindow, "(function() {" + expression + "}).call(window.console._objectToEvaluateOn)", parsedObjectId.objectGroup, false, false); + } finally { + delete inspectedWindow.console._objectToEvaluateOn; } - return props; - }, - - evaluate: function(expression, objectGroup, injectCommandLineAPI) - { - return this._evaluateAndWrap(inspectedWindow.eval, inspectedWindow, expression, objectGroup, false, injectCommandLineAPI); }, _evaluateAndWrap: function(evalFunction, object, expression, objectGroup, isEvalOnCallFrame, injectCommandLineAPI) @@ -287,18 +288,13 @@ InjectedScript.prototype = { } }, - getNodeId: function(node) - { - return InjectedScriptHost.pushNodePathToFrontend(node, false, false); - }, - callFrames: function() { var callFrame = InjectedScriptHost.currentCallFrame(); if (!callFrame) return false; - injectedScript.releaseWrapperObjectGroup("backtrace"); + injectedScript.releaseObjectGroup("backtrace"); var result = []; var depth = 0; do { @@ -326,68 +322,23 @@ InjectedScript.prototype = { return callFrame; }, - _nodeForId: function(nodeId) - { - if (!nodeId) - return null; - return InjectedScriptHost.nodeForId(nodeId); - }, - _objectForId: function(objectId) { return this._idToWrappedObject[objectId.id]; }, - resolveNode: function(nodeId) - { - var node = this._nodeForId(nodeId); - if (!node) - return false; - // FIXME: receive the object group from client. - return this._wrapObject(node, "prototype"); - }, - - getNodeProperties: function(nodeId, properties) - { - var node = this._nodeForId(nodeId); - if (!node) - return false; - properties = eval("(" + properties + ")"); - var result = {}; - for (var i = 0; i < properties.length; ++i) - result[properties[i]] = node[properties[i]]; - return result; - }, - - getNodePrototypes: function(nodeId) - { - this.releaseWrapperObjectGroup("prototypes"); - var node = this._nodeForId(nodeId); - if (!node) - return false; - - var result = []; - var prototype = node; - do { - result.push(this._wrapObject(prototype, "prototypes")); - prototype = prototype.__proto__; - } while (prototype) - return result; - }, - - pushNodeToFrontend: function(objectId) + nodeForObjectId: function(objectId) { var parsedObjectId = this._parseObjectId(objectId); var object = this._objectForId(parsedObjectId); if (!object || this._type(object) !== "node") - return false; - return InjectedScriptHost.pushNodePathToFrontend(object, false, false); + return null; + return object; }, - evaluateOnSelf: function(funcBody, args) + resolveNode: function(node) { - var func = eval("(" + funcBody + ")"); - return func.apply(this, eval("(" + args + ")") || []); + return this._wrapObject(node); }, _isDefined: function(object) @@ -510,7 +461,7 @@ InjectedScript.RemoteObject.fromObject = function(object, objectId, abbreviate) { var type = injectedScript._type(object); var rawType = typeof object; - var hasChildren = (rawType === "object" && object !== null && (Object.getOwnPropertyNames(object).length || !!object.__proto__)) || rawType === "function"; + var hasChildren = (rawType === "object" && object !== null && (!!Object.getOwnPropertyNames(object).length || !!object.__proto__)) || rawType === "function"; var description = ""; try { var description = injectedScript._describe(object, abbreviate); @@ -697,22 +648,7 @@ CommandLineAPIImpl.prototype = { inspect: function(object) { - if (arguments.length === 0) - return; - - inspectedWindow.console.log(object); - if (injectedScript._type(object) === "node") - InjectedScriptHost.pushNodePathToFrontend(object, false, true); - else { - switch (injectedScript._describe(object)) { - case "Database": - InjectedScriptHost.selectDatabase(object); - break; - case "Storage": - InjectedScriptHost.selectDOMStorage(object); - break; - } - } + return injectedScript._inspect(object); }, copy: function(object) @@ -729,8 +665,7 @@ CommandLineAPIImpl.prototype = { _inspectedNode: function(num) { - var nodeId = InjectedScriptHost.inspectedNode(num); - return injectedScript._nodeForId(nodeId); + return InjectedScriptHost.inspectedNode(num); }, _normalizeEventTypes: function(types) diff --git a/Source/WebCore/inspector/Inspector.idl b/Source/WebCore/inspector/Inspector.idl index 80c24db..216d4b1 100644 --- a/Source/WebCore/inspector/Inspector.idl +++ b/Source/WebCore/inspector/Inspector.idl @@ -38,37 +38,32 @@ module core { void openInInspectedWindow(in String url); void setSearchingForNode(in boolean enabled, out boolean newState); - [notify] void frontendReused(); - [notify] void addNodesToSearchResult(out Array nodeIds); - [notify] void bringToFront(); - [notify] void disconnectFromBackend(); - [notify] void inspectedURLChanged(out String url); - [notify] void domContentEventFired(out double time); - [notify] void loadEventFired(out double time); - [notify] void reset(); - [notify] void showPanel(out String panel); - - [notify] void evaluateForTestInFrontend(out long testCallId, out String script); + [event] void frontendReused(); + [event] void bringToFront(); + [event] void disconnectFromBackend(); + [event] void inspectedURLChanged(out String url); + [event] void domContentEventFired(out double time); + [event] void loadEventFired(out double time); + [event] void reset(); + [event] void showPanel(out String panel); + + [event] void evaluateForTestInFrontend(out long testCallId, out String script); void didEvaluateForTestInFrontend(in long testCallId, in String jsonResult); void highlightDOMNode(in long nodeId); void hideDOMNodeHighlight(); void highlightFrame(in unsigned long frameId); void hideFrameHighlight(); - [notify] void updateFocusedNode(out long nodeId); void setUserAgentOverride(in String userAgent); void getCookies(out Array cookies, out String cookiesString); void deleteCookie(in String cookieName, in String domain); - // FIXME: dispatch on agents. - void startTimelineProfiler(); - void stopTimelineProfiler(); + [event] void inspect(out Object objectId, out Object hints); + // FIXME: dispatch on agents. #if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER - void enableDebugger(); - void disableDebugger(); void enableProfiler(); void disableProfiler(); void startProfiling(); @@ -78,46 +73,44 @@ module core { interface [Conditional=INSPECTOR] Runtime { void evaluate(in String expression, in String objectGroup, in boolean includeCommandLineAPI, out Value result); - void getCompletions(in String expression, in boolean includeCommandLineAPI, out Value result); + void evaluateOn(in Object objectId, in String expression, out Value result); void getProperties(in Object objectId, in boolean ignoreHasOwnProperty, in boolean abbreviate, out Value result); void setPropertyValue(in Object objectId, in String propertyName, in String expression, out Value result); - void releaseWrapperObjectGroup(in long injectedScriptId, in String objectGroup); - }; - - interface [Conditional=INSPECTOR] InjectedScript { - void evaluateOnSelf(in String functionBody, in Array argumentsArray, out Value result); + void releaseObject(in Object objectId); + void releaseObjectGroup(in long injectedScriptId, in String objectGroup); }; interface [Conditional=INSPECTOR] Console { void setConsoleMessagesEnabled(in boolean enabled, out boolean newState); - [notify] void addConsoleMessage(out Object messageObj); - [notify] void updateConsoleMessageExpiredCount(out unsigned long count); - [notify] void updateConsoleMessageRepeatCount(out unsigned long count); + [event] void addConsoleMessage(out Object messageObj); + [event] void updateConsoleMessageExpiredCount(out unsigned long count); + [event] void updateConsoleMessageRepeatCount(out unsigned long count); void clearConsoleMessages(); - [notify] void consoleMessagesCleared(); + [event] void consoleMessagesCleared(); void setMonitoringXHREnabled(in boolean enabled); }; interface [Conditional=INSPECTOR] Network { - void cachedResources(out Object resources); + void enable(out Object resources); + void disable(); void resourceContent(in unsigned long frameId, in String url, in boolean base64Encode, out boolean success, out String content); void setExtraHeaders(in Object headers); - [notify] void frameDetachedFromParent(out unsigned long frameId); - [notify] void identifierForInitialRequest(out long identifier, out String url, out Object loader, out Value callStack); - [notify] void willSendRequest(out long identifier, out double time, out Object request, out Object redirectResponse); - [notify] void markResourceAsCached(out long identifier); - [notify] void didReceiveResponse(out long identifier, out double time, out String resourceType, out Object response); - [notify] void didReceiveContentLength(out long identifier, out double time, out long lengthReceived); - [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 setInitialContent(out long identifier, out String sourceString, out String type); - [notify] void didCommitLoadForFrame(out Object frame, out Object loader); - [notify] void didCreateWebSocket(out unsigned long identifier, out String requestURL); - [notify] void willSendWebSocketHandshakeRequest(out unsigned long identifier, out double time, out Object request); - [notify] void didReceiveWebSocketHandshakeResponse(out unsigned long identifier, out double time, out Object response); - [notify] void didCloseWebSocket(out unsigned long identifier, out double time); + [event] void frameDetachedFromParent(out unsigned long frameId); + [event] void identifierForInitialRequest(out long identifier, out String url, out Object loader, out Value callStack); + [event] void willSendRequest(out long identifier, out double time, out Object request, out Object redirectResponse); + [event] void markResourceAsCached(out long identifier); + [event] void didReceiveResponse(out long identifier, out double time, out String resourceType, out Object response); + [event] void didReceiveContentLength(out long identifier, out double time, out long lengthReceived); + [event] void didFinishLoading(out long identifier, out double finishTime); + [event] void didFailLoading(out long identifier, out double time, out String localizedDescription); + [event] void didLoadResourceFromMemoryCache(out double time, out Object resource); + [event] void setInitialContent(out long identifier, out String sourceString, out String type); + [event] void didCommitLoadForFrame(out Object frame, out Object loader); + [event] void didCreateWebSocket(out unsigned long identifier, out String requestURL); + [event] void willSendWebSocketHandshakeRequest(out unsigned long identifier, out double time, out Object request); + [event] void didReceiveWebSocketHandshakeResponse(out unsigned long identifier, out double time, out Object response); + [event] void didCloseWebSocket(out unsigned long identifier, out double time); }; #if defined(ENABLE_DATABASE) && ENABLE_DATABASE @@ -125,10 +118,9 @@ module core { void getDatabaseTableNames(in long databaseId, out Array tableNames); void executeSQL(in long databaseId, in String query, out boolean success, out long transactionId); - [notify] void addDatabase(out Object database); - [notify] void selectDatabase(out int databaseId); - [notify] void sqlTransactionSucceeded(out long transactionId, out Value columnNames, out Value values); - [notify] void sqlTransactionFailed(out long transactionId, out Value sqlError); + [event] void addDatabase(out Object database); + [event] void sqlTransactionSucceeded(out long transactionId, out Value columnNames, out Value values); + [event] void sqlTransactionFailed(out long transactionId, out Value sqlError); }; #endif @@ -137,22 +129,24 @@ module core { void getDOMStorageEntries(in long storageId, out Array entries); void setDOMStorageItem(in long storageId, in String key, in String value, out boolean success); void removeDOMStorageItem(in long storageId, in String key, out boolean success); - [notify] void addDOMStorage(out Object storage); - [notify] void updateDOMStorage(out int storageId); - [notify] void selectDOMStorage(out int storageId); + [event] void addDOMStorage(out Object storage); + [event] void updateDOMStorage(out int storageId); }; #endif #if defined(ENABLE_OFFLINE_WEB_APPLICATIONS) && ENABLE_OFFLINE_WEB_APPLICATIONS interface [Conditional=INSPECTOR] ApplicationCache { void getApplicationCaches(out Value applicationCaches); - [notify] void updateApplicationCacheStatus(out int status); - [notify] void updateNetworkState(out boolean isNowOnline); + [event] void updateApplicationCacheStatus(out int status); + [event] void updateNetworkState(out boolean isNowOnline); }; #endif interface [Conditional=INSPECTOR] DOM { + void getDocument(out Object root); void getChildNodes(in long nodeId); + void querySelector(in long nodeId, in String selectors, in boolean documentWide, out long elementId); + void querySelectorAll(in long nodeId, in String selectors, in boolean documentWide, out Array result); void setAttribute(in long elementId, in String name, in String value, out boolean success); void removeAttribute(in long elementId, in String name, out boolean success); void setTextNodeValue(in long nodeId, in String value, out boolean success); @@ -166,19 +160,18 @@ module core { void performSearch(in String query, in boolean runSynchronously); void searchCanceled(); void pushNodeByPathToFrontend(in String path, out long nodeId); - void resolveNode(in long nodeId, out Value result); - void getNodeProperties(in long nodeId, in Array propertiesArray, out Value result); - void getNodePrototypes(in long nodeId, out Value result); - void pushNodeToFrontend(in Object objectId, out Value result); - - [notify] void setDocument(out Value root); // FIXME: should be requested from the front-end as getDocument. - [notify] void attributesUpdated(out long id, out Array attributes); - [notify] void characterDataModified(out long id, out String newValue); - [notify] void setChildNodes(out long parentId, out Array nodes); - [notify] void setDetachedRoot(out Object root); - [notify] void childNodeCountUpdated(out long id, out int newValue); - [notify] void childNodeInserted(out long parentId, out long prevId, out Object node); - [notify] void childNodeRemoved(out long parentId, out long id); + void resolveNode(in long nodeId, in String objectGroup, out Value result); + void pushNodeToFrontend(in Object objectId, out long nodeId); + + [event] void addNodesToSearchResult(out Array nodeIds); + [event] void documentUpdated(); + [event] void setChildNodes(out long parentId, out Array nodes); + [event] void attributesUpdated(out long id, out Array attributes); + [event] void characterDataModified(out long id, out String newValue); + [event] void setDetachedRoot(out Object root); + [event] void childNodeCountUpdated(out long id, out int newValue); + [event] void childNodeInserted(out long parentId, out long prevId, out Object node); + [event] void childNodeRemoved(out long parentId, out long id); }; interface [Conditional=INSPECTOR] CSS { @@ -194,22 +187,25 @@ module core { void setRuleSelector(in Object ruleId, in String selector, out Value rule); void addRule(in long contextNodeId, in String selector, out Value rule); void getSupportedCSSProperties(out Array cssProperties); - void querySelectorAll(in long documentId, in String selector, out Array result); }; interface [Conditional=INSPECTOR] Timeline { - [notify] void timelineProfilerWasStarted(); - [notify] void timelineProfilerWasStopped(); - [notify] void addRecordToTimeline(out Object record); + void start(); + void stop(); + [event] void timelineProfilerWasStarted(); + [event] void timelineProfilerWasStopped(); + [event] void addRecordToTimeline(out Object record); }; #if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER interface [Conditional=INSPECTOR] Debugger { - [notify] void debuggerWasEnabled(); - [notify] void debuggerWasDisabled(); + void enable(); + void disable(); + [event] void debuggerWasEnabled(); + [event] void debuggerWasDisabled(); - [notify] void parsedScriptSource(out String sourceID, out String url, out int lineOffset, out int columnOffset, out int length, out int scriptWorldType); - [notify] void failedToParseScriptSource(out String url, out String data, out int firstLine, out int errorLine, out String errorMessage); + [event] void parsedScriptSource(out String sourceID, out String url, out int lineOffset, out int columnOffset, out int length, out int scriptWorldType); + [event] void failedToParseScriptSource(out String url, out String data, out int firstLine, out int errorLine, out String errorMessage); void activateBreakpoints(); void deactivateBreakpoints(); @@ -217,16 +213,16 @@ module core { void setJavaScriptBreakpoint(in String url, in int lineNumber, in int columnNumber, in String condition, in boolean enabled, out String breakpointId, out Array locations); void setJavaScriptBreakpointBySourceId(in String sourceId, in int lineNumber, in int columnNumber, in String condition, in boolean enabled, out String breakpointId, out int actualLineNumber, out int actualColumnNumber); void removeJavaScriptBreakpoint(in String breakpointId); - [notify] void breakpointResolved(out String breakpointId, out String sourceId, out int lineNumber, out int columnNumber); + [event] void breakpointResolved(out String breakpointId, out String sourceId, out int lineNumber, out int columnNumber); void continueToLocation(in String sourceId, in int lineNumber, in int columnNumber); void stepOver(); void stepInto(); void stepOut(); void pause(); - [notify] void pausedScript(out Object details); + [event] void pausedScript(out Object details); void resume(); - [notify] void resumedScript(); // FIXME: Make this out parameter of resume if possible. + [event] void resumedScript(); // FIXME: Make this out parameter of resume if possible. void editScriptSource(in String sourceID, in String newContent, out boolean success, out String result, out Value newCallFrames); void getScriptSource(in String sourceID, out String scriptSource); @@ -234,11 +230,10 @@ module core { void setPauseOnExceptionsState(in long pauseOnExceptionsState, out long newState); void evaluateOnCallFrame(in Object callFrameId, in String expression, in String objectGroup, in boolean includeCommandLineAPI, out Value result); - void getCompletionsOnCallFrame(in Object callFrameId, in String expression, in boolean includeCommandLineAPI, out Value result); #if defined(ENABLE_WORKERS) && ENABLE_WORKERS - [notify] void didCreateWorker(out long id, out String url, out boolean isShared); - [notify] void didDestroyWorker(out long id); + [event] void didCreateWorker(out long id, out String url, out boolean isShared); + [event] void didDestroyWorker(out long id); #endif // ENABLE_WORKERS }; @@ -258,8 +253,8 @@ module core { #if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER interface [Conditional=INSPECTOR] Profiler { - [notify] void profilerWasEnabled(); - [notify] void profilerWasDisabled(); + [event] void profilerWasEnabled(); + [event] void profilerWasDisabled(); void getProfileHeaders(out Array headers); void getProfile(in String type, in unsigned long uid, out Object profile); @@ -268,12 +263,13 @@ module core { // FIXME: split into Profiler and HeapProfiler. void takeHeapSnapshot(in boolean detailed); - [notify] void addProfileHeader(out Object header); - [notify] void addHeapSnapshotChunk(out unsigned long uid, out String chunk); - [notify] void finishHeapSnapshot(out unsigned long uid); - [notify] void setRecordingProfile(out boolean isProfiling); - [notify] void resetProfiles(); - [notify] void reportHeapSnapshotProgress(out int done, out int total); + void getExactHeapSnapshotNodeRetainedSize(in unsigned long uid, in unsigned long nodeId, out long size); + [event] void addProfileHeader(out Object header); + [event] void addHeapSnapshotChunk(out unsigned long uid, out String chunk); + [event] void finishHeapSnapshot(out unsigned long uid); + [event] void setRecordingProfile(out boolean isProfiling); + [event] void resetProfiles(); + [event] void reportHeapSnapshotProgress(out int done, out int total); }; #endif // ENABLE_JAVASCRIPT_DEBUGGER } diff --git a/Source/WebCore/inspector/InspectorAgent.cpp b/Source/WebCore/inspector/InspectorAgent.cpp index 9559099..15ceba0 100644 --- a/Source/WebCore/inspector/InspectorAgent.cpp +++ b/Source/WebCore/inspector/InspectorAgent.cpp @@ -62,8 +62,6 @@ #include "InspectorConsoleAgent.h" #include "InspectorController.h" #include "InspectorDOMAgent.h" -#include "InspectorDOMStorageResource.h" -#include "InspectorDatabaseResource.h" #include "InspectorDebuggerAgent.h" #include "InspectorFrontend.h" #include "InspectorFrontendClient.h" @@ -75,6 +73,7 @@ #include "InspectorTimelineAgent.h" #include "InspectorValues.h" #include "InspectorWorkerResource.h" +#include "InstrumentingAgents.h" #include "IntRect.h" #include "Page.h" #include "ProgressTracker.h" @@ -106,14 +105,11 @@ #include <wtf/text/StringConcatenate.h> #if ENABLE(DATABASE) -#include "Database.h" #include "InspectorDatabaseAgent.h" #endif #if ENABLE(DOM_STORAGE) #include "InspectorDOMStorageAgent.h" -#include "Storage.h" -#include "StorageArea.h" #endif #if ENABLE(OFFLINE_WEB_APPLICATIONS) @@ -140,13 +136,29 @@ InspectorAgent::InspectorAgent(Page* page, InspectorClient* client) : m_inspectedPage(page) , m_client(client) , m_frontend(0) - , m_cssAgent(new InspectorCSSAgent()) - , m_state(new InspectorState(client)) + , m_instrumentingAgents(new InstrumentingAgents()) , m_injectedScriptHost(InjectedScriptHost::create(this)) - , m_consoleAgent(new InspectorConsoleAgent(this)) + , m_state(new InspectorState(client)) + , m_domAgent(InspectorDOMAgent::create(m_instrumentingAgents.get(), m_state.get(), m_injectedScriptHost.get())) + , m_cssAgent(new InspectorCSSAgent(m_instrumentingAgents.get(), m_domAgent.get())) +#if ENABLE(DATABASE) + , m_databaseAgent(InspectorDatabaseAgent::create(m_instrumentingAgents.get())) +#endif +#if ENABLE(DOM_STORAGE) + , m_domStorageAgent(InspectorDOMStorageAgent::create(m_instrumentingAgents.get())) +#endif + , m_timelineAgent(InspectorTimelineAgent::create(m_instrumentingAgents.get(), m_state.get())) +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + , m_applicationCacheAgent(new InspectorApplicationCacheAgent(m_instrumentingAgents.get(), page)) +#endif + , m_resourceAgent(InspectorResourceAgent::create(m_instrumentingAgents.get(), page, m_state.get())) + , m_consoleAgent(new InspectorConsoleAgent(m_instrumentingAgents.get(), this, m_state.get(), m_injectedScriptHost.get(), m_domAgent.get())) #if ENABLE(JAVASCRIPT_DEBUGGER) - , m_profilerAgent(InspectorProfilerAgent::create(this)) + , m_debuggerAgent(InspectorDebuggerAgent::create(m_instrumentingAgents.get(), m_state.get(), page, m_injectedScriptHost.get())) + , m_browserDebuggerAgent(InspectorBrowserDebuggerAgent::create(m_instrumentingAgents.get(), m_state.get(), m_domAgent.get(), m_debuggerAgent.get(), this)) + , m_profilerAgent(InspectorProfilerAgent::create(m_instrumentingAgents.get(), m_consoleAgent.get(), page)) #endif + , m_canIssueEvaluateForTestInFrontend(false) { ASSERT_ARG(page, page); ASSERT_ARG(client, client); @@ -163,14 +175,17 @@ InspectorAgent::~InspectorAgent() void InspectorAgent::inspectedPageDestroyed() { - if (m_frontend) - m_frontend->disconnectFromBackend(); + if (m_frontend) { + m_frontend->inspector()->disconnectFromBackend(); + disconnectFrontend(); + } - hideHighlight(); + ErrorString error; + hideHighlight(&error); #if ENABLE(JAVASCRIPT_DEBUGGER) - m_debuggerAgent.clear(); m_browserDebuggerAgent.clear(); + m_debuggerAgent.clear(); #endif ASSERT(m_inspectedPage); @@ -191,17 +206,17 @@ bool InspectorAgent::searchingForNodeInPage() const void InspectorAgent::restoreInspectorStateFromCookie(const String& inspectorStateCookie) { - m_state = new InspectorState(m_client, inspectorStateCookie); + m_state->loadFromCookie(inspectorStateCookie); - m_frontend->frontendReused(); - m_frontend->inspectedURLChanged(inspectedURL().string()); + m_frontend->inspector()->frontendReused(); + m_frontend->inspector()->inspectedURLChanged(inspectedURL().string()); pushDataCollectedOffline(); - m_resourceAgent = InspectorResourceAgent::restore(m_inspectedPage, m_state.get(), m_frontend); - m_timelineAgent = InspectorTimelineAgent::restore(m_state.get(), m_frontend); + m_resourceAgent->restore(); + m_timelineAgent->restore(); #if ENABLE(JAVASCRIPT_DEBUGGER) - restoreDebugger(false); + m_debuggerAgent->restore(); restoreProfiler(ProfilerRestoreResetAgent); if (m_state->getBoolean(InspectorAgentState::userInitiatedProfiling)) startUserInitiatedProfiling(); @@ -228,12 +243,24 @@ void InspectorAgent::focusNode() ASSERT(m_frontend); ASSERT(m_nodeToFocus); - long id = m_domAgent->pushNodePathToFrontend(m_nodeToFocus.get()); - m_frontend->updateFocusedNode(id); + RefPtr<Node> node = m_nodeToFocus.get(); m_nodeToFocus = 0; + + Document* document = node->ownerDocument(); + if (!document) + return; + Frame* frame = document->frame(); + if (!frame) + return; + + InjectedScript injectedScript = m_injectedScriptHost->injectedScriptFor(mainWorldScriptState(frame)); + if (injectedScript.hasNoValue()) + return; + + injectedScript.inspectNode(node.get()); } -void InspectorAgent::highlight(Node* node) +void InspectorAgent::highlight(ErrorString*, Node* node) { if (!enabled()) return; @@ -242,25 +269,25 @@ void InspectorAgent::highlight(Node* node) m_client->highlight(node); } -void InspectorAgent::highlightDOMNode(long nodeId) +void InspectorAgent::highlightDOMNode(ErrorString* error, long nodeId) { Node* node = 0; if (m_domAgent && (node = m_domAgent->nodeForId(nodeId))) - highlight(node); + highlight(error, node); } -void InspectorAgent::highlightFrame(unsigned long frameId) +void InspectorAgent::highlightFrame(ErrorString* error, unsigned long frameId) { Frame* mainFrame = m_inspectedPage->mainFrame(); for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext(mainFrame)) { if (reinterpret_cast<uintptr_t>(frame) == frameId && frame->ownerElement()) { - highlight(frame->ownerElement()); + highlight(error, frame->ownerElement()); return; } } } -void InspectorAgent::hideHighlight() +void InspectorAgent::hideHighlight(ErrorString*) { if (!enabled()) return; @@ -276,8 +303,10 @@ void InspectorAgent::mouseDidMoveOverElement(const HitTestResult& result, unsign Node* node = result.innerNode(); while (node && node->nodeType() == Node::TEXT_NODE) node = node->parentNode(); - if (node) - highlight(node); + if (node) { + ErrorString error; + highlight(&error, node); + } } bool InspectorAgent::handleMousePress() @@ -320,11 +349,13 @@ void InspectorAgent::setSearchingForNode(bool enabled) if (searchingForNodeInPage() == enabled) return; m_state->setBoolean(InspectorAgentState::searchingForNode, enabled); - if (!enabled) - hideHighlight(); + if (!enabled) { + ErrorString error; + hideHighlight(&error); + } } -void InspectorAgent::setSearchingForNode(bool enabled, bool* newState) +void InspectorAgent::setSearchingForNode(ErrorString*, bool enabled, bool* newState) { *newState = enabled; setSearchingForNode(enabled); @@ -332,14 +363,31 @@ void InspectorAgent::setSearchingForNode(bool enabled, bool* newState) void InspectorAgent::setFrontend(InspectorFrontend* inspectorFrontend) { + // We can reconnect to existing front-end -> unmute state. + m_state->unmute(); + m_frontend = inspectorFrontend; createFrontendLifetimeAgents(); - m_cssAgent->setDOMAgent(m_domAgent.get()); +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + m_applicationCacheAgent->setFrontend(m_frontend); +#endif + m_domAgent->setFrontend(m_frontend); m_consoleAgent->setFrontend(m_frontend); - + m_timelineAgent->setFrontend(m_frontend); + m_resourceAgent->setFrontend(m_frontend); +#if ENABLE(JAVASCRIPT_DEBUGGER) + m_debuggerAgent->setFrontend(m_frontend); + m_browserDebuggerAgent->setFrontend(m_frontend); +#endif +#if ENABLE(DATABASE) + m_databaseAgent->setFrontend(m_frontend); +#endif +#if ENABLE(DOM_STORAGE) + m_domStorageAgent->setFrontend(m_frontend); +#endif // Initialize Web Inspector title. - m_frontend->inspectedURLChanged(inspectedURL().string()); + m_frontend->inspector()->inspectedURLChanged(inspectedURL().string()); } void InspectorAgent::disconnectFrontend() @@ -347,82 +395,58 @@ void InspectorAgent::disconnectFrontend() if (!m_frontend) return; + m_canIssueEvaluateForTestInFrontend = false; + m_pendingEvaluateTestCommands.clear(); + // Destroying agents would change the state, but we don't want that. // Pre-disconnect state will be used to restore inspector agents. m_state->mute(); m_frontend = 0; + ErrorString error; #if ENABLE(JAVASCRIPT_DEBUGGER) - // If the window is being closed with the debugger enabled, - // remember this state to re-enable debugger on the next window - // opening. - disableDebugger(); + m_debuggerAgent->clearFrontend(); + m_browserDebuggerAgent->clearFrontend(); #endif setSearchingForNode(false); - hideHighlight(); + hideHighlight(&error); #if ENABLE(JAVASCRIPT_DEBUGGER) - m_profilerAgent->setFrontend(0); + m_profilerAgent->clearFrontend(); m_profilerAgent->stopUserInitiatedProfiling(true); #endif +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + m_applicationCacheAgent->clearFrontend(); +#endif - m_consoleAgent->setFrontend(0); + m_consoleAgent->clearFrontend(); + m_domAgent->clearFrontend(); + m_timelineAgent->clearFrontend(); + m_resourceAgent->clearFrontend(); +#if ENABLE(DATABASE) + m_databaseAgent->clearFrontend(); +#endif +#if ENABLE(DOM_STORAGE) + m_domStorageAgent->clearFrontend(); +#endif releaseFrontendLifetimeAgents(); m_userAgentOverride = ""; } -InspectorResourceAgent* InspectorAgent::resourceAgent() -{ - if (!m_resourceAgent && m_frontend) - m_resourceAgent = InspectorResourceAgent::create(m_inspectedPage, m_state.get(), m_frontend); - return m_resourceAgent.get(); -} - void InspectorAgent::createFrontendLifetimeAgents() { - m_domAgent = InspectorDOMAgent::create(m_injectedScriptHost.get(), m_frontend); m_runtimeAgent = InspectorRuntimeAgent::create(m_injectedScriptHost.get()); - -#if ENABLE(DATABASE) - m_databaseAgent = InspectorDatabaseAgent::create(&m_databaseResources, m_frontend); -#endif - -#if ENABLE(DOM_STORAGE) - m_domStorageAgent = InspectorDOMStorageAgent::create(&m_domStorageResources, m_frontend); -#endif - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - m_applicationCacheAgent = new InspectorApplicationCacheAgent(m_inspectedPage->mainFrame()->loader()->documentLoader(), m_frontend); -#endif } void InspectorAgent::releaseFrontendLifetimeAgents() { - m_resourceAgent.clear(); m_runtimeAgent.clear(); - m_timelineAgent.clear(); - -#if ENABLE(DATABASE) - m_databaseAgent.clear(); -#endif - -#if ENABLE(DOM_STORAGE) - m_domStorageAgent.clear(); -#endif - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - m_applicationCacheAgent.clear(); -#endif - - // This should be invoked prior to m_domAgent destruction. - m_cssAgent->setDOMAgent(0); - m_domAgent.clear(); } -void InspectorAgent::populateScriptObjects() +void InspectorAgent::populateScriptObjects(ErrorString*) { ASSERT(m_frontend); if (!m_frontend) @@ -430,7 +454,7 @@ void InspectorAgent::populateScriptObjects() #if ENABLE(JAVASCRIPT_DEBUGGER) if (m_profilerAgent->enabled()) - m_frontend->profilerWasEnabled(); + m_frontend->profiler()->profilerWasEnabled(); #endif pushDataCollectedOffline(); @@ -438,59 +462,42 @@ void InspectorAgent::populateScriptObjects() if (m_nodeToFocus) focusNode(); - if (!m_requiredPanel.isEmpty()) { - m_frontend->showPanel(m_requiredPanel); - m_requiredPanel = ""; + if (!m_showPanelAfterVisible.isEmpty()) { + m_frontend->inspector()->showPanel(m_showPanelAfterVisible); + m_showPanelAfterVisible = ""; } - restoreDebugger(true); +#if ENABLE(JAVASCRIPT_DEBUGGER) + m_debuggerAgent->enableDebuggerAfterShown(); +#endif restoreProfiler(ProfilerRestoreNoAction); // Dispatch pending frontend commands - for (Vector<pair<long, String> >::iterator it = m_pendingEvaluateTestCommands.begin(); it != m_pendingEvaluateTestCommands.end(); ++it) - m_frontend->evaluateForTestInFrontend((*it).first, (*it).second); - m_pendingEvaluateTestCommands.clear(); + issueEvaluateForTestCommands(); } void InspectorAgent::pushDataCollectedOffline() { m_domAgent->setDocument(m_inspectedPage->mainFrame()->document()); -#if ENABLE(DATABASE) - DatabaseResourcesMap::iterator databasesEnd = m_databaseResources.end(); - for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it) - it->second->bind(m_frontend); -#endif -#if ENABLE(DOM_STORAGE) - DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end(); - for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it) - it->second->bind(m_frontend); -#endif #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(WORKERS) WorkersMap::iterator workersEnd = m_workers.end(); for (WorkersMap::iterator it = m_workers.begin(); it != workersEnd; ++it) { InspectorWorkerResource* worker = it->second.get(); - m_frontend->didCreateWorker(worker->id(), worker->url(), worker->isSharedWorker()); + m_frontend->debugger()->didCreateWorker(worker->id(), worker->url(), worker->isSharedWorker()); } #endif } -void InspectorAgent::restoreDebugger(bool eraseStickyBreakpoints) -{ - ASSERT(m_frontend); -#if ENABLE(JAVASCRIPT_DEBUGGER) - if (m_state->getBoolean(InspectorAgentState::debuggerEnabled)) - enableDebugger(eraseStickyBreakpoints); -#endif -} - void InspectorAgent::restoreProfiler(ProfilerRestoreAction action) { ASSERT(m_frontend); #if ENABLE(JAVASCRIPT_DEBUGGER) m_profilerAgent->setFrontend(m_frontend); - if (m_state->getBoolean(InspectorAgentState::profilerEnabled)) - enableProfiler(); + if (m_state->getBoolean(InspectorAgentState::profilerEnabled)) { + ErrorString error; + enableProfiler(&error); + } if (action == ProfilerRestoreResetAgent) m_profilerAgent->resetFrontendProfiles(); #endif @@ -498,61 +505,14 @@ void InspectorAgent::restoreProfiler(ProfilerRestoreAction action) void InspectorAgent::didCommitLoad(DocumentLoader* loader) { - if (!enabled()) - return; - - if (m_resourceAgent) - m_resourceAgent->didCommitLoad(loader); - - ASSERT(m_inspectedPage); - - if (loader->frame() == m_inspectedPage->mainFrame()) { - if (m_frontend) - m_frontend->inspectedURLChanged(loader->url().string()); - - m_injectedScriptHost->discardInjectedScripts(); - m_consoleAgent->reset(); - - if (m_timelineAgent) - m_timelineAgent->didCommitLoad(); - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - if (m_applicationCacheAgent) - m_applicationCacheAgent->didCommitLoad(loader); -#endif - -#if ENABLE(JAVASCRIPT_DEBUGGER) - if (m_debuggerAgent) { - KURL url = inspectedURLWithoutFragment(); - m_debuggerAgent->inspectedURLChanged(url); - if (m_browserDebuggerAgent) - m_browserDebuggerAgent->inspectedURLChanged(url); - } -#endif - -#if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC) - m_profilerAgent->stopUserInitiatedProfiling(true); - m_profilerAgent->resetState(); -#endif - - if (m_frontend) { - m_frontend->reset(); - m_domAgent->reset(); - m_cssAgent->reset(); - } + if (m_frontend) { + m_frontend->inspector()->inspectedURLChanged(loader->url().string()); + m_frontend->inspector()->reset(); + } + m_injectedScriptHost->discardInjectedScripts(); #if ENABLE(WORKERS) - m_workers.clear(); -#endif -#if ENABLE(DATABASE) - m_databaseResources.clear(); -#endif -#if ENABLE(DOM_STORAGE) - m_domStorageResources.clear(); + m_workers.clear(); #endif - - if (m_frontend) - m_domAgent->setDocument(m_inspectedPage->mainFrame()->document()); - } } void InspectorAgent::domContentLoadedEventFired(DocumentLoader* loader, const KURL& url) @@ -560,12 +520,12 @@ void InspectorAgent::domContentLoadedEventFired(DocumentLoader* loader, const KU if (!enabled() || !isMainResourceLoader(loader, url)) return; - if (m_domAgent) - m_domAgent->mainFrameDOMContentLoaded(); - if (m_timelineAgent) - m_timelineAgent->didMarkDOMContentEvent(); + if (InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent()) + domAgent->mainFrameDOMContentLoaded(); + if (InspectorTimelineAgent* timelineAgent = m_instrumentingAgents->inspectorTimelineAgent()) + timelineAgent->didMarkDOMContentEvent(); if (m_frontend) - m_frontend->domContentEventFired(currentTime()); + m_frontend->inspector()->domContentEventFired(currentTime()); } void InspectorAgent::loadEventFired(DocumentLoader* loader, const KURL& url) @@ -573,16 +533,16 @@ void InspectorAgent::loadEventFired(DocumentLoader* loader, const KURL& url) if (!enabled()) return; - if (m_domAgent) - m_domAgent->loadEventFired(loader->frame()->document()); + if (InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent()) + domAgent->loadEventFired(loader->frame()->document()); if (!isMainResourceLoader(loader, url)) return; - if (m_timelineAgent) - m_timelineAgent->didMarkLoadEvent(); + if (InspectorTimelineAgent* timelineAgent = m_instrumentingAgents->inspectorTimelineAgent()) + timelineAgent->didMarkLoadEvent(); if (m_frontend) - m_frontend->loadEventFired(currentTime()); + m_frontend->inspector()->loadEventFired(currentTime()); } bool InspectorAgent::isMainResourceLoader(DocumentLoader* loader, const KURL& requestUrl) @@ -590,7 +550,7 @@ bool InspectorAgent::isMainResourceLoader(DocumentLoader* loader, const KURL& re return loader->frame() == m_inspectedPage->mainFrame() && requestUrl == loader->requestURL(); } -void InspectorAgent::setUserAgentOverride(const String& userAgent) +void InspectorAgent::setUserAgentOverride(ErrorString*, const String& userAgent) { m_userAgentOverride = userAgent; } @@ -601,19 +561,6 @@ void InspectorAgent::applyUserAgentOverride(String* userAgent) const *userAgent = m_userAgentOverride; } -void InspectorAgent::startTimelineProfiler() -{ - if (m_timelineAgent || !enabled() || !m_frontend) - return; - - m_timelineAgent = InspectorTimelineAgent::create(m_state.get(), m_frontend); -} - -void InspectorAgent::stopTimelineProfiler() -{ - m_timelineAgent.clear(); -} - #if ENABLE(WORKERS) class PostWorkerNotificationToFrontendTask : public ScriptExecutionContext::Task { public: @@ -649,10 +596,10 @@ void InspectorAgent::postWorkerNotificationToFrontend(const InspectorWorkerResou #if ENABLE(JAVASCRIPT_DEBUGGER) switch (action) { case InspectorAgent::WorkerCreated: - m_frontend->didCreateWorker(worker.id(), worker.url(), worker.isSharedWorker()); + m_frontend->debugger()->didCreateWorker(worker.id(), worker.url(), worker.isSharedWorker()); break; case InspectorAgent::WorkerDestroyed: - m_frontend->didDestroyWorker(worker.id()); + m_frontend->debugger()->didDestroyWorker(worker.id()); break; } #endif @@ -683,23 +630,7 @@ void InspectorAgent::didDestroyWorker(intptr_t id) } #endif // ENABLE(WORKERS) -#if ENABLE(DATABASE) -void InspectorAgent::didOpenDatabase(PassRefPtr<Database> database, const String& domain, const String& name, const String& version) -{ - if (!enabled()) - return; - - RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version); - - m_databaseResources.set(resource->id(), resource); - - // Resources are only bound while visible. - if (m_frontend) - resource->bind(m_frontend); -} -#endif - -void InspectorAgent::getCookies(RefPtr<InspectorArray>* cookies, WTF::String* cookiesString) +void InspectorAgent::getCookies(ErrorString*, RefPtr<InspectorArray>* cookies, WTF::String* cookiesString) { // If we can get raw cookies. ListHashSet<Cookie> rawCookiesList; @@ -770,7 +701,7 @@ PassRefPtr<InspectorObject> InspectorAgent::buildObjectForCookie(const Cookie& c return value; } -void InspectorAgent::deleteCookie(const String& cookieName, const String& domain) +void InspectorAgent::deleteCookie(ErrorString*, const String& cookieName, const String& domain) { for (Frame* frame = m_inspectedPage->mainFrame(); frame; frame = frame->tree()->traverseNext(m_inspectedPage->mainFrame())) { Document* document = frame->document(); @@ -783,59 +714,6 @@ void InspectorAgent::deleteCookie(const String& cookieName, const String& domain } } -#if ENABLE(DOM_STORAGE) -void InspectorAgent::didUseDOMStorage(StorageArea* storageArea, bool isLocalStorage, Frame* frame) -{ - if (!enabled()) - return; - - DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end(); - for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it) - if (it->second->isSameHostAndType(frame, isLocalStorage)) - return; - - RefPtr<Storage> domStorage = Storage::create(frame, storageArea); - RefPtr<InspectorDOMStorageResource> resource = InspectorDOMStorageResource::create(domStorage.get(), isLocalStorage, frame); - - m_domStorageResources.set(resource->id(), resource); - - // Resources are only bound while visible. - if (m_frontend) - resource->bind(m_frontend); -} -#endif - -#if ENABLE(WEB_SOCKETS) -void InspectorAgent::didCreateWebSocket(unsigned long identifier, const KURL& requestURL, const KURL& documentURL) -{ - if (!enabled()) - return; - ASSERT(m_inspectedPage); - - if (m_resourceAgent) - m_resourceAgent->didCreateWebSocket(identifier, requestURL); - UNUSED_PARAM(documentURL); -} - -void InspectorAgent::willSendWebSocketHandshakeRequest(unsigned long identifier, const WebSocketHandshakeRequest& request) -{ - if (m_resourceAgent) - m_resourceAgent->willSendWebSocketHandshakeRequest(identifier, request); -} - -void InspectorAgent::didReceiveWebSocketHandshakeResponse(unsigned long identifier, const WebSocketHandshakeResponse& response) -{ - if (m_resourceAgent) - m_resourceAgent->didReceiveWebSocketHandshakeResponse(identifier, response); -} - -void InspectorAgent::didCloseWebSocket(unsigned long identifier) -{ - if (m_resourceAgent) - m_resourceAgent->didCloseWebSocket(identifier); -} -#endif // ENABLE(WEB_SOCKETS) - #if ENABLE(JAVASCRIPT_DEBUGGER) bool InspectorAgent::isRecordingUserInitiatedProfile() const { @@ -852,8 +730,6 @@ void InspectorAgent::startUserInitiatedProfiling() void InspectorAgent::stopUserInitiatedProfiling() { - if (!enabled()) - return; m_profilerAgent->stopUserInitiatedProfiling(); m_state->setBoolean(InspectorAgentState::userInitiatedProfiling, false); showPanel(profilesPanelName); @@ -864,7 +740,7 @@ bool InspectorAgent::profilerEnabled() const return enabled() && m_profilerAgent->enabled(); } -void InspectorAgent::enableProfiler() +void InspectorAgent::enableProfiler(ErrorString*) { if (profilerEnabled()) return; @@ -872,7 +748,7 @@ void InspectorAgent::enableProfiler() m_profilerAgent->enable(false); } -void InspectorAgent::disableProfiler() +void InspectorAgent::disableProfiler(ErrorString*) { m_state->setBoolean(InspectorAgentState::profilerEnabled, false); m_profilerAgent->disable(); @@ -880,64 +756,20 @@ void InspectorAgent::disableProfiler() #endif #if ENABLE(JAVASCRIPT_DEBUGGER) -void InspectorAgent::showAndEnableDebugger() -{ - if (!enabled()) - return; - - if (debuggerEnabled()) - return; - - if (!m_frontend) { - m_state->setBoolean(InspectorAgentState::debuggerEnabled, true); - showPanel(scriptsPanelName); - } else - enableDebugger(true); -} - -void InspectorAgent::enableDebugger(bool eraseStickyBreakpoints) -{ - if (debuggerEnabled()) - return; - m_state->setBoolean(InspectorAgentState::debuggerEnabled, true); - ASSERT(m_inspectedPage); - - m_debuggerAgent = InspectorDebuggerAgent::create(this, m_frontend, eraseStickyBreakpoints); - m_browserDebuggerAgent = InspectorBrowserDebuggerAgent::create(this, eraseStickyBreakpoints); - - m_frontend->debuggerWasEnabled(); -} - -void InspectorAgent::disableDebugger() +void InspectorAgent::showScriptsPanel() { - if (!enabled()) - return; - ASSERT(m_inspectedPage); - m_debuggerAgent.clear(); - m_browserDebuggerAgent.clear(); - - if (m_frontend) { - m_frontend->debuggerWasDisabled(); - m_state->setBoolean(InspectorAgentState::debuggerEnabled, false); - } -} - -void InspectorAgent::resume() -{ - if (m_debuggerAgent) - m_debuggerAgent->resume(); + showPanel(scriptsPanelName); } #endif void InspectorAgent::evaluateForTestInFrontend(long callId, const String& script) { - if (m_frontend) - m_frontend->evaluateForTestInFrontend(callId, script); - else - m_pendingEvaluateTestCommands.append(pair<long, String>(callId, script)); + m_pendingEvaluateTestCommands.append(pair<long, String>(callId, script)); + if (m_canIssueEvaluateForTestInFrontend) + issueEvaluateForTestCommands(); } -void InspectorAgent::didEvaluateForTestInFrontend(long callId, const String& jsonResult) +void InspectorAgent::didEvaluateForTestInFrontend(ErrorString*, long callId, const String& jsonResult) { ScriptState* scriptState = scriptStateFromPage(debuggerWorld(), m_inspectedPage); ScriptObject window; @@ -1043,7 +875,7 @@ void InspectorAgent::drawNodeHighlight(GraphicsContext& context) const IntRect boundingBox = renderer->absoluteBoundingBoxRect(true); boundingBox.move(mainFrameOffset); - IntRect titleReferenceBox = boundingBox; + IntRect titleAnchorBox = boundingBox; ASSERT(m_inspectedPage); @@ -1072,9 +904,6 @@ void InspectorAgent::drawNodeHighlight(GraphicsContext& context) const IntRect marginBox(borderBox.x() - renderBox->marginLeft(), borderBox.y() - renderBox->marginTop(), borderBox.width() + renderBox->marginLeft() + renderBox->marginRight(), borderBox.height() + renderBox->marginTop() + renderBox->marginBottom()); - titleReferenceBox = marginBox; - titleReferenceBox.move(mainFrameOffset); - titleReferenceBox.move(boundingBox.x(), boundingBox.y()); FloatQuad absContentQuad = renderBox->localToAbsoluteQuad(FloatRect(contentBox)); FloatQuad absPaddingQuad = renderBox->localToAbsoluteQuad(FloatRect(paddingBox)); @@ -1086,6 +915,8 @@ void InspectorAgent::drawNodeHighlight(GraphicsContext& context) const absBorderQuad.move(mainFrameOffset); absMarginQuad.move(mainFrameOffset); + titleAnchorBox = absMarginQuad.enclosingBoundingBox(); + drawHighlightForBox(context, absContentQuad, absPaddingQuad, absBorderQuad, absMarginQuad); } else if (renderer->isRenderInline() || isSVGRenderer) { // FIXME: We should show margins/padding/border for inlines. @@ -1103,10 +934,10 @@ void InspectorAgent::drawNodeHighlight(GraphicsContext& context) const return; WebCore::Settings* settings = containingFrame->settings(); - drawElementTitle(context, titleReferenceBox, overlayRect, settings); + drawElementTitle(context, boundingBox, titleAnchorBox, overlayRect, settings); } -void InspectorAgent::drawElementTitle(GraphicsContext& context, const IntRect& boundingBox, const FloatRect& overlayRect, WebCore::Settings* settings) const +void InspectorAgent::drawElementTitle(GraphicsContext& context, const IntRect& boundingBox, const IntRect& anchorBox, const FloatRect& overlayRect, WebCore::Settings* settings) const { static const int rectInflatePx = 4; static const int fontHeightPx = 12; @@ -1139,11 +970,10 @@ void InspectorAgent::drawElementTitle(GraphicsContext& context, const IntRect& b } } - Element* highlightedElement = m_highlightedNode->isElementNode() ? static_cast<Element*>(m_highlightedNode.get()) : 0; nodeTitle += " ["; - nodeTitle += String::number(highlightedElement ? highlightedElement->offsetWidth() : boundingBox.width()); + nodeTitle += String::number(boundingBox.width()); nodeTitle.append(static_cast<UChar>(0x00D7)); // × - nodeTitle += String::number(highlightedElement ? highlightedElement->offsetHeight() : boundingBox.height()); + nodeTitle += String::number(boundingBox.height()); nodeTitle += "]"; FontDescription desc; @@ -1155,7 +985,7 @@ void InspectorAgent::drawElementTitle(GraphicsContext& context, const IntRect& b font.update(0); TextRun nodeTitleRun(nodeTitle); - IntPoint titleBasePoint = IntPoint(boundingBox.x(), boundingBox.maxY() - 1); + IntPoint titleBasePoint = IntPoint(anchorBox.x(), anchorBox.maxY() - 1); titleBasePoint.move(rectInflatePx, rectInflatePx); IntRect titleRect = enclosingIntRect(font.selectionRectForText(nodeTitleRun, titleBasePoint, fontHeightPx)); titleRect.inflate(rectInflatePx); @@ -1174,7 +1004,7 @@ void InspectorAgent::drawElementTitle(GraphicsContext& context, const IntRect& b // If the tip sticks beyond the bottom of overlayRect, show the tip at top of bounding box. if (titleRect.maxY() > overlayRect.maxY()) { - dy = boundingBox.y() - titleRect.maxY() - borderWidthPx; + dy = anchorBox.y() - titleRect.maxY() - borderWidthPx; // If the tip still sticks beyond the bottom of overlayRect, bottom-align the tip with the said boundary. if (titleRect.maxY() + dy > overlayRect.maxY()) dy = overlayRect.maxY() - titleRect.maxY(); @@ -1193,7 +1023,7 @@ void InspectorAgent::drawElementTitle(GraphicsContext& context, const IntRect& b context.drawText(font, nodeTitleRun, IntPoint(titleRect.x() + rectInflatePx, titleRect.y() + font.fontMetrics().height())); } -void InspectorAgent::openInInspectedWindow(const String& url) +void InspectorAgent::openInInspectedWindow(ErrorString*, const String& url) { Frame* mainFrame = m_inspectedPage->mainFrame(); @@ -1211,12 +1041,12 @@ void InspectorAgent::openInInspectedWindow(const String& url) newFrame->loader()->changeLocation(mainFrame->document()->securityOrigin(), newFrame->loader()->completeURL(url), "", false, false); } -void InspectorAgent::addScriptToEvaluateOnLoad(const String& source) +void InspectorAgent::addScriptToEvaluateOnLoad(ErrorString*, const String& source) { m_scriptsToEvaluateOnLoad.append(source); } -void InspectorAgent::removeAllScriptsToEvaluateOnLoad() +void InspectorAgent::removeAllScriptsToEvaluateOnLoad(ErrorString*) { m_scriptsToEvaluateOnLoad.clear(); } @@ -1238,7 +1068,7 @@ KURL InspectorAgent::inspectedURLWithoutFragment() const return url; } -void InspectorAgent::reloadPage(bool ignoreCache) +void InspectorAgent::reloadPage(ErrorString*, bool ignoreCache) { m_inspectedPage->mainFrame()->loader()->reload(ignoreCache); } @@ -1258,10 +1088,21 @@ void InspectorAgent::showConsole() void InspectorAgent::showPanel(const String& panel) { if (!m_frontend) { - m_requiredPanel = panel; + m_showPanelAfterVisible = panel; return; } - m_frontend->showPanel(panel); + m_frontend->inspector()->showPanel(panel); +} + +void InspectorAgent::issueEvaluateForTestCommands() +{ + if (m_frontend) { + Vector<pair<long, String> > copy = m_pendingEvaluateTestCommands; + m_pendingEvaluateTestCommands.clear(); + for (Vector<pair<long, String> >::iterator it = copy.begin(); m_frontend && it != copy.end(); ++it) + m_frontend->inspector()->evaluateForTestInFrontend((*it).first, (*it).second); + m_canIssueEvaluateForTestInFrontend = true; + } } } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorAgent.h b/Source/WebCore/inspector/InspectorAgent.h index 1f14dd9..151dba5 100644 --- a/Source/WebCore/inspector/InspectorAgent.h +++ b/Source/WebCore/inspector/InspectorAgent.h @@ -62,7 +62,6 @@ class InspectorConsoleAgent; class InspectorCSSAgent; class InspectorDOMAgent; class InspectorDOMStorageAgent; -class InspectorDOMStorageResource; class InspectorDatabaseAgent; class InspectorDatabaseResource; class InspectorDebuggerAgent; @@ -77,6 +76,7 @@ class InspectorStorageAgent; class InspectorTimelineAgent; class InspectorValue; class InspectorWorkerResource; +class InstrumentingAgents; class IntRect; class KURL; class Node; @@ -94,10 +94,7 @@ class StorageArea; class InspectorApplicationCacheAgent; #endif -#if ENABLE(WEB_SOCKETS) -class WebSocketHandshakeRequest; -class WebSocketHandshakeResponse; -#endif +typedef String ErrorString; class InspectorAgent { WTF_MAKE_NONCOPYABLE(InspectorAgent); @@ -116,33 +113,33 @@ public: Page* inspectedPage() const { return m_inspectedPage; } KURL inspectedURL() const; KURL inspectedURLWithoutFragment() const; - void reloadPage(bool ignoreCache); + void reloadPage(ErrorString* error, bool ignoreCache); void showConsole(); void restoreInspectorStateFromCookie(const String& inspectorCookie); - void highlight(Node*); - void hideHighlight(); + void highlight(ErrorString* error, Node*); + void hideHighlight(ErrorString* error); void inspect(Node*); - void highlightDOMNode(long nodeId); - void hideDOMNodeHighlight() { hideHighlight(); } + void highlightDOMNode(ErrorString* error, long nodeId); + void hideDOMNodeHighlight(ErrorString* error) { hideHighlight(error); } - void highlightFrame(unsigned long frameId); - void hideFrameHighlight() { hideHighlight(); } + void highlightFrame(ErrorString* error, unsigned long frameId); + void hideFrameHighlight(ErrorString* error) { hideHighlight(error); } void setFrontend(InspectorFrontend*); InspectorFrontend* frontend() const { return m_frontend; } void disconnectFrontend(); - InspectorResourceAgent* resourceAgent(); + InstrumentingAgents* instrumentingAgents() const { return m_instrumentingAgents.get(); } InspectorAgent* inspectorAgent() { return this; } InspectorConsoleAgent* consoleAgent() { return m_consoleAgent.get(); } InspectorCSSAgent* cssAgent() { return m_cssAgent.get(); } InspectorDOMAgent* domAgent() { return m_domAgent.get(); } - InjectedScriptHost* injectedScriptAgent() { return m_injectedScriptHost.get(); } InspectorRuntimeAgent* runtimeAgent() { return m_runtimeAgent.get(); } InspectorTimelineAgent* timelineAgent() { return m_timelineAgent.get(); } + InspectorResourceAgent* resourceAgent() { return m_resourceAgent.get(); } #if ENABLE(DATABASE) InspectorDatabaseAgent* databaseAgent() { return m_databaseAgent.get(); } #endif @@ -166,11 +163,8 @@ public: void didCommitLoad(DocumentLoader*); - void startTimelineProfiler(); - void stopTimelineProfiler(); - - void getCookies(RefPtr<InspectorArray>* cookies, WTF::String* cookiesString); - void deleteCookie(const String& cookieName, const String& domain); + void getCookies(ErrorString* error, RefPtr<InspectorArray>* cookies, WTF::String* cookiesString); + void deleteCookie(ErrorString* error, const String& cookieName, const String& domain); void domContentLoadedEventFired(DocumentLoader*, const KURL&); void loadEventFired(DocumentLoader*, const KURL&); @@ -183,50 +177,30 @@ public: void didDestroyWorker(intptr_t); #endif -#if ENABLE(DATABASE) - void didOpenDatabase(PassRefPtr<Database>, const String& domain, const String& name, const String& version); -#endif - -#if ENABLE(DOM_STORAGE) - void didUseDOMStorage(StorageArea*, bool isLocalStorage, Frame*); -#endif - -#if ENABLE(WEB_SOCKETS) - void didCreateWebSocket(unsigned long identifier, const KURL& requestURL, const KURL& documentURL); - void willSendWebSocketHandshakeRequest(unsigned long identifier, const WebSocketHandshakeRequest&); - void didReceiveWebSocketHandshakeResponse(unsigned long identifier, const WebSocketHandshakeResponse&); - void didCloseWebSocket(unsigned long identifier); -#endif - bool hasFrontend() const { return m_frontend; } void drawNodeHighlight(GraphicsContext&) const; - void openInInspectedWindow(const String& url); - void drawElementTitle(GraphicsContext&, const IntRect& boundingBox, const FloatRect& overlayRect, WebCore::Settings*) const; + void openInInspectedWindow(ErrorString* error, const String& url); + void drawElementTitle(GraphicsContext&, const IntRect& boundingBox, const IntRect& anchorBox, const FloatRect& overlayRect, WebCore::Settings*) const; #if ENABLE(JAVASCRIPT_DEBUGGER) bool isRecordingUserInitiatedProfile() const; - void startProfiling() { startUserInitiatedProfiling(); } + void startProfiling(ErrorString*) { startUserInitiatedProfiling(); } void startUserInitiatedProfiling(); - void stopProfiling() { stopUserInitiatedProfiling(); } + void stopProfiling(ErrorString*) { stopUserInitiatedProfiling(); } void stopUserInitiatedProfiling(); - void enableProfiler(); - void disableProfiler(); + void enableProfiler(ErrorString* error); + void disableProfiler(ErrorString* error); bool profilerEnabled() const; - void showAndEnableDebugger(); - void enableDebugger() { enableDebugger(false); } - void enableDebugger(bool eraseStickyBreakpoints); - void disableDebugger(); - bool debuggerEnabled() const { return m_debuggerAgent; } - void resume(); + void showScriptsPanel(); #endif // Generic code called from custom implementations. void evaluateForTestInFrontend(long testCallId, const String& script); - void addScriptToEvaluateOnLoad(const String& source); - void removeAllScriptsToEvaluateOnLoad(); + void addScriptToEvaluateOnLoad(ErrorString* error, const String& source); + void removeAllScriptsToEvaluateOnLoad(ErrorString* error); void setInspectorExtensionAPI(const String& source); InspectorState* state() { return m_state.get(); } @@ -234,18 +208,17 @@ public: // InspectorAgent API void getInspectorState(RefPtr<InspectorObject>* state); void setMonitoringXHREnabled(bool enabled, bool* newState); - void populateScriptObjects(); + void populateScriptObjects(ErrorString* error); // Following are used from InspectorBackend and internally. - void setSearchingForNode(bool enabled, bool* newState); - void didEvaluateForTestInFrontend(long callId, const String& jsonResult); + void setSearchingForNode(ErrorString* error, bool enabled, bool* newState); + void didEvaluateForTestInFrontend(ErrorString* error, long callId, const String& jsonResult); - void setUserAgentOverride(const String& userAgent); + void setUserAgentOverride(ErrorString* error, const String& userAgent); void applyUserAgentOverride(String* userAgent) const; private: void showPanel(const String& panel); void pushDataCollectedOffline(); - void restoreDebugger(bool eraseStickyBreakpoints); enum ProfilerRestoreAction { ProfilerRestoreNoAction = 0, ProfilerRestoreResetAgent = 1 @@ -266,12 +239,16 @@ private: void focusNode(); bool isMainResourceLoader(DocumentLoader*, const KURL& requestUrl); + void issueEvaluateForTestCommands(); Page* m_inspectedPage; InspectorClient* m_client; InspectorFrontend* m_frontend; - OwnPtr<InspectorCSSAgent> m_cssAgent; + OwnPtr<InstrumentingAgents> m_instrumentingAgents; + RefPtr<InjectedScriptHost> m_injectedScriptHost; + OwnPtr<InspectorState> m_state; OwnPtr<InspectorDOMAgent> m_domAgent; + OwnPtr<InspectorCSSAgent> m_cssAgent; #if ENABLE(DATABASE) OwnPtr<InspectorDatabaseAgent> m_databaseAgent; @@ -282,7 +259,6 @@ private: #endif OwnPtr<InspectorTimelineAgent> m_timelineAgent; - OwnPtr<InspectorState> m_state; #if ENABLE(OFFLINE_WEB_APPLICATIONS) OwnPtr<InspectorApplicationCacheAgent> m_applicationCacheAgent; @@ -293,20 +269,10 @@ private: RefPtr<InspectorResourceAgent> m_resourceAgent; OwnPtr<InspectorRuntimeAgent> m_runtimeAgent; -#if ENABLE(DATABASE) - typedef HashMap<int, RefPtr<InspectorDatabaseResource> > DatabaseResourcesMap; - DatabaseResourcesMap m_databaseResources; -#endif -#if ENABLE(DOM_STORAGE) - typedef HashMap<int, RefPtr<InspectorDOMStorageResource> > DOMStorageResourcesMap; - DOMStorageResourcesMap m_domStorageResources; -#endif - - RefPtr<InjectedScriptHost> m_injectedScriptHost; OwnPtr<InspectorConsoleAgent> m_consoleAgent; Vector<pair<long, String> > m_pendingEvaluateTestCommands; - String m_requiredPanel; + String m_showPanelAfterVisible; Vector<String> m_scriptsToEvaluateOnLoad; String m_inspectorExtensionAPI; #if ENABLE(JAVASCRIPT_DEBUGGER) @@ -317,9 +283,9 @@ private: String m_userAgentOverride; #if ENABLE(WORKERS) typedef HashMap<intptr_t, RefPtr<InspectorWorkerResource> > WorkersMap; - WorkersMap m_workers; #endif + bool m_canIssueEvaluateForTestInFrontend; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorApplicationCacheAgent.cpp b/Source/WebCore/inspector/InspectorApplicationCacheAgent.cpp index b38bb83..625f53d 100644 --- a/Source/WebCore/inspector/InspectorApplicationCacheAgent.cpp +++ b/Source/WebCore/inspector/InspectorApplicationCacheAgent.cpp @@ -35,21 +35,30 @@ #include "InspectorAgent.h" #include "InspectorFrontend.h" #include "InspectorValues.h" +#include "InstrumentingAgents.h" #include "NetworkStateNotifier.h" #include "Page.h" #include "ResourceResponse.h" namespace WebCore { -InspectorApplicationCacheAgent::InspectorApplicationCacheAgent(DocumentLoader* documentLoader, InspectorFrontend* frontend) - : m_documentLoader(documentLoader) - , m_frontend(frontend) +InspectorApplicationCacheAgent::InspectorApplicationCacheAgent(InstrumentingAgents* instrumentingAgents, Page* inspectedPage) + : m_instrumentingAgents(instrumentingAgents) + , m_inspectedPage(inspectedPage) + , m_frontend(0) { } -void InspectorApplicationCacheAgent::didCommitLoad(DocumentLoader* documentLoader) +void InspectorApplicationCacheAgent::setFrontend(InspectorFrontend* frontend) { - m_documentLoader = documentLoader; + m_frontend = frontend->applicationcache(); + m_instrumentingAgents->setInspectorApplicationCacheAgent(this); +} + +void InspectorApplicationCacheAgent::clearFrontend() +{ + m_instrumentingAgents->setInspectorApplicationCacheAgent(0); + m_frontend = 0; } void InspectorApplicationCacheAgent::updateApplicationCacheStatus(Frame* frame) @@ -64,16 +73,17 @@ void InspectorApplicationCacheAgent::networkStateChanged() m_frontend->updateNetworkState(isNowOnline); } -void InspectorApplicationCacheAgent::getApplicationCaches(RefPtr<InspectorValue>* applicationCaches) +void InspectorApplicationCacheAgent::getApplicationCaches(ErrorString*, RefPtr<InspectorValue>* applicationCaches) { - if (m_documentLoader) { - ApplicationCacheHost* host = m_documentLoader->applicationCacheHost(); - ApplicationCacheHost::CacheInfo info = host->applicationCacheInfo(); - - ApplicationCacheHost::ResourceInfoList resources; - host->fillResourceList(&resources); - *applicationCaches = buildObjectForApplicationCache(resources, info); - } + DocumentLoader* documentLoader = m_inspectedPage->mainFrame()->loader()->documentLoader(); + if (!documentLoader) + return; + ApplicationCacheHost* host = documentLoader->applicationCacheHost(); + ApplicationCacheHost::CacheInfo info = host->applicationCacheInfo(); + + ApplicationCacheHost::ResourceInfoList resources; + host->fillResourceList(&resources); + *applicationCaches = buildObjectForApplicationCache(resources, info); } PassRefPtr<InspectorObject> InspectorApplicationCacheAgent::buildObjectForApplicationCache(const ApplicationCacheHost::ResourceInfoList& applicationCacheResources, const ApplicationCacheHost::CacheInfo& applicationCacheInfo) diff --git a/Source/WebCore/inspector/InspectorApplicationCacheAgent.h b/Source/WebCore/inspector/InspectorApplicationCacheAgent.h index 33cee59..34abf81 100644 --- a/Source/WebCore/inspector/InspectorApplicationCacheAgent.h +++ b/Source/WebCore/inspector/InspectorApplicationCacheAgent.h @@ -28,42 +28,48 @@ #if ENABLE(INSPECTOR) && ENABLE(OFFLINE_WEB_APPLICATIONS) #include "ApplicationCacheHost.h" +#include "InspectorFrontend.h" #include <wtf/Noncopyable.h> #include <wtf/PassRefPtr.h> namespace WebCore { -class DocumentLoader; class Frame; class InspectorArray; class InspectorAgent; class InspectorFrontend; class InspectorObject; class InspectorValue; +class InstrumentingAgents; +class Page; class ResourceResponse; +typedef String ErrorString; + class InspectorApplicationCacheAgent { WTF_MAKE_NONCOPYABLE(InspectorApplicationCacheAgent); WTF_MAKE_FAST_ALLOCATED; public: - InspectorApplicationCacheAgent(DocumentLoader*, InspectorFrontend*); + InspectorApplicationCacheAgent(InstrumentingAgents*, Page*); ~InspectorApplicationCacheAgent() { } - void didCommitLoad(DocumentLoader*); + void setFrontend(InspectorFrontend*); + void clearFrontend(); // Backend to Frontend void updateApplicationCacheStatus(Frame*); void networkStateChanged(); // From Frontend - void getApplicationCaches(RefPtr<InspectorValue>* applicationCaches); + void getApplicationCaches(ErrorString* error, RefPtr<InspectorValue>* applicationCaches); private: PassRefPtr<InspectorObject> buildObjectForApplicationCache(const ApplicationCacheHost::ResourceInfoList&, const ApplicationCacheHost::CacheInfo&); PassRefPtr<InspectorArray> buildArrayForApplicationCacheResources(const ApplicationCacheHost::ResourceInfoList&); PassRefPtr<InspectorObject> buildObjectForApplicationCacheResource(const ApplicationCacheHost::ResourceInfo&); - DocumentLoader* m_documentLoader; - InspectorFrontend* m_frontend; + InstrumentingAgents* m_instrumentingAgents; + Page* m_inspectedPage; + InspectorFrontend::ApplicationCache* m_frontend; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.cpp b/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.cpp index 5fe9937..0cba775 100644 --- a/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.cpp +++ b/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.cpp @@ -35,10 +35,11 @@ #if ENABLE(INSPECTOR) && ENABLE(JAVASCRIPT_DEBUGGER) #include "HTMLElement.h" -#include "InspectorAgent.h" #include "InspectorDOMAgent.h" #include "InspectorDebuggerAgent.h" #include "InspectorState.h" +#include "InspectorValues.h" +#include "InstrumentingAgents.h" #include <wtf/text/CString.h> namespace { @@ -65,26 +66,61 @@ namespace BrowserDebuggerAgentState { static const char browserBreakpoints[] = "browserBreakpoints"; } -PassOwnPtr<InspectorBrowserDebuggerAgent> InspectorBrowserDebuggerAgent::create(InspectorAgent* inspectorAgent, bool eraseStickyBreakpoints) +PassOwnPtr<InspectorBrowserDebuggerAgent> InspectorBrowserDebuggerAgent::create(InstrumentingAgents* instrumentingAgents, InspectorState* inspectorState, InspectorDOMAgent* domAgent, InspectorDebuggerAgent* debuggerAgent, InspectorAgent* inspectorAgent) { - return adoptPtr(new InspectorBrowserDebuggerAgent(inspectorAgent, eraseStickyBreakpoints)); + return adoptPtr(new InspectorBrowserDebuggerAgent(instrumentingAgents, inspectorState, domAgent, debuggerAgent, inspectorAgent)); } -InspectorBrowserDebuggerAgent::InspectorBrowserDebuggerAgent(InspectorAgent* inspectorAgent, bool eraseStickyBreakpoints) - : m_inspectorAgent(inspectorAgent) +InspectorBrowserDebuggerAgent::InspectorBrowserDebuggerAgent(InstrumentingAgents* instrumentingAgents, InspectorState* inspectorState, InspectorDOMAgent* domAgent, InspectorDebuggerAgent* debuggerAgent, InspectorAgent* inspectorAgent) + : m_instrumentingAgents(instrumentingAgents) + , m_inspectorState(inspectorState) + , m_domAgent(domAgent) + , m_debuggerAgent(debuggerAgent) + , m_inspectorAgent(inspectorAgent) , m_hasXHRBreakpointWithEmptyURL(false) { - if (eraseStickyBreakpoints) - inspectorAgent->state()->setObject(BrowserDebuggerAgentState::browserBreakpoints, InspectorObject::create()); + m_debuggerAgent->setListener(this); } InspectorBrowserDebuggerAgent::~InspectorBrowserDebuggerAgent() { + m_debuggerAgent->setListener(0); + ASSERT(!m_instrumentingAgents->inspectorBrowserDebuggerAgent()); } -void InspectorBrowserDebuggerAgent::setAllBrowserBreakpoints(PassRefPtr<InspectorObject> breakpoints) +// Browser debugger agent enabled only when JS debugger is enabled. +void InspectorBrowserDebuggerAgent::debuggerWasEnabled() { - m_inspectorAgent->state()->setObject(BrowserDebuggerAgentState::browserBreakpoints, breakpoints); + m_instrumentingAgents->setInspectorBrowserDebuggerAgent(this); +} + +void InspectorBrowserDebuggerAgent::debuggerWasDisabled() +{ + disable(); +} + +void InspectorBrowserDebuggerAgent::disable() +{ + m_instrumentingAgents->setInspectorBrowserDebuggerAgent(0); + clear(); +} + +void InspectorBrowserDebuggerAgent::setFrontend(InspectorFrontend*) +{ + // Erase sticky breakpoints. If we are restoring from a cookie setFrontend msut be called + // before the state is loaded from the cookie. + m_inspectorState->setObject(BrowserDebuggerAgentState::browserBreakpoints, InspectorObject::create()); +} + +void InspectorBrowserDebuggerAgent::clearFrontend() +{ + disable(); +} + +void InspectorBrowserDebuggerAgent::setAllBrowserBreakpoints(ErrorString*, PassRefPtr<InspectorObject> breakpoints) +{ + m_inspectorState->setObject(BrowserDebuggerAgentState::browserBreakpoints, breakpoints); + // FIXME: remove this call to inspector agent and dependency on the inspector agent. inspectedURLChanged(m_inspectorAgent->inspectedURLWithoutFragment()); } @@ -94,7 +130,7 @@ void InspectorBrowserDebuggerAgent::inspectedURLChanged(const String& url) m_XHRBreakpoints.clear(); m_hasXHRBreakpointWithEmptyURL = false; - RefPtr<InspectorObject> allBreakpoints = m_inspectorAgent->state()->getObject(BrowserDebuggerAgentState::browserBreakpoints); + RefPtr<InspectorObject> allBreakpoints = m_inspectorState->getObject(BrowserDebuggerAgentState::browserBreakpoints); RefPtr<InspectorArray> breakpoints = allBreakpoints->getArray(url); if (!breakpoints) return; @@ -116,20 +152,21 @@ void InspectorBrowserDebuggerAgent::restoreStickyBreakpoint(PassRefPtr<Inspector if (!condition) return; + ErrorString error; if (type == eventListenerNativeBreakpointType) { if (!enabled) return; String eventName; if (!condition->getString("eventName", &eventName)) return; - setEventListenerBreakpoint(eventName); + setEventListenerBreakpoint(&error, eventName); } else if (type == xhrNativeBreakpointType) { if (!enabled) return; String url; if (!condition->getString("url", &url)) return; - setXHRBreakpoint(url); + setXHRBreakpoint(&error, url); } } @@ -138,12 +175,12 @@ void InspectorBrowserDebuggerAgent::discardBindings() m_domBreakpoints.clear(); } -void InspectorBrowserDebuggerAgent::setEventListenerBreakpoint(const String& eventName) +void InspectorBrowserDebuggerAgent::setEventListenerBreakpoint(ErrorString*, const String& eventName) { m_eventListenerBreakpoints.add(eventName); } -void InspectorBrowserDebuggerAgent::removeEventListenerBreakpoint(const String& eventName) +void InspectorBrowserDebuggerAgent::removeEventListenerBreakpoint(ErrorString*, const String& eventName) { m_eventListenerBreakpoints.remove(eventName); } @@ -176,9 +213,9 @@ void InspectorBrowserDebuggerAgent::didRemoveDOMNode(Node* node) } } -void InspectorBrowserDebuggerAgent::setDOMBreakpoint(long nodeId, long type) +void InspectorBrowserDebuggerAgent::setDOMBreakpoint(ErrorString*, long nodeId, long type) { - Node* node = m_inspectorAgent->domAgent()->nodeForId(nodeId); + Node* node = m_domAgent->nodeForId(nodeId); if (!node) return; @@ -190,9 +227,9 @@ void InspectorBrowserDebuggerAgent::setDOMBreakpoint(long nodeId, long type) } } -void InspectorBrowserDebuggerAgent::removeDOMBreakpoint(long nodeId, long type) +void InspectorBrowserDebuggerAgent::removeDOMBreakpoint(ErrorString*, long nodeId, long type) { - Node* node = m_inspectorAgent->domAgent()->nodeForId(nodeId); + Node* node = m_domAgent->nodeForId(nodeId); if (!node) return; @@ -211,7 +248,7 @@ void InspectorBrowserDebuggerAgent::removeDOMBreakpoint(long nodeId, long type) void InspectorBrowserDebuggerAgent::willInsertDOMNode(Node*, Node* parent) { - InspectorDebuggerAgent* debuggerAgent = m_inspectorAgent->debuggerAgent(); + InspectorDebuggerAgent* debuggerAgent = m_debuggerAgent; if (!debuggerAgent) return; @@ -225,7 +262,7 @@ void InspectorBrowserDebuggerAgent::willInsertDOMNode(Node*, Node* parent) void InspectorBrowserDebuggerAgent::willRemoveDOMNode(Node* node) { - InspectorDebuggerAgent* debuggerAgent = m_inspectorAgent->debuggerAgent(); + InspectorDebuggerAgent* debuggerAgent = m_debuggerAgent; if (!debuggerAgent) return; @@ -244,7 +281,7 @@ void InspectorBrowserDebuggerAgent::willRemoveDOMNode(Node* node) void InspectorBrowserDebuggerAgent::willModifyDOMAttr(Element* element) { - InspectorDebuggerAgent* debuggerAgent = m_inspectorAgent->debuggerAgent(); + InspectorDebuggerAgent* debuggerAgent = m_debuggerAgent; if (!debuggerAgent) return; @@ -264,9 +301,8 @@ void InspectorBrowserDebuggerAgent::descriptionForDOMEvent(Node* target, long br if ((1 << breakpointType) & inheritableDOMBreakpointTypesMask) { // For inheritable breakpoint types, target node isn't always the same as the node that owns a breakpoint. // Target node may be unknown to frontend, so we need to push it first. - long targetNodeId = m_inspectorAgent->domAgent()->pushNodePathToFrontend(target); - ASSERT(targetNodeId); - description->setNumber("targetNodeId", targetNodeId); + RefPtr<InspectorObject> targetNodeObject = m_domAgent->resolveNode(target, ""); + description->setObject("targetNode", targetNodeObject); // Find breakpoint owner node. if (!insertion) @@ -281,7 +317,7 @@ void InspectorBrowserDebuggerAgent::descriptionForDOMEvent(Node* target, long br description->setBoolean("insertion", insertion); } - long breakpointOwnerNodeId = m_inspectorAgent->domAgent()->pushNodePathToFrontend(breakpointOwner); + long breakpointOwnerNodeId = m_domAgent->boundNodeId(breakpointOwner); ASSERT(breakpointOwnerNodeId); description->setNumber("nodeId", breakpointOwnerNodeId); description->setNumber("type", breakpointType); @@ -314,7 +350,7 @@ void InspectorBrowserDebuggerAgent::updateSubtreeBreakpoints(Node* node, uint32_ void InspectorBrowserDebuggerAgent::pauseOnNativeEventIfNeeded(const String& categoryType, const String& eventName, bool synchronous) { - InspectorDebuggerAgent* debuggerAgent = m_inspectorAgent->debuggerAgent(); + InspectorDebuggerAgent* debuggerAgent = m_debuggerAgent; if (!debuggerAgent) return; @@ -331,7 +367,7 @@ void InspectorBrowserDebuggerAgent::pauseOnNativeEventIfNeeded(const String& cat debuggerAgent->schedulePauseOnNextStatement(NativeBreakpointDebuggerEventType, eventData.release()); } -void InspectorBrowserDebuggerAgent::setXHRBreakpoint(const String& url) +void InspectorBrowserDebuggerAgent::setXHRBreakpoint(ErrorString*, const String& url) { if (url.isEmpty()) m_hasXHRBreakpointWithEmptyURL = true; @@ -339,7 +375,7 @@ void InspectorBrowserDebuggerAgent::setXHRBreakpoint(const String& url) m_XHRBreakpoints.add(url); } -void InspectorBrowserDebuggerAgent::removeXHRBreakpoint(const String& url) +void InspectorBrowserDebuggerAgent::removeXHRBreakpoint(ErrorString*, const String& url) { if (url.isEmpty()) m_hasXHRBreakpointWithEmptyURL = false; @@ -349,7 +385,7 @@ void InspectorBrowserDebuggerAgent::removeXHRBreakpoint(const String& url) void InspectorBrowserDebuggerAgent::willSendXMLHttpRequest(const String& url) { - InspectorDebuggerAgent* debuggerAgent = m_inspectorAgent->debuggerAgent(); + InspectorDebuggerAgent* debuggerAgent = m_debuggerAgent; if (!debuggerAgent) return; @@ -375,6 +411,14 @@ void InspectorBrowserDebuggerAgent::willSendXMLHttpRequest(const String& url) debuggerAgent->breakProgram(NativeBreakpointDebuggerEventType, eventData.release()); } +void InspectorBrowserDebuggerAgent::clear() +{ + m_domBreakpoints.clear(); + m_eventListenerBreakpoints.clear(); + m_XHRBreakpoints.clear(); + m_hasXHRBreakpointWithEmptyURL = false; +} + } // namespace WebCore #endif // ENABLE(INSPECTOR) && ENABLE(JAVASCRIPT_DEBUGGER) diff --git a/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.h b/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.h index fac54bb..7c0bc8d 100644 --- a/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.h +++ b/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.h @@ -33,8 +33,8 @@ #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) +#include "InspectorDebuggerAgent.h" #include "PlatformString.h" - #include <wtf/HashMap.h> #include <wtf/HashSet.h> #include <wtf/PassOwnPtr.h> @@ -45,26 +45,36 @@ namespace WebCore { class Element; class InspectorAgent; +class InspectorDOMAgent; +class InspectorDebuggerAgent; +class InspectorFrontend; class InspectorObject; +class InspectorState; +class InstrumentingAgents; class Node; -class InspectorBrowserDebuggerAgent { +typedef String ErrorString; + +class InspectorBrowserDebuggerAgent : public InspectorDebuggerAgent::Listener { WTF_MAKE_NONCOPYABLE(InspectorBrowserDebuggerAgent); public: - static PassOwnPtr<InspectorBrowserDebuggerAgent> create(InspectorAgent*, bool eraseStickyBreakpoints); + static PassOwnPtr<InspectorBrowserDebuggerAgent> create(InstrumentingAgents*, InspectorState*, InspectorDOMAgent*, InspectorDebuggerAgent*, InspectorAgent*); virtual ~InspectorBrowserDebuggerAgent(); - void setAllBrowserBreakpoints(PassRefPtr<InspectorObject>); + void setFrontend(InspectorFrontend*); + void clearFrontend(); + + void setAllBrowserBreakpoints(ErrorString* error, PassRefPtr<InspectorObject>); void inspectedURLChanged(const String& url); // BrowserDebugger API for InspectorFrontend - void setXHRBreakpoint(const String& url); - void removeXHRBreakpoint(const String& url); - void setEventListenerBreakpoint(const String& eventName); - void removeEventListenerBreakpoint(const String& eventName); - void setDOMBreakpoint(long nodeId, long type); - void removeDOMBreakpoint(long nodeId, long type); + void setXHRBreakpoint(ErrorString* error, const String& url); + void removeXHRBreakpoint(ErrorString* error, const String& url); + void setEventListenerBreakpoint(ErrorString* error, const String& eventName); + void removeEventListenerBreakpoint(ErrorString* error, const String& eventName); + void setDOMBreakpoint(ErrorString* error, long nodeId, long type); + void removeDOMBreakpoint(ErrorString* error, long nodeId, long type); // InspectorInstrumentation API void willInsertDOMNode(Node*, Node* parent); @@ -76,7 +86,12 @@ public: void pauseOnNativeEventIfNeeded(const String& categoryType, const String& eventName, bool synchronous); private: - InspectorBrowserDebuggerAgent(InspectorAgent*, bool eraseStickyBreakpoints); + InspectorBrowserDebuggerAgent(InstrumentingAgents*, InspectorState*, InspectorDOMAgent*, InspectorDebuggerAgent*, InspectorAgent*); + + // InspectorDebuggerAgent::Listener implementation. + virtual void debuggerWasEnabled(); + virtual void debuggerWasDisabled(); + void disable(); void restoreStickyBreakpoint(PassRefPtr<InspectorObject> breakpoint); @@ -85,6 +100,12 @@ private: bool hasBreakpoint(Node*, long type); void discardBindings(); + void clear(); + + InstrumentingAgents* m_instrumentingAgents; + InspectorState* m_inspectorState; + InspectorDOMAgent* m_domAgent; + InspectorDebuggerAgent* m_debuggerAgent; InspectorAgent* m_inspectorAgent; HashMap<Node*, uint32_t> m_domBreakpoints; HashSet<String> m_eventListenerBreakpoints; diff --git a/Source/WebCore/inspector/InspectorCSSAgent.cpp b/Source/WebCore/inspector/InspectorCSSAgent.cpp index f49f89c..b96071d 100644 --- a/Source/WebCore/inspector/InspectorCSSAgent.cpp +++ b/Source/WebCore/inspector/InspectorCSSAgent.cpp @@ -39,8 +39,8 @@ #include "DOMWindow.h" #include "HTMLHeadElement.h" #include "InspectorDOMAgent.h" -#include "InspectorFrontend.h" #include "InspectorValues.h" +#include "InstrumentingAgents.h" #include "Node.h" #include "NodeList.h" #include "StyleSheetList.h" @@ -143,28 +143,26 @@ CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(StyleBase* styleBase) return static_cast<CSSStyleRule*>(rule); } -InspectorCSSAgent::InspectorCSSAgent() - : m_domAgent(0) +InspectorCSSAgent::InspectorCSSAgent(InstrumentingAgents* instrumentingAgents, InspectorDOMAgent* domAgent) + : m_instrumentingAgents(instrumentingAgents) + , m_domAgent(domAgent) , m_lastStyleSheetId(1) , m_lastRuleId(1) , m_lastStyleId(1) { + m_domAgent->setDOMListener(this); + m_instrumentingAgents->setInspectorCSSAgent(this); } InspectorCSSAgent::~InspectorCSSAgent() { + m_instrumentingAgents->setInspectorCSSAgent(0); + // DOM agent should be destroyed after CSS agent. + m_domAgent->setDOMListener(0); + m_domAgent = 0; reset(); } -void InspectorCSSAgent::setDOMAgent(InspectorDOMAgent* domAgent) -{ - if (m_domAgent) - m_domAgent->setDOMListener(0); - m_domAgent = domAgent; - if (m_domAgent) - m_domAgent->setDOMListener(this); -} - void InspectorCSSAgent::reset() { m_idToInspectorStyleSheet.clear(); @@ -173,7 +171,7 @@ void InspectorCSSAgent::reset() m_documentToInspectorStyleSheet.clear(); } -void InspectorCSSAgent::getStylesForNode(long nodeId, RefPtr<InspectorValue>* result) +void InspectorCSSAgent::getStylesForNode(ErrorString*, long nodeId, RefPtr<InspectorValue>* result) { Element* element = elementForId(nodeId); if (!element) @@ -228,7 +226,7 @@ void InspectorCSSAgent::getStylesForNode(long nodeId, RefPtr<InspectorValue>* re *result = resultObject.release(); } -void InspectorCSSAgent::getInlineStyleForNode(long nodeId, RefPtr<InspectorValue>* style) +void InspectorCSSAgent::getInlineStyleForNode(ErrorString*, long nodeId, RefPtr<InspectorValue>* style) { Element* element = elementForId(nodeId); if (!element) @@ -241,7 +239,7 @@ void InspectorCSSAgent::getInlineStyleForNode(long nodeId, RefPtr<InspectorValue *style = styleSheet->buildObjectForStyle(element->style()); } -void InspectorCSSAgent::getComputedStyleForNode(long nodeId, RefPtr<InspectorValue>* style) +void InspectorCSSAgent::getComputedStyleForNode(ErrorString*, long nodeId, RefPtr<InspectorValue>* style) { Element* element = elementForId(nodeId); if (!element) @@ -252,7 +250,7 @@ void InspectorCSSAgent::getComputedStyleForNode(long nodeId, RefPtr<InspectorVal *style = inspectorStyle->buildObjectForStyle(); } -void InspectorCSSAgent::getAllStyles(RefPtr<InspectorArray>* styles) +void InspectorCSSAgent::getAllStyles(ErrorString*, RefPtr<InspectorArray>* styles) { Vector<Document*> documents = m_domAgent->documents(); for (Vector<Document*>::iterator it = documents.begin(); it != documents.end(); ++it) { @@ -267,7 +265,7 @@ void InspectorCSSAgent::getAllStyles(RefPtr<InspectorArray>* styles) } } -void InspectorCSSAgent::getStyleSheet(const String& styleSheetId, RefPtr<InspectorValue>* styleSheetObject) +void InspectorCSSAgent::getStyleSheet(ErrorString*, const String& styleSheetId, RefPtr<InspectorValue>* styleSheetObject) { InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(styleSheetId); if (!inspectorStyleSheet) @@ -276,7 +274,7 @@ void InspectorCSSAgent::getStyleSheet(const String& styleSheetId, RefPtr<Inspect *styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet(); } -void InspectorCSSAgent::getStyleSheetText(const String& styleSheetId, String* url, String* result) +void InspectorCSSAgent::getStyleSheetText(ErrorString*, const String& styleSheetId, String* url, String* result) { InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(styleSheetId); if (!inspectorStyleSheet) @@ -285,7 +283,7 @@ void InspectorCSSAgent::getStyleSheetText(const String& styleSheetId, String* ur inspectorStyleSheet->text(result); } -void InspectorCSSAgent::setStyleSheetText(const String& styleSheetId, const String& text, bool* success) +void InspectorCSSAgent::setStyleSheetText(ErrorString*, const String& styleSheetId, const String& text, bool* success) { InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(styleSheetId); if (!inspectorStyleSheet) { @@ -298,7 +296,7 @@ void InspectorCSSAgent::setStyleSheetText(const String& styleSheetId, const Stri inspectorStyleSheet->reparseStyleSheet(text); } -void InspectorCSSAgent::setPropertyText(const RefPtr<InspectorObject>& fullStyleId, long propertyIndex, const String& text, bool overwrite, RefPtr<InspectorValue>* result) +void InspectorCSSAgent::setPropertyText(ErrorString*, const RefPtr<InspectorObject>& fullStyleId, long propertyIndex, const String& text, bool overwrite, RefPtr<InspectorValue>* result) { InspectorCSSId compoundId(fullStyleId); ASSERT(!compoundId.isEmpty()); @@ -312,7 +310,7 @@ void InspectorCSSAgent::setPropertyText(const RefPtr<InspectorObject>& fullStyle *result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId)); } -void InspectorCSSAgent::toggleProperty(const RefPtr<InspectorObject>& fullStyleId, long propertyIndex, bool disable, RefPtr<InspectorValue>* result) +void InspectorCSSAgent::toggleProperty(ErrorString*, const RefPtr<InspectorObject>& fullStyleId, long propertyIndex, bool disable, RefPtr<InspectorValue>* result) { InspectorCSSId compoundId(fullStyleId); ASSERT(!compoundId.isEmpty()); @@ -326,7 +324,7 @@ void InspectorCSSAgent::toggleProperty(const RefPtr<InspectorObject>& fullStyleI *result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId)); } -void InspectorCSSAgent::setRuleSelector(const RefPtr<InspectorObject>& fullRuleId, const String& selector, RefPtr<InspectorValue>* result) +void InspectorCSSAgent::setRuleSelector(ErrorString*, const RefPtr<InspectorObject>& fullRuleId, const String& selector, RefPtr<InspectorValue>* result) { InspectorCSSId compoundId(fullRuleId); ASSERT(!compoundId.isEmpty()); @@ -342,7 +340,7 @@ void InspectorCSSAgent::setRuleSelector(const RefPtr<InspectorObject>& fullRuleI *result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId)); } -void InspectorCSSAgent::addRule(const long contextNodeId, const String& selector, RefPtr<InspectorValue>* result) +void InspectorCSSAgent::addRule(ErrorString*, const long contextNodeId, const String& selector, RefPtr<InspectorValue>* result) { Node* node = m_domAgent->nodeForId(contextNodeId); if (!node) @@ -358,7 +356,7 @@ void InspectorCSSAgent::addRule(const long contextNodeId, const String& selector *result = inspectorStyleSheet->buildObjectForRule(newRule); } -void InspectorCSSAgent::getSupportedCSSProperties(RefPtr<InspectorArray>* cssProperties) +void InspectorCSSAgent::getSupportedCSSProperties(ErrorString*, RefPtr<InspectorArray>* cssProperties) { RefPtr<InspectorArray> properties = InspectorArray::create(); for (int i = 0; i < numCSSProperties; ++i) @@ -367,26 +365,6 @@ void InspectorCSSAgent::getSupportedCSSProperties(RefPtr<InspectorArray>* cssPro *cssProperties = properties.release(); } -void InspectorCSSAgent::querySelectorAll(const long nodeId, const String& selector, RefPtr<InspectorArray>* result) -{ - Node* node = m_domAgent->nodeForId(nodeId); - if (!node) - return; - if (!node->isDocumentNode()) - node = node->ownerDocument(); - if (!node) - return; - ExceptionCode ec = 0; - RefPtr<NodeList> nodes = static_cast<Document*>(node)->querySelectorAll(selector, ec); - if (ec) - return; - for (unsigned i = 0; i < nodes->length(); ++i) { - Node* affectedNode = nodes->item(i); - long id = m_domAgent->pushNodePathToFrontend(affectedNode); - (*result)->pushNumber(id); - } -} - // static Element* InspectorCSSAgent::inlineStyleElement(CSSStyleDeclaration* style) { diff --git a/Source/WebCore/inspector/InspectorCSSAgent.h b/Source/WebCore/inspector/InspectorCSSAgent.h index 12b3f9b..4e3f57a 100644 --- a/Source/WebCore/inspector/InspectorCSSAgent.h +++ b/Source/WebCore/inspector/InspectorCSSAgent.h @@ -44,6 +44,7 @@ class CSSStyleSheet; class Document; class Element; class InspectorFrontend; +class InstrumentingAgents; class NameNodeMap; class Node; class StyleBase; @@ -51,29 +52,27 @@ class StyleBase; #if ENABLE(INSPECTOR) class InspectorCSSAgent : public InspectorDOMAgent::DOMListener { + WTF_MAKE_NONCOPYABLE(InspectorCSSAgent); public: static CSSStyleSheet* parentStyleSheet(StyleBase*); static CSSStyleRule* asCSSStyleRule(StyleBase*); - InspectorCSSAgent(); + InspectorCSSAgent(InstrumentingAgents*, InspectorDOMAgent*); ~InspectorCSSAgent(); - void setDOMAgent(InspectorDOMAgent* domAgent); - void reset(); - void getStylesForNode(long nodeId, RefPtr<InspectorValue>* result); - void getInlineStyleForNode(long nodeId, RefPtr<InspectorValue>* style); - void getComputedStyleForNode(long nodeId, RefPtr<InspectorValue>* style); - void getAllStyles(RefPtr<InspectorArray>* styles); - void getStyleSheet(const String& styleSheetId, RefPtr<InspectorValue>* result); - void getStyleSheetText(const String& styleSheetId, String* url, String* result); - void setStyleSheetText(const String& styleSheetId, const String& text, bool* success); - void setPropertyText(const RefPtr<InspectorObject>& styleId, long propertyIndex, const String& text, bool overwrite, RefPtr<InspectorValue>* result); - void toggleProperty(const RefPtr<InspectorObject>& styleId, long propertyIndex, bool disable, RefPtr<InspectorValue>* result); - void setRuleSelector(const RefPtr<InspectorObject>& ruleId, const String& selector, RefPtr<InspectorValue>* result); - void addRule(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); + void getStylesForNode(ErrorString* error, long nodeId, RefPtr<InspectorValue>* result); + void getInlineStyleForNode(ErrorString* error, long nodeId, RefPtr<InspectorValue>* style); + void getComputedStyleForNode(ErrorString* error, long nodeId, RefPtr<InspectorValue>* style); + void getAllStyles(ErrorString* error, RefPtr<InspectorArray>* styles); + void getStyleSheet(ErrorString* error, const String& styleSheetId, RefPtr<InspectorValue>* result); + void getStyleSheetText(ErrorString* error, const String& styleSheetId, String* url, String* result); + void setStyleSheetText(ErrorString* error, const String& styleSheetId, const String& text, bool* success); + void setPropertyText(ErrorString* error, const RefPtr<InspectorObject>& styleId, long propertyIndex, const String& text, bool overwrite, RefPtr<InspectorValue>* result); + void toggleProperty(ErrorString* error, const RefPtr<InspectorObject>& styleId, long propertyIndex, bool disable, RefPtr<InspectorValue>* result); + void setRuleSelector(ErrorString* error, const RefPtr<InspectorObject>& ruleId, const String& selector, RefPtr<InspectorValue>* result); + void addRule(ErrorString* error, const long contextNodeId, const String& selector, RefPtr<InspectorValue>* result); + void getSupportedCSSProperties(ErrorString* error, RefPtr<InspectorArray>* result); private: typedef HashMap<String, RefPtr<InspectorStyleSheet> > IdToInspectorStyleSheet; @@ -99,6 +98,7 @@ private: virtual void didRemoveDOMNode(Node*); virtual void didModifyDOMAttr(Element*); + InstrumentingAgents* m_instrumentingAgents; InspectorDOMAgent* m_domAgent; IdToInspectorStyleSheet m_idToInspectorStyleSheet; diff --git a/Source/WebCore/inspector/InspectorConsoleAgent.cpp b/Source/WebCore/inspector/InspectorConsoleAgent.cpp index 7d11a7a..0379590 100644 --- a/Source/WebCore/inspector/InspectorConsoleAgent.cpp +++ b/Source/WebCore/inspector/InspectorConsoleAgent.cpp @@ -27,6 +27,7 @@ #include "InspectorConsoleAgent.h" #if ENABLE(INSPECTOR) +#include "InstrumentingAgents.h" #include "Console.h" #include "ConsoleMessage.h" #include "InjectedScriptHost.h" @@ -54,31 +55,41 @@ static const char monitoringXHR[] = "monitoringXHR"; static const char consoleMessagesEnabled[] = "consoleMessagesEnabled"; } -InspectorConsoleAgent::InspectorConsoleAgent(InspectorAgent* inspectorAgent) - : m_inspectorAgent(inspectorAgent) +InspectorConsoleAgent::InspectorConsoleAgent(InstrumentingAgents* instrumentingAgents, InspectorAgent* inspectorAgent, InspectorState* state, InjectedScriptHost* injectedScriptHost, InspectorDOMAgent* domAgent) + : m_instrumentingAgents(instrumentingAgents) + , m_inspectorAgent(inspectorAgent) + , m_inspectorState(state) + , m_injectedScriptHost(injectedScriptHost) + , m_inspectorDOMAgent(domAgent) , m_frontend(0) , m_previousMessage(0) , m_expiredConsoleMessageCount(0) { + m_instrumentingAgents->setInspectorConsoleAgent(this); } InspectorConsoleAgent::~InspectorConsoleAgent() { + m_instrumentingAgents->setInspectorConsoleAgent(0); + m_instrumentingAgents = 0; m_inspectorAgent = 0; + m_inspectorState = 0; + m_injectedScriptHost = 0; + m_inspectorDOMAgent = 0; } -void InspectorConsoleAgent::setConsoleMessagesEnabled(bool enabled, bool* newState) +void InspectorConsoleAgent::setConsoleMessagesEnabled(ErrorString*, bool enabled, bool* newState) { *newState = enabled; setConsoleMessagesEnabled(enabled); } -void InspectorConsoleAgent::clearConsoleMessages() +void InspectorConsoleAgent::clearConsoleMessages(ErrorString*) { m_consoleMessages.clear(); m_expiredConsoleMessageCount = 0; m_previousMessage = 0; - m_inspectorAgent->injectedScriptHost()->releaseWrapperObjectGroup(0 /* release the group in all scripts */, "console"); + m_injectedScriptHost->releaseObjectGroup(0 /* release the group in all scripts */, "console"); if (InspectorDOMAgent* domAgent = m_inspectorAgent->domAgent()) domAgent->releaseDanglingNodes(); if (m_frontend) @@ -87,14 +98,20 @@ void InspectorConsoleAgent::clearConsoleMessages() void InspectorConsoleAgent::reset() { - clearConsoleMessages(); + ErrorString error; + clearConsoleMessages(&error); m_times.clear(); m_counts.clear(); } void InspectorConsoleAgent::setFrontend(InspectorFrontend* frontend) { - m_frontend = frontend; + m_frontend = frontend->console(); +} + +void InspectorConsoleAgent::clearFrontend() +{ + m_frontend = 0; } void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack) @@ -169,7 +186,7 @@ void InspectorConsoleAgent::resourceRetrievedByXMLHttpRequest(const String& url, { if (!m_inspectorAgent->enabled()) return; - if (m_inspectorAgent->state()->getBoolean(ConsoleAgentState::monitoringXHR)) + if (m_inspectorState->getBoolean(ConsoleAgentState::monitoringXHR)) addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, "XHR finished loading: \"" + url + "\".", sendLineNumber, sendURL); } @@ -195,14 +212,14 @@ void InspectorConsoleAgent::didFailLoading(unsigned long identifier, const Resou addConsoleMessage(new ConsoleMessage(OtherMessageSource, NetworkErrorMessageType, ErrorMessageLevel, message, error.failingURL(), identifier)); } -void InspectorConsoleAgent::setMonitoringXHREnabled(bool enabled) +void InspectorConsoleAgent::setMonitoringXHREnabled(ErrorString*, bool enabled) { - m_inspectorAgent->state()->setBoolean(ConsoleAgentState::monitoringXHR, enabled); + m_inspectorState->setBoolean(ConsoleAgentState::monitoringXHR, enabled); } void InspectorConsoleAgent::setConsoleMessagesEnabled(bool enabled) { - m_inspectorAgent->state()->setBoolean(ConsoleAgentState::consoleMessagesEnabled, enabled); + m_inspectorState->setBoolean(ConsoleAgentState::consoleMessagesEnabled, enabled); if (!enabled || !m_frontend) return; @@ -210,7 +227,7 @@ void InspectorConsoleAgent::setConsoleMessagesEnabled(bool enabled) m_frontend->updateConsoleMessageExpiredCount(m_expiredConsoleMessageCount); unsigned messageCount = m_consoleMessages.size(); for (unsigned i = 0; i < messageCount; ++i) - m_consoleMessages[i]->addToFrontend(m_frontend, m_inspectorAgent->injectedScriptHost()); + m_consoleMessages[i]->addToFrontend(m_frontend, m_injectedScriptHost); } void InspectorConsoleAgent::addConsoleMessage(PassOwnPtr<ConsoleMessage> consoleMessage) @@ -220,13 +237,13 @@ void InspectorConsoleAgent::addConsoleMessage(PassOwnPtr<ConsoleMessage> console if (m_previousMessage && m_previousMessage->isEqual(consoleMessage.get())) { m_previousMessage->incrementCount(); - if (m_inspectorAgent->state()->getBoolean(ConsoleAgentState::consoleMessagesEnabled) && m_frontend) + if (m_inspectorState->getBoolean(ConsoleAgentState::consoleMessagesEnabled) && m_frontend) m_previousMessage->updateRepeatCountInConsole(m_frontend); } else { m_previousMessage = consoleMessage.get(); m_consoleMessages.append(consoleMessage); - if (m_inspectorAgent->state()->getBoolean(ConsoleAgentState::consoleMessagesEnabled) && m_frontend) - m_previousMessage->addToFrontend(m_frontend, m_inspectorAgent->injectedScriptHost()); + if (m_inspectorState->getBoolean(ConsoleAgentState::consoleMessagesEnabled) && m_frontend) + m_previousMessage->addToFrontend(m_frontend, m_injectedScriptHost); } if (!m_frontend && m_consoleMessages.size() >= maximumConsoleMessages) { diff --git a/Source/WebCore/inspector/InspectorConsoleAgent.h b/Source/WebCore/inspector/InspectorConsoleAgent.h index 10ffb02..8d3a570 100644 --- a/Source/WebCore/inspector/InspectorConsoleAgent.h +++ b/Source/WebCore/inspector/InspectorConsoleAgent.h @@ -26,6 +26,7 @@ #define InspectorConsoleAgent_h #include "Console.h" +#include "InspectorFrontend.h" #include <wtf/Forward.h> #include <wtf/HashMap.h> #include <wtf/Noncopyable.h> @@ -38,24 +39,30 @@ namespace WebCore { class ConsoleMessage; class InspectorAgent; +class InspectorDOMAgent; class InspectorFrontend; class InspectorState; +class InjectedScriptHost; +class InstrumentingAgents; class ResourceError; class ResourceResponse; class ScriptArguments; class ScriptCallStack; class ScriptProfile; +typedef String ErrorString; + class InspectorConsoleAgent { WTF_MAKE_NONCOPYABLE(InspectorConsoleAgent); public: - InspectorConsoleAgent(InspectorAgent*); + InspectorConsoleAgent(InstrumentingAgents*, InspectorAgent*, InspectorState*, InjectedScriptHost*, InspectorDOMAgent*); ~InspectorConsoleAgent(); - void setConsoleMessagesEnabled(bool enabled, bool* newState); - void clearConsoleMessages(); + void setConsoleMessagesEnabled(ErrorString* error, bool enabled, bool* newState); + void clearConsoleMessages(ErrorString* error); void reset(); void setFrontend(InspectorFrontend*); + void clearFrontend(); void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>); void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, unsigned lineNumber, const String& sourceID); @@ -71,14 +78,18 @@ public: void addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile>, unsigned lineNumber, const String& sourceURL); void addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL); #endif - void setMonitoringXHREnabled(bool enabled); + void setMonitoringXHREnabled(ErrorString* error, bool enabled); private: void setConsoleMessagesEnabled(bool); void addConsoleMessage(PassOwnPtr<ConsoleMessage>); + InstrumentingAgents* m_instrumentingAgents; InspectorAgent* m_inspectorAgent; - InspectorFrontend* m_frontend; + InspectorState* m_inspectorState; + InjectedScriptHost* m_injectedScriptHost; + InspectorDOMAgent* m_inspectorDOMAgent; + InspectorFrontend::Console* m_frontend; ConsoleMessage* m_previousMessage; Vector<OwnPtr<ConsoleMessage> > m_consoleMessages; unsigned m_expiredConsoleMessageCount; diff --git a/Source/WebCore/inspector/InspectorController.cpp b/Source/WebCore/inspector/InspectorController.cpp index 426e5f3..2f1bea2 100644 --- a/Source/WebCore/inspector/InspectorController.cpp +++ b/Source/WebCore/inspector/InspectorController.cpp @@ -38,11 +38,13 @@ #include "InjectedScriptHost.h" #include "InspectorAgent.h" #include "InspectorBackendDispatcher.h" +#include "InspectorBrowserDebuggerAgent.h" #include "InspectorDebuggerAgent.h" #include "InspectorClient.h" #include "InspectorFrontend.h" #include "InspectorFrontendClient.h" #include "InspectorInstrumentation.h" +#include "InspectorTimelineAgent.h" #include "Page.h" #include "ScriptObject.h" #include "Settings.h" @@ -84,12 +86,14 @@ void InspectorController::didClearWindowObjectInWorld(Frame* frame, DOMWrapperWo void InspectorController::startTimelineProfiler() { - m_inspectorAgent->startTimelineProfiler(); + ErrorString error; + m_inspectorAgent->timelineAgent()->start(&error); } void InspectorController::stopTimelineProfiler() { - m_inspectorAgent->stopTimelineProfiler(); + ErrorString error; + m_inspectorAgent->timelineAgent()->stop(&error); } void InspectorController::connectFrontend() @@ -127,7 +131,7 @@ void InspectorController::show() return; if (m_inspectorFrontend) - m_inspectorFrontend->bringToFront(); + m_inspectorFrontend->inspector()->bringToFront(); else { m_openingFrontend = true; m_inspectorClient->openInspectorFrontend(this); @@ -138,7 +142,7 @@ void InspectorController::close() { if (!m_inspectorFrontend) return; - m_inspectorFrontend->disconnectFromBackend(); + m_inspectorFrontend->inspector()->disconnectFromBackend(); disconnectFrontend(); } @@ -189,18 +193,36 @@ Page* InspectorController::inspectedPage() const bool InspectorController::timelineProfilerEnabled() { - return m_inspectorAgent->timelineAgent(); + return m_inspectorAgent->timelineAgent()->started(); +} + +void InspectorController::setInspectorExtensionAPI(const String& source) +{ + m_inspectorAgent->setInspectorExtensionAPI(source); +} + +void InspectorController::dispatchMessageFromFrontend(const String& message) +{ + m_inspectorBackendDispatcher->dispatch(message); +} + +void InspectorController::hideHighlight() +{ + ErrorString error; + m_inspectorAgent->hideHighlight(&error); } #if ENABLE(JAVASCRIPT_DEBUGGER) void InspectorController::enableProfiler() { - m_inspectorAgent->enableProfiler(); + ErrorString error; + m_inspectorAgent->enableProfiler(&error); } void InspectorController::disableProfiler() { - m_inspectorAgent->disableProfiler(); + ErrorString error; + m_inspectorAgent->disableProfiler(&error); } bool InspectorController::profilerEnabled() @@ -210,17 +232,21 @@ bool InspectorController::profilerEnabled() bool InspectorController::debuggerEnabled() { - return m_inspectorAgent->debuggerEnabled(); + return m_inspectorAgent->debuggerAgent()->enabled(); } void InspectorController::showAndEnableDebugger() { - m_inspectorAgent->showAndEnableDebugger(); + if (!enabled()) + return; + show(); + m_inspectorAgent->showScriptsPanel(); + m_inspectorAgent->debuggerAgent()->startUserInitiatedDebugging(); } void InspectorController::disableDebugger() { - m_inspectorAgent->disableDebugger(); + m_inspectorAgent->debuggerAgent()->disable(); } void InspectorController::startUserInitiatedProfiling() @@ -230,6 +256,9 @@ void InspectorController::startUserInitiatedProfiling() void InspectorController::stopUserInitiatedProfiling() { + if (!enabled()) + return; + show(); m_inspectorAgent->stopUserInitiatedProfiling(); } @@ -238,25 +267,12 @@ bool InspectorController::isRecordingUserInitiatedProfile() const return m_inspectorAgent->isRecordingUserInitiatedProfile(); } -void InspectorController::setInspectorExtensionAPI(const String& source) -{ - m_inspectorAgent->setInspectorExtensionAPI(source); -} - void InspectorController::resume() { - if (InspectorDebuggerAgent* debuggerAgent = m_inspectorAgent->debuggerAgent()) - debuggerAgent->resume(); -} - -void InspectorController::hideHighlight() -{ - m_inspectorAgent->hideHighlight(); -} - -void InspectorController::dispatchMessageFromFrontend(const String& message) -{ - m_inspectorBackendDispatcher->dispatch(message); + if (InspectorDebuggerAgent* debuggerAgent = m_inspectorAgent->debuggerAgent()) { + ErrorString error; + debuggerAgent->resume(&error); + } } #endif diff --git a/Source/WebCore/inspector/InspectorDOMAgent.cpp b/Source/WebCore/inspector/InspectorDOMAgent.cpp index e222edb..3edd72c 100644 --- a/Source/WebCore/inspector/InspectorDOMAgent.cpp +++ b/Source/WebCore/inspector/InspectorDOMAgent.cpp @@ -61,6 +61,8 @@ #include "HTMLFrameOwnerElement.h" #include "InjectedScriptHost.h" #include "InspectorFrontend.h" +#include "InspectorState.h" +#include "InstrumentingAgents.h" #include "MutationEvent.h" #include "Node.h" #include "NodeList.h" @@ -88,6 +90,10 @@ namespace WebCore { +namespace DOMAgentState { +static const char documentRequested[] = "documentRequested"; +}; + class MatchJob { public: virtual void match(ListHashSet<Node*>& resultCollector) = 0; @@ -108,6 +114,19 @@ protected: String m_query; }; +class RevalidateStyleAttributeTask { +public: + RevalidateStyleAttributeTask(InspectorDOMAgent*); + void scheduleFor(Element*); + void reset() { m_timer.stop(); } + void onTimer(Timer<RevalidateStyleAttributeTask>*); + +private: + InspectorDOMAgent* m_domAgent; + Timer<RevalidateStyleAttributeTask> m_timer; + HashSet<RefPtr<Element> > m_elements; +}; + namespace { class MatchExactIdJob : public WebCore::MatchJob { @@ -207,9 +226,33 @@ public: } -InspectorDOMAgent::InspectorDOMAgent(InjectedScriptHost* injectedScriptHost, InspectorFrontend* frontend) - : m_injectedScriptHost(injectedScriptHost) - , m_frontend(frontend) +RevalidateStyleAttributeTask::RevalidateStyleAttributeTask(InspectorDOMAgent* domAgent) + : m_domAgent(domAgent) + , m_timer(this, &RevalidateStyleAttributeTask::onTimer) +{ +} + +void RevalidateStyleAttributeTask::scheduleFor(Element* element) +{ + m_elements.add(element); + if (!m_timer.isActive()) + m_timer.startOneShot(0); +} + +void RevalidateStyleAttributeTask::onTimer(Timer<RevalidateStyleAttributeTask>*) +{ + // The timer is stopped on m_domAgent destruction, so this method will never be called after m_domAgent has been destroyed. + for (HashSet<RefPtr<Element> >::iterator it = m_elements.begin(), end = m_elements.end(); it != end; ++it) + m_domAgent->didModifyDOMAttr(it->get()); + + m_elements.clear(); +} + +InspectorDOMAgent::InspectorDOMAgent(InstrumentingAgents* instrumentingAgents, InspectorState* inspectorState, InjectedScriptHost* injectedScriptHost) + : m_instrumentingAgents(instrumentingAgents) + , m_inspectorState(inspectorState) + , m_injectedScriptHost(injectedScriptHost) + , m_frontend(0) , m_domListener(0) , m_lastNodeId(1) , m_matchJobsTimer(this, &InspectorDOMAgent::onMatchJobsTimer) @@ -221,6 +264,22 @@ InspectorDOMAgent::~InspectorDOMAgent() reset(); } +void InspectorDOMAgent::setFrontend(InspectorFrontend* frontend) +{ + ASSERT(!m_frontend); + m_frontend = frontend->dom(); + m_instrumentingAgents->setInspectorDOMAgent(this); +} + +void InspectorDOMAgent::clearFrontend() +{ + ASSERT(m_frontend); + m_frontend = 0; + m_instrumentingAgents->setInspectorDOMAgent(0); + m_inspectorState->setBoolean(DOMAgentState::documentRequested, false); + reset(); +} + Vector<Document*> InspectorDOMAgent::documents() { Vector<Document*> result; @@ -235,8 +294,12 @@ Vector<Document*> InspectorDOMAgent::documents() void InspectorDOMAgent::reset() { - searchCanceled(); + ErrorString error; + searchCanceled(&error); discardBindings(); + if (m_revalidateStyleAttrTask) + m_revalidateStyleAttrTask->reset(); + m_document = 0; } void InspectorDOMAgent::setDOMListener(DOMListener* listener) @@ -253,11 +316,8 @@ void InspectorDOMAgent::setDocument(Document* doc) m_document = doc; - if (doc) { - if (doc->documentElement()) - pushDocumentToFrontend(); - } else - m_frontend->setDocument(InspectorValue::null()); + if (!doc && m_inspectorState->getBoolean(DOMAgentState::documentRequested)) + m_frontend->documentUpdated(); } void InspectorDOMAgent::releaseDanglingNodes() @@ -303,13 +363,35 @@ void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap) } } -bool InspectorDOMAgent::pushDocumentToFrontend() +Node* InspectorDOMAgent::nodeToSelectOn(long nodeId, bool documentWide) { + Node* node; + if (!nodeId) + node = m_document.get(); + else + node = nodeForId(nodeId); + if (!node) + return 0; + + if (documentWide && nodeId) + node = node->ownerDocument(); + return node; +} + +void InspectorDOMAgent::getDocument(ErrorString*, RefPtr<InspectorObject>* root) +{ + m_inspectorState->setBoolean(DOMAgentState::documentRequested, true); + if (!m_document) - return false; + return; + + // Reset backend state. + RefPtr<Document> doc = m_document; + reset(); + m_document = doc; + if (!m_documentNodeToIdMap.contains(m_document)) - m_frontend->setDocument(buildObjectForNode(m_document.get(), 2, &m_documentNodeToIdMap)); - return true; + *root = buildObjectForNode(m_document.get(), 2, &m_documentNodeToIdMap); } void InspectorDOMAgent::pushChildNodesToFrontend(long nodeId) @@ -326,20 +408,13 @@ void InspectorDOMAgent::pushChildNodesToFrontend(long nodeId) m_frontend->setChildNodes(nodeId, children.release()); } -long InspectorDOMAgent::inspectedNode(unsigned long num) -{ - if (num < m_inspectedNodes.size()) - return m_inspectedNodes[num]; - return 0; -} - void InspectorDOMAgent::discardBindings() { m_documentNodeToIdMap.clear(); m_idToNode.clear(); releaseDanglingNodes(); m_childrenRequested.clear(); - m_inspectedNodes.clear(); + m_injectedScriptHost->clearInspectedNodes(); } Node* InspectorDOMAgent::nodeForId(long id) @@ -353,17 +428,49 @@ Node* InspectorDOMAgent::nodeForId(long id) return 0; } -void InspectorDOMAgent::getChildNodes(long nodeId) +void InspectorDOMAgent::getChildNodes(ErrorString*, long nodeId) { pushChildNodesToFrontend(nodeId); } +void InspectorDOMAgent::querySelector(ErrorString*, long nodeId, const String& selectors, bool documentWide, long* elementId) +{ + *elementId = 0; + Node* node = nodeToSelectOn(nodeId, documentWide); + if (!node) + return; + + ExceptionCode ec = 0; + RefPtr<Element> element = node->querySelector(selectors, ec); + if (ec) + return; + + if (element) + *elementId = pushNodePathToFrontend(element.get()); +} + +void InspectorDOMAgent::querySelectorAll(ErrorString*, long nodeId, const String& selectors, bool documentWide, RefPtr<InspectorArray>* result) +{ + Node* node = nodeToSelectOn(nodeId, documentWide); + if (!node) + return; + + ExceptionCode ec = 0; + RefPtr<NodeList> nodes = node->querySelectorAll(selectors, ec); + if (ec) + return; + + for (unsigned i = 0; i < nodes->length(); ++i) + (*result)->pushNumber(pushNodePathToFrontend(nodes->item(i))); +} + long InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush) { ASSERT(nodeToPush); // Invalid input - // If we are sending information to the client that is currently being created. Send root node first. - if (!pushDocumentToFrontend()) + if (!m_document) + return 0; + if (!m_documentNodeToIdMap.contains(m_document)) return 0; // Return id in case the node is known. @@ -374,13 +481,16 @@ long InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush) Node* node = nodeToPush; Vector<Node*> path; NodeToIdMap* danglingMap = 0; + while (true) { Node* parent = innerParentNode(node); if (!parent) { // Node being pushed is detached -> push subtree root. danglingMap = new NodeToIdMap(); m_danglingNodeToIdMaps.append(danglingMap); - m_frontend->setDetachedRoot(buildObjectForNode(node, 0, danglingMap)); + RefPtr<InspectorArray> children = InspectorArray::create(); + children->pushObject(buildObjectForNode(node, 0, danglingMap)); + m_frontend->setChildNodes(0, children); break; } else { path.append(parent); @@ -400,7 +510,12 @@ long InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush) return map->get(nodeToPush); } -void InspectorDOMAgent::setAttribute(long elementId, const String& name, const String& value, bool* success) +long InspectorDOMAgent::boundNodeId(Node* node) +{ + return m_documentNodeToIdMap.get(node); +} + +void InspectorDOMAgent::setAttribute(ErrorString*, long elementId, const String& name, const String& value, bool* success) { Node* node = nodeForId(elementId); if (node && (node->nodeType() == Node::ELEMENT_NODE)) { @@ -411,7 +526,7 @@ void InspectorDOMAgent::setAttribute(long elementId, const String& name, const S } } -void InspectorDOMAgent::removeAttribute(long elementId, const String& name, bool* success) +void InspectorDOMAgent::removeAttribute(ErrorString*, long elementId, const String& name, bool* success) { Node* node = nodeForId(elementId); if (node && (node->nodeType() == Node::ELEMENT_NODE)) { @@ -422,7 +537,7 @@ void InspectorDOMAgent::removeAttribute(long elementId, const String& name, bool } } -void InspectorDOMAgent::removeNode(long nodeId, long* outNodeId) +void InspectorDOMAgent::removeNode(ErrorString*, long nodeId, long* outNodeId) { Node* node = nodeForId(nodeId); if (!node) @@ -440,7 +555,7 @@ void InspectorDOMAgent::removeNode(long nodeId, long* outNodeId) *outNodeId = nodeId; } -void InspectorDOMAgent::changeTagName(long nodeId, const String& tagName, long* newId) +void InspectorDOMAgent::changeTagName(ErrorString*, long nodeId, const String& tagName, long* newId) { Node* oldNode = nodeForId(nodeId); if (!oldNode || !oldNode->isElementNode()) @@ -475,7 +590,7 @@ void InspectorDOMAgent::changeTagName(long nodeId, const String& tagName, long* pushChildNodesToFrontend(*newId); } -void InspectorDOMAgent::getOuterHTML(long nodeId, WTF::String* outerHTML) +void InspectorDOMAgent::getOuterHTML(ErrorString*, long nodeId, WTF::String* outerHTML) { Node* node = nodeForId(nodeId); if (!node || !node->isHTMLElement()) @@ -484,7 +599,7 @@ void InspectorDOMAgent::getOuterHTML(long nodeId, WTF::String* outerHTML) *outerHTML = toHTMLElement(node)->outerHTML(); } -void InspectorDOMAgent::setOuterHTML(long nodeId, const String& outerHTML, long* newId) +void InspectorDOMAgent::setOuterHTML(ErrorString*, long nodeId, const String& outerHTML, long* newId) { Node* node = nodeForId(nodeId); if (!node || !node->isHTMLElement()) @@ -522,7 +637,7 @@ void InspectorDOMAgent::setOuterHTML(long nodeId, const String& outerHTML, long* pushChildNodesToFrontend(*newId); } -void InspectorDOMAgent::setTextNodeValue(long nodeId, const String& value, bool* success) +void InspectorDOMAgent::setTextNodeValue(ErrorString*, long nodeId, const String& value, bool* success) { Node* node = nodeForId(nodeId); if (node && (node->nodeType() == Node::TEXT_NODE)) { @@ -533,7 +648,7 @@ void InspectorDOMAgent::setTextNodeValue(long nodeId, const String& value, bool* } } -void InspectorDOMAgent::getEventListenersForNode(long nodeId, long* outNodeId, RefPtr<InspectorArray>* listenersArray) +void InspectorDOMAgent::getEventListenersForNode(ErrorString*, long nodeId, long* outNodeId, RefPtr<InspectorArray>* listenersArray) { Node* node = nodeForId(nodeId); *outNodeId = nodeId; @@ -600,14 +715,15 @@ void InspectorDOMAgent::getEventListenersForNode(long nodeId, long* outNodeId, R } } -void InspectorDOMAgent::addInspectedNode(long nodeId) +void InspectorDOMAgent::addInspectedNode(ErrorString*, long nodeId) { - m_inspectedNodes.prepend(nodeId); - while (m_inspectedNodes.size() > 5) - m_inspectedNodes.removeLast(); + Node* node = nodeForId(nodeId); + if (!node) + return; + m_injectedScriptHost->addInspectedNode(node); } -void InspectorDOMAgent::performSearch(const String& whitespaceTrimmedQuery, bool runSynchronously) +void InspectorDOMAgent::performSearch(ErrorString* error, const String& whitespaceTrimmedQuery, bool runSynchronously) { // FIXME: Few things are missing here: // 1) Search works with node granularity - number of matches within node is not calculated. @@ -634,7 +750,7 @@ void InspectorDOMAgent::performSearch(const String& whitespaceTrimmedQuery, bool escapedTagNameQuery.replace("'", "\\'"); // Clear pending jobs. - searchCanceled(); + searchCanceled(error); // Find all frames, iframes and object elements to search their documents. Vector<Document*> docs = documents(); @@ -688,13 +804,13 @@ void InspectorDOMAgent::performSearch(const String& whitespaceTrimmedQuery, bool for (Deque<MatchJob*>::iterator it = m_pendingMatchJobs.begin(); it != m_pendingMatchJobs.end(); ++it) (*it)->match(resultCollector); reportNodesAsSearchResults(resultCollector); - searchCanceled(); + searchCanceled(error); return; } m_matchJobsTimer.startOneShot(0); } -void InspectorDOMAgent::searchCanceled() +void InspectorDOMAgent::searchCanceled(ErrorString*) { if (m_matchJobsTimer.isActive()) m_matchJobsTimer.stop(); @@ -703,32 +819,24 @@ void InspectorDOMAgent::searchCanceled() m_searchResults.clear(); } -void InspectorDOMAgent::resolveNode(long nodeId, RefPtr<InspectorValue>* result) -{ - InjectedScript injectedScript = injectedScriptForNodeId(nodeId); - if (!injectedScript.hasNoValue()) - injectedScript.resolveNode(nodeId, result); -} - -void InspectorDOMAgent::getNodeProperties(long nodeId, PassRefPtr<InspectorArray> propertiesArray, RefPtr<InspectorValue>* result) -{ - InjectedScript injectedScript = injectedScriptForNodeId(nodeId); - if (!injectedScript.hasNoValue()) - injectedScript.getNodeProperties(nodeId, propertiesArray, result); -} - -void InspectorDOMAgent::getNodePrototypes(long nodeId, RefPtr<InspectorValue>* result) +void InspectorDOMAgent::resolveNode(ErrorString* error, long nodeId, const String& objectGroup, RefPtr<InspectorValue>* result) { - InjectedScript injectedScript = injectedScriptForNodeId(nodeId); - if (!injectedScript.hasNoValue()) - injectedScript.getNodePrototypes(nodeId, result); + Node* node = nodeForId(nodeId); + if (!node) { + *error = "No node with given id found."; + return; + } + *result = resolveNode(node, objectGroup); } -void InspectorDOMAgent::pushNodeToFrontend(PassRefPtr<InspectorObject> objectId, RefPtr<InspectorValue>* result) +void InspectorDOMAgent::pushNodeToFrontend(ErrorString*, PassRefPtr<InspectorObject> objectId, long* nodeId) { InjectedScript injectedScript = m_injectedScriptHost->injectedScriptForObjectId(objectId.get()); - if (!injectedScript.hasNoValue()) - injectedScript.pushNodeToFrontend(objectId, result); + Node* node = injectedScript.nodeForObjectId(objectId); + if (node) + *nodeId = pushNodePathToFrontend(node); + else + *nodeId = 0; } String InspectorDOMAgent::documentURLString(Document* document) const @@ -918,7 +1026,8 @@ void InspectorDOMAgent::mainFrameDOMContentLoaded() { // Re-push document once it is loaded. discardBindings(); - pushDocumentToFrontend(); + if (m_inspectorState->getBoolean(DOMAgentState::documentRequested)) + m_frontend->documentUpdated(); } void InspectorDOMAgent::loadEventFired(Document* document) @@ -1017,6 +1126,18 @@ void InspectorDOMAgent::characterDataModified(CharacterData* characterData) m_frontend->characterDataModified(id, characterData->data()); } +void InspectorDOMAgent::didInvalidateStyleAttr(Node* node) +{ + long id = m_documentNodeToIdMap.get(node); + // If node is not mapped yet -> ignore the event. + if (!id) + return; + + if (!m_revalidateStyleAttrTask) + m_revalidateStyleAttrTask = new RevalidateStyleAttributeTask(this); + m_revalidateStyleAttrTask->scheduleFor(static_cast<Element*>(node)); +} + Node* InspectorDOMAgent::nodeForPath(const String& path) { // The path is of form "1,HTML,2,BODY,1,DIV" @@ -1059,7 +1180,8 @@ PassRefPtr<InspectorArray> InspectorDOMAgent::toArray(const Vector<String>& data void InspectorDOMAgent::onMatchJobsTimer(Timer<InspectorDOMAgent>*) { if (!m_pendingMatchJobs.size()) { - searchCanceled(); + ErrorString error; + searchCanceled(&error); return; } @@ -1085,7 +1207,7 @@ void InspectorDOMAgent::reportNodesAsSearchResults(ListHashSet<Node*>& resultCol m_frontend->addNodesToSearchResult(nodeIds.release()); } -void InspectorDOMAgent::copyNode(long nodeId) +void InspectorDOMAgent::copyNode(ErrorString*, long nodeId) { Node* node = nodeForId(nodeId); if (!node) @@ -1094,32 +1216,26 @@ void InspectorDOMAgent::copyNode(long nodeId) Pasteboard::generalPasteboard()->writePlainText(markup); } -void InspectorDOMAgent::pushNodeByPathToFrontend(const String& path, long* nodeId) +void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString*, const String& path, long* nodeId) { if (Node* node = nodeForPath(path)) *nodeId = pushNodePathToFrontend(node); } -InjectedScript InspectorDOMAgent::injectedScriptForNodeId(long nodeId) +PassRefPtr<InspectorObject> InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup) { - Frame* frame = 0; - if (nodeId) { - Node* node = nodeForId(nodeId); - if (node) { - Document* document = node->ownerDocument(); - if (document) - frame = document->frame(); - } - } else - frame = m_document->frame(); + Document* document = node->ownerDocument(); + Frame* frame = document ? document->frame() : 0; + if (!frame) + return 0; - if (frame) - return m_injectedScriptHost->injectedScriptFor(mainWorldScriptState(frame)); + InjectedScript injectedScript = m_injectedScriptHost->injectedScriptFor(mainWorldScriptState(frame)); + if (injectedScript.hasNoValue()) + return 0; - return InjectedScript(); + return injectedScript.wrapNode(node, objectGroup); } - } // namespace WebCore #endif // ENABLE(INSPECTOR) diff --git a/Source/WebCore/inspector/InspectorDOMAgent.h b/Source/WebCore/inspector/InspectorDOMAgent.h index 4e603da..0368880 100644 --- a/Source/WebCore/inspector/InspectorDOMAgent.h +++ b/Source/WebCore/inspector/InspectorDOMAgent.h @@ -32,6 +32,7 @@ #include "InjectedScript.h" #include "InjectedScriptHost.h" +#include "InspectorFrontend.h" #include "InspectorValues.h" #include "Timer.h" @@ -39,6 +40,7 @@ #include <wtf/ListHashSet.h> #include <wtf/HashMap.h> #include <wtf/HashSet.h> +#include <wtf/OwnPtr.h> #include <wtf/PassOwnPtr.h> #include <wtf/RefPtr.h> #include <wtf/Vector.h> @@ -53,9 +55,15 @@ class Event; class InspectorDOMAgent; class InspectorFrontend; class MatchJob; +class InspectorState; +class InstrumentingAgents; class NameNodeMap; class Node; class Page; +class RevalidateStyleAttributeTask; +class ScriptValue; + +typedef String ErrorString; #if ENABLE(INSPECTOR) @@ -83,34 +91,38 @@ public: virtual void didModifyDOMAttr(Element*) = 0; }; - static PassOwnPtr<InspectorDOMAgent> create(InjectedScriptHost* injectedScriptHost, InspectorFrontend* frontend) + static PassOwnPtr<InspectorDOMAgent> create(InstrumentingAgents* instrumentingAgents, InspectorState* inspectorState, InjectedScriptHost* injectedScriptHost) { - return adoptPtr(new InspectorDOMAgent(injectedScriptHost, frontend)); + return adoptPtr(new InspectorDOMAgent(instrumentingAgents, inspectorState, injectedScriptHost)); } - InspectorDOMAgent(InjectedScriptHost*, InspectorFrontend*); ~InspectorDOMAgent(); + void setFrontend(InspectorFrontend*); + void clearFrontend(); + Vector<Document*> documents(); void reset(); // Methods called from the frontend for DOM nodes inspection. - void getChildNodes(long nodeId); - void setAttribute(long elementId, const String& name, const String& value, bool* success); - void removeAttribute(long elementId, const String& name, bool* success); - void removeNode(long nodeId, long* outNodeId); - void changeTagName(long nodeId, const String& tagName, long* newId); - void getOuterHTML(long nodeId, WTF::String* outerHTML); - void setOuterHTML(long nodeId, const String& outerHTML, long* newId); - void setTextNodeValue(long nodeId, const String& value, bool* success); - void getEventListenersForNode(long nodeId, long* outNodeId, RefPtr<InspectorArray>* listenersArray); - void addInspectedNode(long nodeId); - void performSearch(const String& whitespaceTrimmedQuery, bool runSynchronously); - void searchCanceled(); - void resolveNode(long nodeId, RefPtr<InspectorValue>* result); - void getNodeProperties(long nodeId, PassRefPtr<InspectorArray> propertiesArray, RefPtr<InspectorValue>* result); - void getNodePrototypes(long nodeId, RefPtr<InspectorValue>* result); - void pushNodeToFrontend(PassRefPtr<InspectorObject> objectId, RefPtr<InspectorValue>* result); + void querySelector(ErrorString*, long nodeId, const String& selectors, bool documentWide, long* elementId); + void querySelectorAll(ErrorString*, long nodeId, const String& selectors, bool documentWide, RefPtr<InspectorArray>* result); + void getDocument(ErrorString*, RefPtr<InspectorObject>* root); + void getChildNodes(ErrorString*, long nodeId); + void setAttribute(ErrorString*, long elementId, const String& name, const String& value, bool* success); + void removeAttribute(ErrorString*, long elementId, const String& name, bool* success); + void removeNode(ErrorString*, long nodeId, long* outNodeId); + void changeTagName(ErrorString*, long nodeId, const String& tagName, long* newId); + void getOuterHTML(ErrorString*, long nodeId, WTF::String* outerHTML); + void setOuterHTML(ErrorString*, long nodeId, const String& outerHTML, long* newId); + void setTextNodeValue(ErrorString*, long nodeId, const String& value, bool* success); + void getEventListenersForNode(ErrorString*, long nodeId, long* outNodeId, RefPtr<InspectorArray>* listenersArray); + void addInspectedNode(ErrorString*, long nodeId); + void performSearch(ErrorString*, const String& whitespaceTrimmedQuery, bool runSynchronously); + void searchCanceled(ErrorString*); + void resolveNode(ErrorString*, long nodeId, const String& objectGroup, RefPtr<InspectorValue>* result); + void pushNodeToFrontend(ErrorString*, PassRefPtr<InspectorObject> objectId, long* nodeId); + void pushNodeByPathToFrontend(ErrorString*, const String& path, long* nodeId); // Methods called from the InspectorInstrumentation. void setDocument(Document*); @@ -123,17 +135,17 @@ public: void didRemoveDOMNode(Node*); void didModifyDOMAttr(Element*); void characterDataModified(CharacterData*); + void didInvalidateStyleAttr(Node*); Node* nodeForId(long nodeId); - long pushNodePathToFrontend(Node*); - void pushChildNodesToFrontend(long nodeId); - void pushNodeByPathToFrontend(const String& path, long* nodeId); - long inspectedNode(unsigned long num); - void copyNode(long nodeId); + long boundNodeId(Node*); + void copyNode(ErrorString*, long nodeId); void setDOMListener(DOMListener*); String documentURLString(Document*) const; + PassRefPtr<InspectorObject> resolveNode(Node*, const String& objectGroup); + // We represent embedded doms as a part of the same hierarchy. Hence we treat children of frame owners differently. // We also skip whitespace text nodes conditionally. Following methods encapsulate these specifics. static Node* innerFirstChild(Node*); @@ -144,12 +156,17 @@ public: static bool isWhitespace(Node*); private: + InspectorDOMAgent(InstrumentingAgents*, InspectorState*, InjectedScriptHost*); + // Node-related methods. typedef HashMap<RefPtr<Node>, long> NodeToIdMap; long bind(Node*, NodeToIdMap*); void unbind(Node*, NodeToIdMap*); - bool pushDocumentToFrontend(); + Node* nodeToSelectOn(long nodeId, bool documentWide); + + long pushNodePathToFrontend(Node*); + void pushChildNodesToFrontend(long nodeId); bool hasBreakpoint(Node*, long type); void updateSubtreeBreakpoints(Node* root, uint32_t rootMask, bool value); @@ -168,10 +185,10 @@ private: void discardBindings(); - InjectedScript injectedScriptForNodeId(long nodeId); - + InstrumentingAgents* m_instrumentingAgents; + InspectorState* m_inspectorState; InjectedScriptHost* m_injectedScriptHost; - InspectorFrontend* m_frontend; + InspectorFrontend::DOM* m_frontend; DOMListener* m_domListener; NodeToIdMap m_documentNodeToIdMap; // Owns node mappings for dangling nodes. @@ -184,7 +201,7 @@ private: Deque<MatchJob*> m_pendingMatchJobs; Timer<InspectorDOMAgent> m_matchJobsTimer; HashSet<RefPtr<Node> > m_searchResults; - Vector<long> m_inspectedNodes; + OwnPtr<RevalidateStyleAttributeTask> m_revalidateStyleAttrTask; }; #endif // ENABLE(INSPECTOR) diff --git a/Source/WebCore/inspector/InspectorDOMStorageAgent.cpp b/Source/WebCore/inspector/InspectorDOMStorageAgent.cpp index 0919b64..6ea72f6 100644 --- a/Source/WebCore/inspector/InspectorDOMStorageAgent.cpp +++ b/Source/WebCore/inspector/InspectorDOMStorageAgent.cpp @@ -39,21 +39,47 @@ #include "InspectorDOMStorageResource.h" #include "InspectorFrontend.h" #include "InspectorValues.h" +#include "InstrumentingAgents.h" #include "Storage.h" +#include "StorageArea.h" #include "VoidCallback.h" #include <wtf/Vector.h> namespace WebCore { +typedef HashMap<int, RefPtr<InspectorDOMStorageResource> > DOMStorageResourcesMap; + +InspectorDOMStorageAgent::InspectorDOMStorageAgent(InstrumentingAgents* instrumentingAgents) + : m_instrumentingAgents(instrumentingAgents) + , m_frontend(0) +{ + m_instrumentingAgents->setInspectorDOMStorageAgent(this); +} + InspectorDOMStorageAgent::~InspectorDOMStorageAgent() { - DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources->end(); - for (DOMStorageResourcesMap::iterator it = m_domStorageResources->begin(); it != domStorageEnd; ++it) + m_instrumentingAgents->setInspectorDOMStorageAgent(0); + m_instrumentingAgents = 0; +} + +void InspectorDOMStorageAgent::setFrontend(InspectorFrontend* frontend) +{ + m_frontend = frontend; + DOMStorageResourcesMap::iterator resourcesEnd = m_resources.end(); + for (DOMStorageResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) + it->second->bind(m_frontend); +} + +void InspectorDOMStorageAgent::clearFrontend() +{ + DOMStorageResourcesMap::iterator domStorageEnd = m_resources.end(); + for (DOMStorageResourcesMap::iterator it = m_resources.begin(); it != domStorageEnd; ++it) it->second->unbind(); + m_frontend = 0; } -void InspectorDOMStorageAgent::getDOMStorageEntries(long storageId, RefPtr<InspectorArray>* entries) +void InspectorDOMStorageAgent::getDOMStorageEntries(ErrorString*, long storageId, RefPtr<InspectorArray>* entries) { InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId); if (storageResource) { @@ -70,7 +96,7 @@ void InspectorDOMStorageAgent::getDOMStorageEntries(long storageId, RefPtr<Inspe } } -void InspectorDOMStorageAgent::setDOMStorageItem(long storageId, const String& key, const String& value, bool* success) +void InspectorDOMStorageAgent::setDOMStorageItem(ErrorString*, long storageId, const String& key, const String& value, bool* success) { InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId); if (storageResource) { @@ -80,7 +106,7 @@ void InspectorDOMStorageAgent::setDOMStorageItem(long storageId, const String& k } } -void InspectorDOMStorageAgent::removeDOMStorageItem(long storageId, const String& key, bool* success) +void InspectorDOMStorageAgent::removeDOMStorageItem(ErrorString*, long storageId, const String& key, bool* success) { InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId); if (storageResource) { @@ -89,41 +115,52 @@ void InspectorDOMStorageAgent::removeDOMStorageItem(long storageId, const String } } -void InspectorDOMStorageAgent::selectDOMStorage(Storage* storage) +long InspectorDOMStorageAgent::storageId(Storage* storage) { ASSERT(storage); - if (!m_frontend) - return; - Frame* frame = storage->frame(); ExceptionCode ec = 0; bool isLocalStorage = (frame->domWindow()->localStorage(ec) == storage && !ec); - long storageResourceId = 0; - DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources->end(); - for (DOMStorageResourcesMap::iterator it = m_domStorageResources->begin(); it != domStorageEnd; ++it) { - if (it->second->isSameHostAndType(frame, isLocalStorage)) { - storageResourceId = it->first; - break; - } + DOMStorageResourcesMap::iterator domStorageEnd = m_resources.end(); + for (DOMStorageResourcesMap::iterator it = m_resources.begin(); it != domStorageEnd; ++it) { + if (it->second->isSameHostAndType(frame, isLocalStorage)) + return it->first; } - if (storageResourceId) - m_frontend->selectDOMStorage(storageResourceId); -} - -InspectorDOMStorageAgent::InspectorDOMStorageAgent(DOMStorageResourcesMap* domStorageResources, InspectorFrontend* frontend) - : m_domStorageResources(domStorageResources) - , m_frontend(frontend) -{ + return 0; } InspectorDOMStorageResource* InspectorDOMStorageAgent::getDOMStorageResourceForId(long storageId) { - DOMStorageResourcesMap::iterator it = m_domStorageResources->find(storageId); - if (it == m_domStorageResources->end()) + DOMStorageResourcesMap::iterator it = m_resources.find(storageId); + if (it == m_resources.end()) return 0; return it->second.get(); } +void InspectorDOMStorageAgent::didUseDOMStorage(StorageArea* storageArea, bool isLocalStorage, Frame* frame) +{ + DOMStorageResourcesMap::iterator domStorageEnd = m_resources.end(); + for (DOMStorageResourcesMap::iterator it = m_resources.begin(); it != domStorageEnd; ++it) { + if (it->second->isSameHostAndType(frame, isLocalStorage)) + return; + } + + RefPtr<Storage> domStorage = Storage::create(frame, storageArea); + RefPtr<InspectorDOMStorageResource> resource = InspectorDOMStorageResource::create(domStorage.get(), isLocalStorage, frame); + + m_resources.set(resource->id(), resource); + + // Resources are only bound while visible. + if (m_frontend) + resource->bind(m_frontend); +} + +void InspectorDOMStorageAgent::clearResources() +{ + m_resources.clear(); +} + + } // namespace WebCore #endif // ENABLE(INSPECTOR) && ENABLE(DOM_STORE) diff --git a/Source/WebCore/inspector/InspectorDOMStorageAgent.h b/Source/WebCore/inspector/InspectorDOMStorageAgent.h index 987c530..adae9b2 100644 --- a/Source/WebCore/inspector/InspectorDOMStorageAgent.h +++ b/Source/WebCore/inspector/InspectorDOMStorageAgent.h @@ -35,36 +35,48 @@ namespace WebCore { +class Frame; class InspectorArray; class InspectorDOMStorageResource; class InspectorFrontend; +class InstrumentingAgents; class Storage; +class StorageArea; + +typedef String ErrorString; class InspectorDOMStorageAgent { public: - typedef HashMap<int, RefPtr<InspectorDOMStorageResource> > DOMStorageResourcesMap; - - static PassOwnPtr<InspectorDOMStorageAgent> create(DOMStorageResourcesMap* domStorageResources, InspectorFrontend* frontend) + static PassOwnPtr<InspectorDOMStorageAgent> create(InstrumentingAgents* instrumentingAgents) { - return adoptPtr(new InspectorDOMStorageAgent(domStorageResources, frontend)); + return adoptPtr(new InspectorDOMStorageAgent(instrumentingAgents)); } + ~InspectorDOMStorageAgent(); - virtual ~InspectorDOMStorageAgent(); + void setFrontend(InspectorFrontend*); + void clearFrontend(); + + void clearResources(); // Called from the front-end. - void getDOMStorageEntries(long storageId, RefPtr<InspectorArray>* entries); - void setDOMStorageItem(long storageId, const String& key, const String& value, bool* success); - void removeDOMStorageItem(long storageId, const String& key, bool* success); + void getDOMStorageEntries(ErrorString*, long storageId, RefPtr<InspectorArray>* entries); + void setDOMStorageItem(ErrorString*, long storageId, const String& key, const String& value, bool* success); + void removeDOMStorageItem(ErrorString*, long storageId, const String& key, bool* success); // Called from the injected script. - void selectDOMStorage(Storage* storage); + long storageId(Storage*); + + // Called from InspectorInstrumentation + void didUseDOMStorage(StorageArea*, bool isLocalStorage, Frame*); private: - InspectorDOMStorageAgent(DOMStorageResourcesMap*, InspectorFrontend*); + explicit InspectorDOMStorageAgent(InstrumentingAgents*); InspectorDOMStorageResource* getDOMStorageResourceForId(long storageId); - DOMStorageResourcesMap* m_domStorageResources; + InstrumentingAgents* m_instrumentingAgents; + typedef HashMap<long, RefPtr<InspectorDOMStorageResource> > DOMStorageResourcesMap; + DOMStorageResourcesMap m_resources; InspectorFrontend* m_frontend; }; diff --git a/Source/WebCore/inspector/InspectorDOMStorageResource.cpp b/Source/WebCore/inspector/InspectorDOMStorageResource.cpp index cfd5f9f..6ff6418 100644 --- a/Source/WebCore/inspector/InspectorDOMStorageResource.cpp +++ b/Source/WebCore/inspector/InspectorDOMStorageResource.cpp @@ -46,7 +46,7 @@ using namespace JSC; namespace WebCore { -int InspectorDOMStorageResource::s_nextUnusedId = 1; +long InspectorDOMStorageResource::s_nextUnusedId = 1; InspectorDOMStorageResource::InspectorDOMStorageResource(Storage* domStorage, bool isLocalStorage, Frame* frame) : EventListener(InspectorDOMStorageResourceType) @@ -67,13 +67,13 @@ bool InspectorDOMStorageResource::isSameHostAndType(Frame* frame, bool isLocalSt void InspectorDOMStorageResource::bind(InspectorFrontend* frontend) { ASSERT(!m_frontend); - m_frontend = frontend; + m_frontend = frontend->domstorage(); RefPtr<InspectorObject> jsonObject = InspectorObject::create(); jsonObject->setString("host", m_frame->document()->securityOrigin()->host()); jsonObject->setBoolean("isLocalStorage", m_isLocalStorage); jsonObject->setNumber("id", m_id); - frontend->addDOMStorage(jsonObject); + m_frontend->addDOMStorage(jsonObject); } void InspectorDOMStorageResource::unbind() diff --git a/Source/WebCore/inspector/InspectorDOMStorageResource.h b/Source/WebCore/inspector/InspectorDOMStorageResource.h index f0975ba..9ad5b91 100644 --- a/Source/WebCore/inspector/InspectorDOMStorageResource.h +++ b/Source/WebCore/inspector/InspectorDOMStorageResource.h @@ -34,6 +34,7 @@ #if ENABLE(DOM_STORAGE) #include "EventListener.h" +#include "InspectorFrontend.h" #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> @@ -75,11 +76,11 @@ namespace WebCore { RefPtr<Storage> m_domStorage; bool m_isLocalStorage; RefPtr<Frame> m_frame; - InspectorFrontend* m_frontend; - int m_id; + InspectorFrontend::DOMStorage* m_frontend; + long m_id; bool m_reportingChangesToFrontend; - static int s_nextUnusedId; + static long s_nextUnusedId; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorDatabaseAgent.cpp b/Source/WebCore/inspector/InspectorDatabaseAgent.cpp index 221bdf2..45ec42a 100644 --- a/Source/WebCore/inspector/InspectorDatabaseAgent.cpp +++ b/Source/WebCore/inspector/InspectorDatabaseAgent.cpp @@ -34,10 +34,10 @@ #include "Database.h" #include "ExceptionCode.h" -#include "InspectorAgent.h" #include "InspectorDatabaseResource.h" #include "InspectorFrontend.h" #include "InspectorValues.h" +#include "InstrumentingAgents.h" #include "SQLError.h" #include "SQLStatementCallback.h" #include "SQLStatementErrorCallback.h" @@ -61,18 +61,18 @@ public: virtual ~FrontendProvider() { } - InspectorFrontend* frontend() { return m_inspectorFrontend; } + InspectorFrontend::Database* frontend() { return m_inspectorFrontend; } void clearFrontend() { m_inspectorFrontend = 0; } private: - FrontendProvider(InspectorFrontend* inspectorFrontend) : m_inspectorFrontend(inspectorFrontend) { } - InspectorFrontend* m_inspectorFrontend; + FrontendProvider(InspectorFrontend* inspectorFrontend) : m_inspectorFrontend(inspectorFrontend->database()) { } + InspectorFrontend::Database* m_inspectorFrontend; }; namespace { long lastTransactionId = 0; -void reportTransactionFailed(InspectorFrontend* frontend, long transactionId, SQLError* error) +void reportTransactionFailed(InspectorFrontend::Database* frontend, long transactionId, SQLError* error) { if (!frontend) return; @@ -218,12 +218,46 @@ private: } // namespace +void InspectorDatabaseAgent::didOpenDatabase(PassRefPtr<Database> database, const String& domain, const String& name, const String& version) +{ + RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version); + m_resources.set(resource->id(), resource); + // Resources are only bound while visible. + if (m_frontendProvider) + resource->bind(m_frontendProvider->frontend()); +} + +void InspectorDatabaseAgent::clearResources() +{ + m_resources.clear(); +} + +InspectorDatabaseAgent::InspectorDatabaseAgent(InstrumentingAgents* instrumentingAgents) + : m_instrumentingAgents(instrumentingAgents) +{ + m_instrumentingAgents->setInspectorDatabaseAgent(this); +} + InspectorDatabaseAgent::~InspectorDatabaseAgent() { + m_instrumentingAgents->setInspectorDatabaseAgent(0); +} + +void InspectorDatabaseAgent::setFrontend(InspectorFrontend* frontend) +{ + m_frontendProvider = FrontendProvider::create(frontend); + DatabaseResourcesMap::iterator databasesEnd = m_resources.end(); + for (DatabaseResourcesMap::iterator it = m_resources.begin(); it != databasesEnd; ++it) + it->second->bind(m_frontendProvider->frontend()); +} + +void InspectorDatabaseAgent::clearFrontend() +{ m_frontendProvider->clearFrontend(); + m_frontendProvider.clear(); } -void InspectorDatabaseAgent::getDatabaseTableNames(long databaseId, RefPtr<InspectorArray>* names) +void InspectorDatabaseAgent::getDatabaseTableNames(ErrorString*, long databaseId, RefPtr<InspectorArray>* names) { Database* database = databaseForId(databaseId); if (database) { @@ -234,7 +268,7 @@ void InspectorDatabaseAgent::getDatabaseTableNames(long databaseId, RefPtr<Inspe } } -void InspectorDatabaseAgent::executeSQL(long databaseId, const String& query, bool* success, long* transactionId) +void InspectorDatabaseAgent::executeSQL(ErrorString*, long databaseId, const String& query, bool* success, long* transactionId) { Database* database = databaseForId(databaseId); if (!database) { @@ -250,31 +284,21 @@ void InspectorDatabaseAgent::executeSQL(long databaseId, const String& query, bo *success = true; } -Database* InspectorDatabaseAgent::databaseForId(long databaseId) -{ - DatabaseResourcesMap::iterator it = m_databaseResources->find(databaseId); - if (it == m_databaseResources->end()) - return 0; - return it->second->database(); -} - -void InspectorDatabaseAgent::selectDatabase(Database* database) +long InspectorDatabaseAgent::databaseId(Database* database) { - if (!m_frontendProvider->frontend()) - return; - - for (DatabaseResourcesMap::iterator it = m_databaseResources->begin(); it != m_databaseResources->end(); ++it) { - if (it->second->database() == database) { - m_frontendProvider->frontend()->selectDatabase(it->first); - break; - } + for (DatabaseResourcesMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) { + if (it->second->database() == database) + return it->first; } + return 0; } -InspectorDatabaseAgent::InspectorDatabaseAgent(DatabaseResourcesMap* databaseResources, InspectorFrontend* frontend) - : m_databaseResources(databaseResources) - , m_frontendProvider(FrontendProvider::create(frontend)) +Database* InspectorDatabaseAgent::databaseForId(long databaseId) { + DatabaseResourcesMap::iterator it = m_resources.find(databaseId); + if (it == m_resources.end()) + return 0; + return it->second->database(); } } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorDatabaseAgent.h b/Source/WebCore/inspector/InspectorDatabaseAgent.h index 4ad3e62..7e42211 100644 --- a/Source/WebCore/inspector/InspectorDatabaseAgent.h +++ b/Source/WebCore/inspector/InspectorDatabaseAgent.h @@ -39,32 +39,41 @@ class Database; class InspectorArray; class InspectorDatabaseResource; class InspectorFrontend; +class InstrumentingAgents; + +typedef String ErrorString; class InspectorDatabaseAgent { public: class FrontendProvider; - typedef HashMap<int, RefPtr<InspectorDatabaseResource> > DatabaseResourcesMap; - - static PassOwnPtr<InspectorDatabaseAgent> create(DatabaseResourcesMap* databaseResources, InspectorFrontend* frontend) + static PassOwnPtr<InspectorDatabaseAgent> create(InstrumentingAgents* instrumentingAgents) { - return adoptPtr(new InspectorDatabaseAgent(databaseResources, frontend)); + return adoptPtr(new InspectorDatabaseAgent(instrumentingAgents)); } + ~InspectorDatabaseAgent(); + + void setFrontend(InspectorFrontend*); + void clearFrontend(); - virtual ~InspectorDatabaseAgent(); + void clearResources(); // Called from the front-end. - void getDatabaseTableNames(long databaseId, RefPtr<InspectorArray>* names); - void executeSQL(long databaseId, const String& query, bool* success, long* transactionId); + void getDatabaseTableNames(ErrorString* error, long databaseId, RefPtr<InspectorArray>* names); + void executeSQL(ErrorString* error, long databaseId, const String& query, bool* success, long* transactionId); // Called from the injected script. - Database* databaseForId(long databaseId); - void selectDatabase(Database* database); + long databaseId(Database*); + void didOpenDatabase(PassRefPtr<Database>, const String& domain, const String& name, const String& version); private: - InspectorDatabaseAgent(DatabaseResourcesMap*, InspectorFrontend*); + explicit InspectorDatabaseAgent(InstrumentingAgents*); + + Database* databaseForId(long databaseId); - DatabaseResourcesMap* m_databaseResources; + InstrumentingAgents* m_instrumentingAgents; + typedef HashMap<int, RefPtr<InspectorDatabaseResource> > DatabaseResourcesMap; + DatabaseResourcesMap m_resources; RefPtr<FrontendProvider> m_frontendProvider; }; diff --git a/Source/WebCore/inspector/InspectorDatabaseResource.cpp b/Source/WebCore/inspector/InspectorDatabaseResource.cpp index e2d2f81..41342a4 100644 --- a/Source/WebCore/inspector/InspectorDatabaseResource.cpp +++ b/Source/WebCore/inspector/InspectorDatabaseResource.cpp @@ -38,7 +38,7 @@ namespace WebCore { -static int nextUnusedId = 1; +static long nextUnusedId = 1; PassRefPtr<InspectorDatabaseResource> InspectorDatabaseResource::create(PassRefPtr<Database> database, const String& domain, const String& name, const String& version) { @@ -54,7 +54,7 @@ InspectorDatabaseResource::InspectorDatabaseResource(PassRefPtr<Database> databa { } -void InspectorDatabaseResource::bind(InspectorFrontend* frontend) +void InspectorDatabaseResource::bind(InspectorFrontend::Database* frontend) { RefPtr<InspectorObject> jsonObject = InspectorObject::create(); jsonObject->setNumber("id", m_id); diff --git a/Source/WebCore/inspector/InspectorDatabaseResource.h b/Source/WebCore/inspector/InspectorDatabaseResource.h index 24d4f1c..550fcd8 100644 --- a/Source/WebCore/inspector/InspectorDatabaseResource.h +++ b/Source/WebCore/inspector/InspectorDatabaseResource.h @@ -32,6 +32,7 @@ #define InspectorDatabaseResource_h #if ENABLE(DATABASE) +#include "InspectorFrontend.h" #include "PlatformString.h" #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> @@ -45,14 +46,15 @@ class InspectorDatabaseResource : public RefCounted<InspectorDatabaseResource> { public: static PassRefPtr<InspectorDatabaseResource> create(PassRefPtr<Database> database, const String& domain, const String& name, const String& version); - void bind(InspectorFrontend* frontend); + void bind(InspectorFrontend::Database*); Database* database() { return m_database.get(); } long id() const { return m_id; } + private: InspectorDatabaseResource(PassRefPtr<Database>, const String& domain, const String& name, const String& version); RefPtr<Database> m_database; - int m_id; + long m_id; String m_domain; String m_name; String m_version; diff --git a/Source/WebCore/inspector/InspectorDebuggerAgent.cpp b/Source/WebCore/inspector/InspectorDebuggerAgent.cpp index e8b4ad5..0cdc2b0 100644 --- a/Source/WebCore/inspector/InspectorDebuggerAgent.cpp +++ b/Source/WebCore/inspector/InspectorDebuggerAgent.cpp @@ -36,6 +36,7 @@ #include "InspectorFrontend.h" #include "InspectorState.h" #include "InspectorValues.h" +#include "InstrumentingAgents.h" #include "PlatformString.h" #include "ScriptDebugServer.h" #include <wtf/text/StringConcatenate.h> @@ -43,41 +44,121 @@ namespace WebCore { namespace DebuggerAgentState { +static const char debuggerEnabled[] = "debuggerEnabled"; +static const char enableWhenShown[] = "debuggerEnableWhenShown"; static const char javaScriptBreakpoints[] = "javaScriptBreakopints"; }; -PassOwnPtr<InspectorDebuggerAgent> InspectorDebuggerAgent::create(InspectorAgent* inspectorAgent, InspectorFrontend* frontend, bool eraseStickyBreakpoints) +PassOwnPtr<InspectorDebuggerAgent> InspectorDebuggerAgent::create(InstrumentingAgents* instrumentingAgents, InspectorState* inspectorState, Page* inspectedPage, InjectedScriptHost* injectedScriptHost) { - OwnPtr<InspectorDebuggerAgent> agent = adoptPtr(new InspectorDebuggerAgent(inspectorAgent, frontend, eraseStickyBreakpoints)); - ScriptDebugServer::shared().clearBreakpoints(); - // FIXME(WK44513): breakpoints activated flag should be synchronized between all front-ends - ScriptDebugServer::shared().setBreakpointsActivated(true); - ScriptDebugServer::shared().addListener(agent.get(), inspectorAgent->inspectedPage()); - return agent.release(); + return adoptPtr(new InspectorDebuggerAgent(instrumentingAgents, inspectorState, inspectedPage, injectedScriptHost)); } -InspectorDebuggerAgent::InspectorDebuggerAgent(InspectorAgent* inspectorAgent, InspectorFrontend* frontend, bool eraseStickyBreakpoints) - : m_inspectorAgent(inspectorAgent) - , m_frontend(frontend) +InspectorDebuggerAgent::InspectorDebuggerAgent(InstrumentingAgents* instrumentingAgents, InspectorState* inspectorState, Page* inspectedPage, InjectedScriptHost* injectedScriptHost) + : m_instrumentingAgents(instrumentingAgents) + , m_inspectorState(inspectorState) + , m_inspectedPage(inspectedPage) + , m_injectedScriptHost(injectedScriptHost) + , m_frontend(0) , m_pausedScriptState(0) , m_javaScriptPauseScheduled(false) + , m_listener(0) { - if (eraseStickyBreakpoints) - inspectorAgent->state()->setObject(DebuggerAgentState::javaScriptBreakpoints, InspectorObject::create()); } InspectorDebuggerAgent::~InspectorDebuggerAgent() { - ScriptDebugServer::shared().removeListener(this, m_inspectorAgent->inspectedPage()); - m_pausedScriptState = 0; + ASSERT(!m_instrumentingAgents->inspectorDebuggerAgent()); +} + +void InspectorDebuggerAgent::startUserInitiatedDebugging() +{ + if (m_frontend) + enable(false); + else + m_inspectorState->setBoolean(DebuggerAgentState::enableWhenShown, true); +} + +void InspectorDebuggerAgent::enable(bool restoringFromState) +{ + ASSERT(m_frontend); + if (!restoringFromState && enabled()) + return; + m_inspectorState->setBoolean(DebuggerAgentState::debuggerEnabled, true); + m_instrumentingAgents->setInspectorDebuggerAgent(this); + + ScriptDebugServer::shared().clearBreakpoints(); + // FIXME(WK44513): breakpoints activated flag should be synchronized between all front-ends + ScriptDebugServer::shared().setBreakpointsActivated(true); + ScriptDebugServer::shared().addListener(this, m_inspectedPage); + + m_frontend->debuggerWasEnabled(); + if (m_listener) + m_listener->debuggerWasEnabled(); } -void InspectorDebuggerAgent::activateBreakpoints() +void InspectorDebuggerAgent::disable() +{ + if (!enabled()) + return; + m_inspectorState->setBoolean(DebuggerAgentState::debuggerEnabled, false); + m_instrumentingAgents->setInspectorDebuggerAgent(0); + + ScriptDebugServer::shared().removeListener(this, m_inspectedPage); + clear(); + + if (m_frontend) + m_frontend->debuggerWasDisabled(); + if (m_listener) + m_listener->debuggerWasDisabled(); +} + +bool InspectorDebuggerAgent::enabled() +{ + return m_inspectorState->getBoolean(DebuggerAgentState::debuggerEnabled); +} + +void InspectorDebuggerAgent::restore() +{ + if (m_inspectorState->getBoolean(DebuggerAgentState::debuggerEnabled)) + enable(true); +} + +void InspectorDebuggerAgent::setFrontend(InspectorFrontend* frontend) +{ + m_frontend = frontend->debugger(); +} + +void InspectorDebuggerAgent::enableDebuggerAfterShown() +{ + // Erase sticky breakpoints. If we are restoring from a cookie setFrontend msut be called + // before the state is loaded from the cookie. + m_inspectorState->setObject(DebuggerAgentState::javaScriptBreakpoints, InspectorObject::create()); + if (m_inspectorState->getBoolean(DebuggerAgentState::enableWhenShown)) { + m_inspectorState->setBoolean(DebuggerAgentState::enableWhenShown, false); + enable(false); + } +} + +void InspectorDebuggerAgent::clearFrontend() +{ + m_frontend = 0; + + if (!enabled()) + return; + // If the window is being closed with the debugger enabled, + // remember this state to re-enable debugger on the next window + // opening. + disable(); + m_inspectorState->setBoolean(DebuggerAgentState::enableWhenShown, true); +} + +void InspectorDebuggerAgent::activateBreakpoints(ErrorString*) { ScriptDebugServer::shared().activateBreakpoints(); } -void InspectorDebuggerAgent::deactivateBreakpoints() +void InspectorDebuggerAgent::deactivateBreakpoints(ErrorString*) { ScriptDebugServer::shared().deactivateBreakpoints(); } @@ -88,10 +169,10 @@ void InspectorDebuggerAgent::inspectedURLChanged(const String&) m_breakpointIdToDebugServerBreakpointIds.clear(); } -void InspectorDebuggerAgent::setJavaScriptBreakpoint(const String& url, int lineNumber, int columnNumber, const String& condition, bool enabled, String* outBreakpointId, RefPtr<InspectorArray>* locations) +void InspectorDebuggerAgent::setJavaScriptBreakpoint(ErrorString*, const String& url, int lineNumber, int columnNumber, const String& condition, bool enabled, String* outBreakpointId, RefPtr<InspectorArray>* locations) { String breakpointId = makeString(url, ":", String::number(lineNumber), ":", String::number(columnNumber)); - RefPtr<InspectorObject> breakpointsCookie = m_inspectorAgent->state()->getObject(DebuggerAgentState::javaScriptBreakpoints); + RefPtr<InspectorObject> breakpointsCookie = m_inspectorState->getObject(DebuggerAgentState::javaScriptBreakpoints); if (breakpointsCookie->find(breakpointId) != breakpointsCookie->end()) return; RefPtr<InspectorObject> breakpointObject = InspectorObject::create(); @@ -101,7 +182,7 @@ void InspectorDebuggerAgent::setJavaScriptBreakpoint(const String& url, int line breakpointObject->setString("condition", condition); breakpointObject->setBoolean("enabled", enabled); breakpointsCookie->setObject(breakpointId, breakpointObject); - m_inspectorAgent->state()->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie); + m_inspectorState->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie); ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition, enabled); for (ScriptsMap::iterator it = m_scripts.begin(); it != m_scripts.end(); ++it) { @@ -119,7 +200,7 @@ void InspectorDebuggerAgent::setJavaScriptBreakpoint(const String& url, int line *outBreakpointId = breakpointId; } -void InspectorDebuggerAgent::setJavaScriptBreakpointBySourceId(const String& sourceId, int lineNumber, int columnNumber, const String& condition, bool enabled, String* outBreakpointId, int* actualLineNumber, int* actualColumnNumber) +void InspectorDebuggerAgent::setJavaScriptBreakpointBySourceId(ErrorString*, const String& sourceId, int lineNumber, int columnNumber, const String& condition, bool enabled, String* outBreakpointId, int* actualLineNumber, int* actualColumnNumber) { String breakpointId = makeString(sourceId, ":", String::number(lineNumber), ":", String::number(columnNumber)); if (m_breakpointIdToDebugServerBreakpointIds.find(breakpointId) != m_breakpointIdToDebugServerBreakpointIds.end()) @@ -130,11 +211,11 @@ void InspectorDebuggerAgent::setJavaScriptBreakpointBySourceId(const String& sou *outBreakpointId = breakpointId; } -void InspectorDebuggerAgent::removeJavaScriptBreakpoint(const String& breakpointId) +void InspectorDebuggerAgent::removeJavaScriptBreakpoint(ErrorString*, const String& breakpointId) { - RefPtr<InspectorObject> breakpointsCookie = m_inspectorAgent->state()->getObject(DebuggerAgentState::javaScriptBreakpoints); + RefPtr<InspectorObject> breakpointsCookie = m_inspectorState->getObject(DebuggerAgentState::javaScriptBreakpoints); breakpointsCookie->remove(breakpointId); - m_inspectorAgent->state()->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie); + m_inspectorState->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie); BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId); if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end()) @@ -144,7 +225,7 @@ void InspectorDebuggerAgent::removeJavaScriptBreakpoint(const String& breakpoint m_breakpointIdToDebugServerBreakpointIds.remove(debugServerBreakpointIdsIterator); } -void InspectorDebuggerAgent::continueToLocation(const String& sourceId, int lineNumber, int columnNumber) +void InspectorDebuggerAgent::continueToLocation(ErrorString* error, const String& sourceId, int lineNumber, int columnNumber) { if (!m_continueToLocationBreakpointId.isEmpty()) { ScriptDebugServer::shared().removeBreakpoint(m_continueToLocationBreakpointId); @@ -152,7 +233,7 @@ void InspectorDebuggerAgent::continueToLocation(const String& sourceId, int line } ScriptBreakpoint breakpoint(lineNumber, columnNumber, "", true); m_continueToLocationBreakpointId = ScriptDebugServer::shared().setBreakpoint(sourceId, breakpoint, &lineNumber, &columnNumber); - resume(); + resume(error); } bool InspectorDebuggerAgent::resolveBreakpoint(const String& breakpointId, const String& sourceId, const ScriptBreakpoint& breakpoint, int* actualLineNumber, int* actualColumnNumber) @@ -185,13 +266,13 @@ bool InspectorDebuggerAgent::resolveBreakpoint(const String& breakpointId, const return true; } -void InspectorDebuggerAgent::editScriptSource(const String& sourceID, const String& newContent, bool* success, String* result, RefPtr<InspectorValue>* newCallFrames) +void InspectorDebuggerAgent::editScriptSource(ErrorString*, const String& sourceID, const String& newContent, bool* success, String* result, RefPtr<InspectorValue>* newCallFrames) { if ((*success = ScriptDebugServer::shared().editScriptSource(sourceID, newContent, *result))) *newCallFrames = currentCallFrames(); } -void InspectorDebuggerAgent::getScriptSource(const String& sourceID, String* scriptSource) +void InspectorDebuggerAgent::getScriptSource(ErrorString*, const String& sourceID, String* scriptSource) { *scriptSource = m_scripts.get(sourceID).data; } @@ -214,57 +295,50 @@ void InspectorDebuggerAgent::cancelPauseOnNextStatement() ScriptDebugServer::shared().setPauseOnNextStatement(false); } -void InspectorDebuggerAgent::pause() +void InspectorDebuggerAgent::pause(ErrorString*) { schedulePauseOnNextStatement(JavaScriptPauseEventType, InspectorObject::create()); m_javaScriptPauseScheduled = true; } -void InspectorDebuggerAgent::resume() +void InspectorDebuggerAgent::resume(ErrorString*) { ScriptDebugServer::shared().continueProgram(); } -void InspectorDebuggerAgent::stepOver() +void InspectorDebuggerAgent::stepOver(ErrorString*) { ScriptDebugServer::shared().stepOverStatement(); } -void InspectorDebuggerAgent::stepInto() +void InspectorDebuggerAgent::stepInto(ErrorString*) { ScriptDebugServer::shared().stepIntoStatement(); } -void InspectorDebuggerAgent::stepOut() +void InspectorDebuggerAgent::stepOut(ErrorString*) { ScriptDebugServer::shared().stepOutOfFunction(); } -void InspectorDebuggerAgent::setPauseOnExceptionsState(long pauseState, long* newState) +void InspectorDebuggerAgent::setPauseOnExceptionsState(ErrorString*, long pauseState, long* newState) { ScriptDebugServer::shared().setPauseOnExceptionsState(static_cast<ScriptDebugServer::PauseOnExceptionsState>(pauseState)); *newState = ScriptDebugServer::shared().pauseOnExceptionsState(); } -void InspectorDebuggerAgent::evaluateOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, RefPtr<InspectorValue>* result) +void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString*, PassRefPtr<InspectorObject> callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, RefPtr<InspectorValue>* result) { - InjectedScript injectedScript = m_inspectorAgent->injectedScriptHost()->injectedScriptForObjectId(callFrameId.get()); + InjectedScript injectedScript = m_injectedScriptHost->injectedScriptForObjectId(callFrameId.get()); if (!injectedScript.hasNoValue()) injectedScript.evaluateOnCallFrame(callFrameId, expression, objectGroup, includeCommandLineAPI, result); } -void InspectorDebuggerAgent::getCompletionsOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, bool includeCommandLineAPI, RefPtr<InspectorValue>* result) -{ - InjectedScript injectedScript = m_inspectorAgent->injectedScriptHost()->injectedScriptForObjectId(callFrameId.get()); - if (!injectedScript.hasNoValue()) - injectedScript.getCompletionsOnCallFrame(callFrameId, expression, includeCommandLineAPI, result); -} - PassRefPtr<InspectorValue> InspectorDebuggerAgent::currentCallFrames() { if (!m_pausedScriptState) return InspectorValue::null(); - InjectedScript injectedScript = m_inspectorAgent->injectedScriptHost()->injectedScriptFor(m_pausedScriptState); + InjectedScript injectedScript = m_injectedScriptHost->injectedScriptFor(m_pausedScriptState); if (injectedScript.hasNoValue()) { ASSERT_NOT_REACHED(); return InspectorValue::null(); @@ -284,7 +358,7 @@ void InspectorDebuggerAgent::didParseSource(const String& sourceID, const String if (url.isEmpty()) return; - RefPtr<InspectorObject> breakpointsCookie = m_inspectorAgent->state()->getObject(DebuggerAgentState::javaScriptBreakpoints); + RefPtr<InspectorObject> breakpointsCookie = m_inspectorState->getObject(DebuggerAgentState::javaScriptBreakpoints); for (InspectorObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) { RefPtr<InspectorObject> breakpointObject = it->second->asObject(); String breakpointURL; @@ -340,6 +414,16 @@ void InspectorDebuggerAgent::breakProgram(DebuggerEventType type, PassRefPtr<Ins ScriptDebugServer::shared().breakProgram(); } +void InspectorDebuggerAgent::clear() +{ + m_pausedScriptState = 0; + m_scripts.clear(); + m_breakpointIdToDebugServerBreakpointIds.clear(); + m_continueToLocationBreakpointId = String(); + m_breakProgramDetails.clear(); + m_javaScriptPauseScheduled = false; +} + } // namespace WebCore #endif // ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) diff --git a/Source/WebCore/inspector/InspectorDebuggerAgent.h b/Source/WebCore/inspector/InspectorDebuggerAgent.h index 644557f..394034a 100644 --- a/Source/WebCore/inspector/InspectorDebuggerAgent.h +++ b/Source/WebCore/inspector/InspectorDebuggerAgent.h @@ -32,6 +32,7 @@ #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) #include "InjectedScript.h" +#include "InspectorFrontend.h" #include "ScriptBreakpoint.h" #include "ScriptDebugListener.h" #include "ScriptState.h" @@ -42,11 +43,16 @@ #include <wtf/text/StringHash.h> namespace WebCore { + class InjectedScriptHost; -class InspectorAgent; class InspectorFrontend; class InspectorObject; +class InspectorState; class InspectorValue; +class InstrumentingAgents; +class Page; + +typedef String ErrorString; enum DebuggerEventType { JavaScriptPauseEventType, @@ -57,36 +63,55 @@ enum DebuggerEventType { class InspectorDebuggerAgent : public ScriptDebugListener { WTF_MAKE_NONCOPYABLE(InspectorDebuggerAgent); WTF_MAKE_FAST_ALLOCATED; public: - static PassOwnPtr<InspectorDebuggerAgent> create(InspectorAgent*, InspectorFrontend*, bool eraseStickyBreakpoints); + static PassOwnPtr<InspectorDebuggerAgent> create(InstrumentingAgents*, InspectorState*, Page*, InjectedScriptHost*); virtual ~InspectorDebuggerAgent(); + void startUserInitiatedDebugging(); + void enable(ErrorString*) { enable(false); } + void disable(ErrorString*) { disable(); } + void disable(); + bool enabled(); + void restore(); + void setFrontend(InspectorFrontend*); + void enableDebuggerAfterShown(); + void clearFrontend(); + void inspectedURLChanged(const String& url); // Part of the protocol. - void activateBreakpoints(); - void deactivateBreakpoints(); + void activateBreakpoints(ErrorString* error); + void deactivateBreakpoints(ErrorString* error); - void setJavaScriptBreakpoint(const String& url, int lineNumber, int columnNumber, const String& condition, bool enabled, String* breakpointId, RefPtr<InspectorArray>* locations); - void setJavaScriptBreakpointBySourceId(const String& sourceId, int lineNumber, int columnNumber, const String& condition, bool enabled, String* breakpointId, int* actualLineNumber, int* actualColumnNumber); - void removeJavaScriptBreakpoint(const String& breakpointId); - void continueToLocation(const String& sourceId, int lineNumber, int columnNumber); + void setJavaScriptBreakpoint(ErrorString* error, const String& url, int lineNumber, int columnNumber, const String& condition, bool enabled, String* breakpointId, RefPtr<InspectorArray>* locations); + void setJavaScriptBreakpointBySourceId(ErrorString* error, const String& sourceId, int lineNumber, int columnNumber, const String& condition, bool enabled, String* breakpointId, int* actualLineNumber, int* actualColumnNumber); + void removeJavaScriptBreakpoint(ErrorString* error, const String& breakpointId); + void continueToLocation(ErrorString* error, const String& sourceId, int lineNumber, int columnNumber); - void editScriptSource(const String& sourceID, const String& newContent, bool* success, String* result, RefPtr<InspectorValue>* newCallFrames); - void getScriptSource(const String& sourceID, String* scriptSource); + void editScriptSource(ErrorString* error, const String& sourceID, const String& newContent, bool* success, String* result, RefPtr<InspectorValue>* newCallFrames); + void getScriptSource(ErrorString* error, const String& sourceID, String* scriptSource); void schedulePauseOnNextStatement(DebuggerEventType type, PassRefPtr<InspectorValue> data); void cancelPauseOnNextStatement(); void breakProgram(DebuggerEventType type, PassRefPtr<InspectorValue> data); - void pause(); - void resume(); - void stepOver(); - void stepInto(); - void stepOut(); - void setPauseOnExceptionsState(long pauseState, long* newState); - void evaluateOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, RefPtr<InspectorValue>* result); - void getCompletionsOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, bool includeCommandLineAPI, RefPtr<InspectorValue>* result); + void pause(ErrorString* error); + void resume(ErrorString* error); + void stepOver(ErrorString* error); + void stepInto(ErrorString* error); + void stepOut(ErrorString* error); + void setPauseOnExceptionsState(ErrorString* error, long pauseState, long* newState); + void evaluateOnCallFrame(ErrorString* error, PassRefPtr<InspectorObject> callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, RefPtr<InspectorValue>* result); + + class Listener { + public: + virtual ~Listener() { } + virtual void debuggerWasEnabled() = 0; + virtual void debuggerWasDisabled() = 0; + }; + void setListener(Listener* listener) { m_listener = listener; } private: - InspectorDebuggerAgent(InspectorAgent*, InspectorFrontend*, bool eraseStickyBreakpoints); + InspectorDebuggerAgent(InstrumentingAgents*, InspectorState*, Page*, InjectedScriptHost*); + + void enable(bool restoringFromState); PassRefPtr<InspectorValue> currentCallFrames(); @@ -96,6 +121,7 @@ private: virtual void didContinue(); bool resolveBreakpoint(const String& breakpointId, const String& sourceId, const ScriptBreakpoint&, int* actualLineNumber, int* actualColumnNumber); + void clear(); class Script { public: @@ -125,14 +151,18 @@ private: typedef HashMap<String, Script> ScriptsMap; typedef HashMap<String, Vector<String> > BreakpointIdToDebugServerBreakpointIdsMap; - InspectorAgent* m_inspectorAgent; - InspectorFrontend* m_frontend; + InstrumentingAgents* m_instrumentingAgents; + InspectorState* m_inspectorState; + Page* m_inspectedPage; + InjectedScriptHost* m_injectedScriptHost; + InspectorFrontend::Debugger* m_frontend; ScriptState* m_pausedScriptState; ScriptsMap m_scripts; BreakpointIdToDebugServerBreakpointIdsMap m_breakpointIdToDebugServerBreakpointIds; String m_continueToLocationBreakpointId; RefPtr<InspectorObject> m_breakProgramDetails; bool m_javaScriptPauseScheduled; + Listener* m_listener; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorInstrumentation.cpp b/Source/WebCore/inspector/InspectorInstrumentation.cpp index e7bb1eb..dfe1c28 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.cpp +++ b/Source/WebCore/inspector/InspectorInstrumentation.cpp @@ -41,12 +41,16 @@ #include "InspectorAgent.h" #include "InspectorApplicationCacheAgent.h" #include "InspectorBrowserDebuggerAgent.h" +#include "InspectorCSSAgent.h" #include "InspectorConsoleAgent.h" +#include "InspectorDatabaseAgent.h" #include "InspectorDOMAgent.h" +#include "InspectorDOMStorageAgent.h" #include "InspectorDebuggerAgent.h" #include "InspectorProfilerAgent.h" #include "InspectorResourceAgent.h" #include "InspectorTimelineAgent.h" +#include "InstrumentingAgents.h" #include "ScriptArguments.h" #include "ScriptCallStack.h" #include "XMLHttpRequest.h" @@ -99,7 +103,7 @@ void InspectorInstrumentation::inspectedPageDestroyedImpl(InspectorAgent* inspec void InspectorInstrumentation::willInsertDOMNodeImpl(InspectorAgent* inspectorAgent, Node* node, Node* parent) { #if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorAgent->browserDebuggerAgent()) + if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorAgent->instrumentingAgents()->inspectorBrowserDebuggerAgent()) browserDebuggerAgent->willInsertDOMNode(node, parent); #endif } @@ -109,7 +113,7 @@ void InspectorInstrumentation::didInsertDOMNodeImpl(InspectorAgent* inspectorAge if (InspectorDOMAgent* domAgent = inspectorAgent->domAgent()) domAgent->didInsertDOMNode(node); #if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorAgent->browserDebuggerAgent()) + if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorAgent->instrumentingAgents()->inspectorBrowserDebuggerAgent()) browserDebuggerAgent->didInsertDOMNode(node); #endif } @@ -117,7 +121,7 @@ void InspectorInstrumentation::didInsertDOMNodeImpl(InspectorAgent* inspectorAge void InspectorInstrumentation::willRemoveDOMNodeImpl(InspectorAgent* inspectorAgent, Node* node) { #if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorAgent->browserDebuggerAgent()) + if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorAgent->instrumentingAgents()->inspectorBrowserDebuggerAgent()) browserDebuggerAgent->willRemoveDOMNode(node); #endif } @@ -125,7 +129,7 @@ void InspectorInstrumentation::willRemoveDOMNodeImpl(InspectorAgent* inspectorAg void InspectorInstrumentation::didRemoveDOMNodeImpl(InspectorAgent* inspectorAgent, Node* node) { #if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorAgent->browserDebuggerAgent()) + if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorAgent->instrumentingAgents()->inspectorBrowserDebuggerAgent()) browserDebuggerAgent->didRemoveDOMNode(node); #endif if (InspectorDOMAgent* domAgent = inspectorAgent->domAgent()) @@ -135,7 +139,7 @@ void InspectorInstrumentation::didRemoveDOMNodeImpl(InspectorAgent* inspectorAge void InspectorInstrumentation::willModifyDOMAttrImpl(InspectorAgent* inspectorAgent, Element* element) { #if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorAgent->browserDebuggerAgent()) + if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorAgent->instrumentingAgents()->inspectorBrowserDebuggerAgent()) browserDebuggerAgent->willModifyDOMAttr(element); #endif } @@ -146,6 +150,12 @@ void InspectorInstrumentation::didModifyDOMAttrImpl(InspectorAgent* inspectorAge domAgent->didModifyDOMAttr(element); } +void InspectorInstrumentation::didInvalidateStyleAttrImpl(InspectorAgent* inspectorAgent, Node* node) +{ + if (InspectorDOMAgent* domAgent = inspectorAgent->domAgent()) + domAgent->didInvalidateStyleAttr(node); +} + void InspectorInstrumentation::mouseDidMoveOverElementImpl(InspectorAgent* inspectorAgent, const HitTestResult& result, unsigned modifierFlags) { inspectorAgent->mouseDidMoveOverElement(result, modifierFlags); @@ -165,7 +175,7 @@ void InspectorInstrumentation::characterDataModifiedImpl(InspectorAgent* inspect void InspectorInstrumentation::willSendXMLHttpRequestImpl(InspectorAgent* inspectorAgent, const String& url) { #if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorAgent->browserDebuggerAgent()) + if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorAgent->instrumentingAgents()->inspectorBrowserDebuggerAgent()) browserDebuggerAgent->willSendXMLHttpRequest(url); #endif } @@ -498,8 +508,47 @@ void InspectorInstrumentation::frameDetachedFromParentImpl(InspectorAgent* inspe resourceAgent->frameDetachedFromParent(frame); } -void InspectorInstrumentation::didCommitLoadImpl(InspectorAgent* inspectorAgent, DocumentLoader* loader) +void InspectorInstrumentation::didCommitLoadImpl(Page* page, InspectorAgent* inspectorAgent, DocumentLoader* loader) { + if (!inspectorAgent->enabled()) + return; + + InstrumentingAgents* instrumentingAgents = inspectorAgent->instrumentingAgents(); + if (InspectorResourceAgent* resourceAgent = instrumentingAgents->inspectorResourceAgent()) + resourceAgent->didCommitLoad(loader); + + Frame* mainFrame = page->mainFrame(); + if (loader->frame() != mainFrame) + return; + + if (InspectorConsoleAgent* consoleAgent = instrumentingAgents->inspectorConsoleAgent()) + consoleAgent->reset(); +#if ENABLE(JAVASCRIPT_DEBUGGER) + if (InspectorDebuggerAgent* debuggerAgent = instrumentingAgents->inspectorDebuggerAgent()) { + KURL url = inspectorAgent->inspectedURLWithoutFragment(); + debuggerAgent->inspectedURLChanged(url); + if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = instrumentingAgents->inspectorBrowserDebuggerAgent()) + browserDebuggerAgent->inspectedURLChanged(url); + } +#endif +#if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC) + if (InspectorProfilerAgent* profilerAgent = instrumentingAgents->inspectorProfilerAgent()) { + profilerAgent->stopUserInitiatedProfiling(true); + profilerAgent->resetState(); + } +#endif + if (InspectorCSSAgent* cssAgent = instrumentingAgents->inspectorCSSAgent()) + cssAgent->reset(); +#if ENABLE(DATABASE) + if (InspectorDatabaseAgent* databaseAgent = instrumentingAgents->inspectorDatabaseAgent()) + databaseAgent->clearResources(); +#endif +#if ENABLE(DOM_STORAGE) + if (InspectorDOMStorageAgent* domStorageAgent = instrumentingAgents->inspectorDOMStorageAgent()) + domStorageAgent->clearResources(); +#endif + if (InspectorDOMAgent* domAgent = instrumentingAgents->inspectorDOMAgent()) + domAgent->setDocument(mainFrame->document()); inspectorAgent->didCommitLoad(loader); } @@ -585,14 +634,20 @@ bool InspectorInstrumentation::profilerEnabledImpl(InspectorAgent* inspectorAgen #if ENABLE(DATABASE) void InspectorInstrumentation::didOpenDatabaseImpl(InspectorAgent* inspectorAgent, PassRefPtr<Database> database, const String& domain, const String& name, const String& version) { - inspectorAgent->didOpenDatabase(database, domain, name, version); + if (!inspectorAgent->enabled()) + return; + if (InspectorDatabaseAgent* dbAgent = inspectorAgent->instrumentingAgents()->inspectorDatabaseAgent()) + dbAgent->didOpenDatabase(database, domain, name, version); } #endif #if ENABLE(DOM_STORAGE) void InspectorInstrumentation::didUseDOMStorageImpl(InspectorAgent* inspectorAgent, StorageArea* storageArea, bool isLocalStorage, Frame* frame) { - inspectorAgent->didUseDOMStorage(storageArea, isLocalStorage, frame); + if (!inspectorAgent->enabled()) + return; + if (InspectorDOMStorageAgent* domStorageAgent = inspectorAgent->instrumentingAgents()->inspectorDOMStorageAgent()) + domStorageAgent->didUseDOMStorage(storageArea, isLocalStorage, frame); } #endif @@ -609,37 +664,43 @@ void InspectorInstrumentation::didDestroyWorkerImpl(InspectorAgent* inspectorAge #endif #if ENABLE(WEB_SOCKETS) -void InspectorInstrumentation::didCreateWebSocketImpl(InspectorAgent* inspectorAgent, unsigned long identifier, const KURL& requestURL, const KURL& documentURL) +void InspectorInstrumentation::didCreateWebSocketImpl(InspectorAgent* inspectorAgent, unsigned long identifier, const KURL& requestURL, const KURL&) { - inspectorAgent->didCreateWebSocket(identifier, requestURL, documentURL); + if (!inspectorAgent->enabled()) + return; + if (InspectorResourceAgent* resourceAgent = retrieveResourceAgent(inspectorAgent)) + resourceAgent->didCreateWebSocket(identifier, requestURL); } void InspectorInstrumentation::willSendWebSocketHandshakeRequestImpl(InspectorAgent* inspectorAgent, unsigned long identifier, const WebSocketHandshakeRequest& request) { - inspectorAgent->willSendWebSocketHandshakeRequest(identifier, request); + if (InspectorResourceAgent* resourceAgent = retrieveResourceAgent(inspectorAgent)) + resourceAgent->willSendWebSocketHandshakeRequest(identifier, request); } void InspectorInstrumentation::didReceiveWebSocketHandshakeResponseImpl(InspectorAgent* inspectorAgent, unsigned long identifier, const WebSocketHandshakeResponse& response) { - inspectorAgent->didReceiveWebSocketHandshakeResponse(identifier, response); + if (InspectorResourceAgent* resourceAgent = retrieveResourceAgent(inspectorAgent)) + resourceAgent->didReceiveWebSocketHandshakeResponse(identifier, response); } void InspectorInstrumentation::didCloseWebSocketImpl(InspectorAgent* inspectorAgent, unsigned long identifier) { - inspectorAgent->didCloseWebSocket(identifier); + if (InspectorResourceAgent* resourceAgent = retrieveResourceAgent(inspectorAgent)) + resourceAgent->didCloseWebSocket(identifier); } #endif #if ENABLE(OFFLINE_WEB_APPLICATIONS) void InspectorInstrumentation::networkStateChangedImpl(InspectorAgent* inspectorAgent) { - if (InspectorApplicationCacheAgent* applicationCacheAgent = inspectorAgent->applicationCacheAgent()) + if (InspectorApplicationCacheAgent* applicationCacheAgent = inspectorAgent->instrumentingAgents()->inspectorApplicationCacheAgent()) applicationCacheAgent->networkStateChanged(); } void InspectorInstrumentation::updateApplicationCacheStatusImpl(InspectorAgent* inspectorAgent, Frame* frame) { - if (InspectorApplicationCacheAgent* applicationCacheAgent = inspectorAgent->applicationCacheAgent()) + if (InspectorApplicationCacheAgent* applicationCacheAgent = inspectorAgent->instrumentingAgents()->inspectorApplicationCacheAgent()) applicationCacheAgent->updateApplicationCacheStatus(frame); } #endif @@ -652,7 +713,7 @@ bool InspectorInstrumentation::hasFrontend(InspectorAgent* inspectorAgent) void InspectorInstrumentation::pauseOnNativeEventIfNeeded(InspectorAgent* inspectorAgent, const String& categoryType, const String& eventName, bool synchronous) { #if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorAgent->browserDebuggerAgent()) + if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorAgent->instrumentingAgents()->inspectorBrowserDebuggerAgent()) browserDebuggerAgent->pauseOnNativeEventIfNeeded(categoryType, eventName, synchronous); #endif } @@ -667,7 +728,7 @@ void InspectorInstrumentation::cancelPauseOnNativeEvent(InspectorAgent* inspecto InspectorTimelineAgent* InspectorInstrumentation::retrieveTimelineAgent(InspectorAgent* inspectorAgent) { - return inspectorAgent->timelineAgent(); + return inspectorAgent->instrumentingAgents()->inspectorTimelineAgent(); } InspectorTimelineAgent* InspectorInstrumentation::retrieveTimelineAgent(const InspectorInstrumentationCookie& cookie) @@ -680,7 +741,7 @@ InspectorTimelineAgent* InspectorInstrumentation::retrieveTimelineAgent(const In InspectorResourceAgent* InspectorInstrumentation::retrieveResourceAgent(InspectorAgent* inspectorAgent) { - return inspectorAgent->resourceAgent(); + return inspectorAgent->instrumentingAgents()->inspectorResourceAgent(); } } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorInstrumentation.h b/Source/WebCore/inspector/InspectorInstrumentation.h index e406e40..2ea4e4f 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.h +++ b/Source/WebCore/inspector/InspectorInstrumentation.h @@ -78,6 +78,7 @@ public: static void willModifyDOMAttr(Document*, Element*); static void didModifyDOMAttr(Document*, Element*); static void characterDataModified(Document*, CharacterData*); + static void didInvalidateStyleAttr(Document*, Node*); static void mouseDidMoveOverElement(Page*, const HitTestResult&, unsigned modifierFlags); static bool handleMousePress(Page*); @@ -194,6 +195,7 @@ private: static void willModifyDOMAttrImpl(InspectorAgent*, Element*); static void didModifyDOMAttrImpl(InspectorAgent*, Element*); static void characterDataModifiedImpl(InspectorAgent*, CharacterData*); + static void didInvalidateStyleAttrImpl(InspectorAgent*, Node*); static void mouseDidMoveOverElementImpl(InspectorAgent*, const HitTestResult&, unsigned modifierFlags); static bool handleMousePressImpl(InspectorAgent*); @@ -241,7 +243,7 @@ private: static void domContentLoadedEventFiredImpl(InspectorAgent*, Frame*, const KURL&); static void loadEventFiredImpl(InspectorAgent*, Frame*, const KURL&); static void frameDetachedFromParentImpl(InspectorAgent*, Frame*); - static void didCommitLoadImpl(InspectorAgent*, DocumentLoader*); + static void didCommitLoadImpl(Page*, InspectorAgent*, DocumentLoader*); static InspectorInstrumentationCookie willWriteHTMLImpl(InspectorAgent*, unsigned int length, unsigned int startLine); static void didWriteHTMLImpl(const InspectorInstrumentationCookie&, unsigned int endLine); @@ -363,6 +365,14 @@ inline void InspectorInstrumentation::didModifyDOMAttr(Document* document, Eleme #endif } +inline void InspectorInstrumentation::didInvalidateStyleAttr(Document* document, Node* node) +{ +#if ENABLE(INSPECTOR) + if (InspectorAgent* inspectorAgent = inspectorAgentWithFrontendForDocument(document)) + didInvalidateStyleAttrImpl(inspectorAgent, node); +#endif +} + inline void InspectorInstrumentation::mouseDidMoveOverElement(Page* page, const HitTestResult& result, unsigned modifierFlags) { #if ENABLE(INSPECTOR) @@ -733,8 +743,13 @@ inline void InspectorInstrumentation::frameDetachedFromParent(Frame* frame) inline void InspectorInstrumentation::didCommitLoad(Frame* frame, DocumentLoader* loader) { #if ENABLE(INSPECTOR) - if (InspectorAgent* inspectorAgent = inspectorAgentForFrame(frame)) - didCommitLoadImpl(inspectorAgent, loader); + if (!frame) + return; + Page* page = frame->page(); + if (!page) + return; + if (InspectorAgent* inspectorAgent = inspectorAgentForPage(page)) + didCommitLoadImpl(page, inspectorAgent, loader); #endif } diff --git a/Source/WebCore/inspector/InspectorProfilerAgent.cpp b/Source/WebCore/inspector/InspectorProfilerAgent.cpp index 550febf..8867023 100644 --- a/Source/WebCore/inspector/InspectorProfilerAgent.cpp +++ b/Source/WebCore/inspector/InspectorProfilerAgent.cpp @@ -37,6 +37,7 @@ #include "InspectorConsoleAgent.h" #include "InspectorFrontend.h" #include "InspectorValues.h" +#include "InstrumentingAgents.h" #include "KURL.h" #include "Page.h" #include "ScriptDebugServer.h" @@ -56,14 +57,15 @@ static const char* const UserInitiatedProfileName = "org.webkit.profiles.user-in static const char* const CPUProfileType = "CPU"; static const char* const HeapProfileType = "HEAP"; -PassOwnPtr<InspectorProfilerAgent> InspectorProfilerAgent::create(InspectorAgent* inspectorAgent) +PassOwnPtr<InspectorProfilerAgent> InspectorProfilerAgent::create(InstrumentingAgents* instrumentingAgents, InspectorConsoleAgent* consoleAgent, Page* inspectedPage) { - OwnPtr<InspectorProfilerAgent> agent = adoptPtr(new InspectorProfilerAgent(inspectorAgent)); - return agent.release(); + return adoptPtr(new InspectorProfilerAgent(instrumentingAgents, consoleAgent, inspectedPage)); } -InspectorProfilerAgent::InspectorProfilerAgent(InspectorAgent* inspectorAgent) - : m_inspectorAgent(inspectorAgent) +InspectorProfilerAgent::InspectorProfilerAgent(InstrumentingAgents* instrumentingAgents, InspectorConsoleAgent* consoleAgent, Page* inspectedPage) + : m_instrumentingAgents(instrumentingAgents) + , m_consoleAgent(consoleAgent) + , m_inspectedPage(inspectedPage) , m_frontend(0) , m_enabled(false) , m_recordingUserInitiatedProfile(false) @@ -71,10 +73,12 @@ InspectorProfilerAgent::InspectorProfilerAgent(InspectorAgent* inspectorAgent) , m_nextUserInitiatedProfileNumber(1) , m_nextUserInitiatedHeapSnapshotNumber(1) { + m_instrumentingAgents->setInspectorProfilerAgent(this); } InspectorProfilerAgent::~InspectorProfilerAgent() { + m_instrumentingAgents->setInspectorProfilerAgent(0); } void InspectorProfilerAgent::addProfile(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL) @@ -93,7 +97,7 @@ void InspectorProfilerAgent::addProfileFinishedMessageToConsole(PassRefPtr<Scrip RefPtr<ScriptProfile> profile = prpProfile; String title = profile->title(); String message = makeString("Profile \"webkit-profile://", CPUProfileType, '/', encodeWithURLEscapeSequences(title), '#', String::number(profile->uid()), "\" finished."); - m_inspectorAgent->consoleAgent()->addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL); + m_consoleAgent->addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL); } void InspectorProfilerAgent::addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL) @@ -101,7 +105,7 @@ void InspectorProfilerAgent::addStartProfilingMessageToConsole(const String& tit if (!m_frontend) return; String message = makeString("Profile \"webkit-profile://", CPUProfileType, '/', encodeWithURLEscapeSequences(title), "#0\" started."); - m_inspectorAgent->consoleAgent()->addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL); + m_consoleAgent->addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL); } PassRefPtr<InspectorObject> InspectorProfilerAgent::createProfileHeader(const ScriptProfile& profile) @@ -151,7 +155,17 @@ String InspectorProfilerAgent::getCurrentUserInitiatedProfileName(bool increment return makeString(UserInitiatedProfileName, '.', String::number(m_currentUserInitiatedProfileNumber)); } -void InspectorProfilerAgent::getProfileHeaders(RefPtr<InspectorArray>* headers) +void InspectorProfilerAgent::getExactHeapSnapshotNodeRetainedSize(ErrorString*, unsigned long uid, unsigned long nodeId, long* size) +{ + HeapSnapshotsMap::iterator it = m_snapshots.find(uid); + if (it != m_snapshots.end()) { + RefPtr<ScriptHeapSnapshot> snapshot = it->second; + *size = snapshot->exactRetainedSize(nodeId); + } else + *size = -1; +} + +void InspectorProfilerAgent::getProfileHeaders(ErrorString*, RefPtr<InspectorArray>* headers) { ProfilesMap::iterator profilesEnd = m_profiles.end(); for (ProfilesMap::iterator it = m_profiles.begin(); it != profilesEnd; ++it) @@ -165,18 +179,18 @@ namespace { class OutputStream : public ScriptHeapSnapshot::OutputStream { public: - OutputStream(InspectorFrontend* frontend, unsigned long uid) + OutputStream(InspectorFrontend::Profiler* 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; + InspectorFrontend::Profiler* m_frontend; unsigned long m_uid; }; } // namespace -void InspectorProfilerAgent::getProfile(const String& type, unsigned uid, RefPtr<InspectorObject>* profileObject) +void InspectorProfilerAgent::getProfile(ErrorString*, const String& type, unsigned uid, RefPtr<InspectorObject>* profileObject) { if (type == CPUProfileType) { ProfilesMap::iterator it = m_profiles.find(uid); @@ -197,7 +211,7 @@ void InspectorProfilerAgent::getProfile(const String& type, unsigned uid, RefPtr } } -void InspectorProfilerAgent::removeProfile(const String& type, unsigned uid) +void InspectorProfilerAgent::removeProfile(ErrorString*, const String& type, unsigned uid) { if (type == CPUProfileType) { if (m_profiles.contains(uid)) @@ -237,7 +251,7 @@ void InspectorProfilerAgent::startUserInitiatedProfiling() m_recordingUserInitiatedProfile = true; String title = getCurrentUserInitiatedProfileName(true); #if USE(JSC) - JSC::ExecState* scriptState = toJSDOMWindow(m_inspectorAgent->inspectedPage()->mainFrame(), debuggerWorld())->globalExec(); + JSC::ExecState* scriptState = toJSDOMWindow(m_inspectedPage->mainFrame(), debuggerWorld())->globalExec(); #else ScriptState* scriptState = 0; #endif @@ -253,7 +267,7 @@ void InspectorProfilerAgent::stopUserInitiatedProfiling(bool ignoreProfile) m_recordingUserInitiatedProfile = false; String title = getCurrentUserInitiatedProfileName(); #if USE(JSC) - JSC::ExecState* scriptState = toJSDOMWindow(m_inspectorAgent->inspectedPage()->mainFrame(), debuggerWorld())->globalExec(); + JSC::ExecState* scriptState = toJSDOMWindow(m_inspectedPage->mainFrame(), debuggerWorld())->globalExec(); #else // Use null script state to avoid filtering by context security token. // All functions from all iframes should be visible from Inspector UI. @@ -273,7 +287,7 @@ namespace { class HeapSnapshotProgress: public ScriptProfiler::HeapSnapshotProgress { public: - explicit HeapSnapshotProgress(InspectorFrontend* frontend) + explicit HeapSnapshotProgress(InspectorFrontend::Profiler* frontend) : m_frontend(frontend) { } void Start(int totalWork) { @@ -287,13 +301,13 @@ public: void Done() { } bool isCanceled() { return false; } private: - InspectorFrontend* m_frontend; + InspectorFrontend::Profiler* m_frontend; int m_totalWork; }; }; -void InspectorProfilerAgent::takeHeapSnapshot(bool detailed) +void InspectorProfilerAgent::takeHeapSnapshot(ErrorString*, bool detailed) { String title = makeString(UserInitiatedProfileName, '.', String::number(m_nextUserInitiatedHeapSnapshotNumber)); ++m_nextUserInitiatedHeapSnapshotNumber; diff --git a/Source/WebCore/inspector/InspectorProfilerAgent.h b/Source/WebCore/inspector/InspectorProfilerAgent.h index 93637f5..839d801 100644 --- a/Source/WebCore/inspector/InspectorProfilerAgent.h +++ b/Source/WebCore/inspector/InspectorProfilerAgent.h @@ -32,6 +32,7 @@ #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) +#include "InspectorFrontend.h" #include "PlatformString.h" #include <wtf/Forward.h> #include <wtf/HashMap.h> @@ -41,48 +42,56 @@ namespace WebCore { class InspectorArray; -class InspectorAgent; +class InspectorConsoleAgent; class InspectorFrontend; class InspectorObject; +class InstrumentingAgents; +class Page; class ScriptHeapSnapshot; class ScriptProfile; +typedef String ErrorString; + class InspectorProfilerAgent { WTF_MAKE_NONCOPYABLE(InspectorProfilerAgent); WTF_MAKE_FAST_ALLOCATED; public: - static PassOwnPtr<InspectorProfilerAgent> create(InspectorAgent*); + static PassOwnPtr<InspectorProfilerAgent> create(InstrumentingAgents*, InspectorConsoleAgent*, Page*); virtual ~InspectorProfilerAgent(); void addProfile(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL); void addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile>, unsigned lineNumber, const String& sourceURL); void addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL); - void clearProfiles() { resetState(); } + void clearProfiles(ErrorString*) { resetState(); } void disable(); void enable(bool skipRecompile); bool enabled() { return m_enabled; } String getCurrentUserInitiatedProfileName(bool incrementProfileNumber = false); - void getProfileHeaders(RefPtr<InspectorArray>* headers); - void getProfile(const String& type, unsigned uid, RefPtr<InspectorObject>* profileObject); + void getExactHeapSnapshotNodeRetainedSize(ErrorString*, unsigned long uid, unsigned long nodeId, long* size); + void getProfileHeaders(ErrorString* error, RefPtr<InspectorArray>* headers); + void getProfile(ErrorString* error, const String& type, unsigned uid, RefPtr<InspectorObject>* profileObject); bool isRecordingUserInitiatedProfile() { return m_recordingUserInitiatedProfile; } - void removeProfile(const String& type, unsigned uid); + void removeProfile(ErrorString* error, const String& type, unsigned uid); void resetState(); void resetFrontendProfiles(); - void setFrontend(InspectorFrontend* frontend) { m_frontend = frontend; } + void setFrontend(InspectorFrontend* frontend) { m_frontend = frontend->profiler(); } + void clearFrontend() { m_frontend = 0; } void startUserInitiatedProfiling(); void stopUserInitiatedProfiling(bool ignoreProfile = false); - void takeHeapSnapshot(bool detailed); + void takeHeapSnapshot(ErrorString* error, bool detailed); void toggleRecordButton(bool isProfiling); private: typedef HashMap<unsigned int, RefPtr<ScriptProfile> > ProfilesMap; typedef HashMap<unsigned int, RefPtr<ScriptHeapSnapshot> > HeapSnapshotsMap; - InspectorProfilerAgent(InspectorAgent*); + InspectorProfilerAgent(InstrumentingAgents*, InspectorConsoleAgent*, Page*); PassRefPtr<InspectorObject> createProfileHeader(const ScriptProfile& profile); PassRefPtr<InspectorObject> createSnapshotHeader(const ScriptHeapSnapshot& snapshot); - InspectorAgent* m_inspectorAgent; - InspectorFrontend* m_frontend; + InstrumentingAgents* m_instrumentingAgents; + InspectorConsoleAgent* m_consoleAgent; + Page* m_inspectedPage; + InspectorFrontend::Profiler* m_frontend; bool m_enabled; bool m_recordingUserInitiatedProfile; int m_currentUserInitiatedProfileNumber; diff --git a/Source/WebCore/inspector/InspectorResourceAgent.cpp b/Source/WebCore/inspector/InspectorResourceAgent.cpp index 38d9e32..db41640 100644 --- a/Source/WebCore/inspector/InspectorResourceAgent.cpp +++ b/Source/WebCore/inspector/InspectorResourceAgent.cpp @@ -47,6 +47,7 @@ #include "InspectorFrontend.h" #include "InspectorState.h" #include "InspectorValues.h" +#include "InstrumentingAgents.h" #include "KURL.h" #include "Page.h" #include "ProgressTracker.h" @@ -72,11 +73,21 @@ static const char resourceAgentEnabled[] = "resourceAgentEnabled"; static const char extraRequestHeaders[] = "extraRequestHeaders"; } -PassRefPtr<InspectorResourceAgent> InspectorResourceAgent::restore(Page* page, InspectorState* state, InspectorFrontend* frontend) +void InspectorResourceAgent::setFrontend(InspectorFrontend* frontend) { - if (state->getBoolean(ResourceAgentState::resourceAgentEnabled)) - return create(page, state, frontend); - return 0; + m_frontend = frontend->network(); +} + +void InspectorResourceAgent::clearFrontend() +{ + m_frontend = 0; + disable(0); +} + +void InspectorResourceAgent::restore() +{ + if (m_state->getBoolean(ResourceAgentState::resourceAgentEnabled)) + enable(); } bool InspectorResourceAgent::resourceContent(Frame* frame, const KURL& url, String* result) @@ -107,7 +118,7 @@ bool InspectorResourceAgent::resourceContentBase64(Frame* frame, const KURL& url return false; } - *result = base64Encode(data->buffer()); + *result = base64Encode(data->data(), data->size()); return true; } @@ -296,7 +307,7 @@ static void populateObjectWithFrameResources(Frame* frame, PassRefPtr<InspectorO InspectorResourceAgent::~InspectorResourceAgent() { - m_state->setBoolean(ResourceAgentState::resourceAgentEnabled, false); + ASSERT(!m_instrumentingAgents->inspectorResourceAgent()); } void InspectorResourceAgent::identifierForInitialRequest(unsigned long identifier, const KURL& url, DocumentLoader* loader) @@ -311,7 +322,7 @@ void InspectorResourceAgent::identifierForInitialRequest(unsigned long identifie m_frontend->identifierForInitialRequest(identifier, url.string(), loaderObject, callStackValue); } -void InspectorResourceAgent::setExtraHeaders(PassRefPtr<InspectorObject> headers) +void InspectorResourceAgent::setExtraHeaders(ErrorString*, PassRefPtr<InspectorObject> headers) { m_state->setObject(ResourceAgentState::extraRequestHeaders, headers); } @@ -498,12 +509,27 @@ Frame* InspectorResourceAgent::frameForId(unsigned long frameId) return 0; } -void InspectorResourceAgent::cachedResources(RefPtr<InspectorObject>* object) +void InspectorResourceAgent::enable(ErrorString*, RefPtr<InspectorObject>* object) { + enable(); *object = buildObjectForFrameTree(m_page->mainFrame(), true); } -void InspectorResourceAgent::resourceContent(unsigned long frameId, const String& url, bool base64Encode, bool* success, String* content) +void InspectorResourceAgent::enable() +{ + if (!m_frontend) + return; + m_state->setBoolean(ResourceAgentState::resourceAgentEnabled, true); + m_instrumentingAgents->setInspectorResourceAgent(this); +} + +void InspectorResourceAgent::disable(ErrorString*) +{ + m_state->setBoolean(ResourceAgentState::resourceAgentEnabled, false); + m_instrumentingAgents->setInspectorResourceAgent(0); +} + +void InspectorResourceAgent::resourceContent(ErrorString*, unsigned long frameId, const String& url, bool base64Encode, bool* success, String* content) { Frame* frame = frameForId(frameId); if (!frame) { @@ -516,12 +542,12 @@ void InspectorResourceAgent::resourceContent(unsigned long frameId, const String *success = InspectorResourceAgent::resourceContent(frame, KURL(ParsedURLString, url), content); } -InspectorResourceAgent::InspectorResourceAgent(Page* page, InspectorState* state, InspectorFrontend* frontend) - : m_page(page) +InspectorResourceAgent::InspectorResourceAgent(InstrumentingAgents* instrumentingAgents, Page* page, InspectorState* state) + : m_instrumentingAgents(instrumentingAgents) + , m_page(page) , m_state(state) - , m_frontend(frontend) + , m_frontend(0) { - m_state->setBoolean(ResourceAgentState::resourceAgentEnabled, true); } } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorResourceAgent.h b/Source/WebCore/inspector/InspectorResourceAgent.h index fb24b70..f1b3d46 100644 --- a/Source/WebCore/inspector/InspectorResourceAgent.h +++ b/Source/WebCore/inspector/InspectorResourceAgent.h @@ -31,6 +31,7 @@ #ifndef InspectorResourceAgent_h #define InspectorResourceAgent_h +#include "InspectorFrontend.h" #include "PlatformString.h" #include <wtf/PassRefPtr.h> @@ -52,6 +53,7 @@ class InspectorArray; class InspectorFrontend; class InspectorObject; class InspectorState; +class InstrumentingAgents; class KURL; class Page; class ResourceError; @@ -64,13 +66,19 @@ class WebSocketHandshakeRequest; class WebSocketHandshakeResponse; #endif +typedef String ErrorString; + class InspectorResourceAgent : public RefCounted<InspectorResourceAgent> { public: - static PassRefPtr<InspectorResourceAgent> create(Page* page, InspectorState* state, InspectorFrontend* frontend) + static PassRefPtr<InspectorResourceAgent> create(InstrumentingAgents* instrumentingAgents, Page* page, InspectorState* state) { - return adoptRef(new InspectorResourceAgent(page, state, frontend)); + return adoptRef(new InspectorResourceAgent(instrumentingAgents, page, state)); } + void setFrontend(InspectorFrontend*); + void clearFrontend(); + void restore(); + static PassRefPtr<InspectorResourceAgent> restore(Page*, InspectorState*, InspectorFrontend*); static bool resourceContent(Frame*, const KURL&, String* result); @@ -102,16 +110,20 @@ public: Frame* frameForId(unsigned long); // Called from frontend - void cachedResources(RefPtr<InspectorObject>*); - void resourceContent(unsigned long frameId, const String& url, bool base64Encode, bool* resourceFound, String* content); - void setExtraHeaders(PassRefPtr<InspectorObject>); + void enable(ErrorString*, RefPtr<InspectorObject>*); + void disable(ErrorString*); + void resourceContent(ErrorString*, unsigned long frameId, const String& url, bool base64Encode, bool* resourceFound, String* content); + void setExtraHeaders(ErrorString*, PassRefPtr<InspectorObject>); private: - InspectorResourceAgent(Page* page, InspectorState*, InspectorFrontend* frontend); + InspectorResourceAgent(InstrumentingAgents*, Page*, InspectorState*); + + void enable(); + InstrumentingAgents* m_instrumentingAgents; Page* m_page; InspectorState* m_state; - InspectorFrontend* m_frontend; + InspectorFrontend::Network* m_frontend; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorRuntimeAgent.cpp b/Source/WebCore/inspector/InspectorRuntimeAgent.cpp index 7938afd..badd8e1 100644 --- a/Source/WebCore/inspector/InspectorRuntimeAgent.cpp +++ b/Source/WebCore/inspector/InspectorRuntimeAgent.cpp @@ -45,37 +45,44 @@ InspectorRuntimeAgent::InspectorRuntimeAgent(InjectedScriptHost* injectedScriptH InspectorRuntimeAgent::~InspectorRuntimeAgent() { } -void InspectorRuntimeAgent::evaluate(const String& expression, const String& objectGroup, bool includeCommandLineAPI, RefPtr<InspectorValue>* result) +void InspectorRuntimeAgent::evaluate(ErrorString*, const String& expression, const String& objectGroup, bool includeCommandLineAPI, RefPtr<InspectorValue>* result) { InjectedScript injectedScript = m_injectedScriptHost->injectedScriptForMainFrame(); if (!injectedScript.hasNoValue()) injectedScript.evaluate(expression, objectGroup, includeCommandLineAPI, result); } -void InspectorRuntimeAgent::getCompletions(const String& expression, bool includeCommandLineAPI, RefPtr<InspectorValue>* result) +void InspectorRuntimeAgent::evaluateOn(ErrorString*, PassRefPtr<InspectorObject> objectId, const String& expression, RefPtr<InspectorValue>* result) { - InjectedScript injectedScript = m_injectedScriptHost->injectedScriptForMainFrame(); + InjectedScript injectedScript = m_injectedScriptHost->injectedScriptForObjectId(objectId.get()); if (!injectedScript.hasNoValue()) - injectedScript.getCompletions(expression, includeCommandLineAPI, result); + injectedScript.evaluateOn(objectId, expression, result); } -void InspectorRuntimeAgent::getProperties(PassRefPtr<InspectorObject> objectId, bool ignoreHasOwnProperty, bool abbreviate, RefPtr<InspectorValue>* result) +void InspectorRuntimeAgent::getProperties(ErrorString*, PassRefPtr<InspectorObject> objectId, bool ignoreHasOwnProperty, bool abbreviate, RefPtr<InspectorValue>* result) { InjectedScript injectedScript = m_injectedScriptHost->injectedScriptForObjectId(objectId.get()); if (!injectedScript.hasNoValue()) injectedScript.getProperties(objectId, ignoreHasOwnProperty, abbreviate, result); } -void InspectorRuntimeAgent::setPropertyValue(PassRefPtr<InspectorObject> objectId, const String& propertyName, const String& expression, RefPtr<InspectorValue>* result) +void InspectorRuntimeAgent::setPropertyValue(ErrorString*, PassRefPtr<InspectorObject> objectId, const String& propertyName, const String& expression, RefPtr<InspectorValue>* result) { InjectedScript injectedScript = m_injectedScriptHost->injectedScriptForObjectId(objectId.get()); if (!injectedScript.hasNoValue()) injectedScript.setPropertyValue(objectId, propertyName, expression, result); } -void InspectorRuntimeAgent::releaseWrapperObjectGroup(long injectedScriptId, const String& objectGroup) +void InspectorRuntimeAgent::releaseObject(ErrorString*, PassRefPtr<InspectorObject> objectId) +{ + InjectedScript injectedScript = m_injectedScriptHost->injectedScriptForObjectId(objectId.get()); + if (!injectedScript.hasNoValue()) + injectedScript.releaseObject(objectId); +} + +void InspectorRuntimeAgent::releaseObjectGroup(ErrorString*, long injectedScriptId, const String& objectGroup) { - m_injectedScriptHost->releaseWrapperObjectGroup(injectedScriptId, objectGroup); + m_injectedScriptHost->releaseObjectGroup(injectedScriptId, objectGroup); } } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorRuntimeAgent.h b/Source/WebCore/inspector/InspectorRuntimeAgent.h index 9fb2716..4274eea 100644 --- a/Source/WebCore/inspector/InspectorRuntimeAgent.h +++ b/Source/WebCore/inspector/InspectorRuntimeAgent.h @@ -46,6 +46,8 @@ class InjectedScriptHost; class InspectorObject; class InspectorValue; +typedef String ErrorString; + class InspectorRuntimeAgent { WTF_MAKE_NONCOPYABLE(InspectorRuntimeAgent); public: @@ -57,11 +59,12 @@ public: ~InspectorRuntimeAgent(); // Part of the protocol. - void evaluate(const String& expression, const String& objectGroup, bool includeCommandLineAPI, RefPtr<InspectorValue>* result); - void getCompletions(const String& expression, bool includeCommandLineAPI, RefPtr<InspectorValue>* result); - void getProperties(PassRefPtr<InspectorObject> objectId, bool ignoreHasOwnProperty, bool abbreviate, RefPtr<InspectorValue>* result); - void setPropertyValue(PassRefPtr<InspectorObject> objectId, const String& propertyName, const String& expression, RefPtr<InspectorValue>* result); - void releaseWrapperObjectGroup(long injectedScriptId, const String& objectGroup); + void evaluate(ErrorString*, const String& expression, const String& objectGroup, bool includeCommandLineAPI, RefPtr<InspectorValue>* result); + void evaluateOn(ErrorString*, PassRefPtr<InspectorObject> objectId, const String& expression, RefPtr<InspectorValue>* result); + void releaseObject(ErrorString*, PassRefPtr<InspectorObject> objectId); + void getProperties(ErrorString*, PassRefPtr<InspectorObject> objectId, bool ignoreHasOwnProperty, bool abbreviate, RefPtr<InspectorValue>* result); + void setPropertyValue(ErrorString*, PassRefPtr<InspectorObject> objectId, const String& propertyName, const String& expression, RefPtr<InspectorValue>* result); + void releaseObjectGroup(ErrorString*, long injectedScriptId, const String& objectGroup); private: InspectorRuntimeAgent(InjectedScriptHost*); diff --git a/Source/WebCore/inspector/InspectorState.cpp b/Source/WebCore/inspector/InspectorState.cpp index 290ffc2..2988cf2 100644 --- a/Source/WebCore/inspector/InspectorState.cpp +++ b/Source/WebCore/inspector/InspectorState.cpp @@ -42,14 +42,12 @@ InspectorState::InspectorState(InspectorClient* client) { } -InspectorState::InspectorState(InspectorClient* client, const String& json) - : m_client(client) - , m_properties(InspectorObject::create()) - , m_isOnMute(false) +void InspectorState::loadFromCookie(const String& inspectorStateCookie) { - RefPtr<InspectorValue> jsonValue = InspectorValue::parseJSON(json); - if (jsonValue) - m_properties = jsonValue->asObject(); + m_properties.clear(); + RefPtr<InspectorValue> cookie = InspectorValue::parseJSON(inspectorStateCookie); + if (cookie) + m_properties = cookie->asObject(); if (!m_properties) m_properties = InspectorObject::create(); } @@ -59,6 +57,11 @@ void InspectorState::mute() m_isOnMute = true; } +void InspectorState::unmute() +{ + m_isOnMute = false; +} + void InspectorState::updateCookie() { if (!m_isOnMute) diff --git a/Source/WebCore/inspector/InspectorState.h b/Source/WebCore/inspector/InspectorState.h index 3a9c3ed..4407c40 100644 --- a/Source/WebCore/inspector/InspectorState.h +++ b/Source/WebCore/inspector/InspectorState.h @@ -46,10 +46,12 @@ class InspectorClient; class InspectorState { public: InspectorState(InspectorClient*); - InspectorState(InspectorClient*, const String& jsonString); virtual ~InspectorState() {} + void loadFromCookie(const String& inspectorStateCookie); + void mute(); + void unmute(); bool getBoolean(const String& propertyName); String getString(const String& propertyName); diff --git a/Source/WebCore/inspector/InspectorStyleSheet.cpp b/Source/WebCore/inspector/InspectorStyleSheet.cpp index 4af0371..45e6e43 100644 --- a/Source/WebCore/inspector/InspectorStyleSheet.cpp +++ b/Source/WebCore/inspector/InspectorStyleSheet.cpp @@ -1131,7 +1131,7 @@ InspectorStyleSheetForInlineStyle::InspectorStyleSheetForInlineStyle(const Strin void InspectorStyleSheetForInlineStyle::didModifyElementAttribute() { - String newStyleText = m_element->getAttribute("style"); + String newStyleText = elementStyleText(); bool shouldDropSourceData = false; if (m_element->isStyledElement() && m_element->style() != m_inspectorStyle->cssStyle()) { m_inspectorStyle = InspectorStyle::create(InspectorCSSId(id(), 0), inlineStyle(), this); @@ -1168,6 +1168,13 @@ Document* InspectorStyleSheetForInlineStyle::ownerDocument() const bool InspectorStyleSheetForInlineStyle::ensureParsedDataReady() { + // The "style" property value can get changed indirectly, e.g. via element.style.borderWidth = "2px". + const String& currentStyleText = elementStyleText(); + if (m_styleText != currentStyleText) { + m_ruleSourceData.clear(); + m_styleText = currentStyleText; + } + if (m_ruleSourceData) return true; @@ -1192,6 +1199,11 @@ CSSStyleDeclaration* InspectorStyleSheetForInlineStyle::inlineStyle() const return m_element->style(); } +const String& InspectorStyleSheetForInlineStyle::elementStyleText() const +{ + return m_element->getAttribute("style").string(); +} + bool InspectorStyleSheetForInlineStyle::getStyleAttributeRanges(RefPtr<CSSStyleSourceData>* result) { if (!m_element->isStyledElement()) diff --git a/Source/WebCore/inspector/InspectorStyleSheet.h b/Source/WebCore/inspector/InspectorStyleSheet.h index 606d318..92318cb 100644 --- a/Source/WebCore/inspector/InspectorStyleSheet.h +++ b/Source/WebCore/inspector/InspectorStyleSheet.h @@ -243,6 +243,7 @@ protected: private: CSSStyleDeclaration* inlineStyle() const; + const String& elementStyleText() const; bool getStyleAttributeRanges(RefPtr<CSSStyleSourceData>* result); RefPtr<Element> m_element; diff --git a/Source/WebCore/inspector/InspectorTimelineAgent.cpp b/Source/WebCore/inspector/InspectorTimelineAgent.cpp index dd0a119..d45a507 100644 --- a/Source/WebCore/inspector/InspectorTimelineAgent.cpp +++ b/Source/WebCore/inspector/InspectorTimelineAgent.cpp @@ -36,6 +36,7 @@ #include "Event.h" #include "InspectorFrontend.h" #include "InspectorState.h" +#include "InstrumentingAgents.h" #include "IntRect.h" #include "ResourceRequest.h" #include "ResourceResponse.h" @@ -49,15 +50,6 @@ namespace TimelineAgentState { static const char timelineAgentEnabled[] = "timelineAgentEnabled"; } -int InspectorTimelineAgent::s_id = 0; - -PassOwnPtr<InspectorTimelineAgent> InspectorTimelineAgent::restore(InspectorState* state, InspectorFrontend* frontend) -{ - if (state->getBoolean(TimelineAgentState::timelineAgentEnabled)) - return create(state, frontend); - return 0; -} - void InspectorTimelineAgent::pushGCEventRecords() { if (!m_gcEvents.size()) @@ -80,11 +72,59 @@ void InspectorTimelineAgent::didGC(double startTime, double endTime, size_t coll InspectorTimelineAgent::~InspectorTimelineAgent() { - m_frontend->timelineProfilerWasStopped(); + clearFrontend(); +} + +void InspectorTimelineAgent::setFrontend(InspectorFrontend* frontend) +{ + m_frontend = frontend->timeline(); +} + +void InspectorTimelineAgent::clearFrontend() +{ + ErrorString error; + stop(&error); + m_frontend = 0; +} + +void InspectorTimelineAgent::restore() +{ + if (m_state->getBoolean(TimelineAgentState::timelineAgentEnabled)) { + ErrorString error; + start(&error); + } +} + +void InspectorTimelineAgent::start(ErrorString*) +{ + if (!m_frontend) + return; + m_instrumentingAgents->setInspectorTimelineAgent(this); + ScriptGCEvent::addEventListener(this); + m_frontend->timelineProfilerWasStarted(); + m_state->setBoolean(TimelineAgentState::timelineAgentEnabled, true); +} + +void InspectorTimelineAgent::stop(ErrorString*) +{ + if (!started()) + return; + m_instrumentingAgents->setInspectorTimelineAgent(0); + if (m_frontend) + m_frontend->timelineProfilerWasStopped(); ScriptGCEvent::removeEventListener(this); + + clearRecordStack(); + m_gcEvents.clear(); + m_state->setBoolean(TimelineAgentState::timelineAgentEnabled, false); } +bool InspectorTimelineAgent::started() const +{ + return m_state->getBoolean(TimelineAgentState::timelineAgentEnabled); +} + void InspectorTimelineAgent::willCallFunction(const String& scriptName, int scriptLine) { pushCurrentRecord(TimelineRecordFactory::createFunctionCallData(scriptName, scriptLine), FunctionCallTimelineRecordType); @@ -280,14 +320,7 @@ void InspectorTimelineAgent::didMarkLoadEvent() void InspectorTimelineAgent::didCommitLoad() { - m_recordStack.clear(); -} - -void InspectorTimelineAgent::setFrontend(InspectorFrontend* frontend) -{ - ASSERT(frontend); - m_recordStack.clear(); - m_frontend = frontend; + clearRecordStack(); } void InspectorTimelineAgent::addRecordToTimeline(PassRefPtr<InspectorObject> prpRecord, TimelineRecordType type) @@ -329,14 +362,12 @@ void InspectorTimelineAgent::didCompleteCurrentRecord(TimelineRecordType type) } } -InspectorTimelineAgent::InspectorTimelineAgent(InspectorState* state, InspectorFrontend* frontend) - : m_state(state) - , m_frontend(frontend) - , m_id(++s_id) +InspectorTimelineAgent::InspectorTimelineAgent(InstrumentingAgents* instrumentingAgents, InspectorState* state) + : m_instrumentingAgents(instrumentingAgents) + , m_state(state) + , m_frontend(0) + , m_id(1) { - ScriptGCEvent::addEventListener(this); - m_frontend->timelineProfilerWasStarted(); - m_state->setBoolean(TimelineAgentState::timelineAgentEnabled, true); } void InspectorTimelineAgent::pushCurrentRecord(PassRefPtr<InspectorObject> data, TimelineRecordType type) @@ -345,6 +376,13 @@ void InspectorTimelineAgent::pushCurrentRecord(PassRefPtr<InspectorObject> data, RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(WTF::currentTimeMS()); m_recordStack.append(TimelineRecordEntry(record.release(), data, InspectorArray::create(), type)); } + +void InspectorTimelineAgent::clearRecordStack() +{ + m_recordStack.clear(); + m_id++; +} + } // namespace WebCore #endif // ENABLE(INSPECTOR) diff --git a/Source/WebCore/inspector/InspectorTimelineAgent.h b/Source/WebCore/inspector/InspectorTimelineAgent.h index 36c2df2..c4c0f3b 100644 --- a/Source/WebCore/inspector/InspectorTimelineAgent.h +++ b/Source/WebCore/inspector/InspectorTimelineAgent.h @@ -33,6 +33,7 @@ #if ENABLE(INSPECTOR) +#include "InspectorFrontend.h" #include "InspectorValues.h" #include "ScriptGCEvent.h" #include "ScriptGCEventListener.h" @@ -43,10 +44,13 @@ namespace WebCore { class Event; class InspectorFrontend; class InspectorState; +class InstrumentingAgents; class IntRect; class ResourceRequest; class ResourceResponse; +typedef String ErrorString; + // Must be kept in sync with TimelineAgent.js enum TimelineRecordType { EventDispatchTimelineRecordType = 0, @@ -75,19 +79,24 @@ enum TimelineRecordType { class InspectorTimelineAgent : ScriptGCEventListener { WTF_MAKE_NONCOPYABLE(InspectorTimelineAgent); public: - static PassOwnPtr<InspectorTimelineAgent> create(InspectorState* state, InspectorFrontend* frontend) + static PassOwnPtr<InspectorTimelineAgent> create(InstrumentingAgents* instrumentingAgents, InspectorState* state) { - return adoptPtr(new InspectorTimelineAgent(state, frontend)); + return adoptPtr(new InspectorTimelineAgent(instrumentingAgents, state)); } - static PassOwnPtr<InspectorTimelineAgent> restore(InspectorState*, InspectorFrontend*); - ~InspectorTimelineAgent(); + void setFrontend(InspectorFrontend*); + void clearFrontend(); + void restore(); + + void start(ErrorString* error); + void stop(ErrorString* error); + bool started() const; + int id() const { return m_id; } void didCommitLoad(); - void setFrontend(InspectorFrontend*); // Methods called from WebCore. void willCallFunction(const String& scriptName, int scriptLine); @@ -149,7 +158,7 @@ private: TimelineRecordType type; }; - InspectorTimelineAgent(InspectorState*, InspectorFrontend*); + InspectorTimelineAgent(InstrumentingAgents*, InspectorState*); void pushCurrentRecord(PassRefPtr<InspectorObject>, TimelineRecordType); void setHeapSizeStatistic(InspectorObject* record); @@ -159,14 +168,15 @@ private: void addRecordToTimeline(PassRefPtr<InspectorObject>, TimelineRecordType); void pushGCEventRecords(); + void clearRecordStack(); + InstrumentingAgents* m_instrumentingAgents; InspectorState* m_state; - InspectorFrontend* m_frontend; + InspectorFrontend::Timeline* m_frontend; Vector<TimelineRecordEntry> m_recordStack; - static int s_id; - const int m_id; + int m_id; struct GCEvent { GCEvent(double startTime, double endTime, size_t collectedBytes) : startTime(startTime), endTime(endTime), collectedBytes(collectedBytes) diff --git a/Source/WebCore/inspector/InstrumentingAgents.h b/Source/WebCore/inspector/InstrumentingAgents.h new file mode 100644 index 0000000..c53ef00 --- /dev/null +++ b/Source/WebCore/inspector/InstrumentingAgents.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef InstrumentingAgents_h +#define InstrumentingAgents_h + +#include <wtf/FastAllocBase.h> +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class InspectorApplicationCacheAgent; +class InspectorBrowserDebuggerAgent; +class InspectorCSSAgent; +class InspectorConsoleAgent; +class InspectorDOMAgent; +class InspectorDOMStorageAgent; +class InspectorDatabaseAgent; +class InspectorDebuggerAgent; +class InspectorProfilerAgent; +class InspectorResourceAgent; +class InspectorRuntimeAgent; +class InspectorTimelineAgent; + +class InstrumentingAgents { + WTF_MAKE_NONCOPYABLE(InstrumentingAgents); + WTF_MAKE_FAST_ALLOCATED; +public: + InstrumentingAgents() + : m_inspectorCSSAgent(0) + , m_inspectorConsoleAgent(0) + , m_inspectorDOMAgent(0) + , m_inspectorResourceAgent(0) + , m_inspectorRuntimeAgent(0) + , m_inspectorTimelineAgent(0) +#if ENABLE(DOM_STORAGE) + , m_inspectorDOMStorageAgent(0) +#endif +#if ENABLE(DATABASE) + , m_inspectorDatabaseAgent(0) +#endif +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + , m_inspectorApplicationCacheAgent(0) +#endif +#if ENABLE(JAVASCRIPT_DEBUGGER) + , m_inspectorDebuggerAgent(0) + , m_inspectorBrowserDebuggerAgent(0) + , m_inspectorProfilerAgent(0) +#endif + { } + ~InstrumentingAgents() { } + + InspectorCSSAgent* inspectorCSSAgent() const { return m_inspectorCSSAgent; } + void setInspectorCSSAgent(InspectorCSSAgent* agent) { m_inspectorCSSAgent = agent; } + + InspectorConsoleAgent* inspectorConsoleAgent() const { return m_inspectorConsoleAgent; } + void setInspectorConsoleAgent(InspectorConsoleAgent* agent) { m_inspectorConsoleAgent = agent; } + + InspectorDOMAgent* inspectorDOMAgent() const { return m_inspectorDOMAgent; } + void setInspectorDOMAgent(InspectorDOMAgent* agent) { m_inspectorDOMAgent = agent; } + + InspectorResourceAgent* inspectorResourceAgent() const { return m_inspectorResourceAgent; } + void setInspectorResourceAgent(InspectorResourceAgent* agent) { m_inspectorResourceAgent = agent; } + + InspectorRuntimeAgent* inspectorRuntimeAgent() const { return m_inspectorRuntimeAgent; } + void setInspectorRuntimeAgent(InspectorRuntimeAgent* agent) { m_inspectorRuntimeAgent = agent; } + + InspectorTimelineAgent* inspectorTimelineAgent() const { return m_inspectorTimelineAgent; } + void setInspectorTimelineAgent(InspectorTimelineAgent* agent) { m_inspectorTimelineAgent = agent; } + +#if ENABLE(DOM_STORAGE) + InspectorDOMStorageAgent* inspectorDOMStorageAgent() const { return m_inspectorDOMStorageAgent; } + void setInspectorDOMStorageAgent(InspectorDOMStorageAgent* agent) { m_inspectorDOMStorageAgent = agent; } +#endif +#if ENABLE(DATABASE) + InspectorDatabaseAgent* inspectorDatabaseAgent() const { return m_inspectorDatabaseAgent; } + void setInspectorDatabaseAgent(InspectorDatabaseAgent* agent) { m_inspectorDatabaseAgent = agent; } +#endif +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + InspectorApplicationCacheAgent* inspectorApplicationCacheAgent() const { return m_inspectorApplicationCacheAgent; } + void setInspectorApplicationCacheAgent(InspectorApplicationCacheAgent* agent) { m_inspectorApplicationCacheAgent = agent; } +#endif +#if ENABLE(JAVASCRIPT_DEBUGGER) + InspectorDebuggerAgent* inspectorDebuggerAgent() const { return m_inspectorDebuggerAgent; } + void setInspectorDebuggerAgent(InspectorDebuggerAgent* agent) { m_inspectorDebuggerAgent = agent; } + + InspectorBrowserDebuggerAgent* inspectorBrowserDebuggerAgent() const { return m_inspectorBrowserDebuggerAgent; } + void setInspectorBrowserDebuggerAgent(InspectorBrowserDebuggerAgent* agent) { m_inspectorBrowserDebuggerAgent = agent; } + + InspectorProfilerAgent* inspectorProfilerAgent() const { return m_inspectorProfilerAgent; } + void setInspectorProfilerAgent(InspectorProfilerAgent* agent) { m_inspectorProfilerAgent = agent; } +#endif + +private: + InspectorCSSAgent* m_inspectorCSSAgent; + InspectorConsoleAgent* m_inspectorConsoleAgent; + InspectorDOMAgent* m_inspectorDOMAgent; + InspectorResourceAgent* m_inspectorResourceAgent; + InspectorRuntimeAgent* m_inspectorRuntimeAgent; + InspectorTimelineAgent* m_inspectorTimelineAgent; +#if ENABLE(DOM_STORAGE) + InspectorDOMStorageAgent* m_inspectorDOMStorageAgent; +#endif +#if ENABLE(DATABASE) + InspectorDatabaseAgent* m_inspectorDatabaseAgent; +#endif +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + InspectorApplicationCacheAgent* m_inspectorApplicationCacheAgent; +#endif +#if ENABLE(JAVASCRIPT_DEBUGGER) + InspectorDebuggerAgent* m_inspectorDebuggerAgent; + InspectorBrowserDebuggerAgent* m_inspectorBrowserDebuggerAgent; + InspectorProfilerAgent* m_inspectorProfilerAgent; +#endif +}; + +} + +#endif // !defined(InstrumentingAgents_h) diff --git a/Source/WebCore/inspector/front-end/AuditRules.js b/Source/WebCore/inspector/front-end/AuditRules.js index c122ba4..803e9e0 100644 --- a/Source/WebCore/inspector/front-end/AuditRules.js +++ b/Source/WebCore/inspector/front-end/AuditRules.js @@ -65,10 +65,16 @@ WebInspector.AuditRules.getDomainToResourcesMap = function(resources, types, nee WebInspector.AuditRules.evaluateInTargetWindow = function(func, args, callback) { - InspectorBackend.evaluateOnSelf(func.toString(), args, callback); + function mycallback(result) + { + if (result) + callback(JSON.parse(result.description)); + else + callback(null); + } + RuntimeAgent.evaluate("JSON.stringify((" + func + ")(" + JSON.stringify(args) + "))", "", false, mycallback); } - WebInspector.AuditRules.GzipRule = function() { WebInspector.AuditRule.call(this, "network-gzip", "Enable gzip compression"); @@ -83,6 +89,8 @@ WebInspector.AuditRules.GzipRule.prototype = { var summary = result.addChild("", true); for (var i = 0, length = resources.length; i < length; ++i) { var resource = resources[i]; + if (resource.statusCode === 304) + continue; // Do not test 304 Not Modified resources as their contents are always empty. if (this._shouldCompress(resource)) { var size = resource.resourceSize; candidateSize += size; @@ -104,8 +112,11 @@ WebInspector.AuditRules.GzipRule.prototype = { _isCompressed: function(resource) { - var encoding = resource.responseHeaders["Content-Encoding"]; - return encoding === "gzip" || encoding === "deflate"; + var encodingHeader = resource.responseHeaders["Content-Encoding"]; + if (!encodingHeader) + return false; + + return /\b(?:gzip|deflate)\b/.test(encodingHeader); }, _shouldCompress: function(resource) @@ -383,7 +394,7 @@ WebInspector.AuditRules.UnusedCssRule.prototype = { WebInspector.CSSStyleSheet.createForId(styleSheetIds[i], styleSheetCallback.bind(null, styleSheets, i == styleSheetIds.length - 1 ? evalCallback : null)); } - InspectorBackend.getAllStyles(allStylesCallback); + CSSAgent.getAllStyles(allStylesCallback); } } @@ -639,24 +650,23 @@ WebInspector.AuditRules.ImageDimensionsRule = function() WebInspector.AuditRules.ImageDimensionsRule.prototype = { doRun: function(resources, result, callback) { - function doneCallback(context) + var urlToNoDimensionCount = {}; + + function doneCallback() { - var map = context.urlToNoDimensionCount; - for (var url in map) { + for (var url in urlToNoDimensionCount) { var entry = entry || result.addChild("A width and height should be specified for all images in order to speed up page display. The following image(s) are missing a width and/or height:", true); var value = WebInspector.AuditRuleResult.linkifyDisplayName(url); - if (map[url] > 1) - value += String.sprintf(" (%d uses)", map[url]); + if (urlToNoDimensionCount[url] > 1) + value += String.sprintf(" (%d uses)", urlToNoDimensionCount[url]); entry.addChild(value); result.violationCount++; } callback(entry ? result : null); } - function imageStylesReady(imageId, context, styles) + function imageStylesReady(imageId, lastCall, styles) { - --context.imagesLeft; - const node = WebInspector.domAgent.nodeForId(imageId); var src = node.getAttribute("src"); if (!src.asParsedURL()) { @@ -672,14 +682,22 @@ WebInspector.AuditRules.ImageDimensionsRule.prototype = { const computedStyle = styles.computedStyle; if (computedStyle.getPropertyValue("position") === "absolute") { - if (!context.imagesLeft) - doneCallback(context); + if (lastCall) + doneCallback(); return; } var widthFound = "width" in styles.styleAttributes; var heightFound = "height" in styles.styleAttributes; + var inlineStyle = styles.inlineStyle; + if (inlineStyle) { + if (inlineStyle.getPropertyValue("width") !== "") + widthFound = true; + if (inlineStyle.getPropertyValue("height") !== "") + heightFound = true; + } + for (var i = styles.matchedCSSRules.length - 1; i >= 0 && !(widthFound && heightFound); --i) { var style = styles.matchedCSSRules[i].style; if (style.getPropertyValue("width") !== "") @@ -687,41 +705,25 @@ WebInspector.AuditRules.ImageDimensionsRule.prototype = { if (style.getPropertyValue("height") !== "") heightFound = true; } - + if (!widthFound || !heightFound) { - if (src in context.urlToNoDimensionCount) - ++context.urlToNoDimensionCount[src]; + if (src in urlToNoDimensionCount) + ++urlToNoDimensionCount[src]; else - context.urlToNoDimensionCount[src] = 1; + urlToNoDimensionCount[src] = 1; } - if (!context.imagesLeft) - doneCallback(context); + if (lastCall) + doneCallback(); } - function receivedImages(imageIds) + function getStyles(nodeIds) { - if (!imageIds || !imageIds.length) - return callback(null); - var context = {imagesLeft: imageIds.length, urlToNoDimensionCount: {}}; - for (var i = imageIds.length - 1; i >= 0; --i) - WebInspector.cssModel.getStylesAsync(imageIds[i], imageStylesReady.bind(this, imageIds[i], context)); - } - - function pushImageNodes() - { - const nodeIds = []; - var nodes = document.getElementsByTagName("img"); - for (var i = 0; i < nodes.length; ++i) { - if (!nodes[i].src) - continue; - var nodeId = this.getNodeId(nodes[i]); - nodeIds.push(nodeId); - } - return nodeIds; + for (var i = 0; i < nodeIds.length; ++i) + WebInspector.cssModel.getStylesAsync(nodeIds[i], imageStylesReady.bind(this, nodeIds[i], i === nodeIds.length - 1)); } - WebInspector.AuditRules.evaluateInTargetWindow(pushImageNodes, [], receivedImages); + DOMAgent.querySelectorAll(0, "img[src]", true, getStyles); } } diff --git a/Source/WebCore/inspector/front-end/AuditsPanel.js b/Source/WebCore/inspector/front-end/AuditsPanel.js index 47c0b30..3144c78 100644 --- a/Source/WebCore/inspector/front-end/AuditsPanel.js +++ b/Source/WebCore/inspector/front-end/AuditsPanel.js @@ -192,7 +192,7 @@ WebInspector.AuditsPanel.prototype = { _reloadResources: function(callback) { this._pageReloadCallback = callback; - InspectorBackend.reloadPage(false); + InspectorAgent.reloadPage(false); }, _didMainResourceLoad: function() diff --git a/Source/WebCore/inspector/front-end/BreakpointManager.js b/Source/WebCore/inspector/front-end/BreakpointManager.js index 94345d5..b62820e 100644 --- a/Source/WebCore/inspector/front-end/BreakpointManager.js +++ b/Source/WebCore/inspector/front-end/BreakpointManager.js @@ -207,7 +207,7 @@ WebInspector.BreakpointManager.prototype = { } if (!this._breakpointsPushedToFrontend) { - InspectorBackend.setAllBrowserBreakpoints(this._stickyBreakpoints); + BrowserDebuggerAgent.setAllBrowserBreakpoints(this._stickyBreakpoints); this._breakpointsPushedToFrontend = true; } }, @@ -216,6 +216,9 @@ WebInspector.BreakpointManager.prototype = { { function didPushNodeByPathToFrontend(path, nodeId) { + if (!nodeId) + return; + pathToNodeId[path] = nodeId; pendingCalls -= 1; if (pendingCalls) @@ -243,7 +246,7 @@ WebInspector.BreakpointManager.prototype = { continue; pathToNodeId[path] = 0; pendingCalls += 1; - InspectorBackend.pushNodeByPathToFrontend(path, didPushNodeByPathToFrontend.bind(this, path)); + WebInspector.domAgent.pushNodeByPathToFrontend(path, didPushNodeByPathToFrontend.bind(this, path)); } if (!pendingCalls) this._domBreakpointsRestored = true; @@ -268,7 +271,7 @@ WebInspector.BreakpointManager.prototype = { WebInspector.settings.nativeBreakpoints = breakpoints; this._stickyBreakpoints[WebInspector.settings.projectId] = breakpoints; - InspectorBackend.setAllBrowserBreakpoints(this._stickyBreakpoints); + BrowserDebuggerAgent.setAllBrowserBreakpoints(this._stickyBreakpoints); }, _validateBreakpoints: function(persistentBreakpoints) @@ -331,12 +334,12 @@ WebInspector.DOMBreakpoint = function(node, type) WebInspector.DOMBreakpoint.prototype = { _enable: function() { - InspectorBackend.setDOMBreakpoint(this._nodeId, this._type); + BrowserDebuggerAgent.setDOMBreakpoint(this._nodeId, this._type); }, _disable: function() { - InspectorBackend.removeDOMBreakpoint(this._nodeId, this._type); + BrowserDebuggerAgent.removeDOMBreakpoint(this._nodeId, this._type); }, _serializeToJSON: function() @@ -354,12 +357,12 @@ WebInspector.EventListenerBreakpoint = function(eventName) WebInspector.EventListenerBreakpoint.prototype = { _enable: function() { - InspectorBackend.setEventListenerBreakpoint(this._eventName); + BrowserDebuggerAgent.setEventListenerBreakpoint(this._eventName); }, _disable: function() { - InspectorBackend.removeEventListenerBreakpoint(this._eventName); + BrowserDebuggerAgent.removeEventListenerBreakpoint(this._eventName); }, _serializeToJSON: function() @@ -377,12 +380,12 @@ WebInspector.XHRBreakpoint = function(url) WebInspector.XHRBreakpoint.prototype = { _enable: function() { - InspectorBackend.setXHRBreakpoint(this._url); + BrowserDebuggerAgent.setXHRBreakpoint(this._url); }, _disable: function() { - InspectorBackend.removeXHRBreakpoint(this._url); + BrowserDebuggerAgent.removeXHRBreakpoint(this._url); }, _serializeToJSON: function() @@ -476,7 +479,34 @@ WebInspector.DOMBreakpointView.prototype = { populateStatusMessageElement: function(element, eventData) { + if (this._type === WebInspector.DOMBreakpointTypes.SubtreeModified) { + var targetNodeObject = WebInspector.RemoteObject.fromPayload(eventData.targetNode); + targetNodeObject.pushNodeToFrontend(decorateNode.bind(this)); + function decorateNode(targetNodeId) + { + if (!targetNodeId) + return; + + RuntimeAgent.releaseObject(eventData.targetNode); + var targetNode = WebInspector.panels.elements.linkifyNodeById(targetNodeId); + if (eventData.insertion) { + if (targetNodeId !== this._nodeId) + this._format(element, "Paused on a \"%s\" breakpoint set on %s, because a new child was added to its descendant %s.", targetNode); + else + this._format(element, "Paused on a \"%s\" breakpoint set on %s, because a new child was added to that node."); + } else + this._format(element, "Paused on a \"%s\" breakpoint set on %s, because its descendant %s was removed.", targetNode); + } + } else + this._format(element, "Paused on a \"%s\" breakpoint set on %s."); + }, + + _format: function(element, message, extraSubstitution) + { var substitutions = [WebInspector.domBreakpointTypeLabel(this._type), WebInspector.panels.elements.linkifyNodeById(this._nodeId)]; + if (extraSubstitution) + substitutions.push(extraSubstitution); + var formatters = { s: function(substitution) { @@ -489,17 +519,7 @@ WebInspector.DOMBreakpointView.prototype = { b = document.createTextNode(b); element.appendChild(b); } - if (this._type === WebInspector.DOMBreakpointTypes.SubtreeModified) { - var targetNode = WebInspector.panels.elements.linkifyNodeById(eventData.targetNodeId); - if (eventData.insertion) { - if (eventData.targetNodeId !== this._nodeId) - WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s, because a new child was added to its descendant %s.", substitutions.concat(targetNode), formatters, "", append); - else - WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s, because a new child was added to that node.", substitutions, formatters, "", append); - } else - WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s, because its descendant %s was removed.", substitutions.concat(targetNode), formatters, "", append); - } else - WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s.", substitutions, formatters, "", append); + WebInspector.formatLocalized(message, substitutions, formatters, "", append); }, _onRemove: function() diff --git a/Source/WebCore/inspector/front-end/BreakpointsSidebarPane.js b/Source/WebCore/inspector/front-end/BreakpointsSidebarPane.js index 0a47bf8..0c46463 100644 --- a/Source/WebCore/inspector/front-end/BreakpointsSidebarPane.js +++ b/Source/WebCore/inspector/front-end/BreakpointsSidebarPane.js @@ -143,10 +143,10 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = { _debuggerPaused: function(event) { - var breakpointId = this._breakpointIdForDebuggerPausedEvent(event.data); - if (!breakpointId) + var breakpoint = event.data.breakpoint; + if (!breakpoint) return; - var breakpointItem = this._items[breakpointId]; + var breakpointItem = this._items[breakpoint.id]; if (!breakpointItem) return; breakpointItem.element.addStyleClass("breakpoint-hit"); @@ -236,14 +236,6 @@ WebInspector.JavaScriptBreakpointsSidebarPane.prototype = { element.addEventListener("click", clickHandler, false); }, - _breakpointIdForDebuggerPausedEvent: function(details) - { - var callFrame = details.callFrames[0]; - var breakpoint = WebInspector.debuggerModel.findBreakpoint(callFrame.sourceID, callFrame.line); - if (breakpoint) - return breakpoint.id; - }, - _removeBreakpoint: function(breakpointId) { WebInspector.debuggerModel.removeBreakpoint(breakpointId); diff --git a/Source/WebCore/inspector/front-end/CSSStyleModel.js b/Source/WebCore/inspector/front-end/CSSStyleModel.js index 69bd7a9..700417e 100644 --- a/Source/WebCore/inspector/front-end/CSSStyleModel.js +++ b/Source/WebCore/inspector/front-end/CSSStyleModel.js @@ -83,7 +83,7 @@ WebInspector.CSSStyleModel.prototype = { userCallback(result); } - InspectorBackend.getStylesForNode(nodeId, callback.bind(null, userCallback)); + CSSAgent.getStylesForNode(nodeId, callback.bind(null, userCallback)); }, getComputedStyleAsync: function(nodeId, userCallback) @@ -96,7 +96,7 @@ WebInspector.CSSStyleModel.prototype = { userCallback(WebInspector.CSSStyleDeclaration.parsePayload(stylePayload)); } - InspectorBackend.getComputedStyleForNode(nodeId, callback.bind(null, userCallback)); + CSSAgent.getComputedStyleForNode(nodeId, callback.bind(null, userCallback)); }, getInlineStyleAsync: function(nodeId, userCallback) @@ -109,7 +109,7 @@ WebInspector.CSSStyleModel.prototype = { userCallback(WebInspector.CSSStyleDeclaration.parsePayload(stylePayload)); } - InspectorBackend.getInlineStyleForNode(nodeId, callback.bind(null, userCallback)); + CSSAgent.getInlineStyleForNode(nodeId, callback.bind(null, userCallback)); }, setRuleSelector: function(ruleId, nodeId, newSelector, successCallback, failureCallback) @@ -127,10 +127,10 @@ WebInspector.CSSStyleModel.prototype = { if (!rulePayload) failureCallback(); else - InspectorBackend.querySelectorAll(nodeId, newSelector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload)); + DOMAgent.querySelectorAll(nodeId, newSelector, true, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload)); } - InspectorBackend.setRuleSelector(ruleId, newSelector, callback.bind(this, nodeId, successCallback, failureCallback)); + CSSAgent.setRuleSelector(ruleId, newSelector, callback.bind(this, nodeId, successCallback, failureCallback)); }, addRule: function(nodeId, selector, successCallback, failureCallback) @@ -149,10 +149,10 @@ WebInspector.CSSStyleModel.prototype = { // Invalid syntax for a selector failureCallback(); } else - InspectorBackend.querySelectorAll(nodeId, selector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload)); + DOMAgent.querySelectorAll(nodeId, selector, true, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload)); } - InspectorBackend.addRule(nodeId, selector, callback.bind(this, successCallback, failureCallback, selector)); + CSSAgent.addRule(nodeId, selector, callback.bind(this, successCallback, failureCallback, selector)); }, _styleSheetChanged: function(styleSheetId, majorChange) @@ -166,7 +166,7 @@ WebInspector.CSSStyleModel.prototype = { if (resource && resource.type === WebInspector.Resource.Type.Stylesheet) resource.setContent(content, this._onRevert.bind(this, styleSheetId)); } - InspectorBackend.getStyleSheetText(styleSheetId, callback.bind(this)); + CSSAgent.getStyleSheetText(styleSheetId, callback.bind(this)); }, _onRevert: function(styleSheetId, contentToRevertTo) @@ -176,7 +176,7 @@ WebInspector.CSSStyleModel.prototype = { this._styleSheetChanged(styleSheetId, true); this.dispatchEventToListeners("stylesheet changed"); } - InspectorBackend.setStyleSheetText(styleSheetId, contentToRevertTo, callback.bind(this)); + CSSAgent.setStyleSheetText(styleSheetId, contentToRevertTo, callback.bind(this)); } } @@ -348,7 +348,7 @@ WebInspector.CSSStyleDeclaration.prototype = { } } - InspectorBackend.setPropertyText(this.id, index, name + ": " + value + ";", false, callback.bind(null, userCallback)); + CSSAgent.setPropertyText(this.id, index, name + ": " + value + ";", false, callback.bind(null, userCallback)); }, appendProperty: function(name, value, userCallback) @@ -488,7 +488,7 @@ WebInspector.CSSProperty.prototype = { throw "No ownerStyle for property"; // An index past all the properties adds a new property to the style. - InspectorBackend.setPropertyText(this.ownerStyle.id, this.index, propertyText, this.index < this.ownerStyle.pastLastSourcePropertyIndex(), callback.bind(this)); + CSSAgent.setPropertyText(this.ownerStyle.id, this.index, propertyText, this.index < this.ownerStyle.pastLastSourcePropertyIndex(), callback.bind(this)); }, setValue: function(newValue, userCallback) @@ -517,7 +517,7 @@ WebInspector.CSSProperty.prototype = { } } - InspectorBackend.toggleProperty(this.ownerStyle.id, this.index, disabled, callback.bind(this)); + CSSAgent.toggleProperty(this.ownerStyle.id, this.index, disabled, callback.bind(this)); } } @@ -548,7 +548,7 @@ WebInspector.CSSStyleSheet.createForId = function(styleSheetId, userCallback) else userCallback(new WebInspector.CSSStyleSheet(styleSheetPayload)); } - InspectorBackend.getStyleSheet(styleSheetId, callback.bind(this)); + CSSAgent.getStyleSheet(styleSheetId, callback.bind(this)); } WebInspector.CSSStyleSheet.prototype = { @@ -569,6 +569,6 @@ WebInspector.CSSStyleSheet.prototype = { } } - InspectorBackend.setStyleSheetText(this.id, newText, callback.bind(this)); + CSSAgent.setStyleSheetText(this.id, newText, callback.bind(this)); } } diff --git a/Source/WebCore/inspector/front-end/CallStackSidebarPane.js b/Source/WebCore/inspector/front-end/CallStackSidebarPane.js index 503e5f4..e1618b2 100644 --- a/Source/WebCore/inspector/front-end/CallStackSidebarPane.js +++ b/Source/WebCore/inspector/front-end/CallStackSidebarPane.js @@ -23,20 +23,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.CallStackSidebarPane = function() +WebInspector.CallStackSidebarPane = function(model) { WebInspector.SidebarPane.call(this, WebInspector.UIString("Call Stack")); + this._model = model; } WebInspector.CallStackSidebarPane.prototype = { - update: function(callFrames, eventType, eventData) + update: function(details) { this.bodyElement.removeChildren(); this.placards = []; - delete this._selectedCallFrame; - if (!callFrames) { + if (!details) { var infoElement = document.createElement("div"); infoElement.className = "info"; infoElement.textContent = WebInspector.UIString("Not Paused"); @@ -44,6 +44,7 @@ WebInspector.CallStackSidebarPane.prototype = { return; } + var callFrames = details.callFrames; var title; var subtitle; var script; @@ -65,12 +66,10 @@ WebInspector.CallStackSidebarPane.prototype = { else subtitle = WebInspector.UIString("(internal script)"); - if (callFrame.line > 0) { - if (subtitle) - subtitle += ":" + callFrame.line; - else - subtitle = WebInspector.UIString("line %d", callFrame.line); - } + if (subtitle) + subtitle += ":" + (callFrame.line + 1); + else + subtitle = WebInspector.UIString("line %d", callFrame.line + 1); var placard = new WebInspector.Placard(title, subtitle); placard.callFrame = callFrame; @@ -81,30 +80,20 @@ WebInspector.CallStackSidebarPane.prototype = { this.bodyElement.appendChild(placard.element); } - if (WebInspector.debuggerModel.findBreakpoint(callFrames[0].sourceID, callFrames[0].line)) + if (details.breakpoint) this._scriptBreakpointHit(); - else if (eventType === WebInspector.DebuggerEventTypes.NativeBreakpoint) - this._nativeBreakpointHit(eventData); - }, - - get selectedCallFrame() - { - return this._selectedCallFrame; + else if (details.eventType === WebInspector.DebuggerEventTypes.NativeBreakpoint) + this._nativeBreakpointHit(details.eventData); }, set selectedCallFrame(x) { - if (this._selectedCallFrame === x) - return; - - this._selectedCallFrame = x; + this._model.selectedCallFrame = x; for (var i = 0; i < this.placards.length; ++i) { var placard = this.placards[i]; - placard.selected = (placard.callFrame === this._selectedCallFrame); + placard.selected = (placard.callFrame === x); } - - this.dispatchEventToListeners("call frame selected"); }, handleShortcut: function(event) @@ -143,11 +132,11 @@ WebInspector.CallStackSidebarPane.prototype = { _selectedCallFrameIndex: function() { - if (!this._selectedCallFrame) + if (!this._model.selectedCallFrame) return -1; for (var i = 0; i < this.placards.length; ++i) { var placard = this.placards[i]; - if (placard.callFrame === this._selectedCallFrame) + if (placard.callFrame === this._model.selectedCallFrame) return i; } return -1; diff --git a/Source/WebCore/inspector/front-end/ConsoleView.js b/Source/WebCore/inspector/front-end/ConsoleView.js index 35d1ebf..f59d87f 100644 --- a/Source/WebCore/inspector/front-end/ConsoleView.js +++ b/Source/WebCore/inspector/front-end/ConsoleView.js @@ -316,7 +316,7 @@ WebInspector.ConsoleView.prototype = { requestClearMessages: function() { - InspectorBackend.clearConsoleMessages(); + ConsoleAgent.clearConsoleMessages(); }, clearMessages: function() @@ -353,21 +353,30 @@ WebInspector.ConsoleView.prototype = { if (!expressionString && !prefix) return; - var reportCompletions = this._reportCompletions.bind(this, bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix); - // Collect comma separated object properties for the completion. + this.evalInInspectedWindow(expressionString, "completion", true, evaluated.bind(this)); - var includeCommandLineAPI = (!dotNotation && !bracketNotation); - var injectedScriptAccess; - if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused) - InspectorBackend.getCompletionsOnCallFrame(WebInspector.panels.scripts.selectedCallFrameId(), expressionString, includeCommandLineAPI, reportCompletions); - else - InspectorBackend.getCompletions(expressionString, includeCommandLineAPI, reportCompletions); - }, + function evaluated(result) + { + if (!result) + return; + result.getProperties(true, false, evaluatedProperties.bind(this)); + } - _reportCompletions: function(bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix, result, isException) { - if (isException) - return; + function evaluatedProperties(properties) + { + RuntimeAgent.releaseObjectGroup(0, "completion"); + var propertyNames = []; + for (var i = 0; properties && i < properties.length; ++i) + propertyNames.push(properties[i].name); + + var includeCommandLineAPI = (!dotNotation && !bracketNotation); + if (includeCommandLineAPI) + propertyNames.splice(0, 0, "dir", "dirxml", "keys", "values", "profile", "profileEnd", "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear"); + this._reportCompletions(bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix, propertyNames); + } + }, + _reportCompletions: function(bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix, properties) { if (bracketNotation) { if (prefix.length && prefix[0] === "'") var quoteUsed = "'"; @@ -376,7 +385,7 @@ WebInspector.ConsoleView.prototype = { } var results = []; - var properties = Object.keys(result).sort(); + properties.sort(); for (var i = 0; i < properties.length; ++i) { var property = properties[i]; @@ -417,7 +426,7 @@ WebInspector.ConsoleView.prototype = { var itemAction = function () { WebInspector.settings.monitoringXHREnabled = !WebInspector.settings.monitoringXHREnabled; - InspectorBackend.setMonitoringXHREnabled(WebInspector.settings.monitoringXHREnabled); + ConsoleAgent.setMonitoringXHREnabled(WebInspector.settings.monitoringXHREnabled); }.bind(this); var contextMenu = new WebInspector.ContextMenu(); contextMenu.appendCheckboxItem(WebInspector.UIString("XMLHttpRequest logging"), itemAction, WebInspector.settings.monitoringXHREnabled) @@ -513,7 +522,7 @@ WebInspector.ConsoleView.prototype = { evalInInspectedWindow: function(expression, objectGroup, includeCommandLineAPI, callback) { if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused) { - WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression, false, objectGroup, includeCommandLineAPI, callback); + WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression, objectGroup, includeCommandLineAPI, callback); return; } @@ -526,7 +535,7 @@ WebInspector.ConsoleView.prototype = { { callback(WebInspector.RemoteObject.fromPayload(result)); } - InspectorBackend.evaluate(expression, objectGroup, includeCommandLineAPI, evalCallback); + RuntimeAgent.evaluate(expression, objectGroup, includeCommandLineAPI, evalCallback); }, _enterKeyPressed: function(event) diff --git a/Source/WebCore/inspector/front-end/CookieItemsView.js b/Source/WebCore/inspector/front-end/CookieItemsView.js index dc76b39..c8187bb 100644 --- a/Source/WebCore/inspector/front-end/CookieItemsView.js +++ b/Source/WebCore/inspector/front-end/CookieItemsView.js @@ -140,7 +140,7 @@ WebInspector.CookieItemsView.prototype = { _deleteCookie: function(cookie) { - InspectorBackend.deleteCookie(cookie.name, this._cookieDomain); + InspectorAgent.deleteCookie(cookie.name, this._cookieDomain); this._update(); }, diff --git a/Source/WebCore/inspector/front-end/DOMAgent.js b/Source/WebCore/inspector/front-end/DOMAgent.js index 3645bb9..cb28aba 100644 --- a/Source/WebCore/inspector/front-end/DOMAgent.js +++ b/Source/WebCore/inspector/front-end/DOMAgent.js @@ -223,12 +223,11 @@ WebInspector.DOMNode.prototype = { } } -WebInspector.DOMDocument = function(domAgent, defaultView, payload) +WebInspector.DOMDocument = function(domAgent, payload) { WebInspector.DOMNode.call(this, this, payload); this._listeners = {}; this._domAgent = domAgent; - this.defaultView = defaultView; } WebInspector.DOMDocument.prototype = { @@ -269,44 +268,48 @@ WebInspector.DOMDocument.prototype = { WebInspector.DOMDocument.prototype.__proto__ = WebInspector.DOMNode.prototype; - -WebInspector.DOMWindow = function(domAgent) -{ - this._domAgent = domAgent; +WebInspector.DOMAgent = function() { + this._idToDOMNode = null; + this._document = null; + InspectorBackend.registerDomainDispatcher("DOM", new WebInspector.DOMDispatcher(this)); } -WebInspector.DOMWindow.prototype = { - get document() - { - return this._domAgent.document; - }, - - get Node() +WebInspector.DOMAgent.prototype = { + requestDocument: function(callback) { - return WebInspector.DOMNode; + if (this._document) { + if (callback) + callback(this._document); + } else + this._documentUpdated(callback); }, - get Element() + pushNodeToFrontend: function(objectId, callback) { - return WebInspector.DOMNode; + function mycallback() + { + if (this._document) + DOMAgent.pushNodeToFrontend(objectId, callback); + else { + if (callback) + callback(0); + } + } + this.requestDocument(mycallback.bind(this)); }, - Object: function() - { - } -} - -WebInspector.DOMAgent = function() { - this._window = new WebInspector.DOMWindow(this); - this._idToDOMNode = null; - this.document = null; - InspectorBackend.registerDomainDispatcher("DOM", new WebInspector.DOMDispatcher(this)); -} - -WebInspector.DOMAgent.prototype = { - get domWindow() + pushNodeByPathToFrontend: function(path, callback) { - return this._window; + function mycallback() + { + if (this._document) + DOMAgent.pushNodeByPathToFrontend(path, callback); + else { + if (callback) + callback(0); + } + } + this.requestDocument(mycallback.bind(this)); }, getChildNodesAsync: function(parent, callback) @@ -319,25 +322,25 @@ WebInspector.DOMAgent.prototype = { function mycallback() { callback(parent.children); } - InspectorBackend.getChildNodes(parent.id, mycallback); + DOMAgent.getChildNodes(parent.id, mycallback); }, setAttributeAsync: function(node, name, value, callback) { var mycallback = this._didApplyDomChange.bind(this, node, callback); - InspectorBackend.setAttribute(node.id, name, value, mycallback); + DOMAgent.setAttribute(node.id, name, value, mycallback); }, removeAttributeAsync: function(node, name, callback) { var mycallback = this._didApplyDomChange.bind(this, node, callback); - InspectorBackend.removeAttribute(node.id, name, mycallback); + DOMAgent.removeAttribute(node.id, name, mycallback); }, setTextNodeValueAsync: function(node, text, callback) { var mycallback = this._didApplyDomChange.bind(this, node, callback); - InspectorBackend.setTextNodeValue(node.id, text, mycallback); + DOMAgent.setTextNodeValue(node.id, text, mycallback); }, _didApplyDomChange: function(node, callback, success) @@ -356,7 +359,7 @@ WebInspector.DOMAgent.prototype = { var node = this._idToDOMNode[nodeId]; node._setAttributesPayload(attrsArray); var event = {target: node}; - this.document._fireDomEvent("DOMAttrModified", event); + this._document._fireDomEvent("DOMAttrModified", event); }, _characterDataModified: function(nodeId, newValue) @@ -365,7 +368,7 @@ WebInspector.DOMAgent.prototype = { node._nodeValue = newValue; node.textContent = newValue; var event = { target : node }; - this.document._fireDomEvent("DOMCharacterDataModified", event); + this._document._fireDomEvent("DOMCharacterDataModified", event); }, nodeForId: function(nodeId) @@ -373,27 +376,43 @@ WebInspector.DOMAgent.prototype = { return this._idToDOMNode[nodeId]; }, + _documentUpdated: function(callback) + { + function mycallback(root) + { + this._setDocument(root); + if (callback) + callback(this._document); + } + DOMAgent.getDocument(mycallback.bind(this)); + }, + _setDocument: function(payload) { this._idToDOMNode = {}; if (payload && "id" in payload) { - this.document = new WebInspector.DOMDocument(this, this._window, payload); - this._idToDOMNode[payload.id] = this.document; - this._bindNodes(this.document.children); + this._document = new WebInspector.DOMDocument(this, payload); + this._idToDOMNode[payload.id] = this._document; + this._bindNodes(this._document.children); WebInspector.breakpointManager.restoreDOMBreakpoints(); } else - this.document = null; - WebInspector.panels.elements.setDocument(this.document); + this._document = null; + WebInspector.panels.elements.setDocument(this._document); }, _setDetachedRoot: function(payload) { - var root = new WebInspector.DOMNode(this.document, payload); + var root = new WebInspector.DOMNode(this._document, payload); this._idToDOMNode[payload.id] = root; }, _setChildNodes: function(parentId, payloads) { + if (!parentId && payloads.length) { + this._setDetachedRoot(payloads[0]); + return; + } + var parent = this._idToDOMNode[parentId]; parent._setChildrenPayload(payloads); this._bindNodes(parent.children); @@ -426,7 +445,7 @@ WebInspector.DOMAgent.prototype = { var node = parent._insertChild(prev, payload); this._idToDOMNode[node.id] = node; var event = { target : node, relatedNode : parent }; - this.document._fireDomEvent("DOMNodeInserted", event); + this._document._fireDomEvent("DOMNodeInserted", event); }, _childNodeRemoved: function(parentId, nodeId) @@ -435,7 +454,7 @@ WebInspector.DOMAgent.prototype = { var node = this._idToDOMNode[nodeId]; parent.removeChild_(node); var event = { target : node, relatedNode : parent }; - this.document._fireDomEvent("DOMNodeRemoved", event); + this._document._fireDomEvent("DOMNodeRemoved", event); delete this._idToDOMNode[nodeId]; this._removeBreakpoints(node); }, @@ -457,9 +476,9 @@ WebInspector.DOMDispatcher = function(domAgent) } WebInspector.DOMDispatcher.prototype = { - setDocument: function(payload) + documentUpdated: function() { - this._domAgent._setDocument(payload); + this._domAgent._documentUpdated(); }, attributesUpdated: function(nodeId, attrsArray) @@ -477,11 +496,6 @@ WebInspector.DOMDispatcher.prototype = { this._domAgent._setChildNodes(parentId, payloads); }, - setDetachedRoot: function(payload) - { - this._domAgent._setDetachedRoot(payload); - }, - childNodeCountUpdated: function(nodeId, newValue) { this._domAgent._childNodeCountUpdated(nodeId, newValue); @@ -495,6 +509,16 @@ WebInspector.DOMDispatcher.prototype = { childNodeRemoved: function(parentId, nodeId) { this._domAgent._childNodeRemoved(parentId, nodeId); + }, + + inspectElementRequested: function(nodeId) + { + WebInspector.updateFocusedNode(nodeId); + }, + + addNodesToSearchResult: function(nodeIds) + { + WebInspector.panels.elements.addNodesToSearchResult(nodeIds); } } @@ -511,7 +535,7 @@ WebInspector.ApplicationCacheDispatcher.getApplicationCachesAsync = function(cal callback(applicationCaches); } - InspectorBackend.getApplicationCaches(mycallback); + ApplicationCacheAgent.getApplicationCaches(mycallback); } WebInspector.ApplicationCacheDispatcher.prototype = { @@ -540,7 +564,7 @@ WebInspector.Cookies.getCookiesAsync = function(callback) callback(cookies, true); } - InspectorBackend.getCookies(mycallback); + InspectorAgent.getCookies(mycallback); } WebInspector.Cookies.buildCookiesFromString = function(rawCookieString) @@ -585,5 +609,5 @@ WebInspector.EventListeners.getEventListenersForNodeAsync = function(node, callb { if (!node) return; - InspectorBackend.getEventListenersForNode(node.id, callback); + DOMAgent.getEventListenersForNode(node.id, callback); } diff --git a/Source/WebCore/inspector/front-end/DOMStorage.js b/Source/WebCore/inspector/front-end/DOMStorage.js index d3d2226..ea24921 100644 --- a/Source/WebCore/inspector/front-end/DOMStorage.js +++ b/Source/WebCore/inspector/front-end/DOMStorage.js @@ -39,11 +39,6 @@ WebInspector.DOMStorage.prototype = { return this._id; }, - get domStorage() - { - return this._domStorage; - }, - get domain() { return this._domain; @@ -56,17 +51,17 @@ WebInspector.DOMStorage.prototype = { getEntries: function(callback) { - InspectorBackend.getDOMStorageEntries(this._id, callback); + DOMStorageAgent.getDOMStorageEntries(this._id, callback); }, setItem: function(key, value, callback) { - InspectorBackend.setDOMStorageItem(this._id, key, value, callback); + DOMStorageAgent.setDOMStorageItem(this._id, key, value, callback); }, removeItem: function(key, callback) { - InspectorBackend.removeDOMStorageItem(this._id, key, callback); + DOMStorageAgent.removeDOMStorageItem(this._id, key, callback); } } @@ -87,12 +82,6 @@ WebInspector.DOMStorageDispatcher.prototype = { WebInspector.panels.resources.addDOMStorage(domStorage); }, - selectDOMStorage: function(o) - { - WebInspector.showPanel("resources"); - WebInspector.panels.resources.selectDOMStorage(o); - }, - updateDOMStorage: function(storageId) { WebInspector.panels.resources.updateDOMStorage(storageId); diff --git a/Source/WebCore/inspector/front-end/DataGrid.js b/Source/WebCore/inspector/front-end/DataGrid.js index 45f0b55..6d54941 100644 --- a/Source/WebCore/inspector/front-end/DataGrid.js +++ b/Source/WebCore/inspector/front-end/DataGrid.js @@ -809,14 +809,14 @@ WebInspector.DataGrid.prototype = { dataGridNodeFromNode: function(target) { var rowElement = target.enclosingNodeOrSelfWithNodeName("tr"); - return rowElement._dataGridNode; + return rowElement && rowElement._dataGridNode; }, dataGridNodeFromPoint: function(x, y) { var node = this._dataTable.ownerDocument.elementFromPoint(x, y); var rowElement = node.enclosingNodeOrSelfWithNodeName("tr"); - return rowElement._dataGridNode; + return rowElement && rowElement._dataGridNode; }, _clickInHeaderCell: function(event) diff --git a/Source/WebCore/inspector/front-end/Database.js b/Source/WebCore/inspector/front-end/Database.js index faa17fa..e4bafea 100644 --- a/Source/WebCore/inspector/front-end/Database.js +++ b/Source/WebCore/inspector/front-end/Database.js @@ -81,7 +81,7 @@ WebInspector.Database.prototype = { { callback(names.sort()); } - InspectorBackend.getDatabaseTableNames(this._id, sortingCallback); + DatabaseAgent.getDatabaseTableNames(this._id, sortingCallback); }, executeSql: function(query, onSuccess, onError) @@ -94,7 +94,7 @@ WebInspector.Database.prototype = { } WebInspector.DatabaseDispatcher._callbacks[transactionId] = {"onSuccess": onSuccess, "onError": onError}; } - InspectorBackend.executeSQL(this._id, query, callback); + DatabaseAgent.executeSQL(this._id, query, callback); } } @@ -107,8 +107,6 @@ WebInspector.DatabaseDispatcher._callbacks = {}; WebInspector.DatabaseDispatcher.prototype = { addDatabase: function(payload) { - if (!WebInspector.panels.resources) - return; var database = new WebInspector.Database( payload.id, payload.domain, @@ -117,12 +115,6 @@ WebInspector.DatabaseDispatcher.prototype = { WebInspector.panels.resources.addDatabase(database); }, - selectDatabase: function(o) - { - WebInspector.showPanel("resources"); - WebInspector.panels.resources.selectDatabase(o); - }, - sqlTransactionSucceeded: function(transactionId, columnNames, values) { if (!WebInspector.DatabaseDispatcher._callbacks[transactionId]) diff --git a/Source/WebCore/inspector/front-end/DebuggerModel.js b/Source/WebCore/inspector/front-end/DebuggerModel.js index 1bf1e47..d31ff24 100644 --- a/Source/WebCore/inspector/front-end/DebuggerModel.js +++ b/Source/WebCore/inspector/front-end/DebuggerModel.js @@ -52,7 +52,7 @@ WebInspector.DebuggerModel.Events = { WebInspector.DebuggerModel.prototype = { enableDebugger: function() { - InspectorBackend.enableDebugger(); + DebuggerAgent.enable(); if (this._breakpointsPushedToBackend) return; var breakpoints = WebInspector.settings.breakpoints; @@ -68,12 +68,12 @@ WebInspector.DebuggerModel.prototype = { disableDebugger: function() { - InspectorBackend.disableDebugger(); + DebuggerAgent.disable(); }, - continueToLine: function(sourceID, lineNumber) + continueToLocation: function(sourceID, lineNumber, columnNumber) { - InspectorBackend.continueToLocation(sourceID, lineNumber, 0); + DebuggerAgent.continueToLocation(sourceID, lineNumber, columnNumber); }, setBreakpoint: function(url, lineNumber, columnNumber, condition, enabled) @@ -89,7 +89,7 @@ WebInspector.DebuggerModel.prototype = { this._saveBreakpoints(); this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointAdded, breakpoint); } - InspectorBackend.setJavaScriptBreakpoint(url, lineNumber, columnNumber, condition, enabled, didSetBreakpoint.bind(this, this._breakpointsPushedToBackend)); + DebuggerAgent.setJavaScriptBreakpoint(url, lineNumber, columnNumber, condition, enabled, didSetBreakpoint.bind(this, this._breakpointsPushedToBackend)); }, setBreakpointBySourceId: function(sourceID, lineNumber, columnNumber, condition, enabled) @@ -103,12 +103,12 @@ WebInspector.DebuggerModel.prototype = { this._breakpoints[breakpointId] = breakpoint; this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointAdded, breakpoint); } - InspectorBackend.setJavaScriptBreakpointBySourceId(sourceID, lineNumber, columnNumber, condition, enabled, didSetBreakpoint.bind(this)); + DebuggerAgent.setJavaScriptBreakpointBySourceId(sourceID, lineNumber, columnNumber, condition, enabled, didSetBreakpoint.bind(this)); }, removeBreakpoint: function(breakpointId) { - InspectorBackend.removeJavaScriptBreakpoint(breakpointId); + DebuggerAgent.removeJavaScriptBreakpoint(breakpointId); var breakpoint = this._breakpoints[breakpointId]; delete this._breakpoints[breakpointId]; this._saveBreakpoints(); @@ -173,17 +173,6 @@ WebInspector.DebuggerModel.prototype = { return breakpoints; }, - findBreakpoint: function(sourceID, lineNumber) - { - for (var id in this._breakpoints) { - var locations = this._breakpoints[id].locations; - for (var i = 0; i < locations.length; ++i) { - if (locations[i].sourceID == sourceID && locations[i].lineNumber + 1 === lineNumber) - return this._breakpoints[id]; - } - } - }, - reset: function() { this._paused = false; @@ -230,7 +219,7 @@ WebInspector.DebuggerModel.prototype = { } else WebInspector.log(newBodyOrErrorMessage, WebInspector.ConsoleMessage.MessageLevel.Warning); } - InspectorBackend.editScriptSource(sourceID, scriptSource, didEditScriptSource.bind(this)); + DebuggerAgent.editScriptSource(sourceID, scriptSource, didEditScriptSource.bind(this)); }, _updateScriptSource: function(sourceID, scriptSource) @@ -286,6 +275,7 @@ WebInspector.DebuggerModel.prototype = { { this._paused = true; this._callFrames = details.callFrames; + details.breakpoint = this._breakpointForCallFrame(details.callFrames[0]); this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerPaused, details); }, @@ -296,6 +286,23 @@ WebInspector.DebuggerModel.prototype = { this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerResumed); }, + _breakpointForCallFrame: function(callFrame) + { + function match(location) + { + if (location.sourceID != callFrame.sourceID) + return false; + return location.lineNumber === callFrame.line && location.columnNumber === callFrame.column; + } + for (var id in this._breakpoints) { + var breakpoint = this._breakpoints[id]; + for (var i = 0; i < breakpoint.locations.length; ++i) { + if (match(breakpoint.locations[i])) + return breakpoint; + } + } + }, + _parsedScriptSource: function(sourceID, sourceURL, lineOffset, columnOffset, length, scriptWorldType) { var script = new WebInspector.Script(sourceID, sourceURL, "", lineOffset, columnOffset, length, undefined, undefined, scriptWorldType); diff --git a/Source/WebCore/inspector/front-end/DebuggerPresentationModel.js b/Source/WebCore/inspector/front-end/DebuggerPresentationModel.js new file mode 100644 index 0000000..a97db34 --- /dev/null +++ b/Source/WebCore/inspector/front-end/DebuggerPresentationModel.js @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.DebuggerPresentationModel = function() +{ + this._breakpoints = {}; + this._sourceLocationToBreakpointId = {}; + + WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointAdded, this._breakpointAdded, this); + WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointRemoved, this._breakpointRemoved, this); + WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointResolved, this._breakpointResolved, this); +} + +WebInspector.DebuggerPresentationModel.Events = { + BreakpointAdded: "breakpoint-added", + BreakpointRemoved: "breakpoint-removed" +} + +WebInspector.DebuggerPresentationModel.prototype = { + breakpointsForSourceFileId: function(sourceFileId) + { + var breakpoints = []; + for (var id in this._breakpoints) { + var breakpoint = this._breakpoints[id]; + if (breakpoint.sourceFileId === sourceFileId) + breakpoints.push(breakpoint); + } + return breakpoints; + }, + + _breakpointAdded: function(event) + { + var breakpoint = event.data; + var location = breakpoint.locations.length ? breakpoint.locations[0] : breakpoint; + var sourceLocation = this._actualLocationToSourceLocation(breakpoint.url || breakpoint.sourceID, location.lineNumber, location.columnNumber); + + var encodedSourceLocation = this._encodeSourceLocation(sourceLocation.sourceFileId, sourceLocation.lineNumber); + if (encodedSourceLocation in this._sourceLocationToBreakpointId) { + // We can't show more than one breakpoint on a single source frame line. Remove newly added breakpoint. + WebInspector.debuggerModel.removeBreakpoint(breakpoint.id); + return; + } + + var presentationBreakpoint = { + sourceFileId: sourceLocation.sourceFileId, + lineNumber: sourceLocation.lineNumber, + url: breakpoint.url, + resolved: !!breakpoint.locations.length, + condition: breakpoint.condition, + enabled: breakpoint.enabled + }; + + this._sourceLocationToBreakpointId[encodedSourceLocation] = breakpoint.id; + this._breakpoints[breakpoint.id] = presentationBreakpoint; + + this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.BreakpointAdded, presentationBreakpoint); + }, + + _breakpointRemoved: function(event) + { + var breakpointId = event.data; + var breakpoint = this._breakpoints[breakpointId]; + var encodedSourceLocation = this._encodeSourceLocation(breakpoint.sourceFileId, breakpoint.lineNumber); + delete this._breakpoints[breakpointId]; + delete this._sourceLocationToBreakpointId[encodedSourceLocation]; + this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.BreakpointRemoved, breakpoint); + }, + + _breakpointResolved: function(event) + { + var breakpoint = event.data; + this._breakpointRemoved({ data: breakpoint.id }); + this._breakpointAdded({ data: breakpoint }); + }, + + _encodeSourceLocation: function(sourceFileId, lineNumber) + { + return sourceFileId + ":" + lineNumber; + }, + + set selectedCallFrame(callFrame) + { + this._selectedCallFrame = callFrame; + if (!callFrame) + return; + + var script = WebInspector.debuggerModel.scriptForSourceID(callFrame.sourceID); + callFrame.sourceLocation = this._actualLocationToSourceLocation(script.sourceURL || script.sourceID, callFrame.line, callFrame.column); + this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.CallFrameSelected, callFrame); + }, + + get selectedCallFrame() + { + return this._selectedCallFrame; + }, + + _actualLocationToSourceLocation: function(sourceID, lineNumber, columnNumber) + { + // TODO: use source mapping to obtain source location. + return { sourceFileId: sourceID, lineNumber: lineNumber, columnNumber: columnNumber }; + } +} + +WebInspector.DebuggerPresentationModel.prototype.__proto__ = WebInspector.Object.prototype; diff --git a/Source/WebCore/inspector/front-end/DetailedHeapshotGridNodes.js b/Source/WebCore/inspector/front-end/DetailedHeapshotGridNodes.js new file mode 100644 index 0000000..14ba142 --- /dev/null +++ b/Source/WebCore/inspector/front-end/DetailedHeapshotGridNodes.js @@ -0,0 +1,707 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.HeapSnapshotGridNode = function(tree, hasChildren, populateCount) +{ + WebInspector.DataGridNode.call(this, null, hasChildren); + this._defaultPopulateCount = populateCount; + this._provider = null; + this.addEventListener("populate", this._populate, this); +} + +WebInspector.HeapSnapshotGridNode.prototype = { + createCell: function(columnIdentifier) + { + var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier); + if (this._searchMatched) + cell.addStyleClass("highlight"); + return cell; + }, + + _populate: function(event) + { + WebInspector.PleaseWaitMessage.prototype.startAction(this.dataGrid.element, doPopulate.bind(this)); + + function doPopulate() + { + this._provider.sort(this.comparator()); + this._provider.first(); + this.populateChildren(); + this.removeEventListener("populate", this._populate, this); + } + }, + + populateChildren: function(provider, howMany, atIndex) + { + if (!howMany && provider) { + howMany = provider.instancesCount; + provider.resetInstancesCount(); + } + provider = provider || this._provider; + howMany = howMany || this._defaultPopulateCount; + atIndex = atIndex || this.children.length; + var haveSavedChildren = !!this._savedChildren; + if (haveSavedChildren) { + haveSavedChildren = false; + for (var c in this._savedChildren) { + haveSavedChildren = true; + break; + } + } + for ( ; howMany > 0 && provider.hasNext(); provider.next(), provider.incInstancesCount(), --howMany) { + var item = provider.item; + if (haveSavedChildren) { + var hash = this._childHashForEntity(item); + if (hash in this._savedChildren) { + this.insertChild(this._savedChildren[hash], atIndex++); + continue; + } + } + this.insertChild(this._createChildNode(provider), atIndex++); + } + if (provider.hasNext()) + this.insertChild(new WebInspector.ShowMoreDataGridNode(this.populateChildren.bind(this, provider), this._defaultPopulateCount, provider.length), atIndex++); + }, + + _saveChildren: function() + { + this._savedChildren = {}; + for (var i = 0, childrenCount = this.children.length; i < childrenCount; ++i) { + var child = this.children[i]; + if (child.expanded) + this._savedChildren[this._childHashForNode(child)] = child; + } + }, + + sort: function() + { + var comparator = this.comparator(); + WebInspector.PleaseWaitMessage.prototype.startAction(this.dataGrid.element, doSort.bind(this)); + + function doSort() + { + if (!this._provider.sort(comparator)) + return; + this._saveChildren(); + this.removeChildren(); + this._provider.first(); + this.populateChildren(this._provider); + for (var i = 0, l = this.children.length; i < l; ++i) { + var child = this.children[i]; + if (child.expanded) + child.sort(); + } + } + } +}; + +WebInspector.HeapSnapshotGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype; + +WebInspector.HeapSnapshotGenericObjectNode = function(tree, node, hasChildren, populateCount) +{ + WebInspector.HeapSnapshotGridNode.call(this, tree, hasChildren, populateCount); + this._name = node.name; + this._type = node.type; + this._shallowSize = node.selfSize; + this._retainedSize = node.retainedSize; + this._retainedSizeExact = this._shallowSize === this._retainedSize; + this.snapshotNodeId = node.id; + this.snapshotNodeIndex = node.nodeIndex; +}; + +WebInspector.HeapSnapshotGenericObjectNode.prototype = { + createCell: function(columnIdentifier) + { + var cell = columnIdentifier !== "object" ? WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier) : this._createObjectCell(); + if (this._searchMatched) + cell.addStyleClass("highlight"); + return cell; + }, + + _createObjectCell: function() + { + var cell = document.createElement("td"); + cell.className = "object-column"; + var div = document.createElement("div"); + div.className = "source-code event-properties"; + div.style.overflow = "hidden"; + var data = this.data["object"]; + if (this._prefixObjectCell) + this._prefixObjectCell(div, data); + var valueSpan = document.createElement("span"); + valueSpan.className = "value console-formatted-" + data.valueStyle; + valueSpan.textContent = data.value; + div.appendChild(valueSpan); + cell.appendChild(div); + cell.addStyleClass("disclosure"); + if (this.depth) + cell.style.setProperty("padding-left", (this.depth * this.dataGrid.indentWidth) + "px"); + return cell; + }, + + get _countPercent() + { + return this._count / this.tree.snapshot.nodesCount * 100.0; + }, + + get data() + { + var data = this._emptyData(); + + var value = this._name; + var valueStyle = "object"; + switch (this._type) { + case "string": + value = "\"" + value + "\""; + valueStyle = "string"; + break; + case "regexp": + value = "/" + value + "/"; + valueStyle = "string"; + break; + case "closure": + value = "function " + value + "()"; + valueStyle = "function"; + break; + case "number": + valueStyle = "number"; + break; + case "hidden": + valueStyle = "null"; + break; + case "array": + value += "[]"; + break; + }; + data["object"] = { valueStyle: valueStyle, value: value + " @" + this.snapshotNodeId }; + + var view = this.dataGrid.snapshotView; + data["shallowSize"] = view.showShallowSizeAsPercent ? WebInspector.UIString("%.2f%%", this._shallowSizePercent) : Number.bytesToString(this._shallowSize); + data["retainedSize"] = (this._retainedSizeExact ? "" : "\u2248") + (view.showRetainedSizeAsPercent ? WebInspector.UIString("%.2f%%", this._retainedSizePercent) : Number.bytesToString(this._retainedSize)); + + return this._enhanceData ? this._enhanceData(data) : data; + }, + + set exactRetainedSize(size) + { + this._retainedSize = size; + this._retainedSizeExact = true; + this.refresh(); + }, + + get _retainedSizePercent() + { + return this._retainedSize / this.dataGrid.snapshot.totalSize * 100.0; + }, + + get _shallowSizePercent() + { + return this._shallowSize / this.dataGrid.snapshot.totalSize * 100.0; + } +} + +WebInspector.HeapSnapshotGenericObjectNode.prototype.__proto__ = WebInspector.HeapSnapshotGridNode.prototype; + +WebInspector.HeapSnapshotObjectNode = function(tree, edge) +{ + var node = edge.node; + var provider = this._createProvider(tree.snapshot, node.rawEdges); + WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, node, !provider.isEmpty, 100); + this._referenceName = edge.name; + this._referenceType = edge.type; + this._provider = provider; +} + +WebInspector.HeapSnapshotObjectNode.prototype = { + _createChildNode: function(provider) + { + return new WebInspector.HeapSnapshotObjectNode(this.dataGrid, provider.item); + }, + + _createProvider: function(snapshot, rawEdges) + { + var showHiddenData = WebInspector.DetailedHeapshotView.prototype.showHiddenData; + return new WebInspector.HeapSnapshotEdgesProvider( + snapshot, + rawEdges, + function(edge) { + return !edge.isInvisible + && (showHiddenData || (!edge.isHidden && !edge.node.isHidden)); + }); + }, + + _childHashForEntity: function(edge) + { + return edge.type + "#" + edge.name; + }, + + _childHashForNode: function(childNode) + { + return childNode._referenceType + "#" + childNode._referenceName; + }, + + comparator: function() + { + var sortAscending = this.dataGrid.sortOrder === "ascending"; + var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier; + var sortFields = { + object: ["!edgeName", sortAscending, "retainedSize", false], + count: ["!edgeName", true, "retainedSize", false], + shallowSize: ["selfSize", sortAscending, "!edgeName", true], + retainedSize: ["retainedSize", sortAscending, "!edgeName", true] + }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false]; + return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields); + }, + + _emptyData: function() + { + return {count:"", addedCount: "", removedCount: "", countDelta:"", addedSize: "", removedSize: "", sizeDelta: ""}; + }, + + _enhanceData: function(data) + { + var name = this._referenceName; + if (name === "") name = "(empty)"; + var nameClass = "name"; + switch (this._referenceType) { + case "context": + nameClass = "console-formatted-number"; + break; + case "internal": + case "hidden": + nameClass = "console-formatted-null"; + break; + } + data["object"].nameClass = nameClass; + data["object"].name = name; + return data; + }, + + _prefixObjectCell: function(div, data) + { + var nameSpan = document.createElement("span"); + nameSpan.className = data.nameClass; + nameSpan.textContent = data.name; + var separatorSpan = document.createElement("span"); + separatorSpan.className = "separator"; + separatorSpan.textContent = ": "; + div.appendChild(nameSpan); + div.appendChild(separatorSpan); + } +} + +WebInspector.HeapSnapshotObjectNode.prototype.__proto__ = WebInspector.HeapSnapshotGenericObjectNode.prototype; + +WebInspector.HeapSnapshotInstanceNode = function(tree, baseSnapshot, snapshot, node) +{ + var provider = this._createProvider(baseSnapshot || snapshot, node.rawEdges); + WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, node, !provider.isEmpty, 100); + this._isDeletedNode = !!baseSnapshot; + this._provider = provider; +}; + +WebInspector.HeapSnapshotInstanceNode.prototype = { + _createChildNode: function(provider) + { + return new WebInspector.HeapSnapshotObjectNode(this.dataGrid, provider.item); + }, + + _createProvider: function(snapshot, rawEdges) + { + var showHiddenData = WebInspector.DetailedHeapshotView.prototype.showHiddenData; + return new WebInspector.HeapSnapshotEdgesProvider( + snapshot, + rawEdges, + function(edge) { + return !edge.isInvisible + && (showHiddenData || (!edge.isHidden && !edge.node.isHidden)); + }); + }, + + _childHashForEntity: function(edge) + { + return edge.type + "#" + edge.name; + }, + + _childHashForNode: function(childNode) + { + return childNode._referenceType + "#" + childNode._referenceName; + }, + + comparator: function() + { + var sortAscending = this.dataGrid.sortOrder === "ascending"; + var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier; + var sortFields = { + object: ["!edgeName", sortAscending, "retainedSize", false], + count: ["!edgeName", true, "retainedSize", false], + addedSize: ["selfSize", sortAscending, "!edgeName", true], + removedSize: ["selfSize", sortAscending, "!edgeName", true], + shallowSize: ["selfSize", sortAscending, "!edgeName", true], + retainedSize: ["retainedSize", sortAscending, "!edgeName", true] + }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false]; + return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields); + }, + + _emptyData: function() + { + return {count:"", countDelta:"", sizeDelta: ""}; + }, + + _enhanceData: function(data) + { + if (this._isDeletedNode) { + data["addedCount"] = ""; + data["addedSize"] = ""; + data["removedCount"] = "\u2022"; + data["removedSize"] = Number.bytesToString(this._shallowSize); + } else { + data["addedCount"] = "\u2022"; + data["addedSize"] = Number.bytesToString(this._shallowSize); + data["removedCount"] = ""; + data["removedSize"] = ""; + } + return data; + } +} + +WebInspector.HeapSnapshotInstanceNode.prototype.__proto__ = WebInspector.HeapSnapshotGenericObjectNode.prototype; + +WebInspector.HeapSnapshotConstructorNode = function(tree, constructor, aggregate) +{ + WebInspector.HeapSnapshotGridNode.call(this, tree, aggregate.count > 0, 100); + this._name = constructor; + this._count = aggregate.count; + this._shallowSize = aggregate.self; + this._retainedSize = aggregate.maxRet; + this._provider = this._createNodesProvider(tree.snapshot, aggregate.type, aggregate.name); +} + +WebInspector.HeapSnapshotConstructorNode.prototype = { + _createChildNode: function(provider) + { + return new WebInspector.HeapSnapshotInstanceNode(this.dataGrid, null, this.dataGrid.snapshot, provider.item); + }, + + _createNodesProvider: function(snapshot, nodeType, nodeName) + { + return new WebInspector.HeapSnapshotNodesProvider( + snapshot, + snapshot.allNodes, + function (node) { + return node.type === nodeType + && (nodeName === null || node.name === nodeName); + }); + }, + + comparator: function() + { + var sortAscending = this.dataGrid.sortOrder === "ascending"; + var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier; + var sortFields = { + object: ["id", sortAscending, "retainedSize", false], + count: ["id", true, "retainedSize", false], + shallowSize: ["selfSize", sortAscending, "id", true], + retainedSize: ["retainedSize", sortAscending, "id", true] + }[sortColumnIdentifier]; + return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields); + }, + + _childHashForEntity: function(node) + { + return node.id; + }, + + _childHashForNode: function(childNode) + { + return childNode.snapshotNodeId; + }, + + get data() + { + var data = {object: this._name, count: this._count}; + var view = this.dataGrid.snapshotView; + data["count"] = view.showCountAsPercent ? WebInspector.UIString("%.2f%%", this._countPercent) : this._count; + data["shallowSize"] = view.showShallowSizeAsPercent ? WebInspector.UIString("%.2f%%", this._shallowSizePercent) : Number.bytesToString(this._shallowSize); + data["retainedSize"] = "> " + (view.showRetainedSizeAsPercent ? WebInspector.UIString("%.2f%%", this._retainedSizePercent) : Number.bytesToString(this._retainedSize)); + return data; + }, + + get _countPercent() + { + return this._count / this.dataGrid.snapshot.nodesCount * 100.0; + }, + + get _retainedSizePercent() + { + return this._retainedSize / this.dataGrid.snapshot.totalSize * 100.0; + }, + + get _shallowSizePercent() + { + return this._shallowSize / this.dataGrid.snapshot.totalSize * 100.0; + } +}; + +WebInspector.HeapSnapshotConstructorNode.prototype.__proto__ = WebInspector.HeapSnapshotGridNode.prototype; + +WebInspector.HeapSnapshotIteratorsTuple = function(it1, it2) +{ + this._it1 = it1; + this._it2 = it2; +} + +WebInspector.HeapSnapshotIteratorsTuple.prototype = { + first: function() + { + this._it1.first(); + this._it2.first(); + }, + + resetInstancesCount: function() + { + this._it1.resetInstancesCount(); + this._it2.resetInstancesCount(); + }, + + sort: function(comparator) + { + this._it1.sort(comparator); + this._it2.sort(comparator); + } +}; + +WebInspector.HeapSnapshotDiffNode = function(tree, constructor, baseAggregate, aggregate) +{ + if (!baseAggregate) + baseAggregate = { count: 0, self: 0, maxRet: 0, type:aggregate.type, name:aggregate.name, idxs: [] }; + if (!aggregate) + aggregate = { count: 0, self: 0, maxRet: 0, type:baseAggregate.type, name:baseAggregate.name, idxs: [] }; + WebInspector.HeapSnapshotGridNode.call(this, tree, true, 50); + this._name = constructor; + this._calculateDiff(tree.baseSnapshot, tree.snapshot, baseAggregate.idxs, aggregate.idxs); + this._provider = this._createNodesProvider(tree.baseSnapshot, tree.snapshot, aggregate.type, aggregate.name); +} + +WebInspector.HeapSnapshotDiffNode.prototype = { + _calculateDiff: function(baseSnapshot, snapshot, baseIndexes, currentIndexes) + { + var i = 0, l = baseIndexes.length; + var j = 0, m = currentIndexes.length; + this._addedCount = 0; + this._removedCount = 0; + this._addedSize = 0; + this._removedSize = 0; + var nodeA = new WebInspector.HeapSnapshotNode(baseSnapshot); + var nodeB = new WebInspector.HeapSnapshotNode(snapshot); + nodeA.nodeIndex = baseIndexes[i]; + nodeB.nodeIndex = currentIndexes[j]; + while (i < l && j < m) { + if (nodeA.id < nodeB.id) { + this._removedCount++; + this._removedSize += nodeA.selfSize; + nodeA.nodeIndex = baseIndexes[++i]; + } else if (nodeA.id > nodeB.id) { + this._addedCount++; + this._addedSize += nodeB.selfSize; + nodeB.nodeIndex = currentIndexes[++j]; + } else { + nodeA.nodeIndex = baseIndexes[++i]; + nodeB.nodeIndex = currentIndexes[++j]; + } + } + while (i < l) { + this._removedCount++; + this._removedSize += nodeA.selfSize; + nodeA.nodeIndex = baseIndexes[++i]; + } + while (j < m) { + this._addedCount++; + this._addedSize += nodeB.selfSize; + nodeB.nodeIndex = currentIndexes[++j]; + } + this._countDelta = this._addedCount - this._removedCount; + this._sizeDelta = this._addedSize - this._removedSize; + }, + + _createChildNode: function(provider) + { + if (provider === this._provider._it1) + return new WebInspector.HeapSnapshotInstanceNode(this.dataGrid, null, provider.snapshot, provider.item); + else + return new WebInspector.HeapSnapshotInstanceNode(this.dataGrid, provider.snapshot, null, provider.item); + }, + + _createNodesProvider: function(baseSnapshot, snapshot, nodeType, nodeName) + { + return new WebInspector.HeapSnapshotIteratorsTuple( + createProvider(snapshot, baseSnapshot), createProvider(baseSnapshot, snapshot)); + + function createProvider(snapshot, otherSnapshot) + { + return new WebInspector.HeapSnapshotNodesProvider( + snapshot, + snapshot.allNodes, + function (node) { + return node.type === nodeType + && (nodeName === null || node.name === nodeName) + && !(node.id in otherSnapshot.idsMap); + }); + } + }, + + comparator: function() + { + var sortAscending = this.dataGrid.sortOrder === "ascending"; + var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier; + var sortFields = { + object: ["id", sortAscending, "selfSize", false], + addedCount: ["selfSize", sortAscending, "id", true], + removedCount: ["selfSize", sortAscending, "id", true], + countDelta: ["selfSize", sortAscending, "id", true], + addedSize: ["selfSize", sortAscending, "id", true], + removedSize: ["selfSize", sortAscending, "id", true], + sizeDelta: ["selfSize", sortAscending, "id", true] + }[sortColumnIdentifier]; + return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields); + }, + + populateChildren: function(provider, howMany, atIndex) + { + if (!provider && !howMany) { + WebInspector.HeapSnapshotGridNode.prototype.populateChildren.call(this, this._provider._it1, this._defaultPopulateCount); + WebInspector.HeapSnapshotGridNode.prototype.populateChildren.call(this, this._provider._it2, this._defaultPopulateCount); + } else if (!howMany) { + WebInspector.HeapSnapshotGridNode.prototype.populateChildren.call(this, this._provider._it1); + WebInspector.HeapSnapshotGridNode.prototype.populateChildren.call(this, this._provider._it2); + } else + WebInspector.HeapSnapshotGridNode.prototype.populateChildren.call(this, provider, howMany, atIndex); + }, + + _signForDelta: function(delta) + { + if (delta === 0) + return ""; + if (delta > 0) + return "+"; + else + return "\u2212"; // Math minus sign, same width as plus. + }, + + get data() + { + var data = {object: this._name}; + + data["addedCount"] = this._addedCount; + data["removedCount"] = this._removedCount; + data["countDelta"] = WebInspector.UIString("%s%d", this._signForDelta(this._countDelta), Math.abs(this._countDelta)); + data["addedSize"] = Number.bytesToString(this._addedSize); + data["removedSize"] = Number.bytesToString(this._removedSize); + data["sizeDelta"] = WebInspector.UIString("%s%s", this._signForDelta(this._sizeDelta), Number.bytesToString(Math.abs(this._sizeDelta))); + + return data; + }, + + get zeroDiff() + { + return this._addedCount === 0 && this._removedCount === 0; + } +}; + +WebInspector.HeapSnapshotDiffNode.prototype.__proto__ = WebInspector.HeapSnapshotGridNode.prototype; + +WebInspector.HeapSnapshotDominatorObjectNode = function(tree, node) +{ + var provider = this._createProvider(tree.snapshot, node.nodeIndex); + WebInspector.HeapSnapshotGenericObjectNode.call(this, tree, node, !provider.isEmpty, 25); + this._provider = provider; +}; + +WebInspector.HeapSnapshotDominatorObjectNode.prototype = { + _createChildNode: function(provider) + { + return new WebInspector.HeapSnapshotDominatorObjectNode(this.dataGrid, provider.item); + }, + + _createProvider: function(snapshot, nodeIndex) + { + var showHiddenData = WebInspector.DetailedHeapshotView.prototype.showHiddenData; + return new WebInspector.HeapSnapshotNodesProvider( + snapshot, + snapshot.allNodes, + function (node) { + var dominatorIndex = node.dominatorIndex(); + return dominatorIndex === nodeIndex + && dominatorIndex !== node.nodeIndex + && (showHiddenData || !node.isHidden); + }); + }, + + _childHashForEntity: function(node) + { + return node.id; + }, + + _childHashForNode: function(childNode) + { + return childNode.snapshotNodeId; + }, + + comparator: function() + { + var sortAscending = this.dataGrid.sortOrder === "ascending"; + var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier; + var sortFields = { + object: ["id", sortAscending, "retainedSize", false], + shallowSize: ["selfSize", sortAscending, "id", true], + retainedSize: ["retainedSize", sortAscending, "id", true] + }[sortColumnIdentifier]; + return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields); + }, + + _emptyData: function() + { + return {}; + } +}; + +WebInspector.HeapSnapshotDominatorObjectNode.prototype.__proto__ = WebInspector.HeapSnapshotGenericObjectNode.prototype; + +function MixInSnapshotNodeFunctions(sourcePrototype, targetPrototype) +{ + targetPrototype._childHashForEntity = sourcePrototype._childHashForEntity; + targetPrototype._childHashForNode = sourcePrototype._childHashForNode; + targetPrototype.comparator = sourcePrototype.comparator; + targetPrototype._createChildNode = sourcePrototype._createChildNode; + targetPrototype._createProvider = sourcePrototype._createProvider; + targetPrototype.populateChildren = sourcePrototype.populateChildren; + targetPrototype._saveChildren = sourcePrototype._saveChildren; + targetPrototype.sort = sourcePrototype.sort; +} diff --git a/Source/WebCore/inspector/front-end/DetailedHeapshotView.js b/Source/WebCore/inspector/front-end/DetailedHeapshotView.js index 5291bf2..ffce1dd 100644 --- a/Source/WebCore/inspector/front-end/DetailedHeapshotView.js +++ b/Source/WebCore/inspector/front-end/DetailedHeapshotView.js @@ -28,30 +28,879 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +WebInspector.HeapSnapshotContainmentDataGrid = function() +{ + var columns = { + object: { title: WebInspector.UIString("Object"), disclosure: true, sortable: true, sort: "ascending" }, + shallowSize: { title: WebInspector.UIString("Shallow Size"), width: "90px", sortable: true }, + retainedSize: { title: WebInspector.UIString("Retained Size"), width: "90px", sortable: true } + }; + WebInspector.DataGrid.call(this, columns); + this.addEventListener("sorting changed", this.sort, this); + this._defaultPopulateCount = 100; +} + +WebInspector.HeapSnapshotContainmentDataGrid.prototype = { + setDataSource: function(snapshotView, snapshot) + { + this.snapshotView = snapshotView; + this.snapshot = snapshot; + this.snapshotNodeIndex = this.snapshot._rootNodeIndex; + this._provider = this._createProvider(snapshot, snapshot.rootNode.rawEdges); + this.sort(); + } +}; + +MixInSnapshotNodeFunctions(WebInspector.HeapSnapshotObjectNode.prototype, WebInspector.HeapSnapshotContainmentDataGrid.prototype); +WebInspector.HeapSnapshotContainmentDataGrid.prototype.__proto__ = WebInspector.DataGrid.prototype; + +WebInspector.HeapSnapshotSortableDataGrid = function(columns) +{ + WebInspector.DataGrid.call(this, columns); + this.addEventListener("sorting changed", this.sortingChanged, this); +} + +WebInspector.HeapSnapshotSortableDataGrid.prototype = { + sortingChanged: function() + { + var sortAscending = this.sortOrder === "ascending"; + var sortColumnIdentifier = this.sortColumnIdentifier; + var sortFields = this._sortFields(sortColumnIdentifier, sortAscending); + + function SortByTwoFields(nodeA, nodeB) + { + var field1 = nodeA[sortFields[0]]; + var field2 = nodeB[sortFields[0]]; + var result = field1 < field2 ? -1 : (field1 > field2 ? 1 : 0); + if (!sortFields[1]) + result = -result; + if (result !== 0) + return result; + field1 = nodeA[sortFields[2]]; + field2 = nodeB[sortFields[2]]; + result = field1 < field2 ? -1 : (field1 > field2 ? 1 : 0); + if (!sortFields[3]) + result = -result; + return result; + } + + this._performSorting(SortByTwoFields); + }, + + _performSorting: function(sortFunction) + { + var children = this.children; + this.removeChildren(); + children.sort(sortFunction); + for (var i = 0, l = children.length; i < l; ++i) { + var child = children[i]; + this.appendChild(child); + if (child.expanded) + child.sort(); + } + } +}; + +WebInspector.HeapSnapshotSortableDataGrid.prototype.__proto__ = WebInspector.DataGrid.prototype; + +WebInspector.HeapSnapshotConstructorsDataGrid = function() +{ + var columns = { + object: { title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true }, + count: { title: WebInspector.UIString("#"), width: "45px", sortable: true }, + shallowSize: { title: WebInspector.UIString("Shallow Size"), width: "90px", sortable: true }, + retainedSize: { title: WebInspector.UIString("Retained Size"), width: "90px", sort: "descending", sortable: true } + }; + WebInspector.HeapSnapshotSortableDataGrid.call(this, columns); +} + +WebInspector.HeapSnapshotConstructorsDataGrid.prototype = { + _sortFields: function(sortColumn, sortAscending) + { + return { + object: ["_name", sortAscending, "_count", false], + count: ["_count", sortAscending, "_name", true], + shallowSize: ["_shallowSize", sortAscending, "_name", true], + retainedSize: ["_retainedSize", sortAscending, "_name", true] + }[sortColumn]; + }, + + setDataSource: function(snapshotView, snapshot) + { + this.snapshotView = snapshotView; + this.snapshot = snapshot; + this.populateChildren(); + this.sortingChanged(); + }, + + populateChildren: function() + { + var aggregates = this.snapshot.aggregates(); + for (var constructor in aggregates) + this.appendChild(new WebInspector.HeapSnapshotConstructorNode(this, constructor, aggregates[constructor])); + } +}; + +WebInspector.HeapSnapshotConstructorsDataGrid.prototype.__proto__ = WebInspector.HeapSnapshotSortableDataGrid.prototype; + +WebInspector.HeapSnapshotDiffDataGrid = function() +{ + var columns = { + object: { title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true }, + // \xb1 is a "plus-minus" sign. + addedCount: { title: WebInspector.UIString("# New"), width: "72px", sortable: true, sort: "descending" }, + removedCount: { title: WebInspector.UIString("# Deleted"), width: "72px", sortable: true }, + // \u0394 is a Greek delta letter. + countDelta: { title: "\u0394", width: "40px", sortable: true }, + addedSize: { title: WebInspector.UIString("Alloc. Size"), width: "72px", sortable: true }, + removedSize: { title: WebInspector.UIString("Freed Size"), width: "72px", sortable: true }, + sizeDelta: { title: "\u0394", width: "72px", sortable: true } + }; + WebInspector.HeapSnapshotSortableDataGrid.call(this, columns); +} + +WebInspector.HeapSnapshotDiffDataGrid.prototype = { + _sortFields: function(sortColumn, sortAscending) + { + return { + object: ["_name", sortAscending, "_count", false], + addedCount: ["_addedCount", sortAscending, "_name", true], + removedCount: ["_removedCount", sortAscending, "_name", true], + countDelta: ["_countDelta", sortAscending, "_name", true], + addedSize: ["_addedSize", sortAscending, "_name", true], + removedSize: ["_removedSize", sortAscending, "_name", true], + sizeDelta: ["_sizeDelta", sortAscending, "_name", true] + }[sortColumn]; + }, + + setDataSource: function(snapshotView, snapshot) + { + this.snapshotView = snapshotView; + this.snapshot = snapshot; + }, + + setBaseDataSource: function(baseSnapshot) + { + this.baseSnapshot = baseSnapshot; + this.removeChildren(); + if (this.baseSnapshot !== this.snapshot) { + this.populateChildren(); + this.sortingChanged(); + } + }, + + populateChildren: function() + { + var baseClasses = this.baseSnapshot.aggregates(true); + var classes = this.snapshot.aggregates(true); + for (var clss in baseClasses) { + var node = new WebInspector.HeapSnapshotDiffNode(this, clss, baseClasses[clss], classes[clss]); + if (!node.zeroDiff) + this.appendChild(node); + } + for (clss in classes) { + if (!(clss in baseClasses)) { + var node = new WebInspector.HeapSnapshotDiffNode(this, clss, null, classes[clss]); + if (!node.zeroDiff) + this.appendChild(node); + } + } + } +}; + +WebInspector.HeapSnapshotDiffDataGrid.prototype.__proto__ = WebInspector.HeapSnapshotSortableDataGrid.prototype; + +WebInspector.HeapSnapshotDominatorsDataGrid = function() +{ + var columns = { + object: { title: WebInspector.UIString("Object"), disclosure: true, sortable: true }, + shallowSize: { title: WebInspector.UIString("Shallow Size"), width: "90px", sortable: true }, + retainedSize: { title: WebInspector.UIString("Retained Size"), width: "90px", sort: "descending", sortable: true } + }; + WebInspector.DataGrid.call(this, columns); + this.addEventListener("sorting changed", this.sort, this); + this._defaultPopulateCount = 25; +} + +WebInspector.HeapSnapshotDominatorsDataGrid.prototype = { + setDataSource: function(snapshotView, snapshot) + { + this.snapshotView = snapshotView; + this.snapshot = snapshot; + this.snapshotNodeIndex = this.snapshot._rootNodeIndex; + this._provider = this._createProvider(snapshot, this.snapshotNodeIndex); + this.sort(); + } +}; + +MixInSnapshotNodeFunctions(WebInspector.HeapSnapshotDominatorObjectNode.prototype, WebInspector.HeapSnapshotDominatorsDataGrid.prototype); +WebInspector.HeapSnapshotDominatorsDataGrid.prototype.__proto__ = WebInspector.DataGrid.prototype; + +WebInspector.HeapSnapshotRetainingPathsList = function() +{ + var columns = { + path: { title: WebInspector.UIString("Retaining path"), sortable: true }, + len: { title: WebInspector.UIString("Length"), width: "90px", sortable: true, sort: "ascending" } + }; + WebInspector.HeapSnapshotSortableDataGrid.call(this, columns); +} + +WebInspector.HeapSnapshotRetainingPathsList.prototype = { + _sortFields: function(sortColumn, sortAscending) + { + return { + path: ["path", sortAscending, "len", true], + len: ["len", sortAscending, "path", true] + }[sortColumn]; + }, + + setDataSource: function(snapshotView, snapshot, nodeIndex, prefix) + { + this.snapshotView = snapshotView; + this._prefix = prefix; + + if (this.pathFinder) + this.searchCancelled(); + + this.pathFinder = new WebInspector.HeapSnapshotPathFinder(snapshot, nodeIndex); + + this.removeChildren(); + + this._counter = 0; + this.showNext(10); + }, + + showNext: function(pathsCount) + { + WebInspector.PleaseWaitMessage.prototype.show(this.element, this.searchCancelled.bind(this, pathsCount)); + window.setTimeout(startSearching.bind(this), 500); + + function startSearching() + { + if (this._cancel !== this.pathFinder) { + if (this._counter < pathsCount) { + var result = this.pathFinder.findNext(); + if (result === null) { + WebInspector.PleaseWaitMessage.prototype.hide(); + if (!this.children.length) + this.appendChild(new WebInspector.DataGridNode({path:WebInspector.UIString("This object is either only accessible via hidden properties, or current path search depth isn't enough."), len:""}, false)); + return; + } else if (result !== false) { + if (this._prefix) + result.path = this._prefix + result.path; + this.appendChild(new WebInspector.DataGridNode(result, false)); + ++this._counter; + } + window.setTimeout(startSearching.bind(this), 0); + return; + } else + this.searchCancelled.call(this, pathsCount); + } + this._cancel = false; + } + }, + + searchCancelled: function(pathsCount) + { + WebInspector.PleaseWaitMessage.prototype.hide(); + this._counter = 0; + this._cancel = this.pathFinder; + if (pathsCount) { + this.appendChild(new WebInspector.ShowMoreDataGridNode(this.showNext.bind(this), pathsCount)); + this.sortingChanged(); + } + }, + + _performSorting: function(sortFunction) + { + function DataExtractorWrapper(nodeA, nodeB) + { + return sortFunction(nodeA.data, nodeB.data); + } + + this.sortNodes(DataExtractorWrapper); + } +}; + +WebInspector.HeapSnapshotRetainingPathsList.prototype.__proto__ = WebInspector.HeapSnapshotSortableDataGrid.prototype; + WebInspector.DetailedHeapshotView = function(parent, profile) { WebInspector.View.call(this); - this.element.addStyleClass("heap-snapshot-view"); + this.element.addStyleClass("detailed-heapshot-view"); this.parent = parent; - this.profile = profile; + this.parent.addEventListener("profile added", this._updateBaseOptions, this); + + this.showCountAsPercent = false; + this.showShallowSizeAsPercent = false; + this.showRetainedSizeAsPercent = false; + + this.containmentView = new WebInspector.View(); + this.containmentView.element.addStyleClass("view"); + this.containmentDataGrid = new WebInspector.HeapSnapshotContainmentDataGrid(); + this.containmentDataGrid.element.addEventListener("click", this._mouseClickInContainmentGrid.bind(this), true); + this.containmentDataGrid.element.addEventListener("dblclick", this._dblClickInContainmentGrid.bind(this), true); + this.containmentView.element.appendChild(this.containmentDataGrid.element); + this.element.appendChild(this.containmentView.element); + + this.constructorsView = new WebInspector.View(); + this.constructorsView.element.addStyleClass("view"); + this.constructorsDataGrid = new WebInspector.HeapSnapshotConstructorsDataGrid(); + this.constructorsDataGrid.element.addEventListener("click", this._mouseClickInContainmentGrid.bind(this), true); + this.constructorsDataGrid.element.addEventListener("dblclick", this._dblClickInContainmentGrid.bind(this), true); + this.constructorsView.element.appendChild(this.constructorsDataGrid.element); + this.element.appendChild(this.constructorsView.element); + + this.diffView = new WebInspector.View(); + this.diffView.element.addStyleClass("view"); + this.diffDataGrid = new WebInspector.HeapSnapshotDiffDataGrid(); + this.diffDataGrid.element.addEventListener("click", this._mouseClickInContainmentGrid.bind(this), true); + this.diffDataGrid.element.addEventListener("dblclick", this._dblClickInContainmentGrid.bind(this), true); + this.diffView.element.appendChild(this.diffDataGrid.element); + this.element.appendChild(this.diffView.element); + + this.dominatorView = new WebInspector.View(); + this.dominatorView.element.addStyleClass("view"); + this.dominatorDataGrid = new WebInspector.HeapSnapshotDominatorsDataGrid(); + this.dominatorDataGrid.element.addEventListener("click", this._mouseClickInContainmentGrid.bind(this), true); + this.dominatorDataGrid.element.addEventListener("dblclick", this._dblClickInContainmentGrid.bind(this), true); + this.dominatorView.element.appendChild(this.dominatorDataGrid.element); + this.element.appendChild(this.dominatorView.element); + + var retainmentView = new WebInspector.View(); + retainmentView.element.addStyleClass("view retaining-paths-view"); + var retainingPathsTitleDiv = document.createElement("div"); + retainingPathsTitleDiv.className = "title"; + var retainingPathsTitle = document.createElement("span"); + retainingPathsTitle.textContent = WebInspector.UIString("Retaining paths of the selected object"); + retainingPathsTitleDiv.appendChild(retainingPathsTitle); + retainmentView.element.appendChild(retainingPathsTitleDiv); + this.retainmentDataGrid = new WebInspector.HeapSnapshotRetainingPathsList(); + retainmentView.element.appendChild(this.retainmentDataGrid.element); + retainmentView.visible = true; + this.element.appendChild(retainmentView.element); + + this.dataGrid = this.constructorsDataGrid; + this.currentView = this.constructorsView; + + this.viewSelectElement = document.createElement("select"); + this.viewSelectElement.className = "status-bar-item"; + this.viewSelectElement.addEventListener("change", this._changeView.bind(this), false); + + var classesViewOption = document.createElement("option"); + classesViewOption.label = WebInspector.UIString("Summary"); + var diffViewOption = document.createElement("option"); + diffViewOption.label = WebInspector.UIString("Comparison"); + var containmentViewOption = document.createElement("option"); + containmentViewOption.label = WebInspector.UIString("Containment"); + var dominatorsViewOption = document.createElement("option"); + dominatorsViewOption.label = WebInspector.UIString("Dominators"); + this.viewSelectElement.appendChild(classesViewOption); + this.viewSelectElement.appendChild(diffViewOption); + this.viewSelectElement.appendChild(containmentViewOption); + this.viewSelectElement.appendChild(dominatorsViewOption); + this.views = ["Summary", "Comparison", "Containment", "Dominators"]; + this.views.current = 0; + + this._profileUid = profile.uid; + + this.baseSelectElement = document.createElement("select"); + this.baseSelectElement.className = "status-bar-item hidden"; + this.baseSelectElement.addEventListener("change", this._changeBase.bind(this), false); + this._updateBaseOptions(); + + this.percentButton = new WebInspector.StatusBarButton("", "percent-time-status-bar-item status-bar-item"); + this.percentButton.addEventListener("click", this._percentClicked.bind(this), false); + this.helpButton = new WebInspector.StatusBarButton("", "heapshot-help-status-bar-item status-bar-item"); + this.helpButton.addEventListener("click", this._helpClicked.bind(this), false); + + this._loadProfile(this._profileUid, profileCallback.bind(this)); + + function profileCallback(profile) + { + var list = this._profiles(); + var profileIndex; + for (var i = 0; i < list.length; ++i) + if (list[i].uid === profile.uid) { + profileIndex = i; + break; + } + if (profileIndex > 0) + this.baseSelectElement.selectedIndex = profileIndex - 1; + else + this.baseSelectElement.selectedIndex = profileIndex; + this.dataGrid.setDataSource(this, this.profileWrapper); + this._updatePercentButton(); + } } WebInspector.DetailedHeapshotView.prototype = { + dispose: function() + { + if (this._profileWrapper) + this._profileWrapper.dispose(); + if (this._baseProfileWrapper) + this._baseProfileWrapper.dispose(); + }, + + get statusBarItems() + { + return [this.viewSelectElement, this.baseSelectElement, this.percentButton.element, this.helpButton.element]; + }, + get profile() { - return this._profile; + return this.parent.getProfile(WebInspector.HeapSnapshotProfileType.TypeId, this._profileUid); }, - set profile(profile) + get profileWrapper() { - this._profile = profile; + if (!this._profileWrapper) + this._profileWrapper = new WebInspector.HeapSnapshot(this.profile); + return this._profileWrapper; + }, + + get baseProfile() + { + return this.parent.getProfile(WebInspector.HeapSnapshotProfileType.TypeId, this._baseProfileUid); + }, + + get baseProfileWrapper() + { + if (!this._baseProfileWrapper) { + if (this.baseProfile !== this.profile) + this._baseProfileWrapper = new WebInspector.HeapSnapshot(this.baseProfile); + else + this._baseProfileWrapper = this.profileWrapper; + } + return this._baseProfileWrapper; + }, + + show: function(parentElement) + { + WebInspector.View.prototype.show.call(this, parentElement); + if (!this.profile._loaded) + this._loadProfile(this._profileUid, profileCallback1.bind(this)); + else + profileCallback1.call(this, this.profile); + + function profileCallback1(profile) { + this.profileWrapper.restore(profile); + if (this.baseProfile && !this.baseProfile._loaded) + this._loadProfile(this._baseProfileUid, profileCallback2.bind(this)); + else + profileCallback2.call(this, this.baseProfile); + } + + function profileCallback2(profile) { + if (profile) + this.baseProfileWrapper.restore(profile); + this.currentView.show(); + this.dataGrid.updateWidths(); + } + }, + + hide: function() + { + WebInspector.View.prototype.hide.call(this); + this._currentSearchResultIndex = -1; + }, + + resize: function() + { + if (this.dataGrid) + this.dataGrid.updateWidths(); + }, + + refreshShowAsPercents: function() + { + this._updatePercentButton(); + this.refreshVisibleData(); + }, + + searchCanceled: function() + { + if (this._searchResults) { + for (var i = 0; i < this._searchResults.length; ++i) { + var node = this._searchResults[i].node; + delete node._searchMatched; + node.refresh(); + } + } + + delete this._searchFinishedCallback; + this._currentSearchResultIndex = -1; + this._searchResults = []; + }, + + performSearch: function(query, finishedCallback) + { + // Call searchCanceled since it will reset everything we need before doing a new search. + this.searchCanceled(); + + query = query.trim(); + + if (!query.length) + return; + if (this.currentView !== this.constructorsView && this.currentView !== this.diffView) + return; + + this._searchFinishedCallback = finishedCallback; + + function matchesByName(gridNode) { + return ("name" in gridNode) && gridNode.name.hasSubstring(query, true); + } + + function matchesById(gridNode) { + return ("snapshotNodeId" in gridNode) && gridNode.snapshotNodeId === query; + } + + var matchPredicate; + if (query.charAt(0) !== "@") + matchPredicate = matchesByName; + else { + query = parseInt(query.substring(1), 10); + matchPredicate = matchesById; + } + + function matchesQuery(gridNode) + { + delete gridNode._searchMatched; + if (matchPredicate(gridNode)) { + gridNode._searchMatched = true; + gridNode.refresh(); + return true; + } + return false; + } + + var current = this.dataGrid.children[0]; + var depth = 0; + var info = {}; + + // Restrict to type nodes and instances. + const maxDepth = 1; + + while (current) { + if (matchesQuery(current)) + this._searchResults.push({ node: current }); + current = current.traverseNextNode(false, null, (depth >= maxDepth), info); + depth += info.depthChange; + } + + finishedCallback(this, this._searchResults.length); + }, + + jumpToFirstSearchResult: function() + { + if (!this._searchResults || !this._searchResults.length) + return; + this._currentSearchResultIndex = 0; + this._jumpToSearchResult(this._currentSearchResultIndex); + }, + + jumpToLastSearchResult: function() + { + if (!this._searchResults || !this._searchResults.length) + return; + this._currentSearchResultIndex = (this._searchResults.length - 1); + this._jumpToSearchResult(this._currentSearchResultIndex); + }, + + jumpToNextSearchResult: function() + { + if (!this._searchResults || !this._searchResults.length) + return; + if (++this._currentSearchResultIndex >= this._searchResults.length) + this._currentSearchResultIndex = 0; + this._jumpToSearchResult(this._currentSearchResultIndex); + }, + + jumpToPreviousSearchResult: function() + { + if (!this._searchResults || !this._searchResults.length) + return; + if (--this._currentSearchResultIndex < 0) + this._currentSearchResultIndex = (this._searchResults.length - 1); + this._jumpToSearchResult(this._currentSearchResultIndex); + }, + + showingFirstSearchResult: function() + { + return (this._currentSearchResultIndex === 0); + }, + + showingLastSearchResult: function() + { + return (this._searchResults && this._currentSearchResultIndex === (this._searchResults.length - 1)); + }, + + _jumpToSearchResult: function(index) + { + var searchResult = this._searchResults[index]; + if (!searchResult) + return; + + var node = searchResult.node; + node.reveal(); + node.select(); + }, + + refreshVisibleData: function() + { + var child = this.dataGrid.children[0]; + while (child) { + child.refresh(); + child = child.traverseNextNode(false, null, true); + } + }, + + _changeBase: function() + { + if (this._baseProfileUid === this._profiles()[this.baseSelectElement.selectedIndex].uid) + return; + + this._baseProfileUid = this._profiles()[this.baseSelectElement.selectedIndex].uid; + this._loadProfile(this._baseProfileUid, baseProfileLoaded.bind(this)); + + function baseProfileLoaded(profile) + { + delete this._baseProfileWrapper; + this.baseProfile._lastShown = Date.now(); + WebInspector.PleaseWaitMessage.prototype.startAction(this.currentView.element, showDiffData.bind(this)); + } + + function showDiffData() + { + this.diffDataGrid.setBaseDataSource(this.baseProfileWrapper); + } + + if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults) + return; + + // The current search needs to be performed again. First negate out previous match + // count by calling the search finished callback with a negative number of matches. + // Then perform the search again with the same query and callback. + this._searchFinishedCallback(this, -this._searchResults.length); + this.performSearch(this.currentQuery, this._searchFinishedCallback); + }, + + _profiles: function() + { + return WebInspector.panels.profiles.getProfiles(WebInspector.HeapSnapshotProfileType.TypeId); + }, + + _loadProfile: function(profileUid, callback) + { + WebInspector.panels.profiles.loadHeapSnapshot(profileUid, callback); + }, + + isDetailedSnapshot: function(snapshot) + { + var s = new WebInspector.HeapSnapshot(snapshot); + for (var iter = s.rootNode.edges; iter.hasNext(); iter.next()) + if (iter.edge.node.name === "(GC roots)") + return true; + return false; + }, + + processLoadedSnapshot: function(profile, snapshot) + { + profile.nodes = snapshot.nodes; + profile.strings = snapshot.strings; + var s = new WebInspector.HeapSnapshot(profile); + profile.sideBarElement.subtitle = Number.bytesToString(s.totalSize); + }, + + _dblClickInContainmentGrid: function(event) + { + var cell = event.target.enclosingNodeOrSelfWithNodeName("td"); + if (!cell || (!cell.hasStyleClass("retainedSize-column"))) + return; + var nodeItem = event.target.enclosingNodeOrSelfWithNodeName("tr")._dataGridNode; + ProfilerAgent.getExactHeapSnapshotNodeRetainedSize(this._profileUid, nodeItem.snapshotNodeId, setExactRetainedSize); + + function setExactRetainedSize(exactSize) { + if (exactSize && exactSize != -1) + nodeItem.exactRetainedSize = exactSize; + } + }, + + _mouseClickInContainmentGrid: function(event) + { + var cell = event.target.enclosingNodeOrSelfWithNodeName("td"); + if (!cell || !(cell.hasStyleClass("object-column") || cell.hasStyleClass("shallowSize-column"))) + return; + var row = event.target.enclosingNodeOrSelfWithNodeName("tr"); + if (!row) + return; + var nodeItem = row._dataGridNode; + if (!nodeItem || nodeItem.isEventWithinDisclosureTriangle(event) || !nodeItem.snapshotNodeIndex) + return; + + this.retainmentDataGrid.setDataSource(this, nodeItem.isDeletedNode ? nodeItem.dataGrid.baseSnapshot : nodeItem.dataGrid.snapshot, nodeItem.snapshotNodeIndex, nodeItem.isDeletedNode ? this.baseSelectElement.childNodes[this.baseSelectElement.selectedIndex].label + " | " : ""); + }, + + _changeView: function(event) + { + if (!event || !this._profileUid) + return; + if (event.target.selectedIndex === this.views.current) + return; + + this.views.current = event.target.selectedIndex; + this.currentView.hide(); + if (this.views[this.views.current] === "Containment") { + this.currentView = this.containmentView; + this.dataGrid = this.containmentDataGrid; + } else if (this.views[this.views.current] === "Summary") { + this.currentView = this.constructorsView; + this.dataGrid = this.constructorsDataGrid; + } else if (this.views[this.views.current] === "Comparison") { + this.currentView = this.diffView; + this.dataGrid = this.diffDataGrid; + } else if (this.views[this.views.current] === "Dominators") { + this.currentView = this.dominatorView; + this.dataGrid = this.dominatorDataGrid; + } + this.currentView.show(); + this.refreshVisibleData(); + if (this.currentView === this.diffView) { + this.baseSelectElement.removeStyleClass("hidden"); + if (!this.dataGrid.snapshotView) { + this.dataGrid.setDataSource(this, this.profileWrapper); + this._changeBase(); + } + } else { + this.baseSelectElement.addStyleClass("hidden"); + if (!this.dataGrid.snapshotView) + WebInspector.PleaseWaitMessage.prototype.startAction(this.currentView.element, loadData.bind(this)); + } + + function loadData() + { + this.dataGrid.setDataSource(this, this.profileWrapper); + } + + if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults) + return; + + // The current search needs to be performed again. First negate out previous match + // count by calling the search finished callback with a negative number of matches. + // Then perform the search again the with same query and callback. + this._searchFinishedCallback(this, -this._searchResults.length); + this.performSearch(this.currentQuery, this._searchFinishedCallback); + }, + + get _isShowingAsPercent() + { + return this.showCountAsPercent && this.showShallowSizeAsPercent && this.showRetainedSizeAsPercent; + }, + + _percentClicked: function(event) + { + var currentState = this._isShowingAsPercent; + this.showCountAsPercent = !currentState; + this.showShallowSizeAsPercent = !currentState; + this.showRetainedSizeAsPercent = !currentState; + this.refreshShowAsPercents(); + }, + + _helpClicked: function(event) + { + if (!this.helpPopover) { + var refTypes = ["a:", "console-formatted-name", WebInspector.UIString("property"), + "0:", "console-formatted-name", WebInspector.UIString("element"), + "a:", "console-formatted-number", WebInspector.UIString("context var"), + "a:", "console-formatted-null", WebInspector.UIString("system prop")]; + var objTypes = [" a ", "console-formatted-object", "Object", + "\"a\"", "console-formatted-string", "String", + "/a/", "console-formatted-string", "RegExp", + "a()", "console-formatted-function", "Function", + "a[]", "console-formatted-object", "Array", + "num", "console-formatted-number", "Number", + " a ", "console-formatted-null", "System"]; + + var contentElement = document.createElement("table"); + contentElement.className = "heapshot-help"; + var headerRow = document.createElement("tr"); + var propsHeader = document.createElement("th"); + propsHeader.textContent = WebInspector.UIString("Property types:"); + headerRow.appendChild(propsHeader); + var objsHeader = document.createElement("th"); + objsHeader.textContent = WebInspector.UIString("Object types:"); + headerRow.appendChild(objsHeader); + contentElement.appendChild(headerRow); + var len = Math.max(refTypes.length, objTypes.length); + for (var i = 0; i < len; i += 3) { + var row = document.createElement("tr"); + var refCell = document.createElement("td"); + if (refTypes[i]) + appendHelp(refTypes, i, refCell); + row.appendChild(refCell); + var objCell = document.createElement("td"); + if (objTypes[i]) + appendHelp(objTypes, i, objCell); + row.appendChild(objCell); + contentElement.appendChild(row); + } + this.helpPopover = new WebInspector.Popover(contentElement); + + function appendHelp(help, index, cell) + { + var div = document.createElement("div"); + div.className = "source-code event-properties"; + var name = document.createElement("span"); + name.textContent = help[index]; + name.className = help[index + 1]; + div.appendChild(name); + var desc = document.createElement("span"); + desc.textContent = " " + help[index + 2]; + div.appendChild(desc); + cell.appendChild(div); + } + } + if (this.helpPopover.visible) + this.helpPopover.hide(); + else + this.helpPopover.show(this.helpButton.element); + }, + + _updateBaseOptions: function() + { + var list = this._profiles(); + // We're assuming that snapshots can only be added. + if (this.baseSelectElement.length === list.length) + return; + + for (var i = this.baseSelectElement.length, n = list.length; i < n; ++i) { + var baseOption = document.createElement("option"); + var title = list[i].title; + if (!title.indexOf(UserInitiatedProfileName)) + title = WebInspector.UIString("Snapshot %d", title.substring(UserInitiatedProfileName.length + 1)); + baseOption.label = title; + this.baseSelectElement.appendChild(baseOption); + } + }, + + _updatePercentButton: function() + { + if (this._isShowingAsPercent) { + this.percentButton.title = WebInspector.UIString("Show absolute counts and sizes."); + this.percentButton.toggled = true; + } else { + this.percentButton.title = WebInspector.UIString("Show counts and sizes as percentages."); + this.percentButton.toggled = false; + } } }; WebInspector.DetailedHeapshotView.prototype.__proto__ = WebInspector.View.prototype; +WebInspector.DetailedHeapshotView.prototype.showHiddenData = true; + WebInspector.DetailedHeapshotProfileType = function() { WebInspector.ProfileType.call(this, WebInspector.HeapSnapshotProfileType.TypeId, WebInspector.UIString("HEAP SNAPSHOTS")); diff --git a/Source/WebCore/inspector/front-end/ElementsPanel.js b/Source/WebCore/inspector/front-end/ElementsPanel.js index e6af93c..246abe8 100644 --- a/Source/WebCore/inspector/front-end/ElementsPanel.js +++ b/Source/WebCore/inspector/front-end/ElementsPanel.js @@ -57,7 +57,7 @@ WebInspector.ElementsPanel = function() this.panel.updateEventListeners(); if (this._focusedDOMNode) { - InspectorBackend.addInspectedNode(this._focusedDOMNode.id); + DOMAgent.addInspectedNode(this._focusedDOMNode.id); WebInspector.extensionServer.notifyObjectSelected(this.panel.name); } }; @@ -141,6 +141,9 @@ WebInspector.ElementsPanel.prototype = { this.treeOutline.updateSelection(); if (this.recentlyModifiedNodes.length) this.updateModifiedNodes(); + + if (!this.rootDOMNode) + WebInspector.domAgent.requestDocument(); }, hide: function() @@ -211,7 +214,7 @@ WebInspector.ElementsPanel.prototype = { } if (this._selectedPathOnReset) - InspectorBackend.pushNodeByPathToFrontend(this._selectedPathOnReset, selectLastSelectedNode.bind(this)); + WebInspector.domAgent.pushNodeByPathToFrontend(this._selectedPathOnReset, selectLastSelectedNode.bind(this)); else selectNode.call(this); delete this._selectedPathOnReset; @@ -222,11 +225,11 @@ WebInspector.ElementsPanel.prototype = { delete this._searchQuery; this._hideSearchHighlights(); - WebInspector.updateSearchMatchesCount(0, this); + WebInspector.searchController.updateSearchMatchesCount(0, this); - this._currentSearchResultIndex = 0; + delete this._currentSearchResultIndex; this._searchResults = []; - InspectorBackend.searchCanceled(); + DOMAgent.searchCanceled(); }, performSearch: function(query) @@ -242,7 +245,7 @@ WebInspector.ElementsPanel.prototype = { this._matchesCountUpdateTimeout = null; this._searchQuery = query; - InspectorBackend.performSearch(whitespaceTrimmedQuery, false); + DOMAgent.performSearch(whitespaceTrimmedQuery, false); }, populateHrefContextMenu: function(contextMenu, event, anchorElement) @@ -264,14 +267,14 @@ WebInspector.ElementsPanel.prototype = { switchToAndFocus: function(node) { // Reset search restore. - WebInspector.cancelSearch(); + WebInspector.searchController.cancelSearch(); WebInspector.currentPanel = this; this.focusedDOMNode = node; }, _updateMatchesCount: function() { - WebInspector.updateSearchMatchesCount(this._searchResults.length, this); + WebInspector.searchController.updateSearchMatchesCount(this._searchResults.length, this); this._matchesCountUpdateTimeout = null; this._updatedMatchCountOnce = true; }, @@ -291,6 +294,7 @@ WebInspector.ElementsPanel.prototype = { if (!nodeIds.length) return; + var oldSearchResultIndex = this._currentSearchResultIndex; for (var i = 0; i < nodeIds.length; ++i) { var nodeId = nodeIds[i]; var node = WebInspector.domAgent.nodeForId(nodeId); @@ -300,7 +304,10 @@ WebInspector.ElementsPanel.prototype = { this._currentSearchResultIndex = 0; this._searchResults.push(node); } - this._highlightCurrentSearchResult(); + + // Avoid invocations of highlighting for every chunk of nodeIds. + if (oldSearchResultIndex !== this._currentSearchResultIndex) + this._highlightCurrentSearchResult(); this._updateMatchesCountSoon(); }, @@ -375,6 +382,9 @@ WebInspector.ElementsPanel.prototype = { this.recentlyModifiedNodes.push({node: event.target, updated: true}); if (this.visible) this._updateModifiedNodesSoon(); + + if (!this.sidebarPanes.styles.isModifyingStyle && event.target === this.focusedDOMNode) + this._styleSheetChanged(); }, _characterDataModified: function(event) @@ -1023,7 +1033,7 @@ WebInspector.ElementsPanel.prototype = { return; event.clipboardData.clearData(); event.preventDefault(); - InspectorBackend.copyNode(this.focusedDOMNode.id); + DOMAgent.copyNode(this.focusedDOMNode.id); }, rightSidebarResizerDragStart: function(event) @@ -1070,7 +1080,7 @@ WebInspector.ElementsPanel.prototype = { setSearchingForNode: function(enabled) { - InspectorBackend.setSearchingForNode(enabled, this._setSearchingForNode.bind(this)); + InspectorAgent.setSearchingForNode(enabled, this._setSearchingForNode.bind(this)); }, toggleSearchingForNode: function() diff --git a/Source/WebCore/inspector/front-end/ElementsTreeOutline.js b/Source/WebCore/inspector/front-end/ElementsTreeOutline.js index 56c3e75..7b5ff2f 100644 --- a/Source/WebCore/inspector/front-end/ElementsTreeOutline.js +++ b/Source/WebCore/inspector/front-end/ElementsTreeOutline.js @@ -329,8 +329,11 @@ WebInspector.ElementsTreeElement.prototype = { if (this._searchQuery === searchQuery) return; + if (searchQuery) + delete this._searchHighlightedHTML; // A new search query (not clear-the-current-highlighting). + this._searchQuery = searchQuery; - this.updateTitle(); + this.updateTitle(true); }, get hovered() @@ -400,17 +403,35 @@ WebInspector.ElementsTreeElement.prototype = { if (!node.nodeName || node.nodeName.toLowerCase() !== "img") return; - function setTooltip(properties) + function setTooltip(result) { - if (!properties) + if (!result || result.type !== "string") return; - if (properties.offsetHeight === properties.naturalHeight && properties.offsetWidth === properties.naturalWidth) - this.tooltip = WebInspector.UIString("%d × %d pixels", properties.offsetWidth, properties.offsetHeight); - else - this.tooltip = WebInspector.UIString("%d × %d pixels (Natural: %d × %d pixels)", properties.offsetWidth, properties.offsetHeight, properties.naturalWidth, properties.naturalHeight); + try { + var properties = JSON.parse(result.description); + var offsetWidth = properties[0]; + var offsetHeight = properties[1]; + var naturalWidth = properties[2]; + var naturalHeight = properties[3]; + if (offsetHeight === naturalHeight && offsetWidth === naturalWidth) + this.tooltip = WebInspector.UIString("%d \xd7 %d pixels", offsetWidth, offsetHeight); + else + this.tooltip = WebInspector.UIString("%d \xd7 %d pixels (Natural: %d \xd7 %d pixels)", offsetWidth, offsetHeight, naturalWidth, naturalHeight); + } catch (e) { + console.error(e); + } + } + + function resolvedNode(objectPayload) + { + if (!objectPayload) + return; + + var object = WebInspector.RemoteObject.fromPayload(objectPayload); + object.evaluate("return '[' + this.offsetWidth + ',' + this.offsetHeight + ',' + this.naturalWidth + ',' + this.naturalHeight + ']'", setTooltip.bind(this)); } - InspectorBackend.getNodeProperties(node.id, ["naturalHeight", "naturalWidth", "offsetHeight", "offsetWidth"], setTooltip.bind(this)); + DOMAgent.resolveNode(node.id, "", resolvedNode.bind(this)); }, updateSelection: function() @@ -1154,7 +1175,7 @@ WebInspector.ElementsTreeElement.prototype = { moveToNextAttributeIfNeeded.call(newTreeItem); } - InspectorBackend.changeTagName(this.representedObject.id, newText, changeTagNameCallback); + DOMAgent.changeTagName(this.representedObject.id, newText, changeTagNameCallback); }, _textNodeEditingCommitted: function(element, newText) @@ -1198,14 +1219,20 @@ WebInspector.ElementsTreeElement.prototype = { return (tags.length === 1 ? null : tags[tags.length-1]); }, - updateTitle: function() + updateTitle: function(onlySearchQueryChanged) { // If we are editing, return early to prevent canceling the edit. // After editing is committed updateTitle will be called. if (this._editing) return; - this.titleHTML = "<span class=\"highlight\">" + this._nodeTitleInfo(WebInspector.linkifyURL).titleHTML + "</span>"; + if (onlySearchQueryChanged && this._normalHTML) + this.titleHTML = this._normalHTML; + else { + delete this._normalHTML; + this.titleHTML = "<span class=\"highlight\">" + this._nodeTitleInfo(WebInspector.linkifyURL).titleHTML + "</span>"; + } + delete this.selectionElement; this.updateSelection(); this._preventFollowingLinksOnDoubleClick(); @@ -1381,7 +1408,7 @@ WebInspector.ElementsTreeElement.prototype = { parentElement.adjustCollapsedRange(true); } - InspectorBackend.removeNode(this.representedObject.id, removeNodeCallback); + DOMAgent.removeNode(this.representedObject.id, removeNodeCallback); }, _editAsHTML: function() @@ -1408,32 +1435,41 @@ WebInspector.ElementsTreeElement.prototype = { function commitChange(value) { - InspectorBackend.setOuterHTML(node.id, value, selectNode); + DOMAgent.setOuterHTML(node.id, value, selectNode); } - InspectorBackend.getOuterHTML(node.id, this._startEditingAsHTML.bind(this, commitChange)); + DOMAgent.getOuterHTML(node.id, this._startEditingAsHTML.bind(this, commitChange)); }, _copyHTML: function() { - InspectorBackend.copyNode(this.representedObject.id); + DOMAgent.copyNode(this.representedObject.id); }, _highlightSearchResults: function() { if (!this._searchQuery) return; + if (this._searchHighlightedHTML) { + this.listItemElement.innerHTML = this._searchHighlightedHTML; + return; + } + + if (!this._normalHTML) + this._normalHTML = this.titleHTML; + var text = this.listItemElement.textContent; - var regexObject = createSearchRegex(this._searchQuery); + var regexObject = createSearchRegex(this._searchQuery, "g"); var offset = 0; var match = regexObject.exec(text); + var matchRanges = []; while (match) { - highlightSearchResult(this.listItemElement, offset + match.index, match[0].length); - offset += match.index + 1; - text = text.substring(match.index + 1); + matchRanges.push({ offset: match.index, length: match[0].length }); match = regexObject.exec(text); } + highlightSearchResults(this.listItemElement, matchRanges); + this._searchHighlightedHTML = this.listItemElement.innerHTML; } } diff --git a/Source/WebCore/inspector/front-end/ExtensionPanel.js b/Source/WebCore/inspector/front-end/ExtensionPanel.js index 144d55d..142b8c1 100644 --- a/Source/WebCore/inspector/front-end/ExtensionPanel.js +++ b/Source/WebCore/inspector/front-end/ExtensionPanel.js @@ -95,7 +95,7 @@ WebInspector.ExtensionWatchSidebarPane.prototype = { setExpression: function(expression, title) { - InspectorBackend.evaluate(expression, "extension-watch", false, this._onEvaluate.bind(this, title)); + RuntimeAgent.evaluate(expression, "extension-watch", false, this._onEvaluate.bind(this, title)); }, _onEvaluate: function(title, result) diff --git a/Source/WebCore/inspector/front-end/ExtensionServer.js b/Source/WebCore/inspector/front-end/ExtensionServer.js index 7d33b73..f9af7dc 100644 --- a/Source/WebCore/inspector/front-end/ExtensionServer.js +++ b/Source/WebCore/inspector/front-end/ExtensionServer.js @@ -34,6 +34,8 @@ WebInspector.ExtensionServer = function() this._handlers = {}; this._subscribers = {}; this._extraHeaders = {}; + this._resources = {}; + this._lastResourceId = 0; this._status = new WebInspector.ExtensionStatus(); this._registerHandler("addRequestHeaders", this._onAddRequestHeaders.bind(this)); @@ -108,10 +110,15 @@ WebInspector.ExtensionServer.prototype = { delete this._clientObjects[auditRun.id]; }, + resetResources: function() + { + this._resources = {}; + }, + _notifyResourceFinished: function(event) { var resource = event.data; - this._postNotification("resource-finished", resource.identifier, (new WebInspector.HAREntry(resource)).build()); + this._postNotification("resource-finished", this._resourceId(resource), (new WebInspector.HAREntry(resource)).build()); }, _postNotification: function(type, details) @@ -166,7 +173,7 @@ WebInspector.ExtensionServer.prototype = { allHeaders[name] = headers[name]; } } - InspectorBackend.setExtraHeaders(allHeaders); + NetworkAgent.setExtraHeaders(allHeaders); }, _onCreatePanel: function(message, port) @@ -176,13 +183,12 @@ 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.title, message.icon); this._clientObjects[id] = panel; - - var toolbarElement = document.getElementById("toolbar"); - var lastToolbarItem = WebInspector.panelOrder[WebInspector.panelOrder.length - 1].toolbarItem; - WebInspector.addPanelToolbarIcon(toolbarElement, panel, lastToolbarItem); WebInspector.panels[id] = panel; + WebInspector.addPanel(panel); + var iframe = this._createClientIframe(panel.element, message.url); iframe.style.height = "100%"; return this._status.OK(); @@ -255,9 +261,9 @@ WebInspector.ExtensionServer.prototype = { _onReload: function(message) { if (typeof message.userAgent === "string") - InspectorBackend.setUserAgentOverride(message.userAgent); + InspectorAgent.setUserAgentOverride(message.userAgent); - InspectorBackend.reloadPage(false); + InspectorAgent.reloadPage(false); return this._status.OK(); }, @@ -273,7 +279,7 @@ WebInspector.ExtensionServer.prototype = { this._dispatchCallback(message.requestId, port, result); } var evalExpression = "JSON.stringify(eval(unescape('" + escape(message.expression) + "')));"; - InspectorBackend.evaluate(evalExpression, "none", true, callback.bind(this)); + RuntimeAgent.evaluate(evalExpression, "", true, callback.bind(this)); }, _onRevealAndSelect: function(message) @@ -289,7 +295,7 @@ WebInspector.ExtensionServer.prototype = { var id = message.id; var resource = null; - resource = WebInspector.networkResourceById(id) || WebInspector.resourceForURL(id); + resource = this._resourceById(id) || WebInspector.resourceForURL(id); if (!resource) return this._status.E_NOTFOUND(typeof id + ": " + id); @@ -304,9 +310,10 @@ WebInspector.ExtensionServer.prototype = { _onGetHAR: function(request) { - var harLog = new WebInspector.HARLog(); - harLog.includeResourceIds = true; - return harLog.build(); + var harLog = (new WebInspector.HARLog()).build(); + for (var i = 0; i < harLog.entries.length; ++i) + harLog.entries[i]._resourceId = this._resourceId(WebInspector.networkResources[i]); + return harLog; }, _onGetResourceContent: function(message, port) @@ -319,12 +326,26 @@ WebInspector.ExtensionServer.prototype = { }; this._dispatchCallback(message.requestId, port, response); } - var resource = WebInspector.networkResourceById(message.id); + var resource = this._resourceById(message.id); if (!resource) return this._status.E_NOTFOUND(message.id); resource.requestContent(onContentAvailable.bind(this)); }, + _resourceId: function(resource) + { + if (!resource._extensionResourceId) { + resource._extensionResourceId = ++this._lastResourceId; + this._resources[resource._extensionResourceId] = resource; + } + return resource._extensionResourceId; + }, + + _resourceById: function(id) + { + return this._resources[id]; + }, + _onAddAuditCategory: function(request) { var category = new WebInspector.ExtensionAuditCategory(request.id, request.displayName, request.resultCount); diff --git a/Source/WebCore/inspector/front-end/FontView.js b/Source/WebCore/inspector/front-end/FontView.js index 82559ef..55110b7 100644 --- a/Source/WebCore/inspector/front-end/FontView.js +++ b/Source/WebCore/inspector/front-end/FontView.js @@ -33,6 +33,12 @@ WebInspector.FontView = function(resource) this.element.addStyleClass("font"); } +WebInspector.FontView._fontInnerHTML = "ABCDEFGHIJKLM<br>NOPQRSTUVWXYZ<br>abcdefghijklm<br>nopqrstuvwxyz<br>1234567890"; + +WebInspector.FontView._fontId = 0; + +WebInspector.FontView._measureFontSize = 50; + WebInspector.FontView.prototype = { hasContent: function() { @@ -44,33 +50,57 @@ WebInspector.FontView.prototype = { if (this.fontPreviewElement) return; - var uniqueFontName = "WebInspectorFontPreview" + this.resource.identifier; + var uniqueFontName = "WebInspectorFontPreview" + (++WebInspector.FontView._fontId); this.fontStyleElement = document.createElement("style"); this.fontStyleElement.textContent = "@font-face { font-family: \"" + uniqueFontName + "\"; src: url(" + this.resource.url + "); }"; document.head.appendChild(this.fontStyleElement); this.fontPreviewElement = document.createElement("div"); - this.element.appendChild(this.fontPreviewElement); - + this.fontPreviewElement.innerHTML = WebInspector.FontView._fontInnerHTML; this.fontPreviewElement.style.setProperty("font-family", uniqueFontName, null); - this.fontPreviewElement.innerHTML = "ABCDEFGHIJKLM<br>NOPQRSTUVWXYZ<br>abcdefghijklm<br>nopqrstuvwxyz<br>1234567890"; - this._lineCount = this.fontPreviewElement.getElementsByTagName("br").length + 1; + this.fontPreviewElement.style.setProperty("visibility", "hidden", null); - this.updateFontPreviewSize(); + this._dummyElement = document.createElement("div"); + this._dummyElement.style.visibility = "hidden"; + this._dummyElement.style.zIndex = "-1"; + this._dummyElement.style.display = "inline"; + this._dummyElement.style.position = "absolute"; + this._dummyElement.style.setProperty("font-family", uniqueFontName, null); + this._dummyElement.style.setProperty("font-size", WebInspector.FontView._measureFontSize + "px", null); + this._dummyElement.innerHTML = WebInspector.FontView._fontInnerHTML; + + this.element.appendChild(this.fontPreviewElement); }, show: function(parentElement) { WebInspector.ResourceView.prototype.show.call(this, parentElement); this._createContentIfNeeded(); + this.updateFontPreviewSize(); }, resize: function() { - this.updateFontPreviewSize(); - WebInspector.ResourceView.prototype.resize.call(this); + if (this._inResize) + return; + + this._inResize = true; + try { + this.updateFontPreviewSize(); + } finally { + delete this._inResize; + } + }, + + _measureElement: function() + { + this.element.appendChild(this._dummyElement); + var result = { width: this._dummyElement.offsetWidth, height: this._dummyElement.offsetHeight }; + this.element.removeChild(this._dummyElement); + + return result; }, updateFontPreviewSize: function() @@ -78,31 +108,26 @@ WebInspector.FontView.prototype = { if (!this.fontPreviewElement || !this.visible) return; - const measureFontSize = 50; - this.fontPreviewElement.style.setProperty("font-size", measureFontSize + "px", null); - this.fontPreviewElement.style.setProperty("position", "absolute", null); - this.fontPreviewElement.style.removeProperty("height"); + this.fontPreviewElement.style.removeProperty("visibility"); + var dimension = this._measureElement(); - const height = this.fontPreviewElement.offsetHeight; - const width = this.fontPreviewElement.offsetWidth; + const height = dimension.height; + const width = dimension.width; - // Subtract some padding. This should match the padding in the CSS plus room for the scrollbar. + // Subtract some padding. This should match the paddings in the CSS plus room for the scrollbar. const containerWidth = this.element.offsetWidth - 50; + const containerHeight = this.element.offsetHeight - 30; - if (!height || !width || !containerWidth) { + if (!height || !width || !containerWidth || !containerHeight) { this.fontPreviewElement.style.removeProperty("font-size"); - this.fontPreviewElement.style.removeProperty("position"); return; } - var realLineHeight = Math.floor(height / this._lineCount); - var fontSizeLineRatio = measureFontSize / realLineHeight; var widthRatio = containerWidth / width; - var finalFontSize = Math.floor(realLineHeight * widthRatio * fontSizeLineRatio) - 2; + var heightRatio = containerHeight / height; + var finalFontSize = Math.floor(WebInspector.FontView._measureFontSize * Math.min(widthRatio, heightRatio)) - 2; this.fontPreviewElement.style.setProperty("font-size", finalFontSize + "px", null); - this.fontPreviewElement.style.setProperty("height", this.fontPreviewElement.offsetHeight + "px", null); - this.fontPreviewElement.style.removeProperty("position"); } } diff --git a/Source/WebCore/inspector/front-end/HAREntry.js b/Source/WebCore/inspector/front-end/HAREntry.js index 4d690b3..b5223b6 100644 --- a/Source/WebCore/inspector/front-end/HAREntry.js +++ b/Source/WebCore/inspector/front-end/HAREntry.js @@ -189,7 +189,6 @@ WebInspector.HAREntry._toMilliseconds = function(time) WebInspector.HARLog = function() { - this.includeResourceIds = false; } WebInspector.HARLog.prototype = { @@ -230,10 +229,7 @@ WebInspector.HARLog.prototype = { _convertResource: function(resource) { - var entry = (new WebInspector.HAREntry(resource)).build(); - if (this.includeResourceIds) - entry._resourceId = resource.identifier; - return entry; + return (new WebInspector.HAREntry(resource)).build(); }, _pageEventTime: function(time) diff --git a/Source/WebCore/inspector/front-end/HeapSnapshot.js b/Source/WebCore/inspector/front-end/HeapSnapshot.js index ef450af..215f31c 100644 --- a/Source/WebCore/inspector/front-end/HeapSnapshot.js +++ b/Source/WebCore/inspector/front-end/HeapSnapshot.js @@ -80,6 +80,11 @@ WebInspector.HeapSnapshotEdge.prototype = { return this._type() === this._snapshot._edgeInternalType; }, + get isInvisible() + { + return this._type() === this._snapshot._edgeInvisibleType; + }, + get isShortcut() { return this._type() === this._snapshot._edgeShortcutType; @@ -123,6 +128,7 @@ WebInspector.HeapSnapshotEdge.prototype = { return "[" + this.name + "]"; case "internal": case "hidden": + case "invisible": return "{" + this.name + "}"; }; return "?" + this.name + "?"; @@ -377,6 +383,10 @@ WebInspector.HeapSnapshot.prototype = { this._edgeHiddenType = this._edgeTypes.indexOf("hidden"); this._edgeInternalType = this._edgeTypes.indexOf("internal"); this._edgeShortcutType = this._edgeTypes.indexOf("shortcut"); + this._edgeInvisibleType = this._edgeTypes.length; + this._edgeTypes.push("invisible"); + + this._markInvisibleEdges(); }, dispose: function() @@ -549,17 +559,44 @@ WebInspector.HeapSnapshot.prototype = { }); this._aggregatesWithIndexes = true; + }, + + _markInvisibleEdges: function() + { + // Mark hidden edges of global objects as invisible. + // FIXME: This is a temporary measure. Normally, we should + // really hide all hidden nodes. + for (var iter = this.rootNode.edges; iter.hasNext(); iter.next()) { + var edge = iter.edge; + if (!edge.isShortcut) + continue; + var node = edge.node; + var propNames = {}; + for (var innerIter = node.edges; innerIter.hasNext(); innerIter.next()) { + var globalObjEdge = innerIter.edge; + if (globalObjEdge.isShortcut) + propNames[globalObjEdge._nameOrIndex] = true; + } + for (innerIter.first(); innerIter.hasNext(); innerIter.next()) { + var globalObjEdge = innerIter.edge; + if (!globalObjEdge.isShortcut + && globalObjEdge.node.isHidden + && globalObjEdge._hasStringName + && (globalObjEdge._nameOrIndex in propNames)) + this._nodes[globalObjEdge._edges._start + globalObjEdge.edgeIndex + this._edgeTypeOffset] = this._edgeInvisibleType; + } + } } }; -WebInspector.HeapSnapshotFilteredOrderedIterator = function(snapshot, iterator, filter) +WebInspector.HeapSnapshotFilteredOrderedIterator = function(iterator, filter) { - this._snapshot = snapshot; this._filter = filter; this._iterator = iterator; this._iterationOrder = null; this._position = 0; this._lastComparator = null; + this._instancesCount = 0; } WebInspector.HeapSnapshotFilteredOrderedIterator.prototype = { @@ -588,6 +625,16 @@ WebInspector.HeapSnapshotFilteredOrderedIterator.prototype = { return this._position < this._iterationOrder.length; }, + incInstancesCount: function() + { + ++this._instancesCount; + }, + + get instancesCount() + { + return this._instancesCount; + }, + get isEmpty() { if (this._iterationOrder) @@ -623,6 +670,11 @@ WebInspector.HeapSnapshotFilteredOrderedIterator.prototype = { next: function() { ++this._position; + }, + + resetInstancesCount: function() + { + this._instancesCount = 0; } } @@ -633,7 +685,8 @@ WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator = fu WebInspector.HeapSnapshotEdgesProvider = function(snapshot, rawEdges, filter) { - WebInspector.HeapSnapshotFilteredOrderedIterator.call(this, snapshot, new WebInspector.HeapSnapshotEdgeIterator(new WebInspector.HeapSnapshotEdge(snapshot, rawEdges)), filter); + this.snapshot = snapshot; + WebInspector.HeapSnapshotFilteredOrderedIterator.call(this, new WebInspector.HeapSnapshotEdgeIterator(new WebInspector.HeapSnapshotEdge(snapshot, rawEdges)), filter); } WebInspector.HeapSnapshotEdgesProvider.prototype = { @@ -649,8 +702,8 @@ WebInspector.HeapSnapshotEdgesProvider.prototype = { var edgeA = this._iterator.item.clone(); var edgeB = edgeA.clone(); - var nodeA = new WebInspector.HeapSnapshotNode(this._snapshot); - var nodeB = new WebInspector.HeapSnapshotNode(this._snapshot); + var nodeA = new WebInspector.HeapSnapshotNode(this.snapshot); + var nodeB = new WebInspector.HeapSnapshotNode(this.snapshot); function sortByEdgeFieldName(ascending, indexA, indexB) { @@ -715,7 +768,8 @@ WebInspector.HeapSnapshotEdgesProvider.prototype.__proto__ = WebInspector.HeapSn WebInspector.HeapSnapshotNodesProvider = function(snapshot, nodes, filter) { - WebInspector.HeapSnapshotFilteredOrderedIterator.call(this, snapshot, nodes, filter); + this.snapshot = snapshot; + WebInspector.HeapSnapshotFilteredOrderedIterator.call(this, nodes, filter); } WebInspector.HeapSnapshotNodesProvider.prototype = { @@ -729,8 +783,8 @@ WebInspector.HeapSnapshotNodesProvider.prototype = { var ascending1 = comparator.ascending1; var ascending2 = comparator.ascending2; - var nodeA = new WebInspector.HeapSnapshotNode(this._snapshot); - var nodeB = new WebInspector.HeapSnapshotNode(this._snapshot); + var nodeA = new WebInspector.HeapSnapshotNode(this.snapshot); + var nodeB = new WebInspector.HeapSnapshotNode(this.snapshot); function sortByNodeField(fieldName, ascending, indexA, indexB) { @@ -832,7 +886,8 @@ WebInspector.HeapSnapshotPathFinder.prototype = { _skipEdge: function(edge) { - return (this._skipHidden && (edge.isHidden || edge.node.isHidden)) + return edge.isInvisible + || (this._skipHidden && (edge.isHidden || edge.node.isHidden)) || this._hasInPath(edge.nodeIndex); }, diff --git a/Source/WebCore/inspector/front-end/HeapSnapshotView.js b/Source/WebCore/inspector/front-end/HeapSnapshotView.js index 44b95c3..87e02f7 100644 --- a/Source/WebCore/inspector/front-end/HeapSnapshotView.js +++ b/Source/WebCore/inspector/front-end/HeapSnapshotView.js @@ -1010,7 +1010,7 @@ WebInspector.HeapSnapshotProfileType.prototype = { buttonClicked: function() { - InspectorBackend.takeHeapSnapshot(false); + ProfilerAgent.takeHeapSnapshot(false); }, get welcomeMessage() diff --git a/Source/WebCore/inspector/front-end/Images/helpButtonGlyph.png b/Source/WebCore/inspector/front-end/Images/helpButtonGlyph.png Binary files differnew file mode 100644 index 0000000..92fe59a --- /dev/null +++ b/Source/WebCore/inspector/front-end/Images/helpButtonGlyph.png diff --git a/Source/WebCore/inspector/front-end/MetricsSidebarPane.js b/Source/WebCore/inspector/front-end/MetricsSidebarPane.js index 3c0f315..14039ef 100644 --- a/Source/WebCore/inspector/front-end/MetricsSidebarPane.js +++ b/Source/WebCore/inspector/front-end/MetricsSidebarPane.js @@ -40,7 +40,7 @@ WebInspector.MetricsSidebarPane.prototype = { else node = this.node; - if (!node || !node.ownerDocument.defaultView || node.nodeType !== Node.ELEMENT_NODE) { + if (!node || node.nodeType !== Node.ELEMENT_NODE) { this.bodyElement.removeChildren(); return; } diff --git a/Source/WebCore/inspector/front-end/NetworkManager.js b/Source/WebCore/inspector/front-end/NetworkManager.js index da043fe..246b53c 100644 --- a/Source/WebCore/inspector/front-end/NetworkManager.js +++ b/Source/WebCore/inspector/front-end/NetworkManager.js @@ -33,7 +33,7 @@ WebInspector.NetworkManager = function(resourceTreeModel) WebInspector.Object.call(this); this._resourceTreeModel = resourceTreeModel; this._dispatcher = new WebInspector.NetworkDispatcher(resourceTreeModel, this); - InspectorBackend.cachedResources(this._processCachedResources.bind(this)); + NetworkAgent.enable(this._processCachedResources.bind(this)); } WebInspector.NetworkManager.EventTypes = { @@ -44,11 +44,11 @@ WebInspector.NetworkManager.EventTypes = { } WebInspector.NetworkManager.prototype = { - reset: function() + frontendReused: function() { WebInspector.panels.network.clear(); this._resourceTreeModel.reset(); - InspectorBackend.cachedResources(this._processCachedResources.bind(this)); + NetworkAgent.enable(this._processCachedResources.bind(this)); }, requestContent: function(resource, base64Encode, callback) @@ -57,7 +57,7 @@ WebInspector.NetworkManager.prototype = { { callback(success ? content : null); } - InspectorBackend.resourceContent(resource.loader.frameId, resource.url, base64Encode, callbackWrapper); + NetworkAgent.resourceContent(resource.loader.frameId, resource.url, base64Encode, callbackWrapper); }, _processCachedResources: function(mainFramePayload) diff --git a/Source/WebCore/inspector/front-end/NetworkPanel.js b/Source/WebCore/inspector/front-end/NetworkPanel.js index 085f468..06983f0 100644 --- a/Source/WebCore/inspector/front-end/NetworkPanel.js +++ b/Source/WebCore/inspector/front-end/NetworkPanel.js @@ -110,7 +110,7 @@ WebInspector.NetworkPanel.prototype = { { WebInspector.Panel.prototype.resize.call(this); this._dataGrid.updateWidths(); - this._positionSummaryBar(); + this._updateOffscreenRows(); }, updateSidebarWidth: function(width) @@ -133,41 +133,6 @@ WebInspector.NetworkPanel.prototype = { } }, - _positionSummaryBar: function() - { - // Position the total bar. - - var fillerRow = this._dataGrid.dataTableBody.lastChild; - if (this._summaryBarElement.parentElement !== this.element && fillerRow.offsetHeight > 0) { - // Glue status to bottom. - if (this._summaryBarRowNode) { - this._dataGrid.removeChild(this._summaryBarRowNode); - delete this._summaryBarRowNode; - } - this._summaryBarElement.addStyleClass("network-summary-bar-bottom"); - this.element.appendChild(this._summaryBarElement); - this._dataGrid.element.style.bottom = "20px"; - return; - } - - if (!this._summaryBarRowNode && !fillerRow.offsetHeight) { - // Glue status to table. - this._summaryBarRowNode = new WebInspector.NetworkTotalGridNode(this._summaryBarElement); - this._summaryBarElement.removeStyleClass("network-summary-bar-bottom"); - this._dataGrid.appendChild(this._summaryBarRowNode); - this._dataGrid.element.style.bottom = 0; - this._sortItems(); - } - this._updateOffscreenRows(); - }, - - _resetSummaryBar: function() - { - delete this._summaryBarRowNode; - this._summaryBarElement.parentElement.removeChild(this._summaryBarElement); - this._updateSummaryBar(); - }, - _createTimelineGrid: function() { this._timelineGrid = new WebInspector.TimelineGrid(); @@ -368,14 +333,17 @@ WebInspector.NetworkPanel.prototype = { _createSummaryBar: function() { - this._summaryBarElement = document.createElement("div"); - this._summaryBarElement.className = "network-summary-bar"; - this.containerElement.appendChild(this._summaryBarElement); + var tbody = this._dataGrid.dataTableBody; + var tfoot = document.createElement("tfoot"); + var tr = tfoot.createChild("tr", "revealed network-summary-bar"); + var td = tr.createChild("td"); + td.setAttribute("colspan", 7); + tbody.parentNode.insertBefore(tfoot, tbody); + this._summaryBarElement = td; }, _updateSummaryBar: function() { - this._positionSummaryBar(); // Grid is growing. var numRequests = this._resources.length; if (!numRequests) { @@ -387,7 +355,6 @@ WebInspector.NetworkPanel.prototype = { img.src = "Images/warningIcon.png"; this._summaryBarElement.removeChildren(); this._summaryBarElement.appendChild(img); - this._summaryBarElement.appendChild(document.createTextNode(" ")); this._summaryBarElement.appendChild(document.createTextNode( WebInspector.UIString("No requests captured. Reload the page to see detailed information on the network activity."))); return; @@ -438,7 +405,6 @@ WebInspector.NetworkPanel.prototype = { selectMultiple = true; this._filter(e.target, selectMultiple); - this._positionSummaryBar(); }, _filter: function(target, selectMultiple) @@ -478,6 +444,7 @@ WebInspector.NetworkPanel.prototype = { target.addStyleClass("selected"); this._showCategory(target.category); + this._updateOffscreenRows(); return; } @@ -655,7 +622,6 @@ WebInspector.NetworkPanel.prototype = { this.visibleView.show(this._viewsContainerElement); this._dataGrid.updateWidths(); - this._positionSummaryBar(); }, hide: function() @@ -727,6 +693,7 @@ WebInspector.NetworkPanel.prototype = { this._staleResources = []; this._sortItems(); this._updateSummaryBar(); + this._updateOffscreenRows(); this._dataGrid.updateWidths(); if (wasScrolledToLastRow) @@ -756,7 +723,6 @@ WebInspector.NetworkPanel.prototype = { this._resourceGridNodes = {}; this._dataGrid.removeChildren(); - delete this._summaryBarRowNode; this._updateDividersIfNeeded(true); // End reset timeline. @@ -765,7 +731,8 @@ WebInspector.NetworkPanel.prototype = { this._viewsContainerElement.removeChildren(); this._viewsContainerElement.appendChild(this._closeButtonElement); - this._resetSummaryBar(); + this._updateSummaryBar(); + WebInspector.extensionServer.resetResources(); }, get resources() @@ -904,7 +871,7 @@ WebInspector.NetworkPanel.prototype = { this._timelineGrid.element.removeStyleClass("small"); this._viewsContainerElement.removeStyleClass("small"); } - this._positionSummaryBar(); + this._updateOffscreenRows(); }, _getPopoverAnchor: function(element) @@ -1006,7 +973,7 @@ WebInspector.NetworkPanel.prototype = { _contextMenu: function(event) { // createBlobURL is enabled conditionally, do not expose resource export if it's not available. - if (typeof window.webkitURL.createObjectURL !== "function" || !Preferences.resourceExportEnabled) + if ((window.webkitURL && typeof window.webkitURL.createObjectURL !== "function") || !Preferences.resourceExportEnabled) return; var contextMenu = new WebInspector.ContextMenu(); @@ -1049,9 +1016,6 @@ WebInspector.NetworkPanel.prototype = { var unfilteredRowIndex = 0; for (var i = 0; i < recordsCount - 1; ++i) { var row = rows[i]; - // Don't touch summaty - quit instead. - if (this._summaryBarRowNode && row === this._summaryBarRowNode.element) - break; var dataGridNode = this._dataGrid.dataGridNodeFromNode(row); if (dataGridNode.isFilteredOut()) { @@ -1395,7 +1359,7 @@ WebInspector.NetworkDataGridNode.prototype = { _openInNewTab: function() { - InspectorBackend.openInInspectedWindow(this._resource.url); + InspectorAgent.openInInspectedWindow(this._resource.url); }, get selectable() @@ -1711,32 +1675,3 @@ WebInspector.NetworkDataGridNode.ResourcePropertyComparator = function(propertyN } WebInspector.NetworkDataGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype; - -WebInspector.NetworkTotalGridNode = function(element) -{ - this._summaryBarElement = element; - WebInspector.DataGridNode.call(this, {summaryRow: true}); -} - -WebInspector.NetworkTotalGridNode.prototype = { - isFilteredOut: function() - { - return false; - }, - - get selectable() - { - return false; - }, - - createCells: function() - { - var td = document.createElement("td"); - td.setAttribute("colspan", 7); - td.className = "network-summary"; - td.appendChild(this._summaryBarElement); - this._element.appendChild(td); - } -} - -WebInspector.NetworkTotalGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype; diff --git a/Source/WebCore/inspector/front-end/Panel.js b/Source/WebCore/inspector/front-end/Panel.js index 4c42a60..1b99dd4 100644 --- a/Source/WebCore/inspector/front-end/Panel.js +++ b/Source/WebCore/inspector/front-end/Panel.js @@ -46,29 +46,7 @@ WebInspector.Panel.prototype = { if (this._toolbarItem) return this._toolbarItem; - // Sample toolbar item as markup: - // <button class="toolbar-item resources toggleable"> - // <div class="toolbar-icon"></div> - // <div class="toolbar-label">Resources</div> - // </button> - - this._toolbarItem = document.createElement("button"); - this._toolbarItem.className = "toolbar-item toggleable"; - this._toolbarItem.panel = this; - - this._toolbarItem.addStyleClass(this._panelName); - - var iconElement = document.createElement("div"); - iconElement.className = "toolbar-icon"; - this._toolbarItem.appendChild(iconElement); - - if ("toolbarItemLabel" in this) { - var labelElement = document.createElement("div"); - labelElement.className = "toolbar-label"; - labelElement.textContent = this.toolbarItemLabel; - this._toolbarItem.appendChild(labelElement); - } - + this._toolbarItem = WebInspector.Toolbar.createPanelToolbarItem(this); return this._toolbarItem; }, @@ -110,6 +88,12 @@ WebInspector.Panel.prototype = { this._toolbarItem.removeStyleClass("toggled-on"); }, + reset: function() + { + this.searchCanceled(); + WebInspector.resetFocusElement(); + }, + get defaultFocusedElement() { return this.sidebarTreeElement || this.element; @@ -132,7 +116,7 @@ WebInspector.Panel.prototype = { } } - WebInspector.updateSearchMatchesCount(0, this); + WebInspector.searchController.updateSearchMatchesCount(0, this); if (this._currentSearchChunkIntervalIdentifier) { clearInterval(this._currentSearchChunkIntervalIdentifier); @@ -161,7 +145,7 @@ WebInspector.Panel.prototype = { function updateMatchesCount() { - WebInspector.updateSearchMatchesCount(this._totalSearchMatches, this); + WebInspector.searchController.updateSearchMatchesCount(this._totalSearchMatches, this); matchesCountUpdateTimeout = null; } diff --git a/Source/WebCore/inspector/front-end/PleaseWaitMessage.js b/Source/WebCore/inspector/front-end/PleaseWaitMessage.js index 54d805d..e1980a0 100644 --- a/Source/WebCore/inspector/front-end/PleaseWaitMessage.js +++ b/Source/WebCore/inspector/front-end/PleaseWaitMessage.js @@ -59,7 +59,7 @@ WebInspector.PleaseWaitMessage.prototype = { get instance() { - if (!"_instance" in WebInspector.PleaseWaitMessage.prototype) + if (!("_instance" in WebInspector.PleaseWaitMessage.prototype)) WebInspector.PleaseWaitMessage.prototype._instance = new WebInspector.PleaseWaitMessage(); return WebInspector.PleaseWaitMessage.prototype._instance; }, diff --git a/Source/WebCore/inspector/front-end/Popover.js b/Source/WebCore/inspector/front-end/Popover.js index 32535e9..f20b8c6 100644 --- a/Source/WebCore/inspector/front-end/Popover.js +++ b/Source/WebCore/inspector/front-end/Popover.js @@ -40,6 +40,7 @@ WebInspector.Popover = function(contentElement) this.contentElement = contentElement; this._contentDiv = document.createElement("div"); this._contentDiv.className = "content"; + this._visible = false; } WebInspector.Popover.prototype = { @@ -60,6 +61,7 @@ WebInspector.Popover.prototype = { this.element.appendChild(this._contentDiv); document.body.appendChild(this.element); this._positionElement(anchor, preferredWidth, preferredHeight); + this._visible = true; }, hide: function() @@ -68,6 +70,12 @@ WebInspector.Popover.prototype = { delete WebInspector.Popover._popoverElement; document.body.removeChild(this.element); } + this._visible = false; + }, + + get visible() + { + return this._visible; }, _positionElement: function(anchorElement, preferredWidth, preferredHeight) diff --git a/Source/WebCore/inspector/front-end/ProfileView.js b/Source/WebCore/inspector/front-end/ProfileView.js index c325bf7..335bf03 100644 --- a/Source/WebCore/inspector/front-end/ProfileView.js +++ b/Source/WebCore/inspector/front-end/ProfileView.js @@ -94,7 +94,7 @@ WebInspector.CPUProfileView = function(profile) self._updatePercentButton(); } - InspectorBackend.getProfile(this.profile.typeId, this.profile.uid, profileCallback); + ProfilerAgent.getProfile(this.profile.typeId, this.profile.uid, profileCallback); } WebInspector.CPUProfileView.prototype = { @@ -593,9 +593,9 @@ WebInspector.CPUProfileType.prototype = { this._recording = !this._recording; if (this._recording) - InspectorBackend.startProfiling(); + InspectorAgent.startProfiling(); else - InspectorBackend.stopProfiling(); + InspectorAgent.stopProfiling(); }, get welcomeMessage() diff --git a/Source/WebCore/inspector/front-end/ProfilesPanel.js b/Source/WebCore/inspector/front-end/ProfilesPanel.js index b87ea7f..e5fb49e 100644 --- a/Source/WebCore/inspector/front-end/ProfilesPanel.js +++ b/Source/WebCore/inspector/front-end/ProfilesPanel.js @@ -185,8 +185,19 @@ WebInspector.ProfilesPanel.prototype = { _reset: function() { - for (var i = 0; i < this._profiles.length; ++i) + WebInspector.Panel.prototype.reset.call(this); + + for (var i = 0; i < this._profiles.length; ++i) { + var view = this._profiles[i]._profileView; + if (view && ("dispose" in view)) + view.dispose(); delete this._profiles[i]._profileView; + var profile = this._profiles[i]; + if (profile.nodes) { + delete profile.nodes; + delete profile.strings; + } + } delete this.visibleView; delete this.currentQuery; @@ -215,7 +226,7 @@ WebInspector.ProfilesPanel.prototype = { _clearProfiles: function() { - InspectorBackend.clearProfiles(); + ProfilerAgent.clearProfiles(); this._reset(); }, @@ -351,7 +362,7 @@ WebInspector.ProfilesPanel.prototype = { sidebarParent.removeChild(profile._profilesTreeElement); if (!profile.isTemporary) - InspectorBackend.removeProfile(profile.typeId, profile.uid); + ProfilerAgent.removeProfile(profile.typeId, profile.uid); // No other item will be selected if there aren't any other profiles, so // make sure that view gets cleared when the last profile is removed. @@ -409,6 +420,11 @@ WebInspector.ProfilesPanel.prototype = { return !!this._profilesIdMap[this._makeKey(profile.uid, profile.typeId)]; }, + getProfile: function(typeId, uid) + { + return this._profilesIdMap[this._makeKey(uid, typeId)]; + }, + loadHeapSnapshot: function(uid, callback) { var profile = this._profilesIdMap[this._makeKey(uid, WebInspector.HeapSnapshotProfileType.TypeId)]; @@ -424,7 +440,7 @@ WebInspector.ProfilesPanel.prototype = { profile._callbacks = [callback]; profile._json = ""; profile.sideBarElement.subtitle = WebInspector.UIString("Loading…"); - InspectorBackend.getProfile(profile.typeId, profile.uid); + ProfilerAgent.getProfile(profile.typeId, profile.uid); } }, @@ -455,6 +471,12 @@ WebInspector.ProfilesPanel.prototype = { delete profile._is_loading; profile._loaded = true; profile.sideBarElement.subtitle = ""; + + if (!Preferences.detailedHeapProfiles && WebInspector.DetailedHeapshotView.prototype.isDetailedSnapshot(loadedSnapshot)) { + WebInspector.panels.profiles._enableDetailedHeapProfiles(false); + return; + } + if (!Preferences.detailedHeapProfiles) WebInspector.HeapSnapshotView.prototype.processLoadedSnapshot(profile, loadedSnapshot); else @@ -592,10 +614,10 @@ WebInspector.ProfilesPanel.prototype = { { if (this._profilerEnabled) { WebInspector.settings.profilerEnabled = false; - InspectorBackend.disableProfiler(true); + InspectorAgent.disableProfiler(true); } else { WebInspector.settings.profilerEnabled = !!optionalAlways; - InspectorBackend.enableProfiler(); + InspectorAgent.enableProfiler(); } }, @@ -612,7 +634,7 @@ WebInspector.ProfilesPanel.prototype = { this._addProfileHeader(profileHeaders[i]); } - InspectorBackend.getProfileHeaders(populateCallback.bind(this)); + ProfilerAgent.getProfileHeaders(populateCallback.bind(this)); this._profilesWereRequested = true; }, @@ -658,7 +680,7 @@ WebInspector.ProfilesPanel.prototype = { } this._addProfileHeader(this._temporaryTakingSnapshot); } - InspectorBackend.takeHeapSnapshot(detailed); + ProfilerAgent.takeHeapSnapshot(detailed); }, _reportHeapSnapshotProgress: function(done, total) @@ -668,6 +690,63 @@ WebInspector.ProfilesPanel.prototype = { if (done >= total) this._removeProfileHeader(this._temporaryTakingSnapshot); } + }, + + handleShortcut: function(event) + { + if (!Preferences.heapProfilerPresent || Preferences.detailedHeapProfiles) + return; + var combo = ["U+004C", "U+0045", "U+0041", "U+004B", "U+005A"]; // "LEAKZ" + if (this._recognizeKeyboardCombo(combo, event)) { + this._displayDetailedHeapProfilesEnabledHint(); + this._enableDetailedHeapProfiles(true); + } + }, + + _recognizeKeyboardCombo: function(combo, event) + { + var isRecognized = false; + if (!this._comboPosition) { + if (event.keyIdentifier === combo[0]) + this._comboPosition = 1; + } else if (event.keyIdentifier === combo[this._comboPosition]) { + if (++this._comboPosition === combo.length) + isRecognized = true; + } else + delete this._comboPosition; + if (this._comboPosition) + event.handled = true; + return isRecognized; + }, + + _displayDetailedHeapProfilesEnabledHint: function() + { + var message = new WebInspector.HelpScreen("Congratulations!"); + message.contentElement.addStyleClass("help-table"); + message.contentElement.textContent = "Detailed Heap snapshots are now enabled."; + message.show(); + + function hideHint() + { + message._hide(); + } + + setTimeout(hideHint, 2000); + }, + + _enableDetailedHeapProfiles: function(resetAgent) + { + if (resetAgent) + this._clearProfiles(); + else + this._reset(); + var oldProfileType = this._profileTypesByIdMap[WebInspector.HeapSnapshotProfileType.TypeId]; + var profileType = new WebInspector.DetailedHeapshotProfileType(); + profileType.treeElement = oldProfileType.treeElement; + this._profileTypesByIdMap[profileType.id] = profileType; + Preferences.detailedHeapProfiles = true; + this.hide(); + this.show(); } } diff --git a/Source/WebCore/inspector/front-end/PropertiesSidebarPane.js b/Source/WebCore/inspector/front-end/PropertiesSidebarPane.js index a1e37bc..0c314bc 100644 --- a/Source/WebCore/inspector/front-end/PropertiesSidebarPane.js +++ b/Source/WebCore/inspector/front-end/PropertiesSidebarPane.js @@ -42,15 +42,40 @@ WebInspector.PropertiesSidebarPane.prototype = { return; } - function callback(prototypes) + RuntimeAgent.releaseObjectGroup(0, "dom-selection"); + WebInspector.RemoteObject.resolveNode(node, nodeResolved.bind(this)); + + function nodeResolved(objectPayload) { + if (!objectPayload) + return; + var object = WebInspector.RemoteObject.fromPayload(objectPayload); + object.evaluate("var proto = this; result = {}; var counter = 1; while (proto) { result[counter++] = proto; proto = proto.__proto__ }; return result;", nodePrototypesReady.bind(this)); + } + + function nodePrototypesReady(objectPayload) + { + if (!objectPayload) + return; + var object = WebInspector.RemoteObject.fromPayload(objectPayload); + object.getOwnProperties(false, fillSection.bind(this)); + } + + function fillSection(prototypes) + { + if (!prototypes) + return; + var body = this.bodyElement; body.removeChildren(); this.sections = []; // Get array of prototype user-friendly names. for (var i = 0; i < prototypes.length; ++i) { - var prototype = WebInspector.RemoteObject.fromPayload(prototypes[i]); + if (!parseInt(prototypes[i].name)) + continue; + + var prototype = prototypes[i].value; var title = prototype.description; if (title.match(/Prototype$/)) title = title.replace(/Prototype$/, ""); @@ -59,7 +84,6 @@ WebInspector.PropertiesSidebarPane.prototype = { body.appendChild(section.element); } } - InspectorBackend.getNodePrototypes(node.id, callback.bind(this)); } } diff --git a/Source/WebCore/inspector/front-end/RemoteObject.js b/Source/WebCore/inspector/front-end/RemoteObject.js index 10af2e3..4a20cf1 100644 --- a/Source/WebCore/inspector/front-end/RemoteObject.js +++ b/Source/WebCore/inspector/front-end/RemoteObject.js @@ -52,7 +52,7 @@ WebInspector.RemoteObject.resolveNode = function(node, callback) { callback(object ? WebInspector.RemoteObject.fromPayload(object) : null); } - InspectorBackend.resolveNode(node.id, mycallback); + DOMAgent.resolveNode(node.id, "dom-selection", mycallback); } WebInspector.RemoteObject.fromPayload = function(payload) @@ -118,7 +118,7 @@ WebInspector.RemoteObject.prototype = { properties[i].value = WebInspector.RemoteObject.fromPayload(properties[i].value); callback(properties); } - InspectorBackend.getProperties(this._objectId, !!ignoreHasOwnProperty, abbreviate, remoteObjectBinder); + RuntimeAgent.getProperties(this._objectId, !!ignoreHasOwnProperty, abbreviate, remoteObjectBinder); }, setPropertyValue: function(name, value, callback) @@ -127,12 +127,20 @@ WebInspector.RemoteObject.prototype = { callback(false); return; } - InspectorBackend.setPropertyValue(this._objectId, name, value, callback); + RuntimeAgent.setPropertyValue(this._objectId, name, value, callback); }, pushNodeToFrontend: function(callback) { - InspectorBackend.pushNodeToFrontend(this._objectId, callback); + if (this._objectId) + WebInspector.domAgent.pushNodeToFrontend(this._objectId, callback); + else + callback(0); + }, + + evaluate: function(expression, callback) + { + RuntimeAgent.evaluateOn(this._objectId, expression, callback); } } diff --git a/Source/WebCore/inspector/front-end/ResourceHeadersView.js b/Source/WebCore/inspector/front-end/ResourceHeadersView.js index ee1010f..e79078a 100644 --- a/Source/WebCore/inspector/front-end/ResourceHeadersView.js +++ b/Source/WebCore/inspector/front-end/ResourceHeadersView.js @@ -224,7 +224,7 @@ WebInspector.ResourceHeadersView.prototype = { if (this._resource.statusCode) { var statusImageSource = ""; - if (this._resource.statusCode < 300) + if (this._resource.statusCode < 300 || this._resource.statusCode === 304) statusImageSource = "Images/successGreenDot.png"; else if (this._resource.statusCode < 400) statusImageSource = "Images/warningOrangeDot.png"; diff --git a/Source/WebCore/inspector/front-end/ResourceView.js b/Source/WebCore/inspector/front-end/ResourceView.js index e38cd0a..83cf99d5 100644 --- a/Source/WebCore/inspector/front-end/ResourceView.js +++ b/Source/WebCore/inspector/front-end/ResourceView.js @@ -50,9 +50,8 @@ WebInspector.ResourceView.createResourceView = function(resource) case WebInspector.resourceCategories.stylesheets: case WebInspector.resourceCategories.scripts: case WebInspector.resourceCategories.xhr: - var contentProvider = new WebInspector.SourceFrameContentProviderForResource(resource); - var isScript = resource.type === WebInspector.Resource.Type.Script; - var view = new WebInspector.SourceFrame(contentProvider, resource.url, isScript); + var delegate = new WebInspector.SourceFrameDelegateForResourcesPanel(resource); + var view = new WebInspector.SourceFrame(delegate, resource.url); view.resource = resource; return view; case WebInspector.resourceCategories.images: @@ -120,35 +119,31 @@ WebInspector.ResourceView.existingResourceViewForResource = function(resource) } -WebInspector.SourceFrameContentProviderForResource = function(resource) +WebInspector.SourceFrameDelegateForResourcesPanel = function(resource) { - WebInspector.SourceFrameContentProvider.call(this); + WebInspector.SourceFrameDelegate.call(this); this._resource = resource; } //This is a map from resource.type to mime types //found in WebInspector.SourceTokenizer.Registry. -WebInspector.SourceFrameContentProviderForResource.DefaultMIMETypeForResourceType = { +WebInspector.SourceFrameDelegateForResourcesPanel.DefaultMIMETypeForResourceType = { 0: "text/html", 1: "text/css", 4: "text/javascript" } -WebInspector.SourceFrameContentProviderForResource.prototype = { +WebInspector.SourceFrameDelegateForResourcesPanel.prototype = { requestContent: function(callback) { - function contentLoaded(content) + function contentLoaded(text) { - var mimeType = WebInspector.SourceFrameContentProviderForResource.DefaultMIMETypeForResourceType[this._resource.type] || this._resource.mimeType; - callback(mimeType, content); + var mimeType = WebInspector.SourceFrameDelegateForResourcesPanel.DefaultMIMETypeForResourceType[this._resource.type] || this._resource.mimeType; + var sourceMapping = new WebInspector.IdenticalSourceMapping(); + callback(mimeType, new WebInspector.SourceFrameContent(text, sourceMapping, [])); } this._resource.requestContent(contentLoaded.bind(this)); - }, - - scripts: function() - { - return WebInspector.debuggerModel.scriptsForURL(this._resource.url); } } -WebInspector.SourceFrameContentProviderForResource.prototype.__proto__ = WebInspector.SourceFrameContentProvider.prototype; +WebInspector.SourceFrameDelegateForResourcesPanel.prototype.__proto__ = WebInspector.SourceFrameDelegate.prototype; diff --git a/Source/WebCore/inspector/front-end/ResourcesPanel.js b/Source/WebCore/inspector/front-end/ResourcesPanel.js index 7c0649f..3c85892 100644 --- a/Source/WebCore/inspector/front-end/ResourcesPanel.js +++ b/Source/WebCore/inspector/front-end/ResourcesPanel.js @@ -904,7 +904,7 @@ WebInspector.FrameTreeElement.prototype = { this._storagePanel.showCategoryView(this._displayName); this.listItemElement.removeStyleClass("hovered"); - InspectorBackend.hideFrameHighlight(); + InspectorAgent.hideFrameHighlight(); }, get displayName() @@ -937,10 +937,10 @@ WebInspector.FrameTreeElement.prototype = { { if (hovered) { this.listItemElement.addStyleClass("hovered"); - InspectorBackend.highlightFrame(this._frameId); + InspectorAgent.highlightFrame(this._frameId); } else { this.listItemElement.removeStyleClass("hovered"); - InspectorBackend.hideFrameHighlight(); + InspectorAgent.hideFrameHighlight(); } } } @@ -969,7 +969,7 @@ WebInspector.FrameResourceTreeElement.prototype = { ondblclick: function(event) { - InspectorBackend.openInInspectedWindow(this._resource.url); + InspectorAgent.openInInspectedWindow(this._resource.url); }, onattach: function() diff --git a/Source/WebCore/inspector/front-end/Script.js b/Source/WebCore/inspector/front-end/Script.js index 8d3eabf..3f27485 100644 --- a/Source/WebCore/inspector/front-end/Script.js +++ b/Source/WebCore/inspector/front-end/Script.js @@ -120,6 +120,6 @@ WebInspector.Script.prototype = { this._source = source; callback(this._source); } - InspectorBackend.getScriptSource(this.sourceID, didGetScriptSource.bind(this)); + DebuggerAgent.getScriptSource(this.sourceID, didGetScriptSource.bind(this)); } } diff --git a/Source/WebCore/inspector/front-end/ScriptFormatter.js b/Source/WebCore/inspector/front-end/ScriptFormatter.js index 5c00e51..f70d6c6 100644 --- a/Source/WebCore/inspector/front-end/ScriptFormatter.js +++ b/Source/WebCore/inspector/front-end/ScriptFormatter.js @@ -36,6 +36,38 @@ WebInspector.ScriptFormatter = function() this._tasks = []; } +WebInspector.ScriptFormatter.locationToPosition = function(lineEndings, lineNumber, columnNumber) +{ + var position = lineNumber ? lineEndings[lineNumber - 1] + 1 : 0; + return position + columnNumber; +} + +WebInspector.ScriptFormatter.positionToLocation = function(lineEndings, position) +{ + var location = {}; + location.lineNumber = lineEndings.upperBound(position - 1); + if (!location.lineNumber) + location.columnNumber = position; + else + location.columnNumber = position - lineEndings[location.lineNumber - 1] - 1; + return location; +} + +WebInspector.ScriptFormatter.findScriptRanges = function(lineEndings, scripts) +{ + var scriptRanges = []; + for (var i = 0; i < scripts.length; ++i) { + var start = { lineNumber: scripts[i].lineOffset, columnNumber: scripts[i].columnOffset }; + start.position = WebInspector.ScriptFormatter.locationToPosition(lineEndings, start.lineNumber, start.columnNumber); + var endPosition = start.position + scripts[i].length; + var end = WebInspector.ScriptFormatter.positionToLocation(lineEndings, endPosition); + end.position = endPosition; + scriptRanges.push({ start: start, end: end, sourceID: scripts[i].sourceID }); + } + scriptRanges.sort(function(x, y) { return x.start.position - y.start.position; }); + return scriptRanges; +} + WebInspector.ScriptFormatter.prototype = { formatContent: function(content, callback) { @@ -44,7 +76,18 @@ WebInspector.ScriptFormatter.prototype = { function didFormatChunks() { var result = this._buildContentFromChunks(chunks); - callback(new WebInspector.FormattedSourceFrameContent(content, result.text, result.mapping)); + + var sourceMapping = new WebInspector.SourceMappingForFormattedScript(content.text.lineEndings(), result.text.lineEndings(), result.mapping); + var formattedScriptRanges = []; + for (var i = 0; i < content.scriptRanges.length; ++i) { + var scriptRange = content.scriptRanges[i]; + formattedScriptRange = {}; + formattedScriptRange.start = sourceMapping.originalPositionToFormattedLocation(scriptRange.start.position); + formattedScriptRange.end = sourceMapping.originalPositionToFormattedLocation(scriptRange.end.position); + formattedScriptRange.sourceID = scriptRange.sourceID; + formattedScriptRanges.push(formattedScriptRange); + } + callback(new WebInspector.SourceFrameContent(result.text, sourceMapping, formattedScriptRanges)); } this._formatChunks(chunks, 0, didFormatChunks.bind(this)); }, @@ -63,11 +106,12 @@ WebInspector.ScriptFormatter.prototype = { } var currentPosition = 0; for (var i = 0; i < scriptRanges.length; ++i) { - var scriptRange = scriptRanges[i]; - if (currentPosition < scriptRange.start) - addChunk(currentPosition, scriptRange.start, false); - addChunk(scriptRange.start, scriptRange.end, true); - currentPosition = scriptRange.end; + var start = scriptRanges[i].start.position; + var end = scriptRanges[i].end.position; + if (currentPosition < start) + addChunk(currentPosition, start, false); + addChunk(start, end, true); + currentPosition = end; } if (currentPosition < text.length) addChunk(currentPosition, text.length, false); @@ -142,3 +186,48 @@ WebInspector.ScriptFormatter.prototype = { task.callback(task.source, { original: [], formatted: [] }); } } + + +WebInspector.SourceMappingForFormattedScript = function(originalLineEndings, formattedLineEndings, mapping) +{ + WebInspector.SourceMapping.call(this); + this._originalLineEndings = originalLineEndings; + this._formattedLineEndings = formattedLineEndings; + this._mapping = mapping; +} + +WebInspector.SourceMappingForFormattedScript.prototype = { + actualLocationToSourceLocation: function(lineNumber, columnNumber) + { + var position = WebInspector.ScriptFormatter.locationToPosition(this._originalLineEndings, lineNumber, columnNumber); + return this.originalPositionToFormattedLocation(position); + }, + + sourceLocationToActualLocation: function(lineNumber, columnNumber) + { + var formattedPosition = WebInspector.ScriptFormatter.locationToPosition(this._formattedLineEndings, lineNumber, columnNumber); + var position = this._convertPosition(this._mapping.formatted, this._mapping.original, formattedPosition); + return WebInspector.ScriptFormatter.positionToLocation(this._originalLineEndings, position); + }, + + originalPositionToFormattedLocation: function(position) + { + var formattedPosition = this._convertPosition(this._mapping.original, this._mapping.formatted, position); + var location = WebInspector.ScriptFormatter.positionToLocation(this._formattedLineEndings, formattedPosition); + location.position = formattedPosition; + return location; + }, + + _convertPosition: function(positions1, positions2, position) + { + var index = positions1.upperBound(position); + var range1 = positions1[index] - positions1[index - 1]; + var range2 = positions2[index] - positions2[index - 1]; + var position2 = positions2[index - 1]; + if (range1) + position2 += Math.round((position - positions1[index - 1]) * range2 / range1); + return position2; + } +} + +WebInspector.SourceMappingForFormattedScript.prototype.__proto__ = WebInspector.SourceMapping.prototype; diff --git a/Source/WebCore/inspector/front-end/ScriptsPanel.js b/Source/WebCore/inspector/front-end/ScriptsPanel.js index 264291f..2647cee 100644 --- a/Source/WebCore/inspector/front-end/ScriptsPanel.js +++ b/Source/WebCore/inspector/front-end/ScriptsPanel.js @@ -27,6 +27,8 @@ WebInspector.ScriptsPanel = function() { WebInspector.Panel.call(this, "scripts"); + this._presentationModel = new WebInspector.DebuggerPresentationModel(); + this.topStatusBar = document.createElement("div"); this.topStatusBar.className = "status-bar"; this.topStatusBar.id = "scripts-status-bar"; @@ -50,11 +52,11 @@ WebInspector.ScriptsPanel = function() this.forwardButton.addEventListener("click", this._goForward.bind(this), false); this.topStatusBar.appendChild(this.forwardButton); - this.filesSelectElement = document.createElement("select"); - this.filesSelectElement.className = "status-bar-item"; - this.filesSelectElement.id = "scripts-files"; - this.filesSelectElement.addEventListener("change", this._changeVisibleFile.bind(this), false); - this.topStatusBar.appendChild(this.filesSelectElement); + this._filesSelectElement = document.createElement("select"); + this._filesSelectElement.className = "status-bar-item"; + this._filesSelectElement.id = "scripts-files"; + this._filesSelectElement.addEventListener("change", this._filesSelectChanged.bind(this), false); + this.topStatusBar.appendChild(this._filesSelectElement); this.functionsSelectElement = document.createElement("select"); this.functionsSelectElement.className = "status-bar-item"; @@ -138,7 +140,7 @@ WebInspector.ScriptsPanel = function() this.sidebarPanes = {}; this.sidebarPanes.watchExpressions = new WebInspector.WatchExpressionsSidebarPane(); - this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane(); + this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane(this._presentationModel); this.sidebarPanes.scopechain = new WebInspector.ScopeChainSidebarPane(); this.sidebarPanes.jsBreakpoints = new WebInspector.JavaScriptBreakpointsSidebarPane(); if (Preferences.nativeInstrumentationEnabled) { @@ -153,7 +155,6 @@ WebInspector.ScriptsPanel = function() this.sidebarElement.appendChild(this.sidebarPanes[pane].element); this.sidebarPanes.callstack.expanded = true; - this.sidebarPanes.callstack.addEventListener("call frame selected", this._callFrameSelected, this); this.sidebarPanes.scopechain.expanded = true; this.sidebarPanes.jsBreakpoints.expanded = true; @@ -189,6 +190,9 @@ WebInspector.ScriptsPanel = function() WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ScriptSourceChanged, this._scriptSourceChanged, this); WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this); WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this); + this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.BreakpointAdded, this._breakpointAdded, this); + this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.BreakpointRemoved, this._breakpointRemoved, this); + this._presentationModel.addEventListener(WebInspector.DebuggerPresentationModel.Events.CallFrameSelected, this._callFrameSelected, this); } // Keep these in sync with WebCore::ScriptDebugServer @@ -211,7 +215,7 @@ WebInspector.ScriptsPanel.prototype = { get defaultFocusedElement() { - return this.filesSelectElement; + return this._filesSelectElement; }, get paused() @@ -255,23 +259,14 @@ WebInspector.ScriptsPanel.prototype = { var sourceID = event.data.sourceID; var oldSource = event.data.oldSource; - var oldView, newView; var script = WebInspector.debuggerModel.scriptForSourceID(sourceID); if (script.resource) { - oldView = this._urlToSourceFrame[script.resource.url]; - delete this._urlToSourceFrame[script.resource.url]; - newView = this._sourceFrameForResource(script.resource); var revertHandle = WebInspector.debuggerModel.editScriptSource.bind(WebInspector.debuggerModel, sourceID, oldSource); script.resource.setContent(script.source, revertHandle); - } else { - var oldView = script._sourceFrame; - delete script._sourceFrame; - newView = this._sourceFrameForScript(script); } - newView.scrollTop = oldView.scrollTop; - if (this.visibleView === oldView) - this.visibleView = newView; + var sourceFileId = this._sourceFileIdForScript(script); + this._recreateSourceFrame(sourceFileId); var callFrames = WebInspector.debuggerModel.callFrames; if (callFrames.length) @@ -280,11 +275,20 @@ WebInspector.ScriptsPanel.prototype = { _addScript: function(script) { - var resource = WebInspector.networkManager.inflightResourceForURL(script.sourceURL) || WebInspector.resourceForURL(script.sourceURL); + if (!script.sourceURL) { + // Anonymous scripts are shown only when stepping. + return; + } + + var resource = this._resourceForURL(script.sourceURL); if (resource) { if (resource.finished) { // Resource is finished, bind the script right away. script.resource = resource; + + // Add resource url to files select if not already added while debugging inlined scripts. + if (!(resource.url in this._sourceFileIdToFilesSelectOption)) + this._addOptionToFilesSelectAndShowSourceFrameIfNeeded(resource.url); } else { // Resource is not finished, bind the script later. if (!resource._scriptsPendingResourceLoad) { @@ -292,40 +296,84 @@ WebInspector.ScriptsPanel.prototype = { resource.addEventListener("finished", this._resourceLoadingFinished, this); } resource._scriptsPendingResourceLoad.push(script); + + // Source frame content is outdated since we have new script parsed. + this._recreateSourceFrame(script.sourceURL); } + } else if (!(script.sourceURL in this._sourceFileIdToFilesSelectOption)) { + // This is a dynamic script with "//@ sourceURL=" comment. + this._addOptionToFilesSelectAndShowSourceFrameIfNeeded(script.sourceURL); } - this._addScriptToFilesMenu(script); + }, + + _resourceForURL: function(url) + { + return WebInspector.networkManager.inflightResourceForURL(url) || WebInspector.resourceForURL(url); }, _resourceLoadingFinished: function(e) { var resource = e.target; - var visible = false; - var select = this.filesSelectElement; + // Bind scripts to resource. for (var i = 0; i < resource._scriptsPendingResourceLoad.length; ++i) { - // Bind script to resource. var script = resource._scriptsPendingResourceLoad[i]; script.resource = resource; + } + delete resource._scriptsPendingResourceLoad; + + // Recreate source frame to show resource content. + this._recreateSourceFrame(resource.url); + + // Add resource url to files select if not already added while debugging inlined scripts. + if (!(resource.url in this._sourceFileIdToFilesSelectOption)) + this._addOptionToFilesSelectAndShowSourceFrameIfNeeded(resource.url); + }, - if (select.options[select.selectedIndex] === script.filesSelectOption) - visible = true; + _addOptionToFilesSelectAndShowSourceFrameIfNeeded: function(url) + { + this._addOptionToFilesSelect(url); - // Remove script from the files list. - script.filesSelectOption.parentElement.removeChild(script.filesSelectOption); + var lastViewedURL = WebInspector.settings.lastViewedScriptFile; + if (this._filesSelectElement.length === 1) { + // Option we just added is the only option in files select. + // We have to show corresponding source frame immediately. + this._showSourceFrameAndAddToHistory(url); + // Restore original value of lastViewedScriptFile because + // source frame was shown as a result of initial load. + WebInspector.settings.lastViewedScriptFile = lastViewedURL; + } else if (url === lastViewedURL) + this._showSourceFrameAndAddToHistory(url); + }, + + _addOptionToFilesSelect: function(sourceFileId) + { + var script = this._scriptForSourceFileId(sourceFileId); + var select = this._filesSelectElement; + var option = document.createElement("option"); + option.text = script.sourceURL ? WebInspector.displayNameForURL(script.sourceURL) : WebInspector.UIString("(program)"); + if (script.worldType === WebInspector.Script.WorldType.EXTENSIONS_WORLD) + option.addStyleClass("extension-script"); + function optionCompare(a, b) + { + if (a.text === b.text) + return 0; + return a.text < b.text ? -1 : 1; } - // Adding first script will add resource. - this._addScriptToFilesMenu(resource._scriptsPendingResourceLoad[0]); - delete resource._scriptsPendingResourceLoad; + var insertionIndex = insertionIndexForObjectInListSortedByFunction(option, select.childNodes, optionCompare); + if (insertionIndex < 0) + select.appendChild(option); + else + select.insertBefore(option, select.childNodes.item(insertionIndex)); - if (visible) - this._showScriptOrResource(resource, { initialLoad: true }); + option._sourceFileId = sourceFileId; + this._sourceFileIdToFilesSelectOption[sourceFileId] = option; }, addConsoleMessage: function(message) { this._messages.push(message); - var sourceFrame = this._urlToSourceFrame[message.url]; + var sourceFrame = this._sourceFileIdToSourceFrame[message.url]; if (sourceFrame) sourceFrame.addMessage(message); }, @@ -333,36 +381,40 @@ WebInspector.ScriptsPanel.prototype = { clearConsoleMessages: function() { this._messages = []; - for (var url in this._urlToSourceFrame) - this._urlToSourceFrame[url].clearMessages(); + for (var url in this._sourceFileIdToSourceFrame) + this._sourceFileIdToSourceFrame[url].clearMessages(); }, - selectedCallFrameId: function() + _breakpointAdded: function(event) { - var selectedCallFrame = this.sidebarPanes.callstack.selectedCallFrame; - if (!selectedCallFrame) - return null; - return selectedCallFrame.id; + var breakpoint = event.data; + + var sourceFrame = this._sourceFileIdToSourceFrame[breakpoint.sourceFileId]; + if (sourceFrame && sourceFrame.loaded) + sourceFrame.addBreakpoint(breakpoint.lineNumber, breakpoint.resolved, breakpoint.condition, breakpoint.enabled); }, - evaluateInSelectedCallFrame: function(code, updateInterface, objectGroup, includeCommandLineAPI, callback) + _breakpointRemoved: function(event) { - var selectedCallFrame = this.sidebarPanes.callstack.selectedCallFrame; + var breakpoint = event.data; + + var sourceFrame = this._sourceFileIdToSourceFrame[breakpoint.sourceFileId]; + if (sourceFrame && sourceFrame.loaded) + sourceFrame.removeBreakpoint(breakpoint.lineNumber); + }, + + evaluateInSelectedCallFrame: function(code, objectGroup, includeCommandLineAPI, callback) + { + var selectedCallFrame = this._presentationModel.selectedCallFrame; if (!this._paused || !selectedCallFrame) return; - if (typeof updateInterface === "undefined") - updateInterface = true; - function updatingCallbackWrapper(result) { - if (result) { + if (result) callback(WebInspector.RemoteObject.fromPayload(result)); - if (updateInterface) - this.sidebarPanes.scopechain.update(selectedCallFrame); - } } - InspectorBackend.evaluateOnCallFrame(selectedCallFrame.id, code, objectGroup, includeCommandLineAPI, updatingCallbackWrapper.bind(this)); + DebuggerAgent.evaluateOnCallFrame(selectedCallFrame.id, code, objectGroup, includeCommandLineAPI, updatingCallbackWrapper.bind(this)); }, _debuggerPaused: function(event) @@ -377,7 +429,7 @@ WebInspector.ScriptsPanel.prototype = { WebInspector.currentPanel = this; - this.sidebarPanes.callstack.update(callFrames, event.data.eventType, event.data.eventData); + this.sidebarPanes.callstack.update(event.data); this.sidebarPanes.callstack.selectedCallFrame = callFrames[0]; window.focus(); @@ -386,6 +438,8 @@ WebInspector.ScriptsPanel.prototype = { _debuggerResumed: function() { + this._presentationModel.selectedCallFrame = null; + this._paused = false; this._waitingToPause = false; this._stepping = false; @@ -425,10 +479,10 @@ WebInspector.ScriptsPanel.prototype = { this._currentBackForwardIndex = -1; this._updateBackAndForwardButtons(); - this._urlToSourceFrame = {}; + this._sourceFileIdToSourceFrame = {}; + this._sourceFileIdToFilesSelectOption = {}; this._messages = []; - this._resourceForURLInFilesSelect = {}; - this.filesSelectElement.removeChildren(); + this._filesSelectElement.removeChildren(); this.functionsSelectElement.removeChildren(); this.viewsContainerElement.removeChildren(); @@ -458,35 +512,15 @@ WebInspector.ScriptsPanel.prototype = { canShowSourceLine: function(url, line) { - if (!this._debuggerEnabled) - return false; - return !!this._scriptOrResourceForURLAndLine(url, line); + return this._debuggerEnabled && (url in this._sourceFileIdToFilesSelectOption); }, showSourceLine: function(url, line) { - var scriptOrResource = this._scriptOrResourceForURLAndLine(url, line); - this._showScriptOrResource(scriptOrResource, {line: line, shouldHighlightLine: true}); - }, - - _scriptOrResourceForURLAndLine: function(url, line) - { - var scripts = WebInspector.debuggerModel.scriptsForURL(url); - for (var i = 0; i < scripts.length; ++i) { - var script = scripts[i]; - if (script.resource) - return script.resource; - if (script.startingLine <= line && script.startingLine + script.linesCount > line) - return script; - } - return null; - }, - - showView: function(view) - { - if (!view) + if (!(url in this._sourceFileIdToFilesSelectOption)) return; - this._showScriptOrResource(view.resource || view.script); + var sourceFrame = this._showSourceFrameAndAddToHistory(url); + sourceFrame.highlightLine(line); }, handleShortcut: function(event) @@ -500,167 +534,114 @@ WebInspector.ScriptsPanel.prototype = { this.sidebarPanes.callstack.handleShortcut(event); }, - _sourceFrameForScriptOrResource: function(scriptOrResource) + _showSourceFrameAndAddToHistory: function(sourceFileId) { - if (scriptOrResource instanceof WebInspector.Resource) - return this._sourceFrameForResource(scriptOrResource); - return this._sourceFrameForScript(scriptOrResource); + var sourceFrame = this._showSourceFrame(sourceFileId); + + var oldIndex = this._currentBackForwardIndex; + if (oldIndex >= 0) + this._backForwardList.splice(oldIndex + 1, this._backForwardList.length - oldIndex); + + // Check for a previous entry of the same object in _backForwardList. + // If one is found, remove it. + var previousEntryIndex = this._backForwardList.indexOf(sourceFileId); + if (previousEntryIndex !== -1) + this._backForwardList.splice(previousEntryIndex, 1); + + this._backForwardList.push(sourceFileId); + this._currentBackForwardIndex = this._backForwardList.length - 1; + + this._updateBackAndForwardButtons(); + + return sourceFrame; }, - _sourceFrameForResource: function(resource) + _showSourceFrame: function(sourceFileId) { - var sourceFrame = this._urlToSourceFrame[resource.url]; - if (sourceFrame) - return sourceFrame; - var contentProvider = new WebInspector.SourceFrameContentProviderForResource(resource); - var isScript = resource.type === WebInspector.Resource.Type.Script; - sourceFrame = new WebInspector.SourceFrame(contentProvider, resource.url, isScript); - for (var i = 0; i < this._messages.length; ++i) { - var message = this._messages[i]; - if (this._messages[i].url === resource.url) - sourceFrame.addMessage(message); - } - this._urlToSourceFrame[resource.url] = sourceFrame; + var index = this._sourceFileIdToFilesSelectOption[sourceFileId].index; + this._filesSelectElement.selectedIndex = index; + + var sourceFrame = this._sourceFrameForSourceFileId(sourceFileId); + this.visibleView = sourceFrame; + + var script = this._scriptForSourceFileId(sourceFileId); + if (script.sourceURL) + WebInspector.settings.lastViewedScriptFile = script.sourceURL; + return sourceFrame; }, - _sourceFrameForScript: function(script) + _sourceFrameForSourceFileId: function(sourceFileId) { - if (script._sourceFrame) - return script._sourceFrame; - var contentProvider = new WebInspector.SourceFrameContentProviderForScript(script); - script._sourceFrame = new WebInspector.SourceFrame(contentProvider, script.sourceURL, true); - return script._sourceFrame; + var sourceFrame = this._sourceFileIdToSourceFrame[sourceFileId]; + return sourceFrame || this._createSourceFrame(sourceFileId); }, - _showScriptOrResource: function(scriptOrResource, options) + _createSourceFrame: function(sourceFileId) { - // options = {line:, shouldHighlightLine:, fromBackForwardAction:, initialLoad:} - options = options || {}; + var script = this._scriptForSourceFileId(sourceFileId); + var delegate = new WebInspector.SourceFrameDelegateForScriptsPanel(script); + var sourceFrame = new WebInspector.SourceFrame(delegate, script.sourceURL); + sourceFrame._sourceFileId = sourceFileId; + sourceFrame.addEventListener(WebInspector.SourceFrame.Events.Loaded, this._sourceFrameLoaded, this); + this._sourceFileIdToSourceFrame[sourceFileId] = sourceFrame; + return sourceFrame; + }, - if (!scriptOrResource) + _recreateSourceFrame: function(sourceFileId) + { + var oldSourceFrame = this._sourceFileIdToSourceFrame[sourceFileId]; + if (!oldSourceFrame) return; - - var view = this._sourceFrameForScriptOrResource(scriptOrResource); - if (!view) + oldSourceFrame.removeEventListener(WebInspector.SourceFrame.Events.Loaded, this._sourceFrameLoaded, this); + delete this._sourceFileIdToSourceFrame[sourceFileId]; + oldSourceFrame.removeEventListener(WebInspector.SourceFrame.Events.Loaded, this._sourceFrameLoaded, this); + if (this.visibleView !== oldSourceFrame) return; - var url = scriptOrResource.url || scriptOrResource.sourceURL; - if (url && !options.initialLoad) - WebInspector.settings.lastViewedScriptFile = url; - - if (!options.fromBackForwardAction) { - var oldIndex = this._currentBackForwardIndex; - if (oldIndex >= 0) - this._backForwardList.splice(oldIndex + 1, this._backForwardList.length - oldIndex); - - // Check for a previous entry of the same object in _backForwardList. - // If one is found, remove it and update _currentBackForwardIndex to match. - var previousEntryIndex = this._backForwardList.indexOf(scriptOrResource); - if (previousEntryIndex !== -1) { - this._backForwardList.splice(previousEntryIndex, 1); - --this._currentBackForwardIndex; - } + var newSourceFrame = this._createSourceFrame(sourceFileId) + newSourceFrame.scrollTop = oldSourceFrame.scrollTop; + this.visibleView = newSourceFrame; + }, - this._backForwardList.push(scriptOrResource); - ++this._currentBackForwardIndex; + _sourceFrameLoaded: function(event) + { + var sourceFrame = event.target; + var sourceFileId = sourceFrame._sourceFileId; - this._updateBackAndForwardButtons(); + for (var i = 0; i < this._messages.length; ++i) { + var message = this._messages[i]; + if (message.url === sourceFileId) + sourceFrame.addMessage(message); } - this.visibleView = view; - - if (options.line) { - if (view.revealLine) - view.revealLine(options.line); - if (view.highlightLine && options.shouldHighlightLine) - view.highlightLine(options.line); + var breakpoints = this._presentationModel.breakpointsForSourceFileId(sourceFileId); + for (var i = 0; i < breakpoints.length; ++i) { + var breakpoint = breakpoints[i]; + sourceFrame.addBreakpoint(breakpoint.lineNumber, breakpoint.resolved, breakpoint.condition, breakpoint.enabled); } - var option; - if (scriptOrResource instanceof WebInspector.Script) { - option = scriptOrResource.filesSelectOption; - - // hasn't been added yet - happens for stepping in evals, - // so use the force option to force the script into the menu. - if (!option) { - this._addScriptToFilesMenu(scriptOrResource, true); - option = scriptOrResource.filesSelectOption; + var selectedCallFrame = this._presentationModel.selectedCallFrame; + if (selectedCallFrame) { + if (selectedCallFrame.sourceLocation.sourceFileId === sourceFileId) { + sourceFrame.setExecutionLine(selectedCallFrame.sourceLocation.lineNumber); + this._executionSourceFrame = sourceFrame; } - - console.assert(option); - } else - option = scriptOrResource.filesSelectOption; - - if (option) - this.filesSelectElement.selectedIndex = option.index; + } }, - _addScriptToFilesMenu: function(script, force) + _sourceFileIdForScript: function(script) { - if (!script.sourceURL && !force) - return; - - if (script.resource) { - if (this._resourceForURLInFilesSelect[script.resource.url]) - return; - this._resourceForURLInFilesSelect[script.resource.url] = script.resource; - } - - var displayName = script.sourceURL ? WebInspector.displayNameForURL(script.sourceURL) : WebInspector.UIString("(program)"); - - var select = this.filesSelectElement; - var option = document.createElement("option"); - option.representedObject = script.resource || script; - option.url = displayName; - option.startingLine = script.startingLine; - option.text = script.resource || script.startingLine === 1 ? displayName : String.sprintf("%s:%d", displayName, script.startingLine); + return script.sourceURL || script.sourceID; + }, - function optionCompare(a, b) + _scriptForSourceFileId: function(sourceFileId) + { + function filter(script) { - if (a.url < b.url) - return -1; - else if (a.url > b.url) - return 1; - - if (typeof a.startingLine !== "number") - return -1; - if (typeof b.startingLine !== "number") - return -1; - return a.startingLine - b.startingLine; - } - - var insertionIndex = insertionIndexForObjectInListSortedByFunction(option, select.childNodes, optionCompare); - if (insertionIndex < 0) - select.appendChild(option); - else - select.insertBefore(option, select.childNodes.item(insertionIndex)); - - if (script.resource) - script.resource.filesSelectOption = option; - else - script.filesSelectOption = option; - - if (select.options[select.selectedIndex] === option) { - // Call _showScriptOrResource if the option we just appended ended up being selected. - // This will happen for the first item added to the menu. - this._showScriptOrResource(option.representedObject, {initialLoad: true}); - } else { - // If not first item, check to see if this was the last viewed - var url = option.representedObject.url || option.representedObject.sourceURL; - var lastURL = WebInspector.settings.lastViewedScriptFile; - if (url && url === lastURL) { - // For resources containing multiple <script> tags, we first report them separately and - // then glue them all together. They all share url and there is no need to show them all one - // by one. - var isResource = !!option.representedObject.url; - if (isResource || !this.visibleView || !this.visibleView.script || this.visibleView.script.sourceURL !== url) - this._showScriptOrResource(option.representedObject, {initialLoad: true}); - } + return (script.sourceURL || script.sourceID) === sourceFileId; } - - if (script.worldType === WebInspector.Script.WorldType.EXTENSIONS_WORLD) - script.filesSelectOption.addStyleClass("extension-script"); + return WebInspector.debuggerModel.queryScripts(filter)[0]; }, _clearCurrentExecutionLine: function() @@ -670,31 +651,36 @@ WebInspector.ScriptsPanel.prototype = { delete this._executionSourceFrame; }, - _callFrameSelected: function() + _callFrameSelected: function(event) { + var callFrame = event.data; + this._clearCurrentExecutionLine(); - var callStackPane = this.sidebarPanes.callstack; - var currentFrame = callStackPane.selectedCallFrame; - if (!currentFrame) + if (!callFrame) return; - this.sidebarPanes.scopechain.update(currentFrame); + this.sidebarPanes.scopechain.update(callFrame); this.sidebarPanes.watchExpressions.refreshExpressions(); - var script = WebInspector.debuggerModel.scriptForSourceID(currentFrame.sourceID); - var scriptOrResource = script.resource || script; - this._showScriptOrResource(scriptOrResource, {line: currentFrame.line}); - - this._executionSourceFrame = this._sourceFrameForScriptOrResource(scriptOrResource); - if (this._executionSourceFrame) - this._executionSourceFrame.setExecutionLine(currentFrame.line); + var sourceFileId = callFrame.sourceLocation.sourceFileId; + if (!(sourceFileId in this._sourceFileIdToFilesSelectOption)) { + // This happens in two cases: + // 1) Current call frame function is defined in anonymous script (anonymous scripts aren't added to files select by default) + // 2) We are debugging synchronously executed inlined script and there is no resource so far + this._addOptionToFilesSelect(sourceFileId); + } + var sourceFrame = this._showSourceFrameAndAddToHistory(sourceFileId); + if (sourceFrame.loaded) { + sourceFrame.setExecutionLine(callFrame.sourceLocation.lineNumber); + this._executionSourceFrame = sourceFrame; + } }, - _changeVisibleFile: function(event) + _filesSelectChanged: function() { - var select = this.filesSelectElement; - this._showScriptOrResource(select.options[select.selectedIndex].representedObject); + var sourceFileId = this._filesSelectElement[this._filesSelectElement.selectedIndex]._sourceFileId; + this._showSourceFrameAndAddToHistory(sourceFileId); }, _startSidebarResizeDrag: function(event) @@ -747,7 +733,7 @@ WebInspector.ScriptsPanel.prototype = { this._pauseOnExceptionButton.state = pauseOnExceptionsState; WebInspector.settings.pauseOnExceptionState = pauseOnExceptionsState; } - InspectorBackend.setPauseOnExceptionsState(pauseOnExceptionsState, callback.bind(this)); + DebuggerAgent.setPauseOnExceptionsState(pauseOnExceptionsState, callback.bind(this)); }, _updateDebuggerButtons: function() @@ -812,7 +798,7 @@ WebInspector.ScriptsPanel.prototype = { return; } - this._showScriptOrResource(this._backForwardList[--this._currentBackForwardIndex], {fromBackForwardAction: true}); + this._showSourceFrame(this._backForwardList[--this._currentBackForwardIndex]); this._updateBackAndForwardButtons(); }, @@ -823,7 +809,7 @@ WebInspector.ScriptsPanel.prototype = { return; } - this._showScriptOrResource(this._backForwardList[++this._currentBackForwardIndex], {fromBackForwardAction: true}); + this._showSourceFrame(this._backForwardList[++this._currentBackForwardIndex]); this._updateBackAndForwardButtons(); }, @@ -865,11 +851,11 @@ WebInspector.ScriptsPanel.prototype = { if (this._paused) { this._paused = false; this._waitingToPause = false; - InspectorBackend.resume(); + DebuggerAgent.resume(); } else { this._stepping = false; this._waitingToPause = true; - InspectorBackend.pause(); + DebuggerAgent.pause(); } this._clearInterface(); @@ -882,7 +868,7 @@ WebInspector.ScriptsPanel.prototype = { this._clearInterface(); - InspectorBackend.stepOver(); + DebuggerAgent.stepOver(); }, _stepIntoClicked: function() @@ -892,7 +878,7 @@ WebInspector.ScriptsPanel.prototype = { this._clearInterface(); - InspectorBackend.stepInto(); + DebuggerAgent.stepInto(); }, _stepOutClicked: function() @@ -902,18 +888,18 @@ WebInspector.ScriptsPanel.prototype = { this._clearInterface(); - InspectorBackend.stepOut(); + DebuggerAgent.stepOut(); }, toggleBreakpointsClicked: function() { this.toggleBreakpointsButton.toggled = !this.toggleBreakpointsButton.toggled; if (this.toggleBreakpointsButton.toggled) { - InspectorBackend.activateBreakpoints(); + DebuggerAgent.activateBreakpoints(); this.toggleBreakpointsButton.title = WebInspector.UIString("Deactivate all breakpoints."); document.getElementById("main-panels").removeStyleClass("breakpoints-deactivated"); } else { - InspectorBackend.deactivateBreakpoints(); + DebuggerAgent.deactivateBreakpoints(); this.toggleBreakpointsButton.title = WebInspector.UIString("Activate all breakpoints."); document.getElementById("main-panels").addStyleClass("breakpoints-deactivated"); } @@ -976,8 +962,6 @@ WebInspector.ScriptsPanel.prototype = { searchCanceled: function() { - WebInspector.updateSearchMatchesCount(0, this); - if (this._searchView) this._searchView.searchCanceled(); @@ -987,6 +971,8 @@ WebInspector.ScriptsPanel.prototype = { performSearch: function(query) { + WebInspector.searchController.updateSearchMatchesCount(0, this); + if (!this.visibleView) return; @@ -1001,7 +987,7 @@ WebInspector.ScriptsPanel.prototype = { if (!searchMatches) return; - WebInspector.updateSearchMatchesCount(searchMatches, this); + WebInspector.searchController.updateSearchMatchesCount(searchMatches, this); view.jumpToFirstSearchResult(); } @@ -1053,39 +1039,205 @@ WebInspector.ScriptsPanel.prototype = { WebInspector.ScriptsPanel.prototype.__proto__ = WebInspector.Panel.prototype; -WebInspector.SourceFrameContentProviderForScript = function(script) +WebInspector.SourceFrameDelegateForScriptsPanel = function(script) { - WebInspector.SourceFrameContentProvider.call(this); + WebInspector.SourceFrameDelegate.call(this); this._script = script; + this._popoverObjectGroup = "popover"; } -WebInspector.SourceFrameContentProviderForScript.prototype = { +WebInspector.SourceFrameDelegateForScriptsPanel.prototype = { requestContent: function(callback) { - if (this._script.source) { - callback("text/javascript", this._script.source); + function didGetTextAndScriptRanges(mimeType, text, scriptRanges) + { + this._content = new WebInspector.SourceFrameContent(text, new WebInspector.IdenticalSourceMapping(), scriptRanges); + callback(mimeType, this._content); + } + + if (this._script.resource) + this._loadResourceContent(this._script.resource, didGetTextAndScriptRanges.bind(this)); + else + this._loadAndConcatenateScriptsContent(didGetTextAndScriptRanges.bind(this)); + }, + + _loadResourceContent: function(resource, callback) + { + function didRequestContent(text) + { + var mimeType = "text/javascript"; + if (resource.type !== WebInspector.Resource.Type.Script) { + mimeType = "text/html"; + // WebKit html lexer normalizes line endings and scripts are passed to VM with "\n" line endings. + // However, resource content has original line endings, so we have to normalize line endings here. + text = text.replace(/\r\n/g, "\n"); + } + var scripts = this._scripts(); + var scriptRanges = WebInspector.ScriptFormatter.findScriptRanges(text.lineEndings(), scripts); + callback(mimeType, text, scriptRanges); + } + resource.requestContent(didRequestContent.bind(this)); + }, + + _loadAndConcatenateScriptsContent: function(callback) + { + var scripts = this._scripts(); + var scriptsLeft = scripts.length; + var sources = []; + function didRequestSource(index, source) + { + sources[index] = source; + if (--scriptsLeft) + return; + var result = this._buildSource(scripts, sources); + callback(result.mimeType, result.source, result.scriptRanges); + } + for (var i = 0; i < scripts.length; ++i) + scripts[i].requestSource(didRequestSource.bind(this, i)); + }, + + _buildSource: function(scripts, sources) + { + var source = ""; + var lineNumber = 0; + var columnNumber = 0; + var scriptRanges = []; + function appendChunk(chunk, script) + { + var start = { lineNumber: lineNumber, columnNumber: columnNumber }; + source += chunk; + var lineEndings = chunk.lineEndings(); + var lineCount = lineEndings.length; + if (lineCount === 1) + columnNumber += chunk.length; + else { + lineNumber += lineCount - 1; + columnNumber = lineEndings[lineCount - 1] - lineEndings[lineCount - 2] - 1; + } + var end = { lineNumber: lineNumber, columnNumber: columnNumber }; + if (script) + scriptRanges.push({ start: start, end: end, sourceID: script.sourceID }); + } + + var mimeType; + if (scripts.length === 1 && !scripts[0].lineOffset && !scripts[0].columnOffset) { + // Single script source. + mimeType = "text/javascript"; + appendChunk(sources[0], scripts[0]); + } else { + // Scripts inlined in html document. + mimeType = "text/html"; + var scriptOpenTag = "<script>"; + var scriptCloseTag = "</script>"; + for (var i = 0; i < scripts.length; ++i) { + // Fill the gap with whitespace characters. + while (lineNumber < scripts[i].lineOffset) + appendChunk("\n"); + while (columnNumber < scripts[i].columnOffset - scriptOpenTag.length) + appendChunk(" "); + + // Add script tag. + appendChunk(scriptOpenTag); + appendChunk(sources[i], scripts[i]); + appendChunk(scriptCloseTag); + } + } + return { mimeType: mimeType, source: source, scriptRanges: scriptRanges }; + }, + + _scripts: function() + { + var scripts = [this._script]; + if (this._script.sourceURL) + scripts = WebInspector.debuggerModel.scriptsForURL(this._script.sourceURL); + scripts.sort(function(x, y) { return x.lineOffset - y.lineOffset || x.columnOffset - y.columnOffset; }); + return scripts; + }, + + debuggingSupported: function() + { + return true; + }, + + setBreakpoint: function(lineNumber, condition, enabled) + { + var location = this._content.sourceFrameLineNumberToActualLocation(lineNumber); + if (this._script.sourceURL) + WebInspector.debuggerModel.setBreakpoint(this._script.sourceURL, location.lineNumber, location.columnNumber, condition, enabled); + else if (location.sourceID) + WebInspector.debuggerModel.setBreakpointBySourceId(location.sourceID, location.lineNumber, location.columnNumber, condition, enabled); + else return; + + if (!WebInspector.panels.scripts.breakpointsActivated) + WebInspector.panels.scripts.toggleBreakpointsClicked(); + }, + + removeBreakpoint: function(breakpointId) + { + WebInspector.debuggerModel.removeBreakpoint(breakpointId); + }, + + updateBreakpoint: function(breakpointId, condition, enabled) + { + WebInspector.debuggerModel.updateBreakpoint(breakpointId, condition, enabled); + }, + + findBreakpoint: function(lineNumber) + { + var url = this._script.sourceURL; + var location = this._content.sourceFrameLineNumberToActualLocation(lineNumber); + function filter(breakpoint) + { + if (breakpoint.url) { + if (breakpoint.url !== url) + return false; + } else { + if (breakpoint.sourceID !== location.sourceID) + return false; + } + var lineNumber = breakpoint.locations.length ? breakpoint.locations[0].lineNumber : breakpoint.lineNumber; + return lineNumber === location.lineNumber; } + return WebInspector.debuggerModel.queryBreakpoints(filter)[0]; + }, + + continueToLine: function(lineNumber) + { + var location = this._content.sourceFrameLineNumberToActualLocation(lineNumber); + if (location.sourceID) + WebInspector.debuggerModel.continueToLocation(location.sourceID, location.lineNumber, location.columnNumber); + }, - function didRequestSource(content) + canEditScriptSource: function() + { + return Preferences.canEditScriptSource && !this._script.lineOffset && !this._script.columnOffset; + }, + + editScriptSource: function(text) + { + WebInspector.debuggerModel.editScriptSource(this._script.sourceID, text); + }, + + debuggerPaused: function() + { + return WebInspector.panels.scripts.paused; + }, + + evaluateInSelectedCallFrame: function(string, callback) + { + function didEvaluateInSelectedCallFrame(result) { - var source; - if (content) { - var prefix = ""; - for (var i = 0; i < this._script.startingLine - 1; ++i) - prefix += "\n"; - source = prefix + content; - } else - source = WebInspector.UIString("<source is not available>"); - callback("text/javascript", source); + if (!result.isError() && this.debuggerPaused()) + callback(result); } - this._script.requestSource(didRequestSource.bind(this)); + WebInspector.panels.scripts.evaluateInSelectedCallFrame(string, this._popoverObjectGroup, false, didEvaluateInSelectedCallFrame.bind(this)); }, - scripts: function() + releaseEvaluationResult: function() { - return [this._script]; + RuntimeAgent.releaseObjectGroup(0, this._popoverObjectGroup); } } -WebInspector.SourceFrameContentProviderForScript.prototype.__proto__ = WebInspector.SourceFrameContentProvider.prototype; +WebInspector.SourceFrameDelegateForScriptsPanel.prototype.__proto__ = WebInspector.SourceFrameDelegate.prototype; diff --git a/Source/WebCore/inspector/front-end/SearchController.js b/Source/WebCore/inspector/front-end/SearchController.js new file mode 100755 index 0000000..735c424 --- /dev/null +++ b/Source/WebCore/inspector/front-end/SearchController.js @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com). + * Copyright (C) 2009 Joseph Pecoraro + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 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.SearchController = function() +{ + this.element = document.getElementById("search"); + this._matchesElement = document.getElementById("search-results-matches"); + this._toolbarLabelElement = document.getElementById("search-toolbar-label"); + + this.element.addEventListener("search", this._onSearch.bind(this), false); // when the search is emptied + this.element.addEventListener("mousedown", this._onSearchFieldManualFocus.bind(this), false); // when the search field is manually selected + this.element.addEventListener("keydown", this._onKeyDown.bind(this), true); +} + +WebInspector.SearchController.prototype = { + updateSearchMatchesCount: function(matches, panel) + { + if (!panel) + panel = WebInspector.currentPanel; + + panel.currentSearchMatches = matches; + + if (panel === WebInspector.currentPanel) + this._updateSearchMatchesCount(WebInspector.currentPanel.currentQuery && matches); + }, + + updateSearchLabel: function() + { + var panelName = WebInspector.currentPanel && WebInspector.currentPanel.toolbarItemLabel; + if (!panelName) + return; + var newLabel = WebInspector.UIString("Search %s", panelName); + if (WebInspector.attached) + this.element.setAttribute("placeholder", newLabel); + else { + this.element.removeAttribute("placeholder"); + this._toolbarLabelElement.textContent = newLabel; + } + }, + + cancelSearch: function() + { + this.element.value = ""; + this._performSearch(""); + }, + + handleShortcut: function(event) + { + var isMac = WebInspector.isMac(); + + switch (event.keyIdentifier) { + case "U+0046": // F key + if (isMac) + var isFindKey = event.metaKey && !event.ctrlKey && !event.altKey && !event.shiftKey; + else + var isFindKey = event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey; + + if (isFindKey) { + this._focusSearchField(); + event.handled = true; + } + break; + + + case "F3": + if (!isMac) { + this._focusSearchField(); + event.handled = true; + } + break; + + case "U+0047": // G key + var currentPanel = WebInspector.currentPanel; + + if (isMac && event.metaKey && !event.ctrlKey && !event.altKey) { + if (event.shiftKey) { + if (currentPanel.jumpToPreviousSearchResult) + currentPanel.jumpToPreviousSearchResult(); + } else if (currentPanel.jumpToNextSearchResult) + currentPanel.jumpToNextSearchResult(); + event.handled = true; + } + break; + } + }, + + activePanelChanged: function() + { + this.updateSearchLabel(); + + if (!this._currentQuery) + return; + + panel = WebInspector.currentPanel; + if (panel.performSearch) { + function performPanelSearch() + { + this._updateSearchMatchesCount(); + + panel.currentQuery = this._currentQuery; + panel.performSearch(this._currentQuery); + } + + // Perform the search on a timeout so the panel switches fast. + setTimeout(performPanelSearch.bind(this), 0); + } else { + // Update to show Not found for panels that can't be searched. + this._updateSearchMatchesCount(); + } + }, + + _updateSearchMatchesCount: function(matches) + { + if (matches == null) { + this._matchesElement.addStyleClass("hidden"); + return; + } + + if (matches) { + if (matches === 1) + var matchesString = WebInspector.UIString("1 match"); + else + var matchesString = WebInspector.UIString("%d matches", matches); + } else + var matchesString = WebInspector.UIString("Not Found"); + + this._matchesElement.removeStyleClass("hidden"); + this._matchesElement.textContent = matchesString; + WebInspector.toolbar.resize(); + }, + + _focusSearchField: function() + { + this.element.focus(); + this.element.select(); + }, + + _onSearchFieldManualFocus: function(event) + { + WebInspector.currentFocusElement = event.target; + }, + + _onKeyDown: function(event) + { + // Escape Key will clear the field and clear the search results + if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code) { + // If focus belongs here and text is empty - nothing to do, return unhandled. + // When search was selected manually and is currently blank, we'd like Esc stay unhandled + // and hit console drawer handler. + if (event.target.value === "" && this.currentFocusElement === this.previousFocusElement) + return; + event.preventDefault(); + event.stopPropagation(); + + this.cancelSearch(event); + WebInspector.currentFocusElement = WebInspector.previousFocusElement; + if (WebInspector.currentFocusElement === event.target) + WebInspector.currentFocusElement.currentFocusElement.select(); + return false; + } + + if (!isEnterKey(event)) + return false; + + // Select all of the text so the user can easily type an entirely new query. + event.target.select(); + + // Only call performSearch if the Enter key was pressed. Otherwise the search + // performance is poor because of searching on every key. The search field has + // the incremental attribute set, so we still get incremental searches. + this._onSearch(event); + + // Call preventDefault since this was the Enter key. This prevents a "search" event + // from firing for key down. This stops performSearch from being called twice in a row. + event.preventDefault(); + }, + + _onSearch: function(event) + { + var forceSearch = event.keyIdentifier === "Enter"; + this._performSearch(event.target.value, forceSearch, event.shiftKey, false); + }, + + _performSearch: function(query, forceSearch, isBackwardSearch, repeatSearch) + { + var isShortSearch = (query.length < 3); + + // Clear a leftover short search flag due to a non-conflicting forced search. + if (isShortSearch && this._shortSearchWasForcedByKeyEvent && this._currentQuery !== query) + delete this._shortSearchWasForcedByKeyEvent; + + // Indicate this was a forced search on a short query. + if (isShortSearch && forceSearch) + this._shortSearchWasForcedByKeyEvent = true; + + if (!query || !query.length || (!forceSearch && isShortSearch)) { + // Prevent clobbering a short search forced by the user. + if (this._shortSearchWasForcedByKeyEvent) { + delete this._shortSearchWasForcedByKeyEvent; + return; + } + + delete this._currentQuery; + + for (var panelName in WebInspector.panels) { + var panel = WebInspector.panels[panelName]; + var hadCurrentQuery = !!panel.currentQuery; + delete panel.currentQuery; + if (hadCurrentQuery && panel.searchCanceled) + panel.searchCanceled(); + } + + this._updateSearchMatchesCount(); + + return; + } + + var currentPanel = WebInspector.currentPanel; + if (!repeatSearch && query === currentPanel.currentQuery && currentPanel.currentQuery === this._currentQuery) { + // When this is the same query and a forced search, jump to the next + // search result for a good user experience. + if (forceSearch) { + if (!isBackwardSearch && currentPanel.jumpToNextSearchResult) + currentPanel.jumpToNextSearchResult(); + else if (isBackwardSearch && currentPanel.jumpToPreviousSearchResult) + currentPanel.jumpToPreviousSearchResult(); + } + return; + } + + this._currentQuery = query; + + this._updateSearchMatchesCount(); + + if (!currentPanel.performSearch) + return; + + currentPanel.currentQuery = query; + currentPanel.performSearch(query); + } +} diff --git a/Source/WebCore/inspector/front-end/SourceFrame.js b/Source/WebCore/inspector/front-end/SourceFrame.js index f2e0be1..3120159 100644 --- a/Source/WebCore/inspector/front-end/SourceFrame.js +++ b/Source/WebCore/inspector/front-end/SourceFrame.js @@ -28,15 +28,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.SourceFrame = function(contentProvider, url, isScript) +WebInspector.SourceFrame = function(delegate, url) { WebInspector.View.call(this); this.element.addStyleClass("script-view"); - this._contentProvider = contentProvider; + this._delegate = delegate; this._url = url; - this._isScript = isScript; this._textModel = new WebInspector.TextEditorModel(); this._textModel.replaceTabsWithSpaces = true; @@ -47,8 +46,10 @@ WebInspector.SourceFrame = function(contentProvider, url, isScript) this._messages = []; this._rowMessages = {}; this._messageBubbles = {}; +} - this._popoverObjectGroup = "popover"; +WebInspector.SourceFrame.Events = { + Loaded: "loaded" } WebInspector.SourceFrame.prototype = { @@ -59,7 +60,7 @@ WebInspector.SourceFrame.prototype = { if (!this._contentRequested) { this._contentRequested = true; - this._contentProvider.requestContent(this._createTextViewer.bind(this)); + this._delegate.requestContent(this._createTextViewer.bind(this)); } if (this._textViewer) { @@ -85,6 +86,11 @@ WebInspector.SourceFrame.prototype = { this._clearLineHighlight(); }, + get loaded() + { + return !!this._content; + }, + hasContent: function() { return true; @@ -132,12 +138,6 @@ WebInspector.SourceFrame.prototype = { this._textViewer.resize(); }, - sizeToFitContentHeight: function() - { - if (this._textViewer) - this._textViewer.revalidateDecorationsAndPaint(); - }, - get textModel() { return this._textModel; @@ -171,18 +171,34 @@ WebInspector.SourceFrame.prototype = { delete this._lineToHighlight; }, - _createTextViewer: function(mimeType, text) + _startEditing: function() { - this._content = new WebInspector.SourceFrameContent(text, this._contentProvider.scripts()); - this._textModel.setText(null, text); + WebInspector.searchController.cancelSearch(); + this.clearMessages(); + }, + + _endEditing: function(oldRange, newRange) + { + // FIXME: Implement this. + }, + + _createTextViewer: function(mimeType, content) + { + this._content = content; + this._textModel.setText(null, content.text); this._textViewer = new WebInspector.TextViewer(this._textModel, WebInspector.platform, this._url); + this._textViewer.startEditingListener = this._startEditing.bind(this); + this._textViewer.endEditingListener = this._endEditing.bind(this); + var element = this._textViewer.element; - element.addEventListener("contextmenu", this._contextMenu.bind(this), true); - element.addEventListener("mousedown", this._mouseDown.bind(this), true); - element.addEventListener("mousemove", this._mouseMove.bind(this), true); - element.addEventListener("scroll", this._scroll.bind(this), true); - element.addEventListener("dblclick", this._doubleClick.bind(this), true); + if (this._delegate.debuggingSupported()) { + element.addEventListener("contextmenu", this._contextMenu.bind(this), true); + element.addEventListener("mousedown", this._mouseDown.bind(this), true); + element.addEventListener("mousemove", this._mouseMove.bind(this), true); + element.addEventListener("dblclick", this._doubleClick.bind(this), true); + element.addEventListener("scroll", this._scroll.bind(this), true); + } this.element.appendChild(element); this._textViewer.beginUpdates(); @@ -205,11 +221,9 @@ WebInspector.SourceFrame.prototype = { delete this._delayedFindSearchMatches; } - this._textViewer.endUpdates(); + this.dispatchEventToListeners(WebInspector.SourceFrame.Events.Loaded); - WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointAdded, this._breakpointAdded, this); - WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointRemoved, this._breakpointRemoved, this); - WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointResolved, this._breakpointResolved, this); + this._textViewer.endUpdates(); }, _setTextViewerDecorations: function() @@ -222,32 +236,11 @@ WebInspector.SourceFrame.prototype = { this._addExistingMessagesToSource(); this._updateDiffDecorations(); - if (this._executionLine) - this.setExecutionLine(this._executionLine); - - this._breakpointIdToTextViewerLineNumber = {}; - this._textViewerLineNumberToBreakpointId = {}; - var breakpoints = WebInspector.debuggerModel.breakpoints; - for (var id in breakpoints) - this._breakpointAdded({ data: breakpoints[id] }); - this._textViewer.resize(); this._textViewer.endUpdates(); }, - _shouldDisplayBreakpoint: function(breakpoint) - { - if (this._url) - return this._url === breakpoint.url; - var scripts = this._contentProvider.scripts(); - for (var i = 0; i < scripts.length; ++i) { - if (breakpoint.sourceID === scripts[i].sourceID) - return true; - } - return false; - }, - performSearch: function(query, callback) { // Call searchCanceled since it will reset everything we need before doing a new search. @@ -363,20 +356,15 @@ WebInspector.SourceFrame.prototype = { setExecutionLine: function(lineNumber) { - this._executionLine = lineNumber; - if (!this._textViewer) - return; - var textViewerLineNumber = this._originalLocationToTextViewerLineNumber(this._executionLine - 1, 0); - this._textViewer.addDecoration(textViewerLineNumber, "webkit-execution-line"); + this._executionLineNumber = lineNumber; + this._textViewer.addDecoration(lineNumber, "webkit-execution-line"); + this._textViewer.revealLine(lineNumber); }, clearExecutionLine: function() { - if (!this._textViewer) - return; - var textViewerLineNumber = this._originalLocationToTextViewerLineNumber(this._executionLine - 1, 0); - this._textViewer.removeDecoration(textViewerLineNumber, "webkit-execution-line"); - delete this._executionLine; + this._textViewer.removeDecoration(this._executionLineNumber, "webkit-execution-line"); + delete this._executionLineNumber; }, _updateDiffDecorations: function() @@ -467,63 +455,18 @@ WebInspector.SourceFrame.prototype = { msg._resourceMessageLineElement = messageLineElement; }, - _breakpointAdded: function(event) - { - var breakpoint = event.data; - - if (!this._shouldDisplayBreakpoint(breakpoint)) - return; - - var resolved = breakpoint.locations.length; - var location = resolved ? breakpoint.locations[0] : breakpoint; - - var textViewerLineNumber = this._originalLocationToTextViewerLineNumber(location.lineNumber, location.columnNumber); - if (textViewerLineNumber >= this._textModel.linesCount) - return; - - var existingBreakpointId = this._textViewerLineNumberToBreakpointId[textViewerLineNumber]; - if (existingBreakpointId) { - WebInspector.debuggerModel.removeBreakpoint(breakpoint.id); - return; - } - - this._breakpointIdToTextViewerLineNumber[breakpoint.id] = textViewerLineNumber; - this._textViewerLineNumberToBreakpointId[textViewerLineNumber] = breakpoint.id; - this._setBreakpointDecoration(textViewerLineNumber, resolved, breakpoint.enabled, !!breakpoint.condition); - }, - - _breakpointRemoved: function(event) - { - var breakpointId = event.data; - - var textViewerLineNumber = this._breakpointIdToTextViewerLineNumber[breakpointId]; - if (textViewerLineNumber === undefined) - return; - - delete this._breakpointIdToTextViewerLineNumber[breakpointId]; - delete this._textViewerLineNumberToBreakpointId[textViewerLineNumber]; - this._removeBreakpointDecoration(textViewerLineNumber); - }, - - _breakpointResolved: function(event) - { - var breakpoint = event.data; - this._breakpointRemoved({ data: breakpoint.id }); - this._breakpointAdded({ data: breakpoint }); - }, - - _setBreakpointDecoration: function(lineNumber, resolved, enabled, hasCondition) + addBreakpoint: function(lineNumber, resolved, conditional, enabled) { this._textViewer.beginUpdates(); this._textViewer.addDecoration(lineNumber, "webkit-breakpoint"); if (!enabled) this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-disabled"); - if (hasCondition) + if (conditional) this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-conditional"); this._textViewer.endUpdates(); }, - _removeBreakpointDecoration: function(lineNumber) + removeBreakpoint: function(lineNumber) { this._textViewer.beginUpdates(); this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint"); @@ -534,55 +477,48 @@ WebInspector.SourceFrame.prototype = { _contextMenu: function(event) { - if (!WebInspector.panels.scripts) - return; - var target = event.target.enclosingNodeOrSelfWithClass("webkit-line-number"); if (!target) return; - var textViewerLineNumber = target.lineNumber; + var lineNumber = target.lineNumber; var contextMenu = new WebInspector.ContextMenu(); - contextMenu.appendItem(WebInspector.UIString("Continue to Here"), this._continueToLine.bind(this, textViewerLineNumber)); + contextMenu.appendItem(WebInspector.UIString("Continue to Here"), this._delegate.continueToLine.bind(this._delegate, lineNumber)); - var breakpoint = this._findBreakpoint(textViewerLineNumber); + var breakpoint = this._delegate.findBreakpoint(lineNumber); if (!breakpoint) { // This row doesn't have a breakpoint: We want to show Add Breakpoint and Add and Edit Breakpoint. - contextMenu.appendItem(WebInspector.UIString("Add Breakpoint"), this._setBreakpoint.bind(this, textViewerLineNumber, "", true)); + contextMenu.appendItem(WebInspector.UIString("Add Breakpoint"), this._delegate.setBreakpoint.bind(this._delegate, lineNumber, "", true)); function addConditionalBreakpoint() { - this._setBreakpointDecoration(textViewerLineNumber, true, true, true); + this.addBreakpoint(lineNumber, true, true, true); function didEditBreakpointCondition(committed, condition) { - this._removeBreakpointDecoration(textViewerLineNumber); + this.removeBreakpoint(lineNumber); if (committed) - this._setBreakpoint(textViewerLineNumber, condition, true); + this._delegate.setBreakpoint(lineNumber, condition, true); } - this._editBreakpointCondition(textViewerLineNumber, "", didEditBreakpointCondition.bind(this)); + this._editBreakpointCondition(lineNumber, "", didEditBreakpointCondition.bind(this)); } contextMenu.appendItem(WebInspector.UIString("Add Conditional Breakpoint…"), addConditionalBreakpoint.bind(this)); } else { // This row has a breakpoint, we want to show edit and remove breakpoint, and either disable or enable. - function removeBreakpoint() - { - WebInspector.debuggerModel.removeBreakpoint(breakpoint.id); - } - contextMenu.appendItem(WebInspector.UIString("Remove Breakpoint"), removeBreakpoint); + contextMenu.appendItem(WebInspector.UIString("Remove Breakpoint"), this._delegate.removeBreakpoint.bind(this._delegate, breakpoint.id)); function editBreakpointCondition() { function didEditBreakpointCondition(committed, condition) { if (committed) - WebInspector.debuggerModel.updateBreakpoint(breakpoint.id, condition, breakpoint.enabled); + this._delegate.updateBreakpoint(breakpoint.id, condition, breakpoint.enabled); } - this._editBreakpointCondition(textViewerLineNumber, breakpoint.condition, didEditBreakpointCondition.bind(this)); + this._editBreakpointCondition(lineNumber, breakpoint.condition, didEditBreakpointCondition.bind(this)); } contextMenu.appendItem(WebInspector.UIString("Edit Breakpoint…"), editBreakpointCondition.bind(this)); function setBreakpointEnabled(enabled) { - WebInspector.debuggerModel.updateBreakpoint(breakpoint.id, breakpoint.condition, enabled); + this._delegate.updateBreakpoint(breakpoint.id, breakpoint.condition, enabled); } if (breakpoint.enabled) contextMenu.appendItem(WebInspector.UIString("Disable Breakpoint"), setBreakpointEnabled.bind(this, false)); @@ -606,16 +542,16 @@ WebInspector.SourceFrame.prototype = { var target = event.target.enclosingNodeOrSelfWithClass("webkit-line-number"); if (!target) return; - var textViewerLineNumber = target.lineNumber; + var lineNumber = target.lineNumber; - var breakpoint = this._findBreakpoint(textViewerLineNumber); + var breakpoint = this._delegate.findBreakpoint(lineNumber); if (breakpoint) { if (event.shiftKey) - WebInspector.debuggerModel.updateBreakpoint(breakpoint.id, breakpoint.condition, !breakpoint.enabled); + this._delegate.updateBreakpoint(breakpoint.id, breakpoint.condition, !breakpoint.enabled); else - WebInspector.debuggerModel.removeBreakpoint(breakpoint.id); + this._delegate.removeBreakpoint(breakpoint.id); } else - this._setBreakpoint(textViewerLineNumber, "", true); + this._delegate.setBreakpoint(lineNumber, "", true); event.preventDefault(); }, @@ -641,7 +577,7 @@ WebInspector.SourceFrame.prototype = { this._hoverElement = event.target; // Now that cleanup routines are set up above, leave this in case we are not on a break. - if (!WebInspector.panels.scripts || !WebInspector.panels.scripts.paused) + if (!this._delegate.debuggerPaused()) return; // We are interested in identifiers and "this" keyword. @@ -680,16 +616,13 @@ WebInspector.SourceFrame.prototype = { this._popup.hide(); delete this._popup; - InspectorBackend.releaseWrapperObjectGroup(0, this._popoverObjectGroup); + this._delegate.releaseEvaluationResult(); }, _mouseHover: function(element) { delete this._hoverTimer; - if (!WebInspector.panels.scripts || !WebInspector.panels.scripts.paused) - return; - var lineRow = element.enclosingNodeOrSelfWithClass("webkit-line-content"); if (!lineRow) return; @@ -729,9 +662,6 @@ WebInspector.SourceFrame.prototype = { function showObjectPopup(result) { - if (!WebInspector.panels.scripts.paused) - return; - var popupContentElement = null; if (result.type !== "object" && result.type !== "node" && result.type !== "array") { popupContentElement = document.createElement("span"); @@ -766,15 +696,7 @@ WebInspector.SourceFrame.prototype = { popupContentElement.addEventListener("mousemove", killHidePopupTimer.bind(this), true); } - function evaluateCallback(result) - { - if (result.isError()) - return; - if (!WebInspector.panels.scripts.paused) - return; - showObjectPopup.call(this, result); - } - WebInspector.panels.scripts.evaluateInSelectedCallFrame(element.textContent, false, this._popoverObjectGroup, false, evaluateCallback.bind(this)); + this._delegate.evaluateInSelectedCallFrame(element.textContent, showObjectPopup.bind(this)); }, _editBreakpointCondition: function(lineNumber, condition, callback) @@ -820,24 +742,6 @@ WebInspector.SourceFrame.prototype = { return conditionElement; }, - _evalSelectionInCallFrame: function(event) - { - if (!WebInspector.panels.scripts || !WebInspector.panels.scripts.paused) - return; - - var selection = this.element.contentWindow.getSelection(); - if (!selection.rangeCount) - return; - - var expression = selection.getRangeAt(0).toString().trim(); - WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression, false, "console", function(result) { - WebInspector.showConsole(); - var commandMessage = new WebInspector.ConsoleCommand(expression); - WebInspector.console.addMessage(commandMessage); - WebInspector.console.addMessage(new WebInspector.ConsoleCommandResult(result, commandMessage)); - }); - }, - resize: function() { if (this._textViewer) @@ -851,7 +755,7 @@ WebInspector.SourceFrame.prototype = { function didFormat(formattedContent) { - this._formattedContent = formattedContent; + this._content = formattedContent; this._textModel.setText(null, formattedContent.text); this._setTextViewerDecorations(); } @@ -859,91 +763,96 @@ WebInspector.SourceFrame.prototype = { formatter.formatContent(this._content, didFormat.bind(this)) }, - _continueToLine: function(lineNumber) - { - var location = this._textViewerLineNumberToScriptLocation(lineNumber); - if (location.sourceID) - WebInspector.debuggerModel.continueToLine(location.sourceID, location.lineNumber); - }, - _doubleClick: function(event) { - if (!Preferences.canEditScriptSource || !this._isScript) + if (!this._delegate.canEditScriptSource()) return; var lineRow = event.target.enclosingNodeOrSelfWithClass("webkit-line-content"); if (!lineRow) return; // Do not trigger editing from line numbers. - var lineNumber = lineRow.lineNumber; - var location = this._textViewerLineNumberToScriptLocation(lineNumber); - if (!location.sourceID) - return; + this._textViewer.editLine(lineRow, this._didEditLine.bind(this, lineRow.lineNumber)); + }, - function didEditLine(newContent) - { - var lines = []; - var oldLines = this._content.text.split('\n'); - for (var i = 0; i < oldLines.length; ++i) { - if (i === lineNumber) - lines.push(newContent); - else - lines.push(oldLines[i]); - } - WebInspector.debuggerModel.editScriptSource(location.sourceID, lines.join("\n")); + _didEditLine: function(lineNumber, newContent) + { + var lines = []; + var oldLines = this._content.text.split('\n'); + for (var i = 0; i < oldLines.length; ++i) { + if (i === lineNumber) + lines.push(newContent); + else + lines.push(oldLines[i]); } - this._textViewer.editLine(lineRow, didEditLine.bind(this)); + this._delegate.editScriptSource(lines.join("\n")); + } +} + +WebInspector.SourceFrame.prototype.__proto__ = WebInspector.View.prototype; + + +WebInspector.SourceFrameDelegate = function() +{ +} + +WebInspector.SourceFrameDelegate.prototype = { + requestContent: function(callback) + { + // Should be implemented by subclasses. }, - _setBreakpoint: function(lineNumber, condition, enabled) + debuggingSupported: function() { - var location = this._textViewerLineNumberToScriptLocation(lineNumber); - if (this._url) - WebInspector.debuggerModel.setBreakpoint(this._url, location.lineNumber, location.columnNumber, condition, enabled); - else if (location.sourceID) - WebInspector.debuggerModel.setBreakpointBySourceId(location.sourceID, location.lineNumber, location.columnNumber, condition, enabled); - else - return; + return false; + }, - if (!WebInspector.panels.scripts.breakpointsActivated) - WebInspector.panels.scripts.toggleBreakpointsClicked(); + setBreakpoint: function(lineNumber, condition, enabled) + { + // Should be implemented by subclasses. }, - _findBreakpoint: function(textViewerLineNumber) + removeBreakpoint: function(breakpointId) { - var breakpointId = this._textViewerLineNumberToBreakpointId[textViewerLineNumber]; - return WebInspector.debuggerModel.breakpointForId(breakpointId); + // Should be implemented by subclasses. }, - _originalLocationToTextViewerLineNumber: function(lineNumber, columnNumber) + updateBreakpoint: function(breakpointId, condition, enabled) { - if (!this._formattedContent) - return lineNumber; - return this._formattedContent.originalLocationToFormattedLocation(lineNumber, columnNumber).lineNumber; + // Should be implemented by subclasses. }, - _textViewerLineNumberToScriptLocation: function(lineNumber) + findBreakpoint: function(lineNumber) { - if (!this._formattedContent) - return this._content.scriptLocationForLineNumber(lineNumber); - return this._formattedContent.scriptLocationForFormattedLineNumber(lineNumber); - } -} + // Should be implemented by subclasses. + }, -WebInspector.SourceFrame.prototype.__proto__ = WebInspector.View.prototype; + continueToLine: function(lineNumber) + { + // Should be implemented by subclasses. + }, + canEditScriptSource: function() + { + return false; + }, -WebInspector.SourceFrameContentProvider = function() -{ -} + editScriptSource: function(text) + { + // Should be implemented by subclasses. + }, -WebInspector.SourceFrameContentProvider.prototype = { - requestContent: function(callback) + debuggerPaused: function() + { + // Should be implemented by subclasses. + }, + + evaluateInSelectedCallFrame: function(string) { // Should be implemented by subclasses. }, - scripts: function() + releaseEvaluationResult: function() { // Should be implemented by subclasses. } diff --git a/Source/WebCore/inspector/front-end/SourceFrameContent.js b/Source/WebCore/inspector/front-end/SourceFrameContent.js index e4a74ec..91b397b 100644 --- a/Source/WebCore/inspector/front-end/SourceFrameContent.js +++ b/Source/WebCore/inspector/front-end/SourceFrameContent.js @@ -28,24 +28,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.SourceFrameContent = function(text, scripts) +WebInspector.SourceFrameContent = function(text, mapping, scriptRanges) { - if (scripts.length && scripts[0].length < text.length) { - // WebKit html lexer normalizes line endings and scripts are passed to VM with "\n" line endings. - // However, resource content has original line endings, so we have to normalize line endings here. - text = text.replace(/\r\n/g, "\n"); - } this._text = text; - this._lineEndings = text.findAll("\n"); - this._lineEndings.push(text.length); - - this._scriptRanges = []; - for (var i = 0; i < scripts.length; ++i) { - var script = scripts[i]; - var offset = this.locationToPosition(script.lineOffset, script.columnOffset); - this._scriptRanges.push({ start: offset, end: offset + script.length, script: script }); - } - this._scriptRanges.sort(function(x, y) { return x.start - y.start; }); + this._mapping = mapping; + this._scriptRanges = scriptRanges; } WebInspector.SourceFrameContent.prototype = { @@ -59,95 +46,77 @@ WebInspector.SourceFrameContent.prototype = { return this._scriptRanges; }, - locationToPosition: function(lineNumber, columnNumber) - { - var position = lineNumber ? this._lineEndings[lineNumber - 1] + 1 : 0; - return position + columnNumber; - }, - - positionToLocation: function(position) + sourceFrameLineNumberToActualLocation: function(lineNumber) { - var location = {}; - location.lineNumber = this._lineEndings.upperBound(position - 1); - if (!location.lineNumber) - location.columnNumber = position; - else - location.columnNumber = position - this._lineEndings[location.lineNumber - 1] - 1; + // Script content may start right after <script> tag without new line (e.g. "<script>function f()..."). + // In that case, column number should be equal to script column offset. + var columnNumber = 0; + for (var i = 0; i < this._scriptRanges.length; ++i) { + var scriptRange = this._scriptRanges[i]; + if (scriptRange.start.lineNumber < lineNumber) + continue; + if (scriptRange.start.lineNumber === lineNumber) + columnNumber = scriptRange.start.columnNumber; + break; + } + var location = this._mapping.sourceLocationToActualLocation(lineNumber, columnNumber); + location.sourceID = this._sourceIDForSourceFrameLineNumber(lineNumber); return location; }, - scriptLocationForLineNumber: function(lineNumber) - { - var range = this.lineNumberToRange(lineNumber); - return this.scriptLocationForRange(range.start, range.end); - }, - - scriptLocationForRange: function(start, end) + actualLocationToSourceFrameLineNumber: function(lineNumber, columnNumber) { - var position = start; - var scriptRange = this._intersectingScriptRange(start, end); - if (scriptRange) - position = Math.max(position, scriptRange.start); - var scriptLocation = this.positionToLocation(position); - if (scriptRange) - scriptLocation.sourceID = scriptRange.script.sourceID; - return scriptLocation; + return this._mapping.actualLocationToSourceLocation(lineNumber, columnNumber).lineNumber; }, - lineNumberToRange: function(lineNumber) - { - var previousLineEnd = this._lineEndings[lineNumber - 1] || 0; - var lineEnd = this._lineEndings[lineNumber]; - return { start: previousLineEnd + 1, end: lineEnd }; - }, - - _intersectingScriptRange: function(start, end) + _sourceIDForSourceFrameLineNumber: function(lineNumber) { for (var i = 0; i < this._scriptRanges.length; ++i) { var scriptRange = this._scriptRanges[i]; - if (start < scriptRange.end && end > scriptRange.start) - return scriptRange; + if (lineNumber < scriptRange.start.lineNumber) + return; + if (lineNumber > scriptRange.end.lineNumber) + continue; + if (lineNumber === scriptRange.end.lineNumber && !scriptRange.end.columnNumber) + continue; + return scriptRange.sourceID; } } } -WebInspector.FormattedSourceFrameContent = function(originalContent, text, mapping) +WebInspector.SourceMapping = function() { - this._originalContent = originalContent; - this._formattedContent = new WebInspector.SourceFrameContent(text, []); - this._mapping = mapping; } -WebInspector.FormattedSourceFrameContent.prototype = { - get text() +WebInspector.SourceMapping.prototype = { + actualLocationToSourceLocation: function(lineNumber, columnNumber) { - return this._formattedContent.text; + // Should be implemented by subclasses. }, - originalLocationToFormattedLocation: function(lineNumber, columnNumber) + sourceLocationToActualLocation: function(lineNumber, columnNumber) { - var originalPosition = this._originalContent.locationToPosition(lineNumber, columnNumber); - var formattedPosition = this._convertPosition(this._mapping.original, this._mapping.formatted, originalPosition); - return this._formattedContent.positionToLocation(formattedPosition); - }, + // Should be implemented by subclasses. + } +} + + +WebInspector.IdenticalSourceMapping = function() +{ + WebInspector.SourceMapping.call(this); +} - scriptLocationForFormattedLineNumber: function(lineNumber) +WebInspector.IdenticalSourceMapping.prototype = { + actualLocationToSourceLocation: function(lineNumber, columnNumber) { - var range = this._formattedContent.lineNumberToRange(lineNumber); - var start = this._convertPosition(this._mapping.formatted, this._mapping.original, range.start); - var end = this._convertPosition(this._mapping.formatted, this._mapping.original, range.end); - return this._originalContent.scriptLocationForRange(start, end); + return { lineNumber: lineNumber, columnNumber: columnNumber}; }, - _convertPosition: function(positions1, positions2, position) + sourceLocationToActualLocation: function(lineNumber, columnNumber) { - var index = positions1.upperBound(position); - var range1 = positions1[index] - positions1[index - 1]; - var range2 = positions2[index] - positions2[index - 1]; - var position2 = positions2[index - 1]; - if (range1) - position2 += Math.round((position - positions1[index - 1]) * range2 / range1); - return position2; + return { lineNumber: lineNumber, columnNumber: columnNumber}; } } + +WebInspector.IdenticalSourceMapping.prototype.__proto__ = WebInspector.SourceMapping.prototype; diff --git a/Source/WebCore/inspector/front-end/SourceTokenizer.js b/Source/WebCore/inspector/front-end/SourceTokenizer.js index d30744c..bb44a86 100644 --- a/Source/WebCore/inspector/front-end/SourceTokenizer.js +++ b/Source/WebCore/inspector/front-end/SourceTokenizer.js @@ -48,11 +48,6 @@ WebInspector.SourceTokenizer.prototype = { return this._condition; }, - get subTokenizer() - { - return this._condition.subTokenizer; - }, - getLexCondition: function() { return this.condition.lexCondition; diff --git a/Source/WebCore/inspector/front-end/StylesSidebarPane.js b/Source/WebCore/inspector/front-end/StylesSidebarPane.js index 57d3b76..c7d151a 100644 --- a/Source/WebCore/inspector/front-end/StylesSidebarPane.js +++ b/Source/WebCore/inspector/front-end/StylesSidebarPane.js @@ -438,7 +438,7 @@ WebInspector.StylesSidebarPane.prototype = { if (computedStyle) var section = new WebInspector.ComputedStylePropertiesSection(styleRule, usedProperties, disabledComputedProperties, styleRules); else - var section = new WebInspector.StylePropertiesSection(styleRule, editable, styleRule.isInherited, lastWasSeparator); + var section = new WebInspector.StylePropertiesSection(this, styleRule, editable, styleRule.isInherited, lastWasSeparator); section.pane = this; section.expanded = true; @@ -503,7 +503,7 @@ WebInspector.StylesSidebarPane.prototype = { addBlankSection: function() { - var blankSection = new WebInspector.BlankStylePropertiesSection(appropriateSelectorForNode(this.node, true)); + var blankSection = new WebInspector.BlankStylePropertiesSection(this, appropriateSelectorForNode(this.node, true)); blankSection.pane = this; var elementStyleSection = this.sections[0][1]; @@ -591,7 +591,7 @@ WebInspector.ComputedStyleSidebarPane = function() WebInspector.ComputedStyleSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; -WebInspector.StylePropertiesSection = function(styleRule, editable, isInherited, isFirstSection) +WebInspector.StylePropertiesSection = function(parentPane, styleRule, editable, isInherited, isFirstSection) { WebInspector.PropertiesSection.call(this, ""); this.element.className = "styles-section monospace" + (isFirstSection ? " first-styles-section" : ""); @@ -613,6 +613,7 @@ WebInspector.StylePropertiesSection = function(styleRule, editable, isInherited, this._selectorElement.addEventListener("dblclick", this._handleSelectorDoubleClick.bind(this), false); this.element.addEventListener("dblclick", this._handleEmptySpaceDoubleClick.bind(this), false); + this._parentPane = parentPane; this.styleRule = styleRule; this.rule = this.styleRule.rule; this.editable = editable; @@ -792,7 +793,7 @@ WebInspector.StylePropertiesSection.prototype = { var inherited = this.isPropertyInherited(property.name); var overloaded = this.isPropertyOverloaded(property.name, isShorthand); - var item = new WebInspector.StylePropertyTreeElement(this.styleRule, style, property, isShorthand, inherited, overloaded); + var item = new WebInspector.StylePropertyTreeElement(this._parentPane, this.styleRule, style, property, isShorthand, inherited, overloaded); this.propertiesTreeOutline.appendChild(item); handledProperties[property.name] = property; } @@ -813,7 +814,7 @@ WebInspector.StylePropertiesSection.prototype = { { var style = this.styleRule.style; var property = style.newBlankProperty(); - var item = new WebInspector.StylePropertyTreeElement(this.styleRule, style, property, false, false, false); + var item = new WebInspector.StylePropertyTreeElement(this._parentPane, this.styleRule, style, property, false, false, false); this.propertiesTreeOutline.appendChild(item); item.listItemElement.textContent = ""; item._newProperty = true; @@ -1025,7 +1026,7 @@ WebInspector.ComputedStylePropertiesSection.prototype = { for (var i = 0; i < uniqueProperties.length; ++i) { var property = uniqueProperties[i]; var inherited = this._isPropertyInherited(property.name); - var item = new WebInspector.StylePropertyTreeElement(this.styleRule, style, property, false, inherited, false); + var item = new WebInspector.StylePropertyTreeElement(this._parentPane, this.styleRule, style, property, false, inherited, false); this.propertiesTreeOutline.appendChild(item); this._propertyTreeElements[property.name] = item; } @@ -1070,9 +1071,9 @@ WebInspector.ComputedStylePropertiesSection.prototype = { WebInspector.ComputedStylePropertiesSection.prototype.__proto__ = WebInspector.PropertiesSection.prototype; -WebInspector.BlankStylePropertiesSection = function(defaultSelectorText) +WebInspector.BlankStylePropertiesSection = function(parentPane, defaultSelectorText) { - WebInspector.StylePropertiesSection.call(this, {selectorText: defaultSelectorText, rule: {isViaInspector: true}}, true, false, false); + WebInspector.StylePropertiesSection.call(this, parentPane, {selectorText: defaultSelectorText, rule: {isViaInspector: true}}, true, false, false); this.element.addStyleClass("blank-section"); } @@ -1121,8 +1122,9 @@ WebInspector.BlankStylePropertiesSection.prototype = { WebInspector.BlankStylePropertiesSection.prototype.__proto__ = WebInspector.StylePropertiesSection.prototype; -WebInspector.StylePropertyTreeElement = function(styleRule, style, property, shorthand, inherited, overloaded) +WebInspector.StylePropertyTreeElement = function(parentPane, styleRule, style, property, shorthand, inherited, overloaded) { + this._parentPane = parentPane; this._styleRule = styleRule; this.style = style; this.property = property; @@ -1483,7 +1485,7 @@ WebInspector.StylePropertyTreeElement.prototype = { } var liveProperty = this.style.getLiveProperty(name); - var item = new WebInspector.StylePropertyTreeElement(this._styleRule, this.style, liveProperty, false, inherited, overloaded); + var item = new WebInspector.StylePropertyTreeElement(this._parentPane, this._styleRule, this.style, liveProperty, false, inherited, overloaded); this.appendChild(item); } }, @@ -1609,6 +1611,7 @@ WebInspector.StylePropertyTreeElement.prototype = { return "move-forward"; } + this._parentPane.isModifyingStyle = true; WebInspector.startEditing(selectElement, { context: context, commitHandler: this.editingCommitted.bind(this), @@ -1719,6 +1722,7 @@ WebInspector.StylePropertyTreeElement.prototype = { editedElement.parentElement.removeStyleClass("child-editing"); delete this.originalPropertyText; + delete this._parentPane.isModifyingStyle; }, editingCancelled: function(element, context) @@ -1767,6 +1771,7 @@ WebInspector.StylePropertyTreeElement.prototype = { var isDirtyViaPaste = isDataPasted && (this.nameElement.textContent !== context.originalName || this.valueElement.textContent !== context.originalValue); var shouldCommitNewProperty = this._newProperty && (moveToOther || (!moveDirection && !isEditingName) || (isEditingName && blankInput)); if (((userInput !== previousContent || isDirtyViaPaste) && !this._newProperty) || shouldCommitNewProperty) { + this._parentPane.isModifyingStyle = true; this.treeOutline.section._afterUpdate = moveToNextCallback.bind(this, this._newProperty, !blankInput, this.treeOutline.section); var propertyText; if (blankInput || (this._newProperty && /^\s*$/.test(this.valueElement.textContent))) @@ -1781,7 +1786,7 @@ WebInspector.StylePropertyTreeElement.prototype = { } else { if (!isDataPasted && !this._newProperty) this.updateTitle(); - moveToNextCallback(this._newProperty, false, this.treeOutline.section); + moveToNextCallback.call(this, this._newProperty, false, this.treeOutline.section); } var moveToIndex = moveTo && this.treeOutline ? this.treeOutline.children.indexOf(moveTo) : -1; @@ -1789,6 +1794,8 @@ WebInspector.StylePropertyTreeElement.prototype = { // The Callback to start editing the next/previous property/selector. function moveToNextCallback(alreadyNew, valueChanged, section) { + delete this._parentPane.isModifyingStyle; + if (!moveDirection) return; diff --git a/Source/WebCore/inspector/front-end/TestController.js b/Source/WebCore/inspector/front-end/TestController.js index 3bfe28c..e6783f9 100644 --- a/Source/WebCore/inspector/front-end/TestController.js +++ b/Source/WebCore/inspector/front-end/TestController.js @@ -28,40 +28,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.TestController = function(callId) +WebInspector.TestController = function() { - this._callId = callId; - this._waitUntilDone = false; - this.results = []; } WebInspector.TestController.prototype = { - waitUntilDone: function() + notifyDone: function(callId, result) { - this._waitUntilDone = true; - }, - - notifyDone: function(result) - { - if (typeof result === "undefined" && this.results.length) - result = this.results; var message = typeof result === "undefined" ? "\"<undefined>\"" : JSON.stringify(result); - InspectorBackend.didEvaluateForTestInFrontend(this._callId, message); - }, - - runAfterPendingDispatches: function(callback) - { - if (WebInspector.pendingDispatches === 0) { - callback(); - return; - } - setTimeout(this.runAfterPendingDispatches.bind(this), 0, callback); + InspectorAgent.didEvaluateForTestInFrontend(callId, message); } } WebInspector.evaluateForTestInFrontend = function(callId, script) { - var controller = new WebInspector.TestController(callId); function invokeMethod() { try { @@ -71,11 +51,10 @@ WebInspector.evaluateForTestInFrontend = function(callId, script) else result = window.eval(script); - if (!controller._waitUntilDone) - controller.notifyDone(result); + WebInspector.TestController.prototype.notifyDone(callId, result); } catch (e) { - controller.notifyDone(e.toString()); + WebInspector.testController.prototype.notifyDone(callId, e.toString()); } } - controller.runAfterPendingDispatches(invokeMethod); + InspectorBackend.runAfterPendingDispatches(invokeMethod); } diff --git a/Source/WebCore/inspector/front-end/TextEditorHighlighter.js b/Source/WebCore/inspector/front-end/TextEditorHighlighter.js index 4ac831e..9bdcc82 100644 --- a/Source/WebCore/inspector/front-end/TextEditorHighlighter.js +++ b/Source/WebCore/inspector/front-end/TextEditorHighlighter.js @@ -34,6 +34,7 @@ WebInspector.TextEditorHighlighter = function(textModel, damageCallback) this._textModel = textModel; this._tokenizer = WebInspector.SourceTokenizer.Registry.getInstance().getTokenizer("text/html"); this._damageCallback = damageCallback; + this._highlightChunkLimit = 1000; this.reset(); } @@ -43,18 +44,23 @@ WebInspector.TextEditorHighlighter.prototype = { var tokenizer = WebInspector.SourceTokenizer.Registry.getInstance().getTokenizer(mimeType); if (tokenizer) { this._tokenizer = tokenizer; - this._tokenizerCondition = this._tokenizer.initialCondition; + this._tokenizerConditionStringified = JSON.stringify(this._tokenizer.initialCondition); } }, + set highlightChunkLimit(highlightChunkLimit) + { + this._highlightChunkLimit = highlightChunkLimit; + }, + reset: function() { this._lastHighlightedLine = 0; this._lastHighlightedColumn = 0; - this._tokenizerCondition = this._tokenizer.initialCondition; + this._tokenizerConditionStringified = JSON.stringify(this._tokenizer.initialCondition); }, - highlight: function(endLine) + highlight: function(endLine, opt_forceRun) { // First check if we have work to do. if (endLine <= this._lastHighlightedLine) @@ -62,7 +68,7 @@ WebInspector.TextEditorHighlighter.prototype = { this._requestedEndLine = endLine; - if (this._highlightTimer) { + if (this._highlightTimer && !opt_forceRun) { // There is a timer scheduled, it will catch the new job based on the new endLine set. return; } @@ -75,6 +81,58 @@ WebInspector.TextEditorHighlighter.prototype = { this._highlightTimer = setTimeout(this._highlightInChunks.bind(this, endLine), 100); }, + updateHighlight: function(startLine, endLine) + { + if (this._lastHighlightedLine < startLine) { + // Highlighter did not reach this point yet, nothing to update. It will reach it on subsequent timer tick and do the job. + return false; + } + + var savedLastHighlightedLine = this._lastHighlightedLine; + var savedLastHighlightedColumn = this._lastHighlightedColumn; + var savedTokenizerCondition = this._tokenizerConditionStringified; + + this._lastHighlightedLine = startLine; + this._lastHighlightedColumn = 0; + + // Restore highlighter context taken from the previous line. + var attributes = this._textModel.getAttribute(startLine - 1, "highlight") || {}; + this._tokenizerConditionStringified = attributes.postConditionStringified || JSON.stringify(this._tokenizer.initialCondition); + + // Try to update highlight synchronously. + this._highlightLines(endLine); + + if (this._lastHighlightedLine >= this._textModel.linesCount) { + // All is done up to the end. + return true; + } + + var attributes1 = this._textModel.getAttribute(this._lastHighlightedLine - 1, "highlight") || {}; + var attributes2 = this._textModel.getAttribute(this._lastHighlightedLine, "highlight") || {}; + if (this._lastHighlightedColumn === 0 && attributes2.preConditionStringified && attributes1.postConditionStringified === attributes2.preConditionStringified) { + // Highlighting ended ahead of time. Restore previously saved state, unless we have done more than it was before. + if (savedLastHighlightedLine >= this._lastHighlightedLine) { + this._lastHighlightedLine = savedLastHighlightedLine; + this._lastHighlightedColumn = savedLastHighlightedColumn; + this._tokenizerConditionStringified = savedTokenizerCondition; + } + return true; + } else { + // If failed to update highlight synchronously, invalidate highlight data for the subsequent lines. + if (this._lastHighlightedColumn === 0) + this._textModel.removeAttribute(this._lastHighlightedLine, "highlight"); + for (var i = this._lastHighlightedLine + 1; i < this._textModel.linesCount; ++i) + this._textModel.removeAttribute(i, "highlight"); + + // Continue highlighting on subsequent timer ticks. + this._requestedEndLine = endLine; + if (!this._highlightTimer) + this._highlightTimer = setTimeout(this._highlightInChunks.bind(this, endLine), 100); + + return false; + } + }, + _highlightInChunks: function(endLine) { delete this._highlightTimer; @@ -89,6 +147,10 @@ WebInspector.TextEditorHighlighter.prototype = { return; } + // The textModel may have been already updated. + if (this._requestedEndLine > this._textModel.linesCount) + this._requestedEndLine = this._textModel.linesCount; + this._highlightLines(this._requestedEndLine); // Schedule tail highlight if necessary. @@ -98,35 +160,49 @@ WebInspector.TextEditorHighlighter.prototype = { _highlightLines: function(endLine) { - // Tokenizer is stateless and reused accross viewers, restore its condition before highlight and save it after. - this._tokenizer.condition = this._tokenizerCondition; + // Tokenizer is stateless and reused across viewers, restore its condition before highlight and save it after. + this._tokenizer.condition = JSON.parse(this._tokenizerConditionStringified); var tokensCount = 0; for (var lineNumber = this._lastHighlightedLine; lineNumber < endLine; ++lineNumber) { var line = this._textModel.line(lineNumber); this._tokenizer.line = line; - var attributes = this._textModel.getAttribute(lineNumber, "highlight") || {}; + + if (this._lastHighlightedColumn === 0) { + var attributes = {}; + attributes.preConditionStringified = JSON.stringify(this._tokenizer.condition); + this._textModel.setAttribute(lineNumber, "highlight", attributes); + } else + var attributes = this._textModel.getAttribute(lineNumber, "highlight"); // Highlight line. do { var newColumn = this._tokenizer.nextToken(this._lastHighlightedColumn); var tokenType = this._tokenizer.tokenType; if (tokenType) - attributes[this._lastHighlightedColumn] = { length: newColumn - this._lastHighlightedColumn, tokenType: tokenType, subTokenizer: this._tokenizer.subTokenizer }; + attributes[this._lastHighlightedColumn] = { length: newColumn - this._lastHighlightedColumn, tokenType: tokenType }; this._lastHighlightedColumn = newColumn; - if (++tokensCount > 1000) + if (++tokensCount > this._highlightChunkLimit) break; - } while (this._lastHighlightedColumn < line.length) + } while (this._lastHighlightedColumn < line.length); - this._textModel.setAttribute(lineNumber, "highlight", attributes); if (this._lastHighlightedColumn < line.length) { // Too much work for single chunk - exit. break; - } else + } else { this._lastHighlightedColumn = 0; + attributes.postConditionStringified = JSON.stringify(this._tokenizer.condition); + + var nextAttributes = this._textModel.getAttribute(lineNumber + 1, "highlight") || {}; + if (nextAttributes.preConditionStringified === attributes.postConditionStringified) { + // Following lines are up to date, no need to re-highlight. + ++lineNumber; + break; + } + } } this._damageCallback(this._lastHighlightedLine, lineNumber); - this._tokenizerCondition = this._tokenizer.condition; + this._tokenizerConditionStringified = JSON.stringify(this._tokenizer.condition); this._lastHighlightedLine = lineNumber; } } diff --git a/Source/WebCore/inspector/front-end/TextViewer.js b/Source/WebCore/inspector/front-end/TextViewer.js index ce6502d..65b4724 100644 --- a/Source/WebCore/inspector/front-end/TextViewer.js +++ b/Source/WebCore/inspector/front-end/TextViewer.js @@ -37,9 +37,11 @@ WebInspector.TextViewer = function(textModel, platform, url) this.element = document.createElement("div"); this.element.className = "text-editor monospace"; + var enterTextChangeMode = this._enterInternalTextChangeMode.bind(this); + var exitTextChangeMode = this._exitInternalTextChangeMode.bind(this); var syncScrollListener = this._syncScroll.bind(this); var syncDecorationsForLineListener = this._syncDecorationsForLine.bind(this); - this._mainPanel = new WebInspector.TextEditorMainPanel(this._textModel, url, syncScrollListener, syncDecorationsForLineListener); + this._mainPanel = new WebInspector.TextEditorMainPanel(this._textModel, url, syncScrollListener, syncDecorationsForLineListener, enterTextChangeMode, exitTextChangeMode); this._gutterPanel = new WebInspector.TextEditorGutterPanel(this._textModel, syncDecorationsForLineListener); this.element.appendChild(this._mainPanel.element); this.element.appendChild(this._gutterPanel.element); @@ -51,6 +53,21 @@ WebInspector.TextViewer.prototype = { this._mainPanel.mimeType = mimeType; }, + set readOnly(readOnly) + { + this._mainPanel.readOnly = readOnly; + }, + + set startEditingListener(startEditingListener) + { + this._startEditingListener = startEditingListener; + }, + + set endEditingListener(endEditingListener) + { + this._endEditingListener = endEditingListener; + }, + get textModel() { return this._textModel; @@ -129,6 +146,7 @@ WebInspector.TextViewer.prototype = { { this._mainPanel.endUpdates(); this._gutterPanel.endUpdates(); + this._updatePanelOffsets(); }, resize: function() @@ -141,9 +159,31 @@ WebInspector.TextViewer.prototype = { // WebInspector.TextModel listener _textChanged: function(oldRange, newRange, oldText, newText) { - this._mainPanel.textChanged(); - this._gutterPanel.textChanged(); + if (!this._internalTextChangeMode) { + this._mainPanel.textChanged(oldRange, newRange); + this._gutterPanel.textChanged(oldRange, newRange); + this._updatePanelOffsets(); + } + }, + + _enterInternalTextChangeMode: function() + { + this._internalTextChangeMode = true; + + if (this._startEditingListener) + this._startEditingListener(); + }, + + _exitInternalTextChangeMode: function(oldRange, newRange) + { + this._internalTextChangeMode = false; + + // Update the gutter panel. + this._gutterPanel.textChanged(oldRange, newRange); this._updatePanelOffsets(); + + if (this._endEditingListener) + this._endEditingListener(oldRange, newRange); }, _updatePanelOffsets: function() @@ -161,13 +201,8 @@ WebInspector.TextViewer.prototype = { setTimeout(function() { var mainElement = this._mainPanel.element; var gutterElement = this._gutterPanel.element; - // Handle horizontal scroll bar at the bottom of the main panel. - if (gutterElement.offsetHeight > mainElement.clientHeight) - gutterElement.style.setProperty("padding-bottom", (gutterElement.offsetHeight - mainElement.clientHeight) + "px"); - else - gutterElement.style.removeProperty("padding-bottom"); - + this._gutterPanel.syncClientHeight(mainElement.clientHeight); gutterElement.scrollTop = mainElement.scrollTop; }.bind(this), 0); }, @@ -177,13 +212,19 @@ WebInspector.TextViewer.prototype = { if (lineNumber >= this._textModel.linesCount) return; - var mainChunk = this._mainPanel.makeLineAChunk(lineNumber); - var gutterChunk = this._gutterPanel.makeLineAChunk(lineNumber); - var height = mainChunk.height; - if (height) - gutterChunk.element.style.setProperty("height", height + "px"); - else - gutterChunk.element.style.removeProperty("height"); + var mainChunk = this._mainPanel.chunkForLine(lineNumber); + if (mainChunk.linesCount === 1) { + var gutterChunk = this._gutterPanel.makeLineAChunk(lineNumber); + var height = mainChunk.height; + if (height) + gutterChunk.element.style.setProperty("height", height + "px"); + else + gutterChunk.element.style.removeProperty("height"); + } else { + var gutterChunk = this._gutterPanel.chunkForLine(lineNumber); + if (gutterChunk.linesCount === 1) + gutterChunk.element.style.removeProperty("height"); + } } } @@ -193,6 +234,7 @@ WebInspector.TextEditorChunkedPanel = function(textModel) this._defaultChunkSize = 50; this._paintCoalescingLevel = 0; + this._domUpdateCoalescingLevel = 0; } WebInspector.TextEditorChunkedPanel.prototype = { @@ -222,23 +264,27 @@ WebInspector.TextEditorChunkedPanel.prototype = { chunk.removeDecoration(decoration); }, - textChanged: function(oldRange, newRange, oldText, newText) + textChanged: function(oldRange, newRange) { this._buildChunks(); }, _buildChunks: function() { - this.element.removeChildren(); + this.beginDomUpdates(); + + this._container.removeChildren(); this._textChunks = []; for (var i = 0; i < this._textModel.linesCount; i += this._defaultChunkSize) { var chunk = this._createNewChunk(i, i + this._defaultChunkSize); this._textChunks.push(chunk); - this.element.appendChild(chunk.element); + this._container.appendChild(chunk.element); } this._repaintAll(); + + this.endDomUpdates(); }, makeLineAChunk: function(lineNumber) @@ -251,6 +297,8 @@ WebInspector.TextEditorChunkedPanel.prototype = { if (oldChunk.linesCount === 1) return oldChunk; + this.beginDomUpdates(); + var wasExpanded = oldChunk.expanded; oldChunk.expanded = false; @@ -260,24 +308,24 @@ WebInspector.TextEditorChunkedPanel.prototype = { if (lineNumber > oldChunk.startLine) { var prefixChunk = this._createNewChunk(oldChunk.startLine, lineNumber); this._textChunks.splice(insertIndex++, 0, prefixChunk); - this.element.insertBefore(prefixChunk.element, oldChunk.element); + this._container.insertBefore(prefixChunk.element, oldChunk.element); } // Line chunk. var lineChunk = this._createNewChunk(lineNumber, lineNumber + 1); this._textChunks.splice(insertIndex++, 0, lineChunk); - this.element.insertBefore(lineChunk.element, oldChunk.element); + this._container.insertBefore(lineChunk.element, oldChunk.element); // Suffix chunk. if (oldChunk.startLine + oldChunk.linesCount > lineNumber + 1) { var suffixChunk = this._createNewChunk(lineNumber + 1, oldChunk.startLine + oldChunk.linesCount); this._textChunks.splice(insertIndex, 0, suffixChunk); - this.element.insertBefore(suffixChunk.element, oldChunk.element); + this._container.insertBefore(suffixChunk.element, oldChunk.element); } // Remove enclosing chunk. this._textChunks.splice(chunkNumber, 1); - this.element.removeChild(oldChunk.element); + this._container.removeChild(oldChunk.element); if (wasExpanded) { if (prefixChunk) @@ -287,11 +335,17 @@ WebInspector.TextEditorChunkedPanel.prototype = { suffixChunk.expanded = true; } + this.endDomUpdates(); + return lineChunk; }, _scroll: function() { + // FIXME: Replace the "2" with the padding-left value from CSS. + if (this.element.scrollLeft <= 2) + this.element.scrollLeft = 0; + this._scheduleRepaintAll(); if (this._syncScrollListener) this._syncScrollListener(); @@ -316,26 +370,52 @@ WebInspector.TextEditorChunkedPanel.prototype = { this._repaintAll(); }, + beginDomUpdates: function() + { + this._domUpdateCoalescingLevel++; + }, + + endDomUpdates: function() + { + this._domUpdateCoalescingLevel--; + }, + _chunkNumberForLine: function(lineNumber) { - for (var i = 0; i < this._textChunks.length; ++i) { - var line = this._textChunks[i].startLine; - if (lineNumber >= line && lineNumber < line + this._textChunks[i].linesCount) - return i; + function compareLineNumbers(value, chunk) + { + return value < chunk.startLine ? -1 : 1; } - return this._textChunks.length - 1; + var insertBefore = insertionIndexForObjectInListSortedByFunction(lineNumber, this._textChunks, compareLineNumbers); + return insertBefore - 1; }, - _chunkForLine: function(lineNumber) + chunkForLine: function(lineNumber) { return this._textChunks[this._chunkNumberForLine(lineNumber)]; }, + _findVisibleChunks: function(visibleFrom, visibleTo) + { + function compareOffsetTops(value, chunk) + { + return value < chunk.offsetTop ? -1 : 1; + } + var insertBefore = insertionIndexForObjectInListSortedByFunction(visibleFrom, this._textChunks, compareOffsetTops); + + var from = insertBefore - 1; + for (var to = from + 1; to < this._textChunks.length; ++to) { + if (this._textChunks[to].offsetTop >= visibleTo) + break; + } + return { start: from, end: to }; + }, + _repaintAll: function() { delete this._repaintAllTimer; - if (this._paintCoalescingLevel) + if (this._paintCoalescingLevel || this._dirtyLines) return; if (!this._textChunks) @@ -344,25 +424,10 @@ WebInspector.TextEditorChunkedPanel.prototype = { var visibleFrom = this.element.scrollTop; var visibleTo = this.element.scrollTop + this.element.clientHeight; - var offset = 0; - var fromIndex = -1; - var toIndex = 0; - for (var i = 0; i < this._textChunks.length; ++i) { - var chunk = this._textChunks[i]; - var chunkHeight = chunk.height; - if (offset + chunkHeight > visibleFrom && offset < visibleTo) { - if (fromIndex === -1) - fromIndex = i; - toIndex = i + 1; - } else { - if (offset >= visibleTo) - break; - } - offset += chunkHeight; + if (visibleTo) { + var result = this._findVisibleChunks(visibleFrom, visibleTo); + this._expandChunks(result.start, result.end); } - - if (toIndex) - this._expandChunks(fromIndex, toIndex); }, _totalHeight: function(firstElement, lastElement) @@ -370,11 +435,19 @@ WebInspector.TextEditorChunkedPanel.prototype = { lastElement = (lastElement || firstElement).nextElementSibling; if (lastElement) return lastElement.offsetTop - firstElement.offsetTop; - else if (firstElement.offsetParent) - return firstElement.offsetParent.scrollHeight - firstElement.offsetTop; - return firstElement.offsetHeight; + + var offsetParent = firstElement.offsetParent; + if (offsetParent && offsetParent.scrollHeight > offsetParent.clientHeight) + return offsetParent.scrollHeight - firstElement.offsetTop; + + var total = 0; + while (firstElement && firstElement !== lastElement) { + total += firstElement.offsetHeight; + firstElement = firstElement.nextElementSibling; + } + return total; }, - + resize: function() { this._repaintAll(); @@ -390,6 +463,10 @@ WebInspector.TextEditorGutterPanel = function(textModel, syncDecorationsForLineL this.element = document.createElement("div"); this.element.className = "text-editor-lines"; + this._container = document.createElement("div"); + this._container.className = "inner-container"; + this.element.appendChild(this._container); + this.element.addEventListener("scroll", this._scroll.bind(this), false); this.freeCachedElements(); @@ -409,9 +486,59 @@ WebInspector.TextEditorGutterPanel.prototype = { _expandChunks: function(fromIndex, toIndex) { - for (var i = 0; i < this._textChunks.length; ++i) { + for (var i = 0; i < this._textChunks.length; ++i) this._textChunks[i].expanded = (fromIndex <= i && i < toIndex); + }, + + textChanged: function(oldRange, newRange) + { + if (!this._textChunks) { + this._buildChunks(); + return; } + + var linesDiff = newRange.linesCount - oldRange.linesCount; + if (linesDiff) { + // Remove old chunks (if needed). + for (var chunkNumber = this._textChunks.length - 1; chunkNumber >= 0 ; --chunkNumber) { + var chunk = this._textChunks[chunkNumber]; + if (chunk.startLine + chunk.linesCount <= this._textModel.linesCount) + break; + chunk.expanded = false; + this._container.removeChild(chunk.element); + } + this._textChunks.length = chunkNumber + 1; + + // Add new chunks (if needed). + var totalLines = 0; + if (this._textChunks.length) { + var lastChunk = this._textChunks[this._textChunks.length - 1]; + totalLines = lastChunk.startLine + lastChunk.linesCount; + } + for (var i = totalLines; i < this._textModel.linesCount; i += this._defaultChunkSize) { + var chunk = this._createNewChunk(i, i + this._defaultChunkSize); + this._textChunks.push(chunk); + this._container.appendChild(chunk.element); + } + this._repaintAll(); + } else { + // Decorations may have been removed, so we may have to sync those lines. + var chunkNumber = this._chunkNumberForLine(newRange.startLine); + var chunk = this._textChunks[chunkNumber]; + while (chunk && chunk.startLine <= newRange.endLine) { + if (chunk.linesCount === 1) + this._syncDecorationsForLineListener(chunk.startLine); + chunk = this._textChunks[++chunkNumber]; + } + } + }, + + syncClientHeight: function(clientHeight) + { + if (this.element.offsetHeight > clientHeight) + this._container.style.setProperty("padding-bottom", (this.element.offsetHeight - clientHeight) + "px"); + else + this._container.style.removeProperty("padding-bottom"); } } @@ -444,9 +571,8 @@ WebInspector.TextEditorGutterChunk = function(textViewer, startLine, endLine) this.element.appendChild(outerSpan); } else { var lineNumbers = []; - for (var i = startLine; i < endLine; ++i) { + for (var i = startLine; i < endLine; ++i) lineNumbers.push(i + 1); - } this.element.textContent = lineNumbers.join("\n"); } } @@ -454,16 +580,18 @@ WebInspector.TextEditorGutterChunk = function(textViewer, startLine, endLine) WebInspector.TextEditorGutterChunk.prototype = { addDecoration: function(decoration) { - if (typeof decoration === "string") { + this._textViewer.beginDomUpdates(); + if (typeof decoration === "string") this.element.addStyleClass(decoration); - } + this._textViewer.endDomUpdates(); }, removeDecoration: function(decoration) { - if (typeof decoration === "string") { + this._textViewer.beginDomUpdates(); + if (typeof decoration === "string") this.element.removeStyleClass(decoration); - } + this._textViewer.endDomUpdates(); }, get expanded() @@ -484,6 +612,8 @@ WebInspector.TextEditorGutterChunk.prototype = { if (this.linesCount === 1) return; + this._textViewer.beginDomUpdates(); + if (expanded) { this._expandedLineRows = []; var parentElement = this.element.parentElement; @@ -503,12 +633,14 @@ WebInspector.TextEditorGutterChunk.prototype = { elementInserted = true; parentElement.insertBefore(this.element, lineRow); } - this._textViewer._cachedRows.push(lineRow); parentElement.removeChild(lineRow); } + this._textViewer._cachedRows.push(lineRow); } delete this._expandedLineRows; } + + this._textViewer.endDomUpdates(); }, get height() @@ -518,6 +650,11 @@ WebInspector.TextEditorGutterChunk.prototype = { return this._textViewer._totalHeight(this._expandedLineRows[0], this._expandedLineRows[this._expandedLineRows.length - 1]); }, + get offsetTop() + { + return (this._expandedLineRows && this._expandedLineRows.length) ? this._expandedLineRows[0].offsetTop : this.element.offsetTop; + }, + _createRow: function(lineNumber) { var lineRow = this._textViewer._cachedRows.pop() || document.createElement("div"); @@ -528,27 +665,42 @@ WebInspector.TextEditorGutterChunk.prototype = { } } -WebInspector.TextEditorMainPanel = function(textModel, url, syncScrollListener, syncDecorationsForLineListener) +WebInspector.TextEditorMainPanel = function(textModel, url, syncScrollListener, syncDecorationsForLineListener, enterTextChangeMode, exitTextChangeMode) { WebInspector.TextEditorChunkedPanel.call(this, textModel); this._syncScrollListener = syncScrollListener; this._syncDecorationsForLineListener = syncDecorationsForLineListener; + this._enterTextChangeMode = enterTextChangeMode; + this._exitTextChangeMode = exitTextChangeMode; this._url = url; this._highlighter = new WebInspector.TextEditorHighlighter(textModel, this._highlightDataReady.bind(this)); + this._readOnly = true; this.element = document.createElement("div"); this.element.className = "text-editor-contents"; this.element.tabIndex = 0; + this._container = document.createElement("div"); + this._container.className = "inner-container"; + this._container.tabIndex = 0; + this.element.appendChild(this._container); + this.element.addEventListener("scroll", this._scroll.bind(this), false); - this.element.addEventListener("keydown", this._handleKeyDown.bind(this), false); - var handleDOMUpdates = this._handleDOMUpdates.bind(this); - this.element.addEventListener("DOMCharacterDataModified", handleDOMUpdates, false); - this.element.addEventListener("DOMNodeInserted", handleDOMUpdates, false); - this.element.addEventListener("DOMNodeRemoved", handleDOMUpdates, false); + // FIXME: Remove old live editing functionality and Preferences.sourceEditorEnabled flag. + if (!Preferences.sourceEditorEnabled) + this._container.addEventListener("keydown", this._handleKeyDown.bind(this), false); + + // In WebKit the DOMNodeRemoved event is fired AFTER the node is removed, thus it should be + // attached to all DOM nodes that we want to track. Instead, we attach the DOMNodeRemoved + // listeners only on the line rows, and use DOMSubtreeModified to track node removals inside + // the line rows. For more info see: https://bugs.webkit.org/show_bug.cgi?id=55666 + this._handleDOMUpdatesCallback = this._handleDOMUpdates.bind(this); + this._container.addEventListener("DOMCharacterDataModified", this._handleDOMUpdatesCallback, false); + this._container.addEventListener("DOMNodeInserted", this._handleDOMUpdatesCallback, false); + this._container.addEventListener("DOMSubtreeModified", this._handleDOMUpdatesCallback, false); this.freeCachedElements(); this._buildChunks(); @@ -560,6 +712,21 @@ WebInspector.TextEditorMainPanel.prototype = { this._highlighter.mimeType = mimeType; }, + set readOnly(readOnly) + { + // FIXME: Remove the Preferences.sourceEditorEnabled flag. + if (!Preferences.sourceEditorEnabled) + return; + + this.beginDomUpdates(); + this._readOnly = readOnly; + if (this._readOnly) + this._container.removeStyleClass("text-editor-editable"); + else + this._container.addStyleClass("text-editor-editable"); + this.endDomUpdates(); + }, + markAndRevealRange: function(range) { if (this._rangeToMark) { @@ -653,6 +820,9 @@ WebInspector.TextEditorMainPanel.prototype = { _buildChunks: function() { this._highlighter.reset(); + for (var i = 0; i < this._textModel.linesCount; ++i) + this._textModel.removeAttribute(i, "highlight"); + WebInspector.TextEditorChunkedPanel.prototype._buildChunks.call(this); }, @@ -672,9 +842,8 @@ WebInspector.TextEditorMainPanel.prototype = { this._highlighter.highlight(lastVisibleLine); delete this._muteHighlightListener; - for (var i = 0; i < this._textChunks.length; ++i) { + for (var i = 0; i < this._textChunks.length; ++i) this._textChunks[i].expanded = (fromIndex <= i && i < toIndex); - } this._restoreSelection(selection); }, @@ -686,13 +855,46 @@ WebInspector.TextEditorMainPanel.prototype = { this._paintLines(fromLine, toLine, true /*restoreSelection*/); }, + _markSkippedPaintLines: function(startLine, endLine) + { + if (!this._skippedPaintLines) + this._skippedPaintLines = [ { startLine: startLine, endLine: endLine } ]; + else { + for (var i = 0; i < this._skippedPaintLines.length; ++i) { + var chunk = this._skippedPaintLines[i]; + if (chunk.startLine <= endLine && chunk.endLine >= startLine) { + chunk.startLine = Math.min(chunk.startLine, startLine); + chunk.endLine = Math.max(chunk.endLine, endLine); + return; + } + } + this._skippedPaintLines.push({ startLine: startLine, endLine: endLine }); + } + }, + + _paintSkippedLines: function() + { + if (!this._skippedPaintLines || this._dirtyLines) + return; + for (var i = 0; i < this._skippedPaintLines.length; ++i) { + var chunk = this._skippedPaintLines[i]; + this._paintLines(chunk.startLine, chunk.endLine); + } + delete this._skippedPaintLines; + }, + _paintLines: function(fromLine, toLine, restoreSelection) { + if (this._dirtyLines) { + this._markSkippedPaintLines(fromLine, toLine); + return; + } + var selection; - var chunk = this._chunkForLine(fromLine); + var chunk = this.chunkForLine(fromLine); for (var i = fromLine; i < toLine; ++i) { if (i >= chunk.startLine + chunk.linesCount) - chunk = this._chunkForLine(i); + chunk = this.chunkForLine(i); var lineRow = chunk.getExpandedLineRow(i); if (!lineRow) continue; @@ -706,46 +908,56 @@ WebInspector.TextEditorMainPanel.prototype = { _paintLine: function(lineRow, lineNumber) { - var highlight = this._textModel.getAttribute(lineNumber, "highlight"); - if (!highlight) { - if (this._rangeToMark && this._rangeToMark.startLine === lineNumber) - this._markedRangeElement = highlightSearchResult(lineRow, this._rangeToMark.startColumn, this._rangeToMark.endColumn - this._rangeToMark.startColumn); + if (this._dirtyLines) { + this._markSkippedPaintLines(lineNumber, lineNumber + 1); return; } - lineRow.removeChildren(); - var line = this._textModel.line(lineNumber); - if (!line) - lineRow.appendChild(document.createElement("br")); - - var plainTextStart = -1; - for (var j = 0; j < line.length;) { - if (j > 1000) { - // This line is too long - do not waste cycles on minified js highlighting. - if (plainTextStart === -1) - plainTextStart = j; - break; + this.beginDomUpdates(); + try { + var highlight = this._textModel.getAttribute(lineNumber, "highlight"); + if (!highlight) { + if (this._rangeToMark && this._rangeToMark.startLine === lineNumber) + this._markedRangeElement = highlightSearchResult(lineRow, this._rangeToMark.startColumn, this._rangeToMark.endColumn - this._rangeToMark.startColumn); + return; } - var attribute = highlight[j]; - if (!attribute || !attribute.tokenType) { - if (plainTextStart === -1) - plainTextStart = j; - j++; - } else { - if (plainTextStart !== -1) { - this._appendTextNode(lineRow, line.substring(plainTextStart, j)); - plainTextStart = -1; + + lineRow.removeChildren(); + var line = this._textModel.line(lineNumber); + if (!line) + lineRow.appendChild(document.createElement("br")); + + var plainTextStart = -1; + for (var j = 0; j < line.length;) { + if (j > 1000) { + // This line is too long - do not waste cycles on minified js highlighting. + if (plainTextStart === -1) + plainTextStart = j; + break; + } + var attribute = highlight[j]; + if (!attribute || !attribute.tokenType) { + if (plainTextStart === -1) + plainTextStart = j; + j++; + } else { + if (plainTextStart !== -1) { + this._appendTextNode(lineRow, line.substring(plainTextStart, j)); + plainTextStart = -1; + } + this._appendSpan(lineRow, line.substring(j, j + attribute.length), attribute.tokenType); + j += attribute.length; } - this._appendSpan(lineRow, line.substring(j, j + attribute.length), attribute.tokenType); - j += attribute.length; } + if (plainTextStart !== -1) + this._appendTextNode(lineRow, line.substring(plainTextStart, line.length)); + if (this._rangeToMark && this._rangeToMark.startLine === lineNumber) + this._markedRangeElement = highlightSearchResult(lineRow, this._rangeToMark.startColumn, this._rangeToMark.endColumn - this._rangeToMark.startColumn); + if (lineRow.decorationsElement) + lineRow.appendChild(lineRow.decorationsElement); + } finally { + this.endDomUpdates(); } - if (plainTextStart !== -1) - this._appendTextNode(lineRow, line.substring(plainTextStart, line.length)); - if (this._rangeToMark && this._rangeToMark.startLine === lineNumber) - this._markedRangeElement = highlightSearchResult(lineRow, this._rangeToMark.startColumn, this._rangeToMark.endColumn - this._rangeToMark.startColumn); - if (lineRow.decorationsElement) - lineRow.appendChild(lineRow.decorationsElement); }, _releaseLinesHighlight: function(lineRow) @@ -774,7 +986,7 @@ WebInspector.TextEditorMainPanel.prototype = { return null; var selectionRange = selection.getRangeAt(0); // Selection may be outside of the viewer. - if (!this.element.isAncestor(selectionRange.startContainer) || !this.element.isAncestor(selectionRange.endContainer)) + if (!this._container.isAncestor(selectionRange.startContainer) || !this._container.isAncestor(selectionRange.endContainer)) return null; var start = this._selectionToPosition(selectionRange.startContainer, selectionRange.startOffset); var end = selectionRange.collapsed ? start : this._selectionToPosition(selectionRange.endContainer, selectionRange.endOffset); @@ -795,9 +1007,9 @@ WebInspector.TextEditorMainPanel.prototype = { _selectionToPosition: function(container, offset) { - if (container === this.element && offset === 0) + if (container === this._container && offset === 0) return { line: 0, column: 0 }; - if (container === this.element && offset === 1) + if (container === this._container && offset === 1) return { line: this._textModel.linesCount - 1, column: this._textModel.lineLength(this._textModel.linesCount - 1) }; var lineRow = container.enclosingNodeOrSelfWithNodeName("DIV"); @@ -835,7 +1047,7 @@ WebInspector.TextEditorMainPanel.prototype = { _positionToSelection: function(line, column) { - var chunk = this._chunkForLine(line); + var chunk = this.chunkForLine(line); var lineRow = chunk.getExpandedLineRow(line); if (lineRow) var rangeBoundary = lineRow.rangeBoundaryForOffset(column); @@ -909,17 +1121,268 @@ WebInspector.TextEditorMainPanel.prototype = { _handleDOMUpdates: function(e) { + if (this._domUpdateCoalescingLevel) + return; + var target = e.target; + if (target === this._container) + return; + var lineRow = target.enclosingNodeOrSelfWithClass("webkit-line-content"); - if (lineRow === target || !lineRow || !lineRow.decorationsElement || !lineRow.decorationsElement.isAncestor(target)) + if (!lineRow) return; - if (this._syncDecorationsForLineListener) { - // Wait until this event is processed and only then sync the sizes. This is necessary in - // case of the DOMNodeRemoved event, because it is dispatched before the removal takes place. - setTimeout(function() { + + if (lineRow.decorationsElement && (lineRow.decorationsElement === target || lineRow.decorationsElement.isAncestor(target))) { + if (this._syncDecorationsForLineListener) this._syncDecorationsForLineListener(lineRow.lineNumber); - }.bind(this), 0); + return; + } + + if (this._readOnly) + return; + + var lineNumber = lineRow.lineNumber; + if (this._dirtyLines) { + this._dirtyLines.start = Math.min(this._dirtyLines.start, lineNumber); + this._dirtyLines.end = Math.max(this._dirtyLines.end, lineNumber + 1); + } else { + this._dirtyLines = { start: lineNumber, end: lineNumber + 1 }; + setTimeout(this._applyDomUpdates.bind(this), 0); + // Remove marked ranges, if any. + this.markAndRevealRange(null); + } + }, + + _applyDomUpdates: function() + { + if (!this._dirtyLines) + return; + + // Check if the editor had been set readOnly by the moment when this async callback got executed. + if (this._readOnly) { + delete this._dirtyLines; + return; + } + + // This is a "foreign" call outside of this class. Should be before we delete the dirty lines flag. + this._enterTextChangeMode(); + + var dirtyLines = this._dirtyLines; + delete this._dirtyLines; + + var firstChunkNumber = this._chunkNumberForLine(dirtyLines.start); + var startLine = this._textChunks[firstChunkNumber].startLine; + var endLine = this._textModel.linesCount; + + // Collect lines. + var firstLineRow; + if (firstChunkNumber) { + var chunk = this._textChunks[firstChunkNumber - 1]; + firstLineRow = chunk.expanded ? chunk.getExpandedLineRow(chunk.startLine + chunk.linesCount - 1) : chunk.element; + firstLineRow = firstLineRow.nextSibling; + } else + firstLineRow = this._container.firstChild; + + var lines = []; + for (var lineRow = firstLineRow; lineRow; lineRow = lineRow.nextSibling) { + if (typeof lineRow.lineNumber === "number" && lineRow.lineNumber >= dirtyLines.end) { + endLine = lineRow.lineNumber; + break; + } + // Update with the newest lineNumber, so that the call to the _getSelection method below should work. + lineRow.lineNumber = startLine + lines.length; + this._collectLinesFromDiv(lines, lineRow); + } + + // Try to decrease the range being replaced if possible. + var startOffset = 0; + while (startLine < dirtyLines.start && startOffset < lines.length) { + if (this._textModel.line(startLine) !== lines[startOffset]) + break; + ++startOffset; + ++startLine; + } + + var endOffset = lines.length; + while (endLine > dirtyLines.end && endOffset > startOffset) { + if (this._textModel.line(endLine - 1) !== lines[endOffset - 1]) + break; + --endOffset; + --endLine; + } + + lines = lines.slice(startOffset, endOffset); + + var selection = this._getSelection(); + + if (lines.length === 0 && endLine < this._textModel.linesCount) { + var oldRange = new WebInspector.TextRange(startLine, 0, endLine, 0); + var newRange = this._textModel.setText(oldRange, ""); + } else { + var oldRange = new WebInspector.TextRange(startLine, 0, endLine - 1, this._textModel.lineLength(endLine - 1)); + var newRange = this._textModel.setText(oldRange, lines.join("\n")); + } + + this.beginDomUpdates(); + this._removeDecorationsInRange(oldRange); + this._updateChunksForRanges(oldRange, newRange); + this._updateHighlightsForRange(newRange); + this._paintSkippedLines(); + this.endDomUpdates(); + + this._restoreSelection(selection); + + this._exitTextChangeMode(oldRange, newRange); + }, + + _removeDecorationsInRange: function(range) + { + for (var i = this._chunkNumberForLine(range.startLine); i < this._textChunks.length; ++i) { + var chunk = this._textChunks[i]; + if (chunk.startLine > range.endLine) + break; + chunk.removeAllDecorations(); + } + }, + + _updateChunksForRanges: function(oldRange, newRange) + { + // Update the chunks in range: firstChunkNumber <= index <= lastChunkNumber + var firstChunkNumber = this._chunkNumberForLine(oldRange.startLine); + var lastChunkNumber = firstChunkNumber; + while (lastChunkNumber + 1 < this._textChunks.length) { + if (this._textChunks[lastChunkNumber + 1].startLine > oldRange.endLine) + break; + ++lastChunkNumber; + } + + var startLine = this._textChunks[firstChunkNumber].startLine; + var linesCount = this._textChunks[lastChunkNumber].startLine + this._textChunks[lastChunkNumber].linesCount - startLine; + var linesDiff = newRange.linesCount - oldRange.linesCount; + linesCount += linesDiff; + + if (linesDiff) { + // Lines shifted, update the line numbers of the chunks below. + for (var chunkNumber = lastChunkNumber + 1; chunkNumber < this._textChunks.length; ++chunkNumber) + this._textChunks[chunkNumber].startLine += linesDiff; + } + + var firstLineRow; + if (firstChunkNumber) { + var chunk = this._textChunks[firstChunkNumber - 1]; + firstLineRow = chunk.expanded ? chunk.getExpandedLineRow(chunk.startLine + chunk.linesCount - 1) : chunk.element; + firstLineRow = firstLineRow.nextSibling; + } else + firstLineRow = this._container.firstChild; + + // Most frequent case: a chunk remained the same. + for (var chunkNumber = firstChunkNumber; chunkNumber <= lastChunkNumber; ++chunkNumber) { + var chunk = this._textChunks[chunkNumber]; + var lineNumber = chunk.startLine; + for (var lineRow = firstLineRow; lineRow && lineNumber < chunk.startLine + chunk.linesCount; lineRow = lineRow.nextSibling) { + if (lineRow.lineNumber !== lineNumber || lineRow !== chunk.getExpandedLineRow(lineNumber) || lineRow.textContent !== this._textModel.line(lineNumber) || !lineRow.firstChild) + break; + ++lineNumber; + } + if (lineNumber < chunk.startLine + chunk.linesCount) + break; + chunk.updateCollapsedLineRow(); + ++firstChunkNumber; + firstLineRow = lineRow; + startLine += chunk.linesCount; + linesCount -= chunk.linesCount; + } + + if (firstChunkNumber > lastChunkNumber && linesCount === 0) + return; + + // Maybe merge with the next chunk, so that we should not create 1-sized chunks when appending new lines one by one. + var chunk = this._textChunks[lastChunkNumber + 1]; + var linesInLastChunk = linesCount % this._defaultChunkSize; + if (chunk && !chunk.decorated && linesInLastChunk > 0 && linesInLastChunk + chunk.linesCount <= this._defaultChunkSize) { + ++lastChunkNumber; + linesCount += chunk.linesCount; + } + + var scrollTop = this.element.scrollTop; + var scrollLeft = this.element.scrollLeft; + + // Delete all DOM elements that were either controlled by the old chunks, or have just been inserted. + var firstUnmodifiedLineRow = null; + var chunk = this._textChunks[lastChunkNumber + 1]; + if (chunk) { + firstUnmodifiedLineRow = chunk.expanded ? chunk.getExpandedLineRow(chunk.startLine) : chunk.element; } + while (firstLineRow && firstLineRow !== firstUnmodifiedLineRow) { + var lineRow = firstLineRow; + firstLineRow = firstLineRow.nextSibling; + this._container.removeChild(lineRow); + } + + // Replace old chunks with the new ones. + for (var chunkNumber = firstChunkNumber; linesCount > 0; ++chunkNumber) { + var chunkLinesCount = Math.min(this._defaultChunkSize, linesCount); + var newChunk = this._createNewChunk(startLine, startLine + chunkLinesCount); + this._container.insertBefore(newChunk.element, firstUnmodifiedLineRow); + + if (chunkNumber <= lastChunkNumber) + this._textChunks[chunkNumber] = newChunk; + else + this._textChunks.splice(chunkNumber, 0, newChunk); + startLine += chunkLinesCount; + linesCount -= chunkLinesCount; + } + if (chunkNumber <= lastChunkNumber) + this._textChunks.splice(chunkNumber, lastChunkNumber - chunkNumber + 1); + + this.element.scrollTop = scrollTop; + this.element.scrollLeft = scrollLeft; + }, + + _updateHighlightsForRange: function(range) + { + var visibleFrom = this.element.scrollTop; + var visibleTo = this.element.scrollTop + this.element.clientHeight; + + var result = this._findVisibleChunks(visibleFrom, visibleTo); + var chunk = this._textChunks[result.end - 1]; + var lastVisibleLine = chunk.startLine + chunk.linesCount; + + lastVisibleLine = Math.max(lastVisibleLine, range.endLine); + + var updated = this._highlighter.updateHighlight(range.startLine, lastVisibleLine); + if (!updated) { + // Highlights for the chunks below are invalid, so just collapse them. + for (var i = this._chunkNumberForLine(range.startLine); i < this._textChunks.length; ++i) + this._textChunks[i].expanded = false; + } + + this._repaintAll(); + }, + + _collectLinesFromDiv: function(lines, element) + { + var textContents = []; + var node = element.traverseNextNode(element); + while (node) { + if (element.decorationsElement === node) { + node = node.nextSibling; + continue; + } + if (node.nodeName.toLowerCase() === "br") + textContents.push("\n"); + else if (node.nodeType === Node.TEXT_NODE) + textContents.push(node.textContent); + node = node.traverseNextNode(element); + } + + var textContent = textContents.join(""); + // The last \n (if any) does not "count" in a DIV. + textContent = textContent.replace(/\n$/, ""); + + textContents = textContent.split("\n"); + for (var i = 0; i < textContents.length; ++i) + lines.push(textContents[i]); } } @@ -933,49 +1396,73 @@ WebInspector.TextEditorMainChunk = function(textViewer, startLine, endLine) this.element = document.createElement("div"); this.element.lineNumber = startLine; this.element.className = "webkit-line-content"; + this.element.addEventListener("DOMNodeRemoved", this._textViewer._handleDOMUpdatesCallback, false); - this.startLine = startLine; + this._startLine = startLine; endLine = Math.min(this._textModel.linesCount, endLine); this.linesCount = endLine - startLine; this._expanded = false; - var lines = []; - for (var i = startLine; i < endLine; ++i) { - lines.push(this._textModel.line(i)); - } - - this.element.textContent = lines.join("\n"); - - // The last empty line will get swallowed otherwise. - if (!lines[lines.length - 1]) - this.element.appendChild(document.createElement("br")); + this.updateCollapsedLineRow(); } WebInspector.TextEditorMainChunk.prototype = { addDecoration: function(decoration) { - if (typeof decoration === "string") { + this._textViewer.beginDomUpdates(); + if (typeof decoration === "string") this.element.addStyleClass(decoration); - return; - } - if (!this.element.decorationsElement) { - this.element.decorationsElement = document.createElement("div"); - this.element.decorationsElement.className = "webkit-line-decorations"; - this.element.appendChild(this.element.decorationsElement); + else { + if (!this.element.decorationsElement) { + this.element.decorationsElement = document.createElement("div"); + this.element.decorationsElement.className = "webkit-line-decorations"; + this.element.appendChild(this.element.decorationsElement); + } + this.element.decorationsElement.appendChild(decoration); } - this.element.decorationsElement.appendChild(decoration); + this._textViewer.endDomUpdates(); }, removeDecoration: function(decoration) { - if (typeof decoration === "string") { + this._textViewer.beginDomUpdates(); + if (typeof decoration === "string") this.element.removeStyleClass(decoration); - return; + else if (this.element.decorationsElement) + this.element.decorationsElement.removeChild(decoration); + this._textViewer.endDomUpdates(); + }, + + removeAllDecorations: function() + { + this._textViewer.beginDomUpdates(); + this.element.className = "webkit-line-content"; + if (this.element.decorationsElement) { + this.element.removeChild(this.element.decorationsElement); + delete this.element.decorationsElement; + } + this._textViewer.endDomUpdates(); + }, + + get decorated() + { + return this.element.className !== "webkit-line-content" || !!(this.element.decorationsElement && this.element.decorationsElement.firstChild); + }, + + get startLine() + { + return this._startLine; + }, + + set startLine(startLine) + { + this._startLine = startLine; + this.element.lineNumber = startLine; + if (this._expandedLineRows) { + for (var i = 0; i < this._expandedLineRows.length; ++i) + this._expandedLineRows[i].lineNumber = startLine + i; } - if (!this.element.decorationsElement) - return; - this.element.decorationsElement.removeChild(decoration); }, get expanded() @@ -996,6 +1483,8 @@ WebInspector.TextEditorMainChunk.prototype = { return; } + this._textViewer.beginDomUpdates(); + if (expanded) { this._expandedLineRows = []; var parentElement = this.element.parentElement; @@ -1016,12 +1505,14 @@ WebInspector.TextEditorMainChunk.prototype = { elementInserted = true; parentElement.insertBefore(this.element, lineRow); } - this._textViewer._releaseLinesHighlight(lineRow); parentElement.removeChild(lineRow); } + this._textViewer._releaseLinesHighlight(lineRow); } delete this._expandedLineRows; } + + this._textViewer.endDomUpdates(); }, get height() @@ -1031,11 +1522,17 @@ WebInspector.TextEditorMainChunk.prototype = { return this._textViewer._totalHeight(this._expandedLineRows[0], this._expandedLineRows[this._expandedLineRows.length - 1]); }, + get offsetTop() + { + return (this._expandedLineRows && this._expandedLineRows.length) ? this._expandedLineRows[0].offsetTop : this.element.offsetTop; + }, + _createRow: function(lineNumber) { var lineRow = this._textViewer._cachedRows.pop() || document.createElement("div"); lineRow.lineNumber = lineNumber; lineRow.className = "webkit-line-content"; + lineRow.addEventListener("DOMNodeRemoved", this._textViewer._handleDOMUpdatesCallback, false); lineRow.textContent = this._textModel.line(lineNumber); if (!lineRow.textContent) lineRow.appendChild(document.createElement("br")); @@ -1049,5 +1546,22 @@ WebInspector.TextEditorMainChunk.prototype = { if (!this._expandedLineRows) return this.element; return this._expandedLineRows[lineNumber - this.startLine]; + }, + + updateCollapsedLineRow: function() + { + if (this.linesCount === 1 && this._expanded) + return; + + var lines = []; + for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) + lines.push(this._textModel.line(i)); + + this.element.removeChildren(); + this.element.textContent = lines.join("\n"); + + // The last empty line will get swallowed otherwise. + if (!lines[lines.length - 1]) + this.element.appendChild(document.createElement("br")); } } diff --git a/Source/WebCore/inspector/front-end/TimelinePanel.js b/Source/WebCore/inspector/front-end/TimelinePanel.js index 1d8b9c9..62c5de0 100644 --- a/Source/WebCore/inspector/front-end/TimelinePanel.js +++ b/Source/WebCore/inspector/front-end/TimelinePanel.js @@ -270,10 +270,10 @@ WebInspector.TimelinePanel.prototype = { _toggleTimelineButtonClicked: function() { if (this.toggleTimelineButton.toggled) - InspectorBackend.stopTimelineProfiler(); + TimelineAgent.stop(); else { this._clearPanel(); - InspectorBackend.startTimelineProfiler(); + TimelineAgent.start(); } }, @@ -865,7 +865,6 @@ WebInspector.TimelinePanel.FormattedRecord = function(record, parentRecord, pane this.endTime = (typeof record.endTime !== "undefined") ? record.endTime / 1000 : this.startTime; this._selfTime = this.endTime - this.startTime; this._lastChildEndTime = this.endTime; - this.originalRecordForTests = record; if (record.stackTrace && record.stackTrace.length) this.stackTrace = record.stackTrace; this.totalHeapSize = record.totalHeapSize; diff --git a/Source/WebCore/inspector/front-end/Toolbar.js b/Source/WebCore/inspector/front-end/Toolbar.js new file mode 100755 index 0000000..d1cc9a6 --- /dev/null +++ b/Source/WebCore/inspector/front-end/Toolbar.js @@ -0,0 +1,220 @@ + /* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com). + * Copyright (C) 2009 Joseph Pecoraro + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 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.Toolbar = function() +{ + this.element = document.getElementById("toolbar"); + this.element.addEventListener("mousedown", this._toolbarDragStart.bind(this), true); + + this._dropdownButton = document.getElementById("toolbar-dropdown-arrow"); + this._dropdownButton.addEventListener("click", this._toggleDropdown.bind(this), false); + + document.getElementById("close-button-left").addEventListener("click", this._onClose, true); + document.getElementById("close-button-right").addEventListener("click", this._onClose, true); +} + +WebInspector.Toolbar.prototype = { + resize: function() + { + this._updateDropdownButtonAndHideDropdown(); + }, + + addPanel: function(panel) + { + this.element.appendChild(panel.toolbarItem); + this.resize(); + }, + + _toolbarDragStart: function(event) + { + if ((!WebInspector.attached && WebInspector.platformFlavor !== WebInspector.PlatformFlavor.MacLeopard && WebInspector.platformFlavor !== WebInspector.PlatformFlavor.MacSnowLeopard) || WebInspector.port == "qt") + return; + + var target = event.target; + if (target.hasStyleClass("toolbar-item") && target.hasStyleClass("toggleable")) + return; + + if (target !== this.element && !target.hasStyleClass("toolbar-item")) + return; + + this.element.lastScreenX = event.screenX; + this.element.lastScreenY = event.screenY; + + WebInspector.elementDragStart(this.element, this._toolbarDrag.bind(this), this._toolbarDragEnd.bind(this), event, (WebInspector.attached ? "row-resize" : "default")); + }, + + _toolbarDragEnd: function(event) + { + WebInspector.elementDragEnd(event); + + delete this.element.lastScreenX; + delete this.element.lastScreenY; + }, + + _toolbarDrag: function(event) + { + if (WebInspector.attached) { + var height = window.innerHeight - (event.screenY - this.element.lastScreenY); + + InspectorFrontendHost.setAttachedWindowHeight(height); + } else { + var x = event.screenX - this.element.lastScreenX; + var y = event.screenY - this.element.lastScreenY; + + // We cannot call window.moveBy here because it restricts the movement + // of the window at the edges. + InspectorFrontendHost.moveWindowBy(x, y); + } + + this.element.lastScreenX = event.screenX; + this.element.lastScreenY = event.screenY; + + event.preventDefault(); + }, + + _onClose: function() + { + WebInspector.close(); + }, + + _setDropdownVisible: function(visible) + { + if (!this._dropdown) { + if (!visible) + return; + this._dropdown = new WebInspector.ToolbarDropdown(); + } + if (visible) + this._dropdown.show(); + else + this._dropdown.hide(); + }, + + _toggleDropdown: function() + { + this._setDropdownVisible(!this._dropdown || !this._dropdown.visible); + }, + + _updateDropdownButtonAndHideDropdown: function() + { + this._setDropdownVisible(false); + + var toolbar = document.getElementById("toolbar"); + if (this.element.scrollHeight > this.element.clientHeight) + this._dropdownButton.removeStyleClass("hidden"); + else + this._dropdownButton.addStyleClass("hidden"); + } +}; + +WebInspector.Toolbar.createPanelToolbarItem = function(panel) +{ + var toolbarItem = document.createElement("button"); + toolbarItem.className = "toolbar-item toggleable"; + toolbarItem.panel = panel; + toolbarItem.addStyleClass(panel._panelName); + function onToolbarItemClicked() + { + WebInspector.toolbar._updateDropdownButtonAndHideDropdown(); + WebInspector.currentPanel = panel; + } + toolbarItem.addEventListener("click", onToolbarItemClicked); + + var iconElement = toolbarItem.createChild("div", "toolbar-icon"); + + if ("toolbarItemLabel" in panel) + toolbarItem.createChild("div", "toolbar-label").textContent = panel.toolbarItemLabel; + + if (panel === WebInspector.currentPanel) + toolbarItem.addStyleClass("toggled-on"); + + return toolbarItem; +} + +WebInspector.ToolbarDropdown = function() +{ + this._toolbar = document.getElementById("toolbar"); + this._arrow = document.getElementById("toolbar-dropdown-arrow"); + this.element = document.createElement("div"); + this.element.id = "toolbar-dropdown"; + this._contentElement = this.element.createChild("div", "scrollable-content"); + this._contentElement.tabIndex = 0; + this._contentElement.addEventListener("keydown", this._onKeyDown.bind(this), true); +} + +WebInspector.ToolbarDropdown.prototype = { + show: function() + { + if (this.visible) + return; + var style = this.element.style; + this._populate(); + var top = this._arrow.totalOffsetTop + this._arrow.clientHeight; + this._arrow.addStyleClass("dropdown-visible"); + this.element.style.top = top + "px"; + this.element.style.left = this._arrow.totalOffsetLeft + "px"; + this._contentElement.style.maxHeight = window.innerHeight - top - 20 + "px"; + this._toolbar.appendChild(this.element); + WebInspector.currentFocusElement = this.contentElement; + }, + + hide: function() + { + if (!this.visible) + return; + this._arrow.removeStyleClass("dropdown-visible"); + this.element.parentNode.removeChild(this.element); + this._contentElement.removeChildren(); + }, + + get visible() + { + return !!this.element.parentNode; + }, + + _populate: function() + { + var toolbarItems = this._toolbar.querySelectorAll(".toolbar-item.toggleable"); + + for (var i = 0; i < toolbarItems.length; ++i) { + if (toolbarItems[i].offsetTop > 0) + this._contentElement.appendChild(WebInspector.Toolbar.createPanelToolbarItem(toolbarItems[i].panel)); + } + }, + + _onKeyDown: function(event) + { + if (event.keyCode !== WebInspector.KeyboardShortcut.Keys.Esc.code) + return; + event.stopPropagation(); + this.hide(); + } +}; diff --git a/Source/WebCore/inspector/front-end/WatchExpressionsSidebarPane.js b/Source/WebCore/inspector/front-end/WatchExpressionsSidebarPane.js index a6f59ca..bb3460d 100644 --- a/Source/WebCore/inspector/front-end/WatchExpressionsSidebarPane.js +++ b/Source/WebCore/inspector/front-end/WatchExpressionsSidebarPane.js @@ -120,7 +120,7 @@ WebInspector.WatchExpressionsSection.prototype = { } // TODO: pass exact injected script id. - InspectorBackend.releaseWrapperObjectGroup(0, this._watchObjectGroupId) + RuntimeAgent.releaseObjectGroup(0, this._watchObjectGroupId) var properties = []; // Count the properties, so we known when to call this.updateProperties() diff --git a/Source/WebCore/inspector/front-end/WebKit.qrc b/Source/WebCore/inspector/front-end/WebKit.qrc index dd325ba..91d72d8 100644 --- a/Source/WebCore/inspector/front-end/WebKit.qrc +++ b/Source/WebCore/inspector/front-end/WebKit.qrc @@ -27,9 +27,11 @@ <file>Database.js</file> <file>DatabaseQueryView.js</file> <file>DatabaseTableView.js</file> + <file>DetailedHeapshotGridNodes.js</file> <file>DetailedHeapshotView.js</file> <file>DataGrid.js</file> <file>DebuggerModel.js</file> + <file>DebuggerPresentationModel.js</file> <file>DOMAgent.js</file> <file>DOMStorage.js</file> <file>DOMStorageItemsView.js</file> @@ -85,6 +87,7 @@ <file>ScriptFormatter.js</file> <file>ScriptFormatterWorker.js</file> <file>ScriptsPanel.js</file> + <file>SearchController.js</file> <file>Section.js</file> <file>Settings.js</file> <file>ShortcutsHelp.js</file> @@ -110,6 +113,7 @@ <file>TimelineGrid.js</file> <file>TimelineOverviewPane.js</file> <file>TimelinePanel.js</file> + <file>Toolbar.js</file> <file>TopDownProfileDataGridTree.js</file> <file>treeoutline.js</file> <file>utilities.js</file> diff --git a/Source/WebCore/inspector/front-end/WorkersSidebarPane.js b/Source/WebCore/inspector/front-end/WorkersSidebarPane.js index b254f3c..efdb936 100644 --- a/Source/WebCore/inspector/front-end/WorkersSidebarPane.js +++ b/Source/WebCore/inspector/front-end/WorkersSidebarPane.js @@ -74,9 +74,9 @@ WebInspector.WorkersSidebarPane.prototype = { setInstrumentation: function(enabled) { - InspectorBackend.removeAllScriptsToEvaluateOnLoad(); + InspectorAgent.removeAllScriptsToEvaluateOnLoad(); if (enabled) - InspectorBackend.addScriptToEvaluateOnLoad("(" + InjectedFakeWorker + ")"); + InspectorAgent.addScriptToEvaluateOnLoad("(" + InjectedFakeWorker + ")"); }, reset: function() diff --git a/Source/WebCore/inspector/front-end/heapProfiler.css b/Source/WebCore/inspector/front-end/heapProfiler.css index 03a6dd0..add02a1 100644 --- a/Source/WebCore/inspector/front-end/heapProfiler.css +++ b/Source/WebCore/inspector/front-end/heapProfiler.css @@ -134,3 +134,108 @@ width: 50%; left: 25%; } + +.detailed-heapshot-view { + display: none; + overflow: hidden; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + -webkit-box-orient: vertical; +} + +.detailed-heapshot-view.visible { + display: -webkit-box; +} + +.detailed-heapshot-view .view { + display: none; + -webkit-box-flex: 3; + -webkit-box-orient: vertical; +} + +.detailed-heapshot-view .view.visible { + display: -webkit-box; +} + +.detailed-heapshot-view .data-grid { + border: none; + position: relative; + -webkit-box-flex: 1; +} + +.detailed-heapshot-view .data-grid td.count-column { + text-align: right; +} + +.detailed-heapshot-view .data-grid td.addedCount-column { + text-align: right; +} + +.detailed-heapshot-view .data-grid td.removedCount-column { + text-align: right; +} + +.detailed-heapshot-view .data-grid td.countDelta-column { + text-align: right; +} + +.detailed-heapshot-view .data-grid td.addedSize-column { + text-align: right; +} + +.detailed-heapshot-view .data-grid td.removedSize-column { + text-align: right; +} + +.detailed-heapshot-view .data-grid td.sizeDelta-column { + text-align: right; +} + +.detailed-heapshot-view .data-grid td.shallowSize-column { + text-align: right; +} + +.detailed-heapshot-view .data-grid td.retainedSize-column { + text-align: right; +} + +.detailed-heapshot-view .console-formatted-object, .console-formatted-node { + display: inline; + position: static; +} + +.detailed-heapshot-view .delimiter { + height: 24px; + background-color: #d6dde5; +} + +.detailed-heapshot-view .retaining-paths-view { + -webkit-box-flex: 1; +} + +.detailed-heapshot-view .retaining-paths-view .title { + background-color: rgb(235, 235, 235); + background-image: url(Images/statusbarBackground.png); + background-repeat: repeat-x; + height: 23px; + font: -webkit-small-control; + font-weight: bold; + color: rgb(48, 48, 48); + text-shadow: rgba(255, 255, 255, 0.75) 0 1px 0; +} + +.detailed-heapshot-view .retaining-paths-view .title > span { + vertical-align: middle; + margin-left: 4px; +} + +.heapshot-help-status-bar-item .glyph { + -webkit-mask-image: url(Images/helpButtonGlyph.png); +} + +table.heapshot-help { + border-spacing: 12px 2px; +} diff --git a/Source/WebCore/inspector/front-end/inspector.css b/Source/WebCore/inspector/front-end/inspector.css index c992806..a7bd3b3 100644 --- a/Source/WebCore/inspector/front-end/inspector.css +++ b/Source/WebCore/inspector/front-end/inspector.css @@ -76,7 +76,6 @@ img { left: 0; right: 0; height: 56px; - display: -webkit-box; padding: 0 5px; background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(191, 191, 191)), to(rgb(151, 151, 151))); border-bottom: 1px solid rgb(80, 80, 80); @@ -111,32 +110,23 @@ body.attached.inactive #toolbar { } .toolbar-item { - display: -webkit-box; - padding: 4px 6px; margin: 0; + padding: 0 6px; background-color: transparent; border-style: none; border-color: transparent; - -webkit-box-orient: vertical; - -webkit-box-align: center; - -webkit-box-pack: end; +} + +.toolbar-item.toggleable { + padding-top: 4px; } .toolbar-item.toggleable.toggled-on { border-width: 0 2px 0 2px; - padding: 4px 4px; + padding: 4px 4px 0 4px; -webkit-border-image: url(Images/toolbarItemSelected.png) 0 2 0 2; } -.toolbar-item.flexable-space { - -webkit-box-flex: 1; - visibility: hidden; -} - -.toolbar-item input { - margin-bottom: 8px; -} - .toolbar-icon { display: inline-block; width: 32px; @@ -144,7 +134,8 @@ body.attached.inactive #toolbar { -webkit-background-size: 100% auto; } -body.attached .toolbar-icon { +body.attached .toolbar-icon, +#toolbar-dropdown .toolbar-icon { width: 24px; height: 24px; vertical-align: middle; @@ -168,9 +159,9 @@ body.attached .toolbar-item:active .toolbar-icon { text-shadow: none; } -body.attached .toolbar-label { +body.attached .toolbar-label, +#toolbar-dropdown .toolbar-label { display: inline-block; - vertical-align: middle; margin-left: 3px; } @@ -178,25 +169,145 @@ body.attached #search-toolbar-label { display: none; } +#toolbar-controls { + float: right; + display: -webkit-box; + -webkit-box-align: center; + height: 100%; +} + +#toolbar-dropdown-arrow { + font-size: 16px; + font-weight: bold; + border: 0; + background-color: transparent; + -webkit-border-radius: 5px; + text-shadow: none; +} + +body.attached #toolbar-dropdown-arrow { + font-size: 14px; + padding-bottom: 4px; +} + +#toolbar-dropdown-arrow.dropdown-visible { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(251, 251, 251, 0.9)), to(rgba(231, 231, 231, 0.9))); +} + +#toolbar-dropdown-arrow:hover { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(191, 191, 191, 0.7)), to(rgba(171, 171, 171, 0.5))); +} + +#toolbar-dropdown-arrow:active { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(111, 111, 111, 0.8)), to(rgba(91, 91, 91, 0.8))); +} + +#toolbar-dropdown { + position: absolute; + z-index: 1000; + -webkit-box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.4); + border: 1px solid rgb(128, 128, 128); + padding: 4px; + background-color: inherit; + background-image: inherit; +} + +body.detached.platform-mac-leopard #toolbar-dropdown, +body.detached.platform-mac-snowleopard #toolbar-dropdown { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(191, 191, 191)), to(rgb(151, 151, 151))); +} + +#toolbar-dropdown .scrollable-content { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-box-align: start; +} + +#toolbar-dropdown .toolbar-item { + display: -webkit-box; + -webkit-box-orient: horizontal; + margin: 0px 2px; + padding: 4px; + width: 100%; + border: 1px solid rgba(0, 0, 0, 0); +} + +#toolbar-dropdown .toolbar-item.toggleable.toggled-on { + border: 1px solid rgba(100, 100, 120, 0.4); + -webkit-border-image: none; + background: -webkit-gradient(linear, left top, left bottom, from(rgba(128, 128, 128, 0.6)), to(rgba(128, 128, 128, 0.6)), color-stop(20%, rgba(158, 158, 158, 0.2)), color-stop(80%, rgba(158, 158, 158, 0.2))); +} + +#toolbar-dropdown .toolbar-item:hover { + -webkit-border-image: none; + border: 1px solid rgba(100, 100, 120, 0.8); +} + +#toolbar-dropdown .toolbar-item.toggleable.toggled-on:hover { + border: 1px solid rgba(100, 100, 120, 1); +} + +#toolbar-dropdown .toolbar-icon { + margin-right: 0.5em; +} + +#toolbar-dropdown .toolbar-item:active .toolbar-icon { + background-position: 0 24px; +} + +.scrollable-content { + position: static; + height: 100%; + overflow-y: auto; + width: 100%; + margin-right: 12px; + padding-right: 3px; +} + +.scrollable-content::-webkit-scrollbar { + width: 11px; +} + +.scrollable-content::-webkit-scrollbar-corner, +.scrollable-content::-webkit-resizer { + display: none; +} + +.scrollable-content::-webkit-scrollbar-thumb:vertical { + background: -webkit-gradient(linear, left top, right top, from(rgb(192, 192, 192)), to(rgb(192, 192, 192)), color-stop(40%, rgb(214, 214, 214))); + border-radius: 5px; + min-height: 20px; +} + +.scrollable-content::-webkit-scrollbar-thumb:vertical:hover, +.scrollable-content::-webkit-scrollbar-thumb:vertical:active { + background: -webkit-gradient(linear, left top, right top, from(rgb(230, 230, 230)), to(rgb(230, 230, 230)), color-stop(40%, rgb(252, 252, 252))); +} + +.scrollable-content::-webkit-scrollbar-track:vertical { + background: -webkit-gradient(linear, left top, right top, from(rgb(128, 128, 128)), to(rgb(164, 164, 164)), color-stop(25%, rgb(164, 164, 164))); + border-radius: 5px; +} + +.toolbar-search-item { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-box-align: center; + -webkit-box-pack: end; +} + #search { width: 205px; font-size: 16px; - margin-bottom: 5px; } body.attached #search { font-size: 11px; - margin-bottom: 8px; } #search-results-matches { font-size: 11px; text-shadow: rgba(255, 255, 255, 0.5) 0 1px 0; - margin-bottom: 22px; -} - -body.attached #search-results-matches { - margin-bottom: 6px; } .toolbar-item.elements .toolbar-icon { @@ -238,7 +349,7 @@ body.attached #search-results-matches { background-position: 0 0; background-color: transparent; border: 0 none transparent; - margin: 5px 0; + margin-top: 9px; } #close-button-left:hover, #close-button-right:hover { @@ -249,6 +360,10 @@ body.attached #search-results-matches { background-position: 28px 0; } +.close-left { + float: left; +} + body.detached .toolbar-item.close-left, body.detached .toolbar-item.close-right { display: none; } diff --git a/Source/WebCore/inspector/front-end/inspector.html b/Source/WebCore/inspector/front-end/inspector.html index 0435dc3..d6c810e 100644 --- a/Source/WebCore/inspector/front-end/inspector.html +++ b/Source/WebCore/inspector/front-end/inspector.html @@ -142,8 +142,10 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="ProfileView.js"></script> <script type="text/javascript" src="HeapSnapshot.js"></script> <script type="text/javascript" src="HeapSnapshotView.js"></script> + <script type="text/javascript" src="DetailedHeapshotGridNodes.js"></script> <script type="text/javascript" src="DetailedHeapshotView.js"></script> <script type="text/javascript" src="DebuggerModel.js"></script> + <script type="text/javascript" src="DebuggerPresentationModel.js"></script> <script type="text/javascript" src="DOMAgent.js"></script> <script type="text/javascript" src="TimelineAgent.js"></script> <script type="text/javascript" src="TimelinePanel.js"></script> @@ -154,14 +156,18 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="ShortcutsHelp.js"></script> <script type="text/javascript" src="HAREntry.js"></script> <script type="text/javascript" src="CookieParser.js"></script> + <script type="text/javascript" src="Toolbar.js"></script> + <script type="text/javascript" src="SearchController.js"></script> </head> <body class="detached"> <div id="toolbar"> <div class="toolbar-item close-left"><button id="close-button-left"></button></div> - <div class="toolbar-item flexable-space"></div> - <div class="toolbar-item hidden" id="search-results-matches"></div> - <div class="toolbar-item"><input id="search" type="search" incremental results="0"><div id="search-toolbar-label" class="toolbar-label"></div></div> - <div class="toolbar-item close-right"><button id="close-button-right"></button></div> + <div id="toolbar-controls"> + <div class="toolbar-item"><button id="toolbar-dropdown-arrow" class="toolbar-label">»</button></div> + <div class="toolbar-item hidden" id="search-results-matches"></div> + <div class="toolbar-item toolbar-search-item"><input id="search" type="search" incremental results="0"><div id="search-toolbar-label" class="toolbar-label"></div></div> + <div class="toolbar-item close-right"><button id="close-button-right"></button></div> + </div> </div> <div id="main"> <div id="main-panels" spellcheck="false"></div> diff --git a/Source/WebCore/inspector/front-end/inspector.js b/Source/WebCore/inspector/front-end/inspector.js index 0959289..b4c3fda 100644 --- a/Source/WebCore/inspector/front-end/inspector.js +++ b/Source/WebCore/inspector/front-end/inspector.js @@ -138,6 +138,12 @@ var WebInspector = { this._previousFocusElement.blur(); }, + resetFocusElement: function() + { + this.currentFocusElement = null; + this._previousFocusElement = null; + }, + get currentPanel() { return this._currentPanel; @@ -153,30 +159,10 @@ var WebInspector = { this._currentPanel = x; - this.updateSearchLabel(); - if (x) { x.show(); - - if (this.currentQuery) { - if (x.performSearch) { - function performPanelSearch() - { - this.updateSearchMatchesCount(); - - x.currentQuery = this.currentQuery; - x.performSearch(this.currentQuery); - } - - // Perform the search on a timeout so the panel switches fast. - setTimeout(performPanelSearch.bind(this), 0); - } else { - // Update to show Not found for panels that can't be searched. - this.updateSearchMatchesCount(); - } - } + WebInspector.searchController.activePanelChanged(); } - for (var panelName in WebInspector.panels) { if (WebInspector.panels[panelName] === x) { WebInspector.settings.lastActivePanel = panelName; @@ -248,8 +234,6 @@ var WebInspector = { this._attached = x; - this.updateSearchLabel(); - var dockToggleButton = document.getElementById("dock-status-bar-item"); var body = document.body; @@ -262,8 +246,11 @@ var WebInspector = { body.addStyleClass("detached"); dockToggleButton.title = WebInspector.UIString("Dock to main window."); } - if (this.drawer) - this.drawer.resize(); + + // This may be called before onLoadedDone, hence the bulk of inspector objects may + // not be created yet. + if (WebInspector.searchController) + WebInspector.searchController.updateSearchLabel(); }, get errors() @@ -360,9 +347,9 @@ var WebInspector = { this._highlightedDOMNodeId = nodeId; if (nodeId) - InspectorBackend.highlightDOMNode(nodeId); + InspectorAgent.highlightDOMNode(nodeId); else - InspectorBackend.hideDOMNodeHighlight(); + InspectorAgent.hideDOMNodeHighlight(); }, highlightDOMNodeForTwoSeconds: function(nodeId) @@ -492,17 +479,16 @@ WebInspector.doLoadedDone = function() this.debuggerModel = new WebInspector.DebuggerModel(); this.breakpointManager = new WebInspector.BreakpointManager(); + this.searchController = new WebInspector.SearchController(); this.panels = {}; this._createPanels(); this._panelHistory = new WebInspector.PanelHistory(); - - var toolbarElement = document.getElementById("toolbar"); - var previousToolbarItem = toolbarElement.children[0]; + this.toolbar = new WebInspector.Toolbar(); this.panelOrder = []; for (var panelName in this.panels) - previousToolbarItem = WebInspector.addPanelToolbarIcon(toolbarElement, this.panels[panelName], previousToolbarItem); + this.addPanel(this.panels[panelName]); this.Tips = { ResourceNotCompressed: {id: 0, message: WebInspector.UIString("You could save bandwidth by having your web server compress this transfer with gzip or zlib.")} @@ -534,15 +520,6 @@ WebInspector.doLoadedDone = function() errorWarningCount.addEventListener("click", this.showConsole.bind(this), false); this._updateErrorAndWarningCounts(); - var searchField = document.getElementById("search"); - searchField.addEventListener("search", this.performSearch.bind(this), false); // when the search is emptied - searchField.addEventListener("mousedown", this._searchFieldManualFocus.bind(this), false); // when the search field is manually selected - searchField.addEventListener("keydown", this._searchKeyDown.bind(this), true); - - toolbarElement.addEventListener("mousedown", this.toolbarDragStart, true); - document.getElementById("close-button-left").addEventListener("click", this.close, true); - document.getElementById("close-button-right").addEventListener("click", this.close, true); - this.extensionServer.initExtensions(); function onPopulateScriptObjects() @@ -550,35 +527,29 @@ WebInspector.doLoadedDone = function() if (!WebInspector.currentPanel) WebInspector.showPanel(WebInspector.settings.lastActivePanel); } - InspectorBackend.populateScriptObjects(onPopulateScriptObjects); + InspectorAgent.populateScriptObjects(onPopulateScriptObjects); if (Preferences.debuggerAlwaysEnabled || WebInspector.settings.debuggerEnabled) this.debuggerModel.enableDebugger(); if (Preferences.profilerAlwaysEnabled || WebInspector.settings.profilerEnabled) - InspectorBackend.enableProfiler(); + InspectorAgent.enableProfiler(); if (WebInspector.settings.monitoringXHREnabled) - InspectorBackend.setMonitoringXHREnabled(true); + ConsoleAgent.setMonitoringXHREnabled(true); - InspectorBackend.setConsoleMessagesEnabled(true); + ConsoleAgent.setConsoleMessagesEnabled(true); function propertyNamesCallback(names) { WebInspector.cssNameCompletions = new WebInspector.CSSCompletions(names); } // As a DOMAgent method, this needs to happen after the frontend has loaded and the agent is available. - InspectorBackend.getSupportedCSSProperties(propertyNamesCallback); + CSSAgent.getSupportedCSSProperties(propertyNamesCallback); } -WebInspector.addPanelToolbarIcon = function(toolbarElement, panel, previousToolbarItem) +WebInspector.addPanel = function(panel) { - var panelToolbarItem = panel.toolbarItem; this.panelOrder.push(panel); - panelToolbarItem.addEventListener("click", this._toolbarItemClicked.bind(this)); - if (previousToolbarItem) - toolbarElement.insertBefore(panelToolbarItem, previousToolbarItem.nextSibling); - else - toolbarElement.insertBefore(panelToolbarItem, toolbarElement.firstChild); - return panelToolbarItem; + this.toolbar.addPanel(panel); } var windowLoaded = function() @@ -599,16 +570,19 @@ var windowLoaded = function() window.addEventListener("DOMContentLoaded", windowLoaded, false); +// We'd like to enforce asynchronous interaction between the inspector controller and the frontend. +// It is needed to prevent re-entering the backend code. +// Also, native dispatches do not guarantee setTimeouts to be serialized, so we +// enforce serialization using 'messagesToDispatch' queue. It is also important that JSC debugger +// tests require that each command was dispatch within individual timeout callback, so we don't batch them. + +var messagesToDispatch = []; + WebInspector.dispatch = function(message) { - // We'd like to enforce asynchronous interaction between the inspector controller and the frontend. - // This is important to LayoutTests. - function delayDispatch() - { - InspectorBackend.dispatch(message); - WebInspector.pendingDispatches--; - } - WebInspector.pendingDispatches++; - setTimeout(delayDispatch, 0); + messagesToDispatch.push(message); + setTimeout(function() { + InspectorBackend.dispatch(messagesToDispatch.shift()); + }, 0); } WebInspector.dispatchMessageFromBackend = function(messageObject) @@ -621,6 +595,7 @@ WebInspector.windowResize = function(event) if (this.currentPanel) this.currentPanel.resize(); this.drawer.resize(); + this.toolbar.resize(); } WebInspector.windowFocused = function(event) @@ -727,7 +702,7 @@ WebInspector.openResource = function(resourceURL, inResourcesPanel) WebInspector.panels.resources.showResource(resource); WebInspector.showPanel("resources"); } else - InspectorBackend.openInInspectedWindow(resource ? resource.url : resourceURL); + InspectorAgent.openInInspectedWindow(resource ? resource.url : resourceURL); } WebInspector._registerShortcuts = function() @@ -783,6 +758,12 @@ WebInspector.documentKeyDown = function(event) } } + WebInspector.searchController.handleShortcut(event); + if (event.handled) { + event.preventDefault(); + return; + } + var isMac = WebInspector.isMac(); switch (event.keyIdentifier) { case "Left": @@ -809,36 +790,6 @@ WebInspector.documentKeyDown = function(event) this.drawer.visible = !this.drawer.visible; break; - case "U+0046": // F key - if (isMac) - var isFindKey = event.metaKey && !event.ctrlKey && !event.altKey && !event.shiftKey; - else - var isFindKey = event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey; - - if (isFindKey) { - WebInspector.focusSearchField(); - event.preventDefault(); - } - break; - - case "F3": - if (!isMac) { - WebInspector.focusSearchField(); - event.preventDefault(); - } - break; - - case "U+0047": // G key - if (isMac && event.metaKey && !event.ctrlKey && !event.altKey) { - if (event.shiftKey) { - if (this.currentPanel.jumpToPreviousSearchResult) - this.currentPanel.jumpToPreviousSearchResult(); - } else if (this.currentPanel.jumpToNextSearchResult) - this.currentPanel.jumpToNextSearchResult(); - event.preventDefault(); - } - break; - // Windows and Mac have two different definitions of [, so accept both. case "U+005B": case "U+00DB": // [ key @@ -875,13 +826,13 @@ WebInspector.documentKeyDown = function(event) case "U+0052": // R key if ((event.metaKey && isMac) || (event.ctrlKey && !isMac)) { - InspectorBackend.reloadPage(event.shiftKey); + InspectorAgent.reloadPage(event.shiftKey); event.preventDefault(); } break; case "F5": if (!isMac) - InspectorBackend.reloadPage(event.ctrlKey || event.shiftKey); + InspectorAgent.reloadPage(event.ctrlKey || event.shiftKey); break; } } @@ -1005,27 +956,6 @@ WebInspector.animateStyle = function(animations, duration, callback) }; } -WebInspector.updateSearchLabel = function() -{ - if (!this.currentPanel) - return; - - var newLabel = WebInspector.UIString("Search %s", this.currentPanel.toolbarItemLabel); - if (this.attached) - document.getElementById("search").setAttribute("placeholder", newLabel); - else { - document.getElementById("search").removeAttribute("placeholder"); - document.getElementById("search-toolbar-label").textContent = newLabel; - } -} - -WebInspector.focusSearchField = function() -{ - var searchField = document.getElementById("search"); - searchField.focus(); - searchField.select(); -} - WebInspector.toggleAttach = function() { if (!this.attached) @@ -1034,58 +964,6 @@ WebInspector.toggleAttach = function() InspectorFrontendHost.requestDetachWindow(); } -WebInspector.toolbarDragStart = function(event) -{ - if ((!WebInspector.attached && WebInspector.platformFlavor !== WebInspector.PlatformFlavor.MacLeopard && WebInspector.platformFlavor !== WebInspector.PlatformFlavor.MacSnowLeopard) || WebInspector.port == "qt") - return; - - var target = event.target; - if (target.hasStyleClass("toolbar-item") && target.hasStyleClass("toggleable")) - return; - - var toolbar = document.getElementById("toolbar"); - if (target !== toolbar && !target.hasStyleClass("toolbar-item")) - return; - - toolbar.lastScreenX = event.screenX; - toolbar.lastScreenY = event.screenY; - - WebInspector.elementDragStart(toolbar, WebInspector.toolbarDrag, WebInspector.toolbarDragEnd, event, (WebInspector.attached ? "row-resize" : "default")); -} - -WebInspector.toolbarDragEnd = function(event) -{ - var toolbar = document.getElementById("toolbar"); - - WebInspector.elementDragEnd(event); - - delete toolbar.lastScreenX; - delete toolbar.lastScreenY; -} - -WebInspector.toolbarDrag = function(event) -{ - var toolbar = document.getElementById("toolbar"); - - if (WebInspector.attached) { - var height = window.innerHeight - (event.screenY - toolbar.lastScreenY); - - InspectorFrontendHost.setAttachedWindowHeight(height); - } else { - var x = event.screenX - toolbar.lastScreenX; - var y = event.screenY - toolbar.lastScreenY; - - // We cannot call window.moveBy here because it restricts the movement - // of the window at the edges. - InspectorFrontendHost.moveWindowBy(x, y); - } - - toolbar.lastScreenX = event.screenX; - toolbar.lastScreenY = event.screenY; - - event.preventDefault(); -} - WebInspector.elementDragStart = function(element, dividerDrag, elementDragEnd, event, cursor) { if (this._elementDraggingEventListener || this._elementEndDraggingEventListener) @@ -1307,6 +1185,23 @@ WebInspector.drawLoadingPieChart = function(canvas, percent) { g.fill(); } +WebInspector.inspect = function(objectId, hints) +{ + var object = WebInspector.RemoteObject.fromPayload(objectId); + if (object.type === "node") { + // Request node from backend and focus it. + object.pushNodeToFrontend(WebInspector.updateFocusedNode.bind(WebInspector)); + } else if (hints.databaseId) { + WebInspector.currentPanel = WebInspector.panels.resources; + WebInspector.panels.resources.selectDatabase(hints.databaseId); + } else if (hints.domStorageId) { + WebInspector.currentPanel = WebInspector.panels.resources; + WebInspector.panels.resources.selectDOMStorage(hints.domStorageId); + } + + RuntimeAgent.releaseObject(objectId); +} + WebInspector.updateFocusedNode = function(nodeId) { this._updateFocusedNode(nodeId); @@ -1518,156 +1413,12 @@ WebInspector.addMainEventListeners = function(doc) doc.addEventListener("click", this.documentClick.bind(this), true); } -WebInspector._searchFieldManualFocus = function(event) -{ - this.currentFocusElement = event.target; - this._previousFocusElement = event.target; -} - -WebInspector._searchKeyDown = function(event) -{ - // Escape Key will clear the field and clear the search results - if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code) { - // If focus belongs here and text is empty - nothing to do, return unhandled. - if (event.target.value === "" && this.currentFocusElement === this.previousFocusElement) - return; - event.preventDefault(); - event.stopPropagation(); - // When search was selected manually and is currently blank, we'd like Esc stay unhandled - // and hit console drawer handler. - event.target.value = ""; - - this.performSearch(event); - this.currentFocusElement = this.previousFocusElement; - if (this.currentFocusElement === event.target) - this.currentFocusElement.select(); - return false; - } - - if (!isEnterKey(event)) - return false; - - // Select all of the text so the user can easily type an entirely new query. - event.target.select(); - - // Only call performSearch if the Enter key was pressed. Otherwise the search - // performance is poor because of searching on every key. The search field has - // the incremental attribute set, so we still get incremental searches. - this.performSearch(event); - - // Call preventDefault since this was the Enter key. This prevents a "search" event - // from firing for key down. This stops performSearch from being called twice in a row. - event.preventDefault(); -} - -WebInspector.performSearch = function(event) -{ - var forceSearch = event.keyIdentifier === "Enter"; - this.doPerformSearch(event.target.value, forceSearch, event.shiftKey, false); -} - -WebInspector.cancelSearch = function() -{ - document.getElementById("search").value = ""; - this.doPerformSearch(""); -} - -WebInspector.doPerformSearch = function(query, forceSearch, isBackwardSearch, repeatSearch) -{ - var isShortSearch = (query.length < 3); - - // Clear a leftover short search flag due to a non-conflicting forced search. - if (isShortSearch && this.shortSearchWasForcedByKeyEvent && this.currentQuery !== query) - delete this.shortSearchWasForcedByKeyEvent; - - // Indicate this was a forced search on a short query. - if (isShortSearch && forceSearch) - this.shortSearchWasForcedByKeyEvent = true; - - if (!query || !query.length || (!forceSearch && isShortSearch)) { - // Prevent clobbering a short search forced by the user. - if (this.shortSearchWasForcedByKeyEvent) { - delete this.shortSearchWasForcedByKeyEvent; - return; - } - - delete this.currentQuery; - - for (var panelName in this.panels) { - var panel = this.panels[panelName]; - var hadCurrentQuery = !!panel.currentQuery; - delete panel.currentQuery; - if (hadCurrentQuery && panel.searchCanceled) - panel.searchCanceled(); - } - - this.updateSearchMatchesCount(); - - return; - } - - if (!repeatSearch && query === this.currentPanel.currentQuery && this.currentPanel.currentQuery === this.currentQuery) { - // When this is the same query and a forced search, jump to the next - // search result for a good user experience. - if (forceSearch) { - if (!isBackwardSearch && this.currentPanel.jumpToNextSearchResult) - this.currentPanel.jumpToNextSearchResult(); - else if (isBackwardSearch && this.currentPanel.jumpToPreviousSearchResult) - this.currentPanel.jumpToPreviousSearchResult(); - } - return; - } - - this.currentQuery = query; - - this.updateSearchMatchesCount(); - - if (!this.currentPanel.performSearch) - return; - - this.currentPanel.currentQuery = query; - this.currentPanel.performSearch(query); -} - WebInspector.frontendReused = function() { - this.networkManager.reset(); + this.networkManager.frontendReused(); this.reset(); } -WebInspector.addNodesToSearchResult = function(nodeIds) -{ - WebInspector.panels.elements.addNodesToSearchResult(nodeIds); -} - -WebInspector.updateSearchMatchesCount = function(matches, panel) -{ - if (!panel) - panel = this.currentPanel; - - panel.currentSearchMatches = matches; - - if (panel !== this.currentPanel) - return; - - if (!this.currentPanel.currentQuery) { - document.getElementById("search-results-matches").addStyleClass("hidden"); - return; - } - - if (matches) { - if (matches === 1) - var matchesString = WebInspector.UIString("1 match"); - else - var matchesString = WebInspector.UIString("%d matches", matches); - } else - var matchesString = WebInspector.UIString("Not Found"); - - var matchesToolbarElement = document.getElementById("search-results-matches"); - matchesToolbarElement.removeStyleClass("hidden"); - matchesToolbarElement.textContent = matchesString; -} - WebInspector.UIString = function(string) { if (window.localizedStrings && string in window.localizedStrings) @@ -1675,7 +1426,7 @@ WebInspector.UIString = function(string) else { if (!(string in WebInspector.missingLocalizedStrings)) { if (!WebInspector.InspectorBackendStub) - console.error("Localized string \"" + string + "\" not found."); + console.warn("Localized string \"" + string + "\" not found."); WebInspector.missingLocalizedStrings[string] = true; } diff --git a/Source/WebCore/inspector/front-end/networkPanel.css b/Source/WebCore/inspector/front-end/networkPanel.css index c750323..2711347 100644 --- a/Source/WebCore/inspector/front-end/networkPanel.css +++ b/Source/WebCore/inspector/front-end/networkPanel.css @@ -22,7 +22,7 @@ -webkit-background-size: 1px 42px; } -.network-sidebar .data-grid td:not(.network-summary) { +.network-sidebar .data-grid td { line-height: 17px; height: 37px; border-right: 1px solid rgb(210, 210, 210); @@ -496,34 +496,34 @@ /* Summary */ +.network-sidebar tr.filler td { + padding-bottom: 20px !important; +} + .network-summary-bar { + position: absolute; + left: 0; + right: 0; + bottom: 0; + margin-right: -14px; background-color: rgb(101, 111, 130); +} + +.network-sidebar .data-grid .network-summary-bar td { color: white; height: 20px; + border: none; font-size: 11px; font-weight: bold; - padding-top: 3px; - padding-left: 10px; - z-index: 2000; + padding: 0 0 0 8px; white-space: pre; overflow : hidden; text-overflow : ellipsis; } -.network-summary-bar-bottom { - position: absolute; - bottom: 0; - left: 0; - right: 0; - padding-top: 3px; -} - -.data-grid td .network-summary-bar { - white-space: pre; -} - -.network-sidebar .data-grid td.network-summary { - padding: 0; +.network-summary-bar img { + vertical-align: middle; + padding-right: 8px; } /* Viewer */ diff --git a/Source/WebCore/inspector/front-end/textViewer.css b/Source/WebCore/inspector/front-end/textViewer.css index f6aa65e..59f2a43 100644 --- a/Source/WebCore/inspector/front-end/textViewer.css +++ b/Source/WebCore/inspector/front-end/textViewer.css @@ -15,6 +15,9 @@ bottom: 0; overflow: hidden; -webkit-user-select: none; + background-color: rgb(240, 240, 240); + border-right: 1px solid rgb(187, 187, 187); + min-width: 19px; } .text-editor-contents { @@ -27,6 +30,15 @@ -webkit-user-select: text; } +.text-editor-contents .inner-container { + position: absolute; + top: 0; + left: 0; + right: auto; + bottom: auto; + min-width: 100%; +} + .text-editor-editable { -webkit-user-modify: read-write-plaintext-only; } @@ -80,8 +92,6 @@ .webkit-line-number { color: rgb(128, 128, 128); - background-color: rgb(240, 240, 240); - border-right: 1px solid rgb(187, 187, 187); text-align: right; vertical-align: top; word-break: normal; diff --git a/Source/WebCore/inspector/front-end/utilities.js b/Source/WebCore/inspector/front-end/utilities.js index 5ed9a8c..31a5f0c 100644 --- a/Source/WebCore/inspector/front-end/utilities.js +++ b/Source/WebCore/inspector/front-end/utilities.js @@ -218,7 +218,8 @@ Element.prototype.pruneEmptyTextNodes = function() Element.prototype.isScrolledToBottom = function() { - return this.scrollTop === this.scrollHeight - this.offsetHeight; + // This code works only for 0-width border + return this.scrollTop + this.clientHeight === this.scrollHeight; } Node.prototype.enclosingNodeOrSelfWithNodeNameInArray = function(nameArray) @@ -399,6 +400,15 @@ String.prototype.findAll = function(string) return matches; } +String.prototype.lineEndings = function() +{ + if (!this._lineEndings) { + this._lineEndings = this.findAll("\n"); + this._lineEndings.push(this.length); + } + return this._lineEndings; +} + String.prototype.asParsedURL = function() { // RegExp groups: @@ -1010,52 +1020,91 @@ function isEnterKey(event) { return event.keyCode !== 229 && event.keyIdentifier === "Enter"; } - function highlightSearchResult(element, offset, length) { + var result = highlightSearchResults(element, [{offset: offset, length: length }]); + return result.length ? result[0] : null; +} + +function highlightSearchResults(element, resultRanges) +{ + var highlightNodes = []; var lineText = element.textContent; - var endOffset = offset + length; - var highlightNode = document.createElement("span"); - highlightNode.className = "webkit-search-result"; - highlightNode.textContent = lineText.substring(offset, endOffset); - - var boundary = element.rangeBoundaryForOffset(offset); - var textNode = boundary.container; - var text = textNode.textContent; - - if (boundary.offset + length < text.length) { - // Selection belong to a single split mode. - textNode.textContent = text.substring(boundary.offset + length); - textNode.parentElement.insertBefore(highlightNode, textNode); - var prefixNode = document.createTextNode(text.substring(0, boundary.offset)); - textNode.parentElement.insertBefore(prefixNode, highlightNode); - return highlightNode; - } + var textNodeSnapshot = document.evaluate(".//text()", element, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + + var snapshotLength = textNodeSnapshot.snapshotLength; + var snapshotNodeOffset = 0; + var currentSnapshotItem = 0; + + for (var i = 0; i < resultRanges.length; ++i) { + var resultLength = resultRanges[i].length; + var startOffset = resultRanges[i].offset; + var endOffset = startOffset + resultLength; + var length = resultLength; + var textNode; + var textNodeOffset; + var found; + + while (currentSnapshotItem < snapshotLength) { + textNode = textNodeSnapshot.snapshotItem(currentSnapshotItem++); + var textNodeLength = textNode.nodeValue.length; + if (snapshotNodeOffset + textNodeLength >= startOffset) { + textNodeOffset = startOffset - snapshotNodeOffset; + snapshotNodeOffset += textNodeLength; + found = true; + break; + } + snapshotNodeOffset += textNodeLength; + } - var parentElement = textNode.parentElement; - var anchorElement = textNode.nextSibling; + if (!found) { + textNode = element; + textNodeOffset = 0; + } - length -= text.length - boundary.offset; - textNode.textContent = text.substring(0, boundary.offset); - textNode = textNode.traverseNextTextNode(element); + var highlightNode = document.createElement("span"); + highlightNode.className = "webkit-search-result"; + highlightNode.textContent = lineText.substring(startOffset, endOffset); - while (textNode) { var text = textNode.textContent; - if (length < text.length) { - textNode.textContent = text.substring(length); - break; + if (textNodeOffset + resultLength < text.length) { + // Selection belongs to a single split mode. + textNode.textContent = text.substring(textNodeOffset + resultLength); + textNode.parentElement.insertBefore(highlightNode, textNode); + var prefixNode = document.createTextNode(text.substring(0, textNodeOffset)); + textNode.parentElement.insertBefore(prefixNode, highlightNode); + + highlightNodes.push(highlightNode); + continue; + } + + var parentElement = textNode.parentElement; + var anchorElement = textNode.nextSibling; + + length -= text.length - textNodeOffset; + textNode.textContent = text.substring(0, textNodeOffset); + + while (currentSnapshotItem < snapshotLength) { + textNode = textNodeSnapshot.snapshotItem(currentSnapshotItem++); + snapshotNodeOffset += textNode.nodeValue.length; + var text = textNode.textContent; + if (length < text.length) { + textNode.textContent = text.substring(length); + break; + } + + length -= text.length; + textNode.textContent = ""; } - length -= text.length; - textNode.textContent = ""; - textNode = textNode.traverseNextTextNode(element); + parentElement.insertBefore(highlightNode, anchorElement); + highlightNodes.push(highlightNode); } - parentElement.insertBefore(highlightNode, anchorElement); - return highlightNode; + return highlightNodes; } -function createSearchRegex(query) +function createSearchRegex(query, extraFlags) { var regex = ""; for (var i = 0; i < query.length; ++i) { @@ -1064,7 +1113,7 @@ function createSearchRegex(query) char = "\\]"; regex += "[" + char + "]"; } - return new RegExp(regex, "i"); + return new RegExp(regex, "i" + (extraFlags || "")); } function offerFileForDownload(contents) |