summaryrefslogtreecommitdiffstats
path: root/webkit/glue/devtools
diff options
context:
space:
mode:
authorpfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-01 10:04:26 +0000
committerpfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-01 10:04:26 +0000
commitc85fd527a167276e470a9cc414fae0343072a594 (patch)
treed3388392feebdc7e117f0fcdcb434c959b9e4d15 /webkit/glue/devtools
parent43cf325be09379594dd96e0b35146585cdfd6a34 (diff)
downloadchromium_src-c85fd527a167276e470a9cc414fae0343072a594.zip
chromium_src-c85fd527a167276e470a9cc414fae0343072a594.tar.gz
chromium_src-c85fd527a167276e470a9cc414fae0343072a594.tar.bz2
DevTools: Support r/o properties inspection.
Review URL: http://codereview.chromium.org/56067 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12949 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue/devtools')
-rw-r--r--webkit/glue/devtools/debugger_agent_impl.cc62
-rw-r--r--webkit/glue/devtools/debugger_agent_impl.h20
-rw-r--r--webkit/glue/devtools/dom_agent_impl.cc20
-rw-r--r--webkit/glue/devtools/dom_agent_impl.h2
-rw-r--r--webkit/glue/devtools/js/base.js2
-rw-r--r--webkit/glue/devtools/js/debugger_agent.js2
-rw-r--r--webkit/glue/devtools/js/devtools.html2
-rw-r--r--webkit/glue/devtools/js/devtools.js145
-rw-r--r--webkit/glue/devtools/js/devtools_host_stub.js37
-rw-r--r--webkit/glue/devtools/js/inject.js82
-rw-r--r--webkit/glue/devtools/tools_agent.h16
11 files changed, 363 insertions, 27 deletions
diff --git a/webkit/glue/devtools/debugger_agent_impl.cc b/webkit/glue/devtools/debugger_agent_impl.cc
index fde98cb..b52db2a 100644
--- a/webkit/glue/devtools/debugger_agent_impl.cc
+++ b/webkit/glue/devtools/debugger_agent_impl.cc
@@ -4,11 +4,24 @@
#include "config.h"
-#include <wtf/Assertions.h>
+#include "Document.h"
+#include "Node.h"
#undef LOG
+#include "grit/webkit_resources.h"
+#include "V8Binding.h"
+#include "v8_index.h"
+#include "v8_proxy.h"
#include "webkit/glue/devtools/debugger_agent_impl.h"
#include "webkit/glue/devtools/debugger_agent_manager.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/webkit_glue.h"
+
+using WebCore::Document;
+using WebCore::Node;
+using WebCore::String;
+using WebCore::V8ClassIndex;
+using WebCore::V8Proxy;
DebuggerAgentImpl::DebuggerAgentImpl(DebuggerAgentDelegate* delegate)
: delegate_(delegate) {
@@ -26,3 +39,50 @@ void DebuggerAgentImpl::DebugBreak() {
void DebuggerAgentImpl::DebuggerOutput(const std::string& command) {
delegate_->DebuggerOutput(command);
}
+
+void DebuggerAgentImpl::SetDocument(Document* document) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
+ if (!document) {
+ context_ = v8::Context::New(NULL /* no extensions */, global_template);
+ return;
+ }
+
+ // TODO(pfeldman): Do not modify existing context - introduce utility one
+ // instead.
+ context_ = v8::Persistent<v8::Context>::New(
+ V8Proxy::GetContext(document->frame()));
+ v8::Context::Scope context_scope(context_);
+
+ std::string basejs = webkit_glue::GetDataResource(IDR_DEVTOOLS_BASE_JS);
+ v8::Script::Compile(v8::String::New(basejs.c_str()))->Run();
+ std::string jsonjs = webkit_glue::GetDataResource(IDR_DEVTOOLS_JSON_JS);
+ v8::Script::Compile(v8::String::New(jsonjs.c_str()))->Run();
+ std::string injectjs = webkit_glue::GetDataResource(IDR_DEVTOOLS_INJECT_JS);
+ v8::Script::Compile(v8::String::New(injectjs.c_str()))->Run();
+}
+
+String DebuggerAgentImpl::ExecuteUtilityFunction(
+ const String &function_name,
+ Node* node,
+ const String& json_args) {
+ v8::HandleScope scope;
+ v8::Context::Scope context_scope(v8::Local<v8::Context>::New(context_));
+ v8::Handle<v8::Function> function = v8::Local<v8::Function>::Cast(
+ context_->Global()->Get(v8::String::New(function_name.utf8().data())));
+
+ v8::Handle<v8::Value> node_wrapper =
+ V8Proxy::ToV8Object(V8ClassIndex::NODE, node);
+ v8::Handle<v8::String> json_args_wrapper = v8::Handle<v8::String>(
+ v8::String::New(json_args.utf8().data()));
+ v8::Handle<v8::Value> args[] = {
+ node_wrapper,
+ json_args_wrapper
+ };
+
+ v8::Handle<v8::Value> res_obj = function->Call(
+ context_->Global(), 2, args);
+
+ v8::Handle<v8::String> res_json = v8::Handle<v8::String>::Cast(res_obj);
+ return WebCore::toWebCoreString(res_json);
+}
diff --git a/webkit/glue/devtools/debugger_agent_impl.h b/webkit/glue/devtools/debugger_agent_impl.h
index 2eb6411..aa0db70 100644
--- a/webkit/glue/devtools/debugger_agent_impl.h
+++ b/webkit/glue/devtools/debugger_agent_impl.h
@@ -5,20 +5,38 @@
#ifndef WEBKIT_GLUE_DEVTOOLS_DEBUGGER_AGENT_IMPL_H_
#define WEBKIT_GLUE_DEVTOOLS_DEBUGGER_AGENT_IMPL_H_
+#include "v8.h"
#include "webkit/glue/devtools/debugger_agent.h"
+namespace WebCore {
+class Document;
+class Node;
+class String;
+}
+
class DebuggerAgentImpl : public DebuggerAgent {
public:
explicit DebuggerAgentImpl(DebuggerAgentDelegate* delegate);
virtual ~DebuggerAgentImpl();
+ // Initializes dom agent with the given document.
+ void SetDocument(WebCore::Document* document);
+
// DebuggerAgent implementation.
virtual void DebugBreak();
void DebuggerOutput(const std::string& out);
- private:
+ // Executes utility function with the given node and json
+ // args as parameters. These functions must be implemented in
+ // the inject.js file.
+ WebCore::String ExecuteUtilityFunction(
+ const WebCore::String& function_name,
+ WebCore::Node* node,
+ const WebCore::String& json_args);
+ private:
+ v8::Persistent<v8::Context> context_;
DebuggerAgentDelegate* delegate_;
DISALLOW_COPY_AND_ASSIGN(DebuggerAgentImpl);
diff --git a/webkit/glue/devtools/dom_agent_impl.cc b/webkit/glue/devtools/dom_agent_impl.cc
index a3a3d75..81016462 100644
--- a/webkit/glue/devtools/dom_agent_impl.cc
+++ b/webkit/glue/devtools/dom_agent_impl.cc
@@ -478,24 +478,24 @@ ListValue* DomAgentImpl::BuildValueForNode(Node* node, int depth) {
}
ListValue* DomAgentImpl::BuildValueForElementAttributes(Element* element) {
- OwnPtr<ListValue> attributesValue(new ListValue());
+ OwnPtr<ListValue> attributes_value(new ListValue());
// Go through all attributes and serialize them.
- const NamedNodeMap *attrMap = element->attributes(true);
- if (!attrMap) {
- return attributesValue.release();
+ const NamedNodeMap* attr_map = element->attributes(true);
+ if (!attr_map) {
+ return attributes_value.release();
}
- unsigned numAttrs = attrMap->length();
- for (unsigned i = 0; i < numAttrs; i++) {
+ unsigned num_attrs = attr_map->length();
+ for (unsigned i = 0; i < num_attrs; i++) {
// Add attribute pair
- const Attribute *attribute = attrMap->attributeItem(i);
+ const Attribute *attribute = attr_map->attributeItem(i);
OwnPtr<Value> name(Value::CreateStringValue(
webkit_glue::StringToStdWString(attribute->name().toString())));
OwnPtr<Value> value(Value::CreateStringValue(
webkit_glue::StringToStdWString(attribute->value())));
- attributesValue->Append(name.release());
- attributesValue->Append(value.release());
+ attributes_value->Append(name.release());
+ attributes_value->Append(value.release());
}
- return attributesValue.release();
+ return attributes_value.release();
}
ListValue* DomAgentImpl::BuildValueForElementChildren(
diff --git a/webkit/glue/devtools/dom_agent_impl.h b/webkit/glue/devtools/dom_agent_impl.h
index 0a8eb31..89a9df9 100644
--- a/webkit/glue/devtools/dom_agent_impl.h
+++ b/webkit/glue/devtools/dom_agent_impl.h
@@ -77,7 +77,7 @@ class DomAgentImpl : public DomAgent {
static PassRefPtr<EventListenerWrapper> Create(
DomAgentImpl* dom_agent_impl);
virtual ~EventListenerWrapper() {}
- virtual void handleEvent(WebCore::Event* event, bool isWindowEvent);
+ virtual void handleEvent(WebCore::Event* event, bool is_window_event);
private:
explicit EventListenerWrapper(DomAgentImpl* dom_agent_impl);
DomAgentImpl* dom_agent_impl_;
diff --git a/webkit/glue/devtools/js/base.js b/webkit/glue/devtools/js/base.js
index d0e35e3..307765c 100644
--- a/webkit/glue/devtools/js/base.js
+++ b/webkit/glue/devtools/js/base.js
@@ -33,7 +33,7 @@
* @define {boolean} Overridden to true by the compiler when
* --mark_as_compiled is specified.
*/
-var COMPILED = false;
+var COMPILED = true;
/**
diff --git a/webkit/glue/devtools/js/debugger_agent.js b/webkit/glue/devtools/js/debugger_agent.js
index 820393c..b22ff20 100644
--- a/webkit/glue/devtools/js/debugger_agent.js
+++ b/webkit/glue/devtools/js/debugger_agent.js
@@ -50,7 +50,7 @@ devtools.DebuggerAgent.prototype.requestScripts = function() {
});
devtools.DebuggerAgent.sendCommand_(cmd);
// Force v8 execution so that it gets to processing the requested command.
- devtools.tools.evaluateJavaSctipt('javascript:void(0)');
+ devtools.tools.evaluateJavaScript("javascript:void(0)");
};
diff --git a/webkit/glue/devtools/js/devtools.html b/webkit/glue/devtools/js/devtools.html
index 2e995d0..3176bea 100644
--- a/webkit/glue/devtools/js/devtools.html
+++ b/webkit/glue/devtools/js/devtools.html
@@ -10,7 +10,7 @@ example not to create WebKit Database tab and remove corresponding js files
from here. Longer term we would like to employ closure + basic js compilation.
That way js libraries would know their dependencies and js compiler would be
able to compile them into a single file. After that this HTML file will
-include single <sctipt src='fe-compiled.js'> and will become upstreamable.
+include single <script src='fe-compiled.js'> and will become upstreamable.
Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
diff --git a/webkit/glue/devtools/js/devtools.js b/webkit/glue/devtools/js/devtools.js
index 31d7782..78f47da 100644
--- a/webkit/glue/devtools/js/devtools.js
+++ b/webkit/glue/devtools/js/devtools.js
@@ -14,7 +14,9 @@ goog.require('devtools.DomAgent');
goog.require('devtools.NetAgent');
devtools.ToolsAgent = function() {
- RemoteToolsAgent.DidEvaluateJavaSctipt = devtools.Callback.processCallback;
+ RemoteToolsAgent.DidEvaluateJavaScript = devtools.Callback.processCallback;
+ RemoteToolsAgent.DidExecuteUtilityFunction =
+ devtools.Callback.processCallback;
RemoteToolsAgent.UpdateFocusedNode =
goog.bind(this.updateFocusedNode, this);
RemoteToolsAgent.FrameNavigate =
@@ -36,13 +38,44 @@ devtools.ToolsAgent.prototype.reset = function() {
/**
- * @param {string} script Sctipt exression to be evaluated in the context of the
+ * @param {string} script Script exression to be evaluated in the context of the
* inspected page.
- * @param {Function} callback
+ * @param {function(string):undefined} callback Function to call with the
+ * result.
*/
-devtools.ToolsAgent.prototype.evaluateJavaSctipt = function(script, callback) {
+devtools.ToolsAgent.prototype.evaluateJavaScript = function(script, callback) {
var callbackId = devtools.Callback.wrap(callback);
- RemoteToolsAgent.EvaluateJavaSctipt(callbackId, script);
+ RemoteToolsAgent.EvaluateJavaScript(callbackId, script);
+};
+
+
+/**
+ * Returns all properties of the given node.
+ * @param {devtools.DomNode} node Node to get properties for.
+ * @param {Array.<string>} path Path to the object.
+ * @param {number} protoDepth Depth to the exact proto level.
+ * @param {function(string):undefined} callback Function to call with the
+ * result.
+ */
+devtools.ToolsAgent.prototype.getNodePropertiesAsync = function(nodeId,
+ path, protoDepth, callback) {
+ var callbackId = devtools.Callback.wrap(callback);
+ RemoteToolsAgent.ExecuteUtilityFunction(callbackId,
+ 'devtools$$getProperties', nodeId,
+ goog.json.serialize([path, protoDepth]));
+};
+
+
+/**
+ * Returns prototype chain for a given node.
+ * @param {devtools.DomNode} node Node to get prototypes for.
+ * @param {Function} callback.
+ */
+devtools.ToolsAgent.prototype.getNodePrototypesAsync = function(nodeId,
+ callback) {
+ var callbackId = devtools.Callback.wrap(callback);
+ RemoteToolsAgent.ExecuteUtilityFunction(callbackId,
+ 'devtools$$getPrototypes', nodeId, '');
};
@@ -184,3 +217,105 @@ WebInspector.ElementsPanel.prototype.jumpToPreviousSearchResult = function() {
WebInspector.Console.prototype._evalInInspectedWindow = function(expr) {
return devtools.tools.evaluate(expr);
};
+
+
+WebInspector.PropertiesSidebarPane.prototype.update = function(object) {
+ var body = this.bodyElement;
+ body.removeChildren();
+
+ this.sections = [];
+
+ if (!object) {
+ return;
+ }
+
+
+ var self = this;
+ devtools.tools.getNodePrototypesAsync(object.id_, function(json) {
+ var prototypes = goog.json.parse(json);
+ for (var i = 0; i < prototypes.length; ++i) {
+ var prototype = {};
+ prototype.id_ = object.id_;
+ prototype.protoDepth_ = i;
+ var section = new WebInspector.ObjectPropertiesSection(prototype,
+ prototypes[i]);
+ self.sections.push(section);
+ body.appendChild(section.element);
+ }
+ });
+};
+
+
+WebInspector.ObjectPropertiesSection.prototype.onpopulate = function() {
+ var nodeId = this.object.id_;
+ var protoDepth = this.object.protoDepth_;
+ var path = [];
+ devtools.tools.getNodePropertiesAsync(nodeId, path, protoDepth,
+ goog.partial(WebInspector.didGetNodePropertiesAsync_,
+ this.propertiesTreeOutline,
+ this.treeElementConstructor,
+ nodeId,
+ path));
+};
+
+
+WebInspector.ObjectPropertyTreeElement.prototype.onpopulate = function() {
+ var nodeId = this.parentObject.devtools$$nodeId_;
+ var path = this.parentObject.devtools$$path_.slice(0);
+ path.push(this.propertyName);
+ devtools.tools.getNodePropertiesAsync(nodeId, path, -1, goog.partial(
+ WebInspector.didGetNodePropertiesAsync_,
+ this,
+ this.treeOutline.section.treeElementConstructor,
+ nodeId, path));
+};
+
+
+/**
+ * Dummy object used during properties inspection.
+ * @see WebInspector.didGetNodePropertiesAsync_
+ */
+WebInspector.dummyObject_ = { 'foo' : 'bar' };
+
+
+/**
+ * Dummy function used during properties inspection.
+ * @see WebInspector.didGetNodePropertiesAsync_
+ */
+WebInspector.dummyFunction_ = function() {};
+
+
+/**
+ * Callback function used with the getNodeProperties.
+ */
+WebInspector.didGetNodePropertiesAsync_ = function(treeOutline, constructor,
+ nodeId, path, json) {
+ var props = goog.json.parse(json);
+ var properties = [];
+ var obj = {};
+ obj.devtools$$nodeId_ = nodeId;
+ obj.devtools$$path_ = path;
+ for (var i = 0; i < props.length; i += 3) {
+ var type = props[i];
+ var name = props[i + 1];
+ var value = props[i + 2];
+ properties.push(name);
+ if (type == 'object') {
+ // fake object is going to be replaced on expand.
+ obj[name] = WebInspector.dummyObject_;
+ } else if (type == 'function') {
+ // fake function is going to be replaced on expand.
+ obj[name] = WebInspector.dummyFunction_;
+ } else {
+ obj[name] = value;
+ }
+ }
+ properties.sort();
+
+ treeOutline.removeChildren();
+
+ for (var i = 0; i < properties.length; ++i) {
+ var propertyName = properties[i];
+ treeOutline.appendChild(new constructor(obj, propertyName));
+ }
+};
diff --git a/webkit/glue/devtools/js/devtools_host_stub.js b/webkit/glue/devtools/js/devtools_host_stub.js
index 17b49e8..73b290e 100644
--- a/webkit/glue/devtools/js/devtools_host_stub.js
+++ b/webkit/glue/devtools/js/devtools_host_stub.js
@@ -146,10 +146,43 @@ RemoteToolsAgentStub.prototype.evaluate = function(expr) {
window.eval(expr);
};
-RemoteToolsAgentStub.prototype.EvaluateJavaSctipt = function(callId, script) {
+RemoteToolsAgentStub.prototype.EvaluateJavaScript = function(callId, script) {
setTimeout(function() {
var result = eval(script);
- RemoteToolsAgent.DidEvaluateJavaSctipt(callId, result);
+ RemoteToolsAgent.DidEvaluateJavaScript(callId, result);
+ }, 0);
+};
+
+
+RemoteToolsAgentStub.prototype.ExecuteUtilityFunction = function(callId,
+ functionName, nodeId, args) {
+ setTimeout(function() {
+ var result = [];
+ if (functionName == 'devtools$$getProperties') {
+ result = [
+ 'undefined', 'undefined_key', undefined,
+ 'string', 'string_key', 'value',
+ 'function', 'func', undefined,
+ 'array', 'array_key', [10],
+ 'object', 'object_key', undefined,
+ 'boolean', 'boolean_key', true,
+ 'number', 'num_key', 911,
+ 'date', 'date_key', new Date() ];
+ } else if (functionName == 'devtools$$getPrototypes') {
+ result = ['Proto1', 'Proto2', 'Proto3'];
+ } else {
+ alert('Unexpected utility function:' + functionName);
+ }
+ RemoteToolsAgent.DidExecuteUtilityFunction(callId,
+ goog.json.serialize(result));
+ }, 0);
+};
+
+
+RemoteToolsAgentStub.prototype.GetNodePrototypes = function(callId, nodeId) {
+ setTimeout(function() {
+ RemoteToolsAgent.DidGetNodePrototypes(callId,
+ goog.json.serialize());
}, 0);
};
diff --git a/webkit/glue/devtools/js/inject.js b/webkit/glue/devtools/js/inject.js
new file mode 100644
index 0000000..4e97462
--- /dev/null
+++ b/webkit/glue/devtools/js/inject.js
@@ -0,0 +1,82 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Javascript that is being injected into the inspectable page
+ * while debugging.
+ */
+goog.require('goog.json');
+
+/**
+ * Returns JSON-serialized array of properties for a given node
+ * on a given path.
+ * @param {Node} node Node to get property value for.
+ * @param {string} args JSON-serialized [{Array.<string>} Path to the
+ * nested object, {number} Depth to the actual proto to inspect].
+ * @return {string} JSON-serialized array where each property is represented
+ * by the tree entryies [{string} type, {string} name, {Object} value].
+ */
+function devtools$$getProperties(node, args) {
+ // Parse parameters.
+ var parsedArgs = goog.json.parse(args);
+ var path = parsedArgs[0];
+ var protoDepth = parsedArgs[1];
+
+ var result = [];
+ var obj = node;
+
+ // Follow the path.
+ for (var i = 0; obj && i < path.length; ++i) {
+ obj = obj[path[i]];
+ }
+
+ if (!obj) {
+ return '[]';
+ }
+
+ // Get to the necessary proto layer.
+ for (var i = 0; obj && i < protoDepth; ++i) {
+ obj = obj.__proto__;
+ }
+
+ if (!obj) {
+ return '[]';
+ }
+
+ // Go over properties, prepare results.
+ for (var name in obj) {
+ if (protoDepth != -1 && 'hasOwnProperty' in obj &&
+ !obj.hasOwnProperty(name)) {
+ continue;
+ }
+ var type = typeof obj[name];
+ result.push(type);
+ result.push(name);
+ if (type == 'string') {
+ var str = obj[name];
+ result.push(str.length > 99 ? str.substr(0, 99) + '...' : str);
+ } else if (type != 'object' && type != 'array' &&
+ type != 'function') {
+ result.push(obj[name]);
+ } else {
+ result.push(undefined);
+ }
+ }
+ return goog.json.serialize(result);
+}
+
+
+/**
+ * Returns JSON-serialized array of prototypes for a given node.
+ * @param {Node} node Node to get prorotypes for.
+ * @return {string} JSON-serialized array where each item is a proto name.
+ */
+function devtools$$getPrototypes(node, args) {
+ var result = [];
+ for (var prototype = node; prototype; prototype = prototype.__proto__) {
+ var description = Object.prototype.toString.call(prototype);
+ result.push(description.replace(/^\[object (.*)\]$/i, '$1'));
+ }
+ return goog.json.serialize(result);
+}
diff --git a/webkit/glue/devtools/tools_agent.h b/webkit/glue/devtools/tools_agent.h
index 8db0de6..fb9268c 100644
--- a/webkit/glue/devtools/tools_agent.h
+++ b/webkit/glue/devtools/tools_agent.h
@@ -17,7 +17,12 @@
METHOD0(HideDOMNodeHighlight) \
\
/* Executes JavaScript in the context of the inspected window. */ \
- METHOD2(EvaluateJavaSctipt, int /* call_id */, String /* JS expression */)
+ METHOD2(EvaluateJavaScript, int /* call_id */, String /* JS expression */) \
+ \
+ /* Requests that utility js function is executed with the given args. */ \
+ METHOD4(ExecuteUtilityFunction, int /* call_id */, \
+ String /* function_name */, int /* context_node_id */, \
+ String /* json_args */)
DEFINE_RPC_CLASS(ToolsAgent, TOOLS_AGENT_STRUCT)
@@ -26,11 +31,14 @@ DEFINE_RPC_CLASS(ToolsAgent, TOOLS_AGENT_STRUCT)
/* Updates focused node on the client. */ \
METHOD1(UpdateFocusedNode, int /* node_id */) \
\
- /* Response message to EvaluateJavaSctipt. */ \
- METHOD2(DidEvaluateJavaSctipt, int /* call_id */, String /* result */) \
+ /* Response message to EvaluateJavaScript. */ \
+ METHOD2(DidEvaluateJavaScript, int /* call_id */, String /* result */) \
\
/* Updates focused node on the client. */ \
- METHOD2(FrameNavigate, std::string /* url */, bool /* top_level */)
+ METHOD2(FrameNavigate, std::string /* url */, bool /* top_level */) \
+ \
+ /* Response to the GetNodeProperties. */ \
+ METHOD2(DidExecuteUtilityFunction, int /* call_id */, String /* json */)
DEFINE_RPC_CLASS(ToolsAgentDelegate, TOOLS_AGENT_DELEGATE_STRUCT)