Diff
Modified: trunk/Source/WebCore/ChangeLog (116856 => 116857)
--- trunk/Source/WebCore/ChangeLog 2012-05-12 14:29:42 UTC (rev 116856)
+++ trunk/Source/WebCore/ChangeLog 2012-05-12 16:35:48 UTC (rev 116857)
@@ -1,3 +1,60 @@
+2012-05-12 Yury Semikhatsky <[email protected]>
+
+ Web Inspector: heap profiler should allow revealing an element which is logged to the console
+ https://bugs.webkit.org/show_bug.cgi?id=86204
+
+ Reviewed by Pavel Feldman.
+
+ JS objects in the console have context menu item that allows to reveal them in a heap snapshot view.
+
+ * English.lproj/localizedStrings.js:
+ * inspector/front-end/ConsoleMessage.js:
+ (WebInspector.ConsoleMessageImpl.prototype._formatParameterAsObject):
+ * inspector/front-end/ContextMenu.js:
+ (WebInspector.ContextMenu.prototype.isEmpty):
+ * inspector/front-end/DataGrid.js:
+ (WebInspector.DataGridNode.prototype._detach):
+ (WebInspector.DataGridNode.prototype.wasDetached):
+ * inspector/front-end/HeapSnapshot.js:
+ (WebInspector.HeapSnapshot.prototype.nodeClassName):
+ (WebInspector.HeapSnapshotNodesProvider.prototype.nodePosition):
+ * inspector/front-end/HeapSnapshotDataGrids.js:
+ (WebInspector.HeapSnapshotSortableDataGrid):
+ (WebInspector.HeapSnapshotSortableDataGrid.prototype.highlightObjectByHeapSnapshotId):
+ (WebInspector.HeapSnapshotSortableDataGrid.prototype.highlightNode):
+ (WebInspector.HeapSnapshotSortableDataGrid.prototype.nodeWasDetached):
+ (WebInspector.HeapSnapshotSortableDataGrid.prototype._clearCurrentHighlight):
+ (WebInspector.HeapSnapshotViewportDataGrid):
+ (WebInspector.HeapSnapshotViewportDataGrid.prototype.highlightNode):
+ (WebInspector.HeapSnapshotViewportDataGrid.prototype._onScroll):
+ (WebInspector.HeapSnapshotConstructorsDataGrid):
+ (WebInspector.HeapSnapshotConstructorsDataGrid.prototype.highlightObjectByHeapSnapshotId.didGetClassName):
+ (WebInspector.HeapSnapshotConstructorsDataGrid.prototype.highlightObjectByHeapSnapshotId):
+ (WebInspector.HeapSnapshotConstructorsDataGrid.prototype.setDataSource):
+ * inspector/front-end/HeapSnapshotGridNodes.js:
+ (WebInspector.HeapSnapshotGridNode.prototype.wasDetached):
+ (WebInspector.HeapSnapshotConstructorNode.prototype.revealNodeBySnapshotObjectId):
+ (WebInspector.HeapSnapshotConstructorNode.prototype.revealNodeBySnapshotObjectId.didPopulateChildren):
+ * inspector/front-end/HeapSnapshotProxy.js:
+ (WebInspector.HeapSnapshotProxy.prototype.nodeClassName):
+ (WebInspector.HeapSnapshotProviderProxy.prototype.nodePosition):
+ * inspector/front-end/ObjectPropertiesSection.js:
+ (WebInspector.ObjectPropertiesSection.ContextMenuProvider):
+ (WebInspector.ObjectPropertiesSection.ContextMenuProvider.prototype.populateContextMenu):
+ (WebInspector.ObjectPropertiesSection.addContextMenuProvider):
+ (WebInspector.ObjectPropertiesSection.prototype.enableContextMenu):
+ (WebInspector.ObjectPropertiesSection.prototype._contextMenuEventFired):
+ * inspector/front-end/ProfilesPanel.js:
+ (WebInspector.ProfilesPanel.prototype.showObject):
+ (WebInspector.RevealInHeapSnapshotContextMenuProvider):
+ (WebInspector.RevealInHeapSnapshotContextMenuProvider.prototype.populateContextMenu.revealInSummaryView):
+ (WebInspector.RevealInHeapSnapshotContextMenuProvider.prototype.populateContextMenu.didReceiveHeapObjectId):
+ (WebInspector.RevealInHeapSnapshotContextMenuProvider.prototype.populateContextMenu):
+ * inspector/front-end/profilesPanel.css:
+ (.highlighted-row):
+ (@-webkit-keyframes row_highlight):
+ (to):
+
2012-05-12 Ilya Tikhonovsky <[email protected]>
Web Inspector: move recording button state control out of addProfileHeader.
Modified: trunk/Source/WebCore/English.lproj/localizedStrings.js
(Binary files differ)
Modified: trunk/Source/WebCore/inspector/front-end/ConsoleMessage.js (116856 => 116857)
--- trunk/Source/WebCore/inspector/front-end/ConsoleMessage.js 2012-05-12 14:29:42 UTC (rev 116856)
+++ trunk/Source/WebCore/inspector/front-end/ConsoleMessage.js 2012-05-12 16:35:48 UTC (rev 116857)
@@ -264,7 +264,9 @@
_formatParameterAsObject: function(obj, elem)
{
- elem.appendChild(new WebInspector.ObjectPropertiesSection(obj, obj.description).element);
+ var section = new WebInspector.ObjectPropertiesSection(obj, obj.description);
+ section.enableContextMenu();
+ elem.appendChild(section.element);
},
_formatParameterAsNode: function(object, elem)
Modified: trunk/Source/WebCore/inspector/front-end/ContextMenu.js (116856 => 116857)
--- trunk/Source/WebCore/inspector/front-end/ContextMenu.js 2012-05-12 14:29:42 UTC (rev 116856)
+++ trunk/Source/WebCore/inspector/front-end/ContextMenu.js 2012-05-12 16:35:48 UTC (rev 116857)
@@ -80,6 +80,14 @@
this._items.push({type: "separator"});
},
+ /**
+ * @return {boolean}
+ */
+ isEmpty: function()
+ {
+ return !this._items.length;
+ },
+
_itemSelected: function(id)
{
if (this._handlers[id])
Modified: trunk/Source/WebCore/inspector/front-end/DataGrid.js (116856 => 116857)
--- trunk/Source/WebCore/inspector/front-end/DataGrid.js 2012-05-12 14:29:42 UTC (rev 116856)
+++ trunk/Source/WebCore/inspector/front-end/DataGrid.js 2012-05-12 16:35:48 UTC (rev 116857)
@@ -1606,8 +1606,14 @@
for (var i = 0; i < this.children.length; ++i)
this.children[i]._detach();
+
+ this.wasDetached();
},
+ wasDetached: function()
+ {
+ },
+
savePosition: function()
{
if (this._savedPosition)
Modified: trunk/Source/WebCore/inspector/front-end/HeapSnapshot.js (116856 => 116857)
--- trunk/Source/WebCore/inspector/front-end/HeapSnapshot.js 2012-05-12 14:29:42 UTC (rev 116856)
+++ trunk/Source/WebCore/inspector/front-end/HeapSnapshot.js 2012-05-12 16:35:48 UTC (rev 116857)
@@ -1286,6 +1286,15 @@
return diff;
},
+ nodeClassName: function(snapshotObjectId)
+ {
+ for (var it = this._allNodes; it.hasNext(); it.next()) {
+ if (it.node.id === snapshotObjectId)
+ return it.node.className;
+ }
+ return null;
+ },
+
_parseFilter: function(filter)
{
if (!filter)
@@ -1593,6 +1602,22 @@
}
WebInspector.HeapSnapshotNodesProvider.prototype = {
+ nodePosition: function(snapshotObjectId)
+ {
+ this._createIterationOrder();
+ if (this.isEmpty)
+ return -1;
+ this.sortAll();
+
+ var node = new WebInspector.HeapSnapshotNode(this.snapshot);
+ for (var i = 0; i < this._iterationOrder.length; i++) {
+ node.nodeIndex = this._iterationOrder[i];
+ if (node.id === snapshotObjectId)
+ return i;
+ }
+ return -1;
+ },
+
serializeItem: function(node)
{
return {
Modified: trunk/Source/WebCore/inspector/front-end/HeapSnapshotDataGrids.js (116856 => 116857)
--- trunk/Source/WebCore/inspector/front-end/HeapSnapshotDataGrids.js 2012-05-12 14:29:42 UTC (rev 116856)
+++ trunk/Source/WebCore/inspector/front-end/HeapSnapshotDataGrids.js 2012-05-12 16:35:48 UTC (rev 116857)
@@ -40,6 +40,10 @@
* @type {number}
*/
this._recursiveSortingDepth = 0;
+ /**
+ * @type {WebInspector.HeapSnapshotGridNode}
+ */
+ this._highlightedNode = null;
this.addEventListener("sorting changed", this.sortingChanged, this);
}
@@ -70,6 +74,37 @@
return this.rootNode().children;
},
+ /**
+ * @param {ProfilerAgent.HeapSnapshotObjectId} heapSnapshotObjectId
+ */
+ highlightObjectByHeapSnapshotId: function(heapSnapshotObjectId)
+ {
+ },
+
+ /**
+ * @param {WebInspector.HeapSnapshotGridNode} node
+ */
+ highlightNode: function(node)
+ {
+ this._clearCurrentHighlight();
+ this._highlightedNode = node;
+ this._highlightedNode.element.addStyleClass("highlighted-row");
+ },
+
+ nodeWasDetached: function(node)
+ {
+ if (this._highlightedNode === node)
+ this._clearCurrentHighlight();
+ },
+
+ _clearCurrentHighlight: function()
+ {
+ if (!this._highlightedNode)
+ return
+ this._highlightedNode.element.removeStyleClass("highlighted-row");
+ this._highlightedNode = null;
+ },
+
changeNameFilter: function(filter)
{
filter = filter.toLowerCase();
@@ -166,6 +201,10 @@
this._topLevelNodes = [];
this._topPadding = new WebInspector.HeapSnapshotPaddingNode();
this._bottomPadding = new WebInspector.HeapSnapshotPaddingNode();
+ /**
+ * @type {WebInspector.HeapSnapshotGridNode}
+ */
+ this._nodeToHighlightAfterScroll = null;
}
WebInspector.HeapSnapshotViewportDataGrid.prototype = {
@@ -233,6 +272,16 @@
this._topLevelNodes = [];
},
+ /**
+ * @override
+ * @param {WebInspector.HeapSnapshotGridNode} node
+ */
+ highlightNode: function(node)
+ {
+ node.element.scrollIntoViewIfNeeded(true);
+ this._nodeToHighlightAfterScroll = node;
+ },
+
_addPaddingRows: function(top, bottom)
{
if (this._topPadding.element.parentNode !== this.dataTableBody)
@@ -257,6 +306,11 @@
_onScroll: function(event)
{
this.updateVisibleNodes();
+
+ if (this._nodeToHighlightAfterScroll) {
+ WebInspector.HeapSnapshotSortableDataGrid.prototype.highlightNode.call(this, this._nodeToHighlightAfterScroll);
+ this._nodeToHighlightAfterScroll = null;
+ }
}
}
@@ -371,6 +425,8 @@
WebInspector.HeapSnapshotViewportDataGrid.call(this, columns);
this._profileIndex = -1;
this._topLevelNodes = [];
+
+ this._objectIdToSelect = null;
}
WebInspector.HeapSnapshotConstructorsDataGrid.prototype = {
@@ -385,12 +441,42 @@
}[sortColumn];
},
+ /**
+ * @override
+ * @param {ProfilerAgent.HeapSnapshotObjectId} id
+ */
+ highlightObjectByHeapSnapshotId: function(id)
+ {
+ if (!this.snapshot) {
+ this._objectIdToSelect = id;
+ return;
+ }
+
+ function didGetClassName(className)
+ {
+ var constructorNodes = this.topLevelNodes();
+ for (var i = 0; i < constructorNodes.length; i++) {
+ var parent = constructorNodes[i];
+ if (parent._name === className) {
+ parent.revealNodeBySnapshotObjectId(parseInt(id, 10));
+ return;
+ }
+ }
+ }
+ this.snapshot.nodeClassName(parseInt(id, 10), didGetClassName.bind(this));
+ },
+
setDataSource: function(snapshotView, snapshot)
{
this.snapshotView = snapshotView;
this.snapshot = snapshot;
if (this._profileIndex === -1)
this._populateChildren();
+
+ if (this._objectIdToSelect) {
+ this.highlightObjectByHeapSnapshotId(this._objectIdToSelect);
+ this._objectIdToSelect = null;
+ }
},
_populateChildren: function()
Modified: trunk/Source/WebCore/inspector/front-end/HeapSnapshotGridNodes.js (116856 => 116857)
--- trunk/Source/WebCore/inspector/front-end/HeapSnapshotGridNodes.js 2012-05-12 14:29:42 UTC (rev 116856)
+++ trunk/Source/WebCore/inspector/front-end/HeapSnapshotGridNodes.js 2012-05-12 16:35:48 UTC (rev 116857)
@@ -84,6 +84,14 @@
{
},
+ /**
+ * @override
+ */
+ wasDetached: function()
+ {
+ this._dataGrid.nodeWasDetached(this);
+ },
+
_toPercentString: function(num)
{
return num.toFixed(0) + "\u2009%"; // \u2009 is a thin space.
@@ -689,6 +697,36 @@
}
WebInspector.HeapSnapshotConstructorNode.prototype = {
+ /**
+ * @param {number} snapshotObjectId
+ */
+ revealNodeBySnapshotObjectId: function(snapshotObjectId)
+ {
+ function didGetNodePosition(nodePosition)
+ {
+ if (nodePosition !== -1)
+ this._populateChildren(nodePosition, null, didPopulateChildren.bind(this, nodePosition));
+ }
+
+ function didPopulateChildren(nodePosition)
+ {
+ var indexOfFirsChildInRange = 0;
+ for (var i = 0; i < this._retrievedChildrenRanges.length; i++) {
+ var range = this._retrievedChildrenRanges[i];
+ if (range.from <= nodePosition && nodePosition < range.to) {
+ var childIndex = indexOfFirsChildInRange + nodePosition - range.from;
+ var instanceNode = this.children[childIndex];
+ this._dataGrid.highlightNode(instanceNode);
+ return;
+ }
+ indexOfFirsChildInRange += range.to - range.from + 1;
+ }
+ }
+
+ this.expand();
+ this._provider.nodePosition(snapshotObjectId, didGetNodePosition.bind(this));
+ },
+
createCell: function(columnIdentifier)
{
var cell = columnIdentifier !== "object" ? this._createValueCell(columnIdentifier) : WebInspector.HeapSnapshotGridNode.prototype.createCell.call(this, columnIdentifier);
Modified: trunk/Source/WebCore/inspector/front-end/HeapSnapshotProxy.js (116856 => 116857)
--- trunk/Source/WebCore/inspector/front-end/HeapSnapshotProxy.js 2012-05-12 14:29:42 UTC (rev 116856)
+++ trunk/Source/WebCore/inspector/front-end/HeapSnapshotProxy.js 2012-05-12 16:35:48 UTC (rev 116857)
@@ -382,6 +382,11 @@
this.callMethod(callback, "calculateSnapshotDiff", baseSnapshotId, baseSnapshotAggregates);
},
+ nodeClassName: function(snapshotObjectId, callback)
+ {
+ this.callMethod(callback, "nodeClassName", snapshotObjectId);
+ },
+
createEdgesProvider: function(nodeIndex, filter)
{
return this.callFactoryMethod(null, "createEdgesProvider", "WebInspector.HeapSnapshotProviderProxy", nodeIndex, filter);
@@ -486,6 +491,11 @@
}
WebInspector.HeapSnapshotProviderProxy.prototype = {
+ nodePosition: function(snapshotObjectId, callback)
+ {
+ this.callMethod(callback, "nodePosition", snapshotObjectId);
+ },
+
isEmpty: function(callback)
{
this.callGetter(callback, "isEmpty");
Modified: trunk/Source/WebCore/inspector/front-end/ObjectPropertiesSection.js (116856 => 116857)
--- trunk/Source/WebCore/inspector/front-end/ObjectPropertiesSection.js 2012-05-12 14:29:42 UTC (rev 116856)
+++ trunk/Source/WebCore/inspector/front-end/ObjectPropertiesSection.js 2012-05-12 16:35:48 UTC (rev 116857)
@@ -50,7 +50,54 @@
WebInspector.ObjectPropertiesSection._arrayLoadThreshold = 100;
+
+/**
+ * @interface
+ */
+WebInspector.ObjectPropertiesSection.ContextMenuProvider = function()
+{
+}
+
+WebInspector.ObjectPropertiesSection.ContextMenuProvider.prototype = {
+ /**
+ * @param {WebInspector.ObjectPropertiesSection} section
+ * @param {WebInspector.ContextMenu} contextMenu
+ */
+ populateContextMenu: function(section, contextMenu)
+ {
+ }
+}
+
+
+/**
+ * @type {Array.<WebInspector.ObjectPropertiesSection.ContextMenuProvider>}
+ */
+WebInspector.ObjectPropertiesSection._contextMenuProviers = [];
+
+/**
+ * @param {WebInspector.ObjectPropertiesSection.ContextMenuProvider} provider
+ */
+WebInspector.ObjectPropertiesSection.addContextMenuProvider = function(provider)
+{
+ WebInspector.ObjectPropertiesSection._contextMenuProviers.push(provider);
+}
+
WebInspector.ObjectPropertiesSection.prototype = {
+ enableContextMenu: function()
+ {
+ this.element.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), true);
+ },
+
+ _contextMenuEventFired: function(event)
+ {
+ var contextMenu = new WebInspector.ContextMenu();
+ var providers = WebInspector.ObjectPropertiesSection._contextMenuProviers;
+ for (var i = 0; i < providers.length; i++)
+ providers[i].populateContextMenu(this, contextMenu);
+ if (!contextMenu.isEmpty())
+ contextMenu.show(event);
+ },
+
onpopulate: function()
{
this.update();
Modified: trunk/Source/WebCore/inspector/front-end/ProfilesPanel.js (116856 => 116857)
--- trunk/Source/WebCore/inspector/front-end/ProfilesPanel.js 2012-05-12 14:29:42 UTC (rev 116856)
+++ trunk/Source/WebCore/inspector/front-end/ProfilesPanel.js 2012-05-12 16:35:48 UTC (rev 116857)
@@ -229,6 +229,7 @@
this._createFileSelectorElement();
this.element.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
+ WebInspector.ObjectPropertiesSection.addContextMenuProvider(new WebInspector.RevealInHeapSnapshotContextMenuProvider());
}
WebInspector.ProfilesPanel.EventTypes = {
@@ -576,6 +577,27 @@
},
/**
+ * @param {ProfilerAgent.HeapSnapshotObjectId} snapshotObjectId
+ */
+ showObject: function(snapshotObjectId)
+ {
+ var heapProfiles = this.getProfiles(WebInspector.HeapSnapshotProfileType.TypeId);
+ for (var i = 0; i < heapProfiles.length; i++) {
+ var profile = ""
+ // TODO: allow to choose snapshot if there are several options.
+ if (profile.maxJSObjectId >= snapshotObjectId) {
+ this.showProfile(profile);
+ profile._profileView.changeView("Summary", function() {
+ if (profile._profileView.dataGrid !== profile._profileView.constructorsDataGrid)
+ return;
+ profile._profileView.dataGrid.highlightObjectByHeapSnapshotId(snapshotObjectId);
+ });
+ break;
+ }
+ }
+ },
+
+ /**
* @param {string} typeId
* @return {WebInspector.ProfileHeader}
*/
@@ -1041,8 +1063,54 @@
WebInspector.ProfilesPanel.prototype.__proto__ = WebInspector.Panel.prototype;
+
/**
+ * @implements {WebInspector.ObjectPropertiesSection.ContextMenuProvider}
* @constructor
+ */
+WebInspector.RevealInHeapSnapshotContextMenuProvider = function()
+{
+}
+
+WebInspector.RevealInHeapSnapshotContextMenuProvider.prototype = {
+ /**
+ * @override
+ * @param {WebInspector.ObjectPropertiesSection} section
+ * @param {WebInspector.ContextMenu} contextMenu
+ */
+ populateContextMenu: function(section, contextMenu)
+ {
+ if (WebInspector.inspectorView.currentPanel() !== WebInspector.panels.profiles)
+ return;
+
+ var objectId = section.object.objectId;
+ if (!objectId)
+ return;
+
+ var heapProfiles = WebInspector.panels.profiles.getProfiles(WebInspector.HeapSnapshotProfileType.TypeId);
+ if (!heapProfiles.length)
+ return;
+
+ function revealInSummaryView()
+ {
+ ProfilerAgent.getHeapObjectId(objectId, didReceiveHeapObjectId.bind(this));
+ }
+
+ function didReceiveHeapObjectId(error, result)
+ {
+ if (WebInspector.inspectorView.currentPanel() !== WebInspector.panels.profiles)
+ return;
+ if (!error)
+ WebInspector.panels.profiles.showObject(result);
+ }
+
+ contextMenu.appendItem(WebInspector.UIString("Reveal in Summary View"), revealInSummaryView.bind(this));
+ }
+}
+
+
+/**
+ * @constructor
* @implements {ProfilerAgent.Dispatcher}
*/
WebInspector.ProfilerDispatcher = function(profiler)
Modified: trunk/Source/WebCore/inspector/front-end/profilesPanel.css (116856 => 116857)
--- trunk/Source/WebCore/inspector/front-end/profilesPanel.css 2012-05-12 14:29:42 UTC (rev 116856)
+++ trunk/Source/WebCore/inspector/front-end/profilesPanel.css 2012-05-12 16:35:48 UTC (rev 116857)
@@ -186,3 +186,12 @@
body.inactive .profile-launcher-view-content button.running:not(.status-bar-item) {
color: rgb(220, 130, 130);
}
+
+.highlighted-row {
+ -webkit-animation: "row_highlight" 2s 0s;
+}
+
+@-webkit-keyframes row_highlight {
+ from {background-color: rgb(255, 255, 120); }
+ to { background-color: white; }
+}