2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * @extends {WebInspector.DataGrid}
34 * @param {!WebInspector.ProfileType.DataDisplayDelegate} dataDisplayDelegate
35 * @param {!Array.<!WebInspector.DataGrid.ColumnDescriptor>} columns
37 WebInspector.HeapSnapshotSortableDataGrid = function(dataDisplayDelegate, columns)
39 WebInspector.DataGrid.call(this, columns);
40 this._dataDisplayDelegate = dataDisplayDelegate;
45 this._recursiveSortingDepth = 0;
47 * @type {?WebInspector.HeapSnapshotGridNode}
49 this._highlightedNode = null;
53 this._populatedAndSorted = false;
55 * @type {?WebInspector.StatusBarInput}
57 this._nameFilter = null;
58 this.addEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.SortingComplete, this._sortingComplete, this);
59 this.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this.sortingChanged, this);
62 WebInspector.HeapSnapshotSortableDataGrid.Events = {
63 ContentShown: "ContentShown",
64 SortingComplete: "SortingComplete"
67 WebInspector.HeapSnapshotSortableDataGrid.prototype = {
69 * @param {!WebInspector.StatusBarInput} nameFilter
71 setNameFilter: function(nameFilter)
73 this._nameFilter = nameFilter;
79 defaultPopulateCount: function()
84 _disposeAllNodes: function()
86 var children = this.topLevelNodes();
87 for (var i = 0, l = children.length; i < l; ++i)
88 children[i].dispose();
96 if (this._nameFilter) {
97 this._nameFilter.addEventListener(WebInspector.StatusBarInput.Event.TextChanged, this._onNameFilterChanged, this);
98 this.updateVisibleNodes(true);
100 if (this._populatedAndSorted)
101 this.dispatchEventToListeners(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, this);
104 _sortingComplete: function()
106 this.removeEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.SortingComplete, this._sortingComplete, this);
107 this._populatedAndSorted = true;
108 this.dispatchEventToListeners(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, this);
116 if (this._nameFilter)
117 this._nameFilter.removeEventListener(WebInspector.StatusBarInput.Event.TextChanged, this._onNameFilterChanged, this);
118 this._clearCurrentHighlight();
122 * @param {!WebInspector.ContextMenu} contextMenu
123 * @param {?Event} event
125 populateContextMenu: function(contextMenu, event)
127 var td = event.target.enclosingNodeOrSelfWithNodeName("td");
130 var node = td.heapSnapshotNode;
133 * @this {WebInspector.HeapSnapshotSortableDataGrid}
135 function revealInDominatorsView()
137 this._dataDisplayDelegate.showObject(node.snapshotNodeId, "Dominators");
141 * @this {WebInspector.HeapSnapshotSortableDataGrid}
143 function revealInSummaryView()
145 this._dataDisplayDelegate.showObject(node.snapshotNodeId, "Summary");
148 if (node instanceof WebInspector.HeapSnapshotRetainingObjectNode) {
149 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Summary view" : "Reveal in Summary View"), revealInSummaryView.bind(this));
150 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Dominators view" : "Reveal in Dominators View"), revealInDominatorsView.bind(this));
151 } else if (node instanceof WebInspector.HeapSnapshotInstanceNode || node instanceof WebInspector.HeapSnapshotObjectNode) {
152 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Dominators view" : "Reveal in Dominators View"), revealInDominatorsView.bind(this));
153 } else if (node instanceof WebInspector.HeapSnapshotDominatorObjectNode) {
154 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Summary view" : "Reveal in Summary View"), revealInSummaryView.bind(this));
158 resetSortingCache: function()
160 delete this._lastSortColumnIdentifier;
161 delete this._lastSortAscending;
165 * @return {!Array.<!WebInspector.HeapSnapshotGridNode>}
167 topLevelNodes: function()
169 return this.rootNode().children;
173 * @param {!HeapProfilerAgent.HeapSnapshotObjectId} heapSnapshotObjectId
174 * @param {function(boolean)} callback
176 highlightObjectByHeapSnapshotId: function(heapSnapshotObjectId, callback)
181 * @param {!WebInspector.HeapSnapshotGridNode} node
183 highlightNode: function(node)
185 var prevNode = this._highlightedNode;
186 this._clearCurrentHighlight();
187 this._highlightedNode = node;
188 WebInspector.runCSSAnimationOnce(this._highlightedNode.element, "highlighted-row");
191 nodeWasDetached: function(node)
193 if (this._highlightedNode === node)
194 this._clearCurrentHighlight();
197 _clearCurrentHighlight: function()
199 if (!this._highlightedNode)
201 this._highlightedNode.element.classList.remove("highlighted-row");
202 this._highlightedNode = null;
205 resetNameFilter: function()
207 this._nameFilter.setValue("");
208 this._onNameFilterChanged();
211 _onNameFilterChanged: function()
213 this.updateVisibleNodes(true);
216 sortingChanged: function()
218 var sortAscending = this.isSortOrderAscending();
219 var sortColumnIdentifier = this.sortColumnIdentifier();
220 if (this._lastSortColumnIdentifier === sortColumnIdentifier && this._lastSortAscending === sortAscending)
222 this._lastSortColumnIdentifier = sortColumnIdentifier;
223 this._lastSortAscending = sortAscending;
224 var sortFields = this._sortFields(sortColumnIdentifier, sortAscending);
226 function SortByTwoFields(nodeA, nodeB)
228 var field1 = nodeA[sortFields[0]];
229 var field2 = nodeB[sortFields[0]];
230 var result = field1 < field2 ? -1 : (field1 > field2 ? 1 : 0);
235 field1 = nodeA[sortFields[2]];
236 field2 = nodeB[sortFields[2]];
237 result = field1 < field2 ? -1 : (field1 > field2 ? 1 : 0);
242 this._performSorting(SortByTwoFields);
245 _performSorting: function(sortFunction)
247 this.recursiveSortingEnter();
248 var children = this.allChildren(this.rootNode());
249 this.rootNode().removeChildren();
250 children.sort(sortFunction);
251 for (var i = 0, l = children.length; i < l; ++i) {
252 var child = children[i];
253 this.appendChildAfterSorting(child);
257 this.recursiveSortingLeave();
260 appendChildAfterSorting: function(child)
262 var revealed = child.revealed;
263 this.rootNode().appendChild(child);
264 child.revealed = revealed;
267 recursiveSortingEnter: function()
269 ++this._recursiveSortingDepth;
272 recursiveSortingLeave: function()
274 if (!this._recursiveSortingDepth)
276 if (--this._recursiveSortingDepth)
278 this.updateVisibleNodes(true);
279 this.dispatchEventToListeners(WebInspector.HeapSnapshotSortableDataGrid.Events.SortingComplete);
283 * @param {boolean} force
285 updateVisibleNodes: function(force)
290 * @param {!WebInspector.DataGridNode} parent
291 * @return {!Array.<!WebInspector.HeapSnapshotGridNode>}
293 allChildren: function(parent)
295 return parent.children;
299 * @param {!WebInspector.DataGridNode} parent
300 * @param {!WebInspector.DataGridNode} node
301 * @param {number} index
303 insertChild: function(parent, node, index)
305 parent.insertChild(node, index);
309 * @param {!WebInspector.HeapSnapshotGridNode} parent
310 * @param {number} index
312 removeChildByIndex: function(parent, index)
314 parent.removeChild(parent.children[index]);
318 * @param {!WebInspector.HeapSnapshotGridNode} parent
320 removeAllChildren: function(parent)
322 parent.removeChildren();
325 __proto__: WebInspector.DataGrid.prototype
331 * @extends {WebInspector.HeapSnapshotSortableDataGrid}
332 * @param {!WebInspector.ProfileType.DataDisplayDelegate} dataDisplayDelegate
333 * @param {!Array.<!WebInspector.DataGrid.ColumnDescriptor>} columns
335 WebInspector.HeapSnapshotViewportDataGrid = function(dataDisplayDelegate, columns)
337 WebInspector.HeapSnapshotSortableDataGrid.call(this, dataDisplayDelegate, columns);
338 this.scrollContainer.addEventListener("scroll", this._onScroll.bind(this), true);
340 * @type {?WebInspector.HeapSnapshotGridNode}
342 this._nodeToHighlightAfterScroll = null;
343 this._topPadding = new WebInspector.HeapSnapshotPaddingNode();
344 this._topPaddingHeight = 0;
345 this.dataTableBody.insertBefore(this._topPadding.element, this.dataTableBody.firstChild);
346 this._bottomPadding = new WebInspector.HeapSnapshotPaddingNode();
347 this._bottomPaddingHeight = 0;
348 this.dataTableBody.insertBefore(this._bottomPadding.element, this.dataTableBody.lastChild);
351 WebInspector.HeapSnapshotViewportDataGrid.prototype = {
353 * @return {!Array.<!WebInspector.HeapSnapshotGridNode>}
355 topLevelNodes: function()
357 return this.allChildren(this.rootNode());
360 appendChildAfterSorting: function(child)
362 // Do nothing here, it will be added in updateVisibleNodes.
367 * @param {boolean} force
368 * @param {!Array.<!WebInspector.HeapSnapshotGridNode>=} pathToReveal
370 updateVisibleNodes: function(force, pathToReveal)
372 // Guard zone is used to ensure there are always some extra items
373 // above and below the viewport to support keyboard navigation.
374 var guardZoneHeight = 40;
375 var scrollHeight = this.scrollContainer.scrollHeight;
376 var scrollTop = this.scrollContainer.scrollTop;
377 var scrollBottom = scrollHeight - scrollTop - this.scrollContainer.offsetHeight;
378 scrollTop = Math.max(0, scrollTop - guardZoneHeight);
379 scrollBottom = Math.max(0, scrollBottom - guardZoneHeight);
380 var viewPortHeight = scrollHeight - scrollTop - scrollBottom;
382 // Do nothing if populated nodes still fit the viewport.
383 if (!force && scrollTop >= this._topPaddingHeight && scrollBottom >= this._bottomPaddingHeight)
385 var hysteresisHeight = 500;
386 scrollTop -= hysteresisHeight;
387 viewPortHeight += 2 * hysteresisHeight;
389 var selectedNode = this.selectedNode;
390 this.rootNode().removeChildren();
392 this._topPaddingHeight = 0;
393 this._bottomPaddingHeight = 0;
395 this._addVisibleNodes(this.rootNode(), scrollTop, scrollTop + viewPortHeight, pathToReveal || null);
397 this._topPadding.setHeight(this._topPaddingHeight);
398 this._bottomPadding.setHeight(this._bottomPaddingHeight);
401 // Keep selection even if the node is not in the current viewport.
402 if (selectedNode.parent)
403 selectedNode.select(true);
405 this.selectedNode = selectedNode;
410 * @param {!WebInspector.DataGridNode} parentNode
411 * @param {number} topBound
412 * @param {number} bottomBound
413 * @param {?Array.<!WebInspector.HeapSnapshotGridNode>} pathToReveal
416 _addVisibleNodes: function(parentNode, topBound, bottomBound, pathToReveal)
418 if (!parentNode.expanded)
421 var nodeToReveal = pathToReveal ? pathToReveal[0] : null;
422 var restPathToReveal = pathToReveal && pathToReveal.length > 1 ? pathToReveal.slice(1) : null;
423 var children = this.allChildren(parentNode);
425 var nameFilterValue = this._nameFilter ? this._nameFilter.value().toLowerCase() : "";
426 // Iterate over invisible nodes beyond the upper bound of viewport.
427 // Do not insert them into the grid, but count their total height.
428 for (var i = 0; i < children.length; ++i) {
429 var child = children[i];
430 if (nameFilterValue && child.filteredOut && child.filteredOut(nameFilterValue))
432 var newTop = topPadding + this._nodeHeight(child);
433 if (nodeToReveal === child || (!nodeToReveal && newTop > topBound))
438 // Put visible nodes into the data grid.
439 var position = topPadding;
440 for (; i < children.length && (nodeToReveal || position < bottomBound); ++i) {
441 var child = children[i];
442 if (nameFilterValue && child.filteredOut && child.filteredOut(nameFilterValue))
444 var hasChildren = child.hasChildren;
445 child.removeChildren();
446 child.hasChildren = hasChildren;
447 child.revealed = true;
448 parentNode.appendChild(child);
449 position += child.nodeSelfHeight();
450 position += this._addVisibleNodes(child, topBound - position, bottomBound - position, restPathToReveal);
451 if (nodeToReveal === child)
455 // Count the invisible nodes beyond the bottom bound of the viewport.
456 var bottomPadding = 0;
457 for (; i < children.length; ++i) {
458 var child = children[i];
459 if (nameFilterValue && child.filteredOut && child.filteredOut(nameFilterValue))
461 bottomPadding += this._nodeHeight(child);
464 this._topPaddingHeight += topPadding;
465 this._bottomPaddingHeight += bottomPadding;
466 return position + bottomPadding;
470 * @param {!WebInspector.HeapSnapshotGridNode} node
473 _nodeHeight: function(node)
477 var result = node.nodeSelfHeight();
480 var children = this.allChildren(node);
481 for (var i = 0; i < children.length; i++)
482 result += this._nodeHeight(children[i]);
490 defaultAttachLocation: function()
492 return this._bottomPadding.element;
496 * @param {!Array.<!WebInspector.HeapSnapshotGridNode>} pathToReveal
498 revealTreeNode: function(pathToReveal)
500 this.updateVisibleNodes(true, pathToReveal);
504 * @param {!WebInspector.DataGridNode} parent
505 * @return {!Array.<!WebInspector.HeapSnapshotGridNode>}
507 allChildren: function(parent)
509 return parent._allChildren || (parent._allChildren = []);
513 * @param {!WebInspector.DataGridNode} parent
514 * @param {!WebInspector.DataGridNode} node
516 appendNode: function(parent, node)
518 this.allChildren(parent).push(node);
522 * @param {!WebInspector.DataGridNode} parent
523 * @param {!WebInspector.DataGridNode} node
524 * @param {number} index
526 insertChild: function(parent, node, index)
528 this.allChildren(parent).splice(index, 0, node);
531 removeChildByIndex: function(parent, index)
533 this.allChildren(parent).splice(index, 1);
536 removeAllChildren: function(parent)
538 parent._allChildren = [];
541 removeTopLevelNodes: function()
543 this._disposeAllNodes();
544 this.rootNode().removeChildren();
545 this.rootNode()._allChildren = [];
550 * @param {!WebInspector.HeapSnapshotGridNode} node
552 highlightNode: function(node)
554 if (this._isScrolledIntoView(node.element)) {
555 this.updateVisibleNodes(true);
556 WebInspector.HeapSnapshotSortableDataGrid.prototype.highlightNode.call(this, node);
558 node.element.scrollIntoViewIfNeeded(true);
559 this._nodeToHighlightAfterScroll = node;
564 * @param {!Element} element
567 _isScrolledIntoView: function(element)
569 var viewportTop = this.scrollContainer.scrollTop;
570 var viewportBottom = viewportTop + this.scrollContainer.clientHeight;
571 var elemTop = element.offsetTop
572 var elemBottom = elemTop + element.offsetHeight;
573 return elemBottom <= viewportBottom && elemTop >= viewportTop;
578 WebInspector.HeapSnapshotSortableDataGrid.prototype.onResize.call(this);
579 this.updateVisibleNodes(false);
582 _onScroll: function(event)
584 this.updateVisibleNodes(false);
586 if (this._nodeToHighlightAfterScroll) {
587 WebInspector.HeapSnapshotSortableDataGrid.prototype.highlightNode.call(this, this._nodeToHighlightAfterScroll);
588 this._nodeToHighlightAfterScroll = null;
592 __proto__: WebInspector.HeapSnapshotSortableDataGrid.prototype
598 WebInspector.HeapSnapshotPaddingNode = function()
600 this.element = document.createElement("tr");
601 this.element.classList.add("revealed");
605 WebInspector.HeapSnapshotPaddingNode.prototype = {
606 setHeight: function(height)
608 this.element.style.height = height + "px";
610 removeFromTable: function()
612 var parent = this.element.parentNode;
614 parent.removeChild(this.element);
621 * @extends {WebInspector.HeapSnapshotSortableDataGrid}
622 * @param {!WebInspector.ProfileType.DataDisplayDelegate} dataDisplayDelegate
623 * @param {!Array.<!WebInspector.DataGrid.ColumnDescriptor>=} columns
625 WebInspector.HeapSnapshotContainmentDataGrid = function(dataDisplayDelegate, columns)
627 columns = columns || [
628 {id: "object", title: WebInspector.UIString("Object"), disclosure: true, sortable: true},
629 {id: "distance", title: WebInspector.UIString("Distance"), width: "80px", sortable: true},
630 {id: "shallowSize", title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true},
631 {id: "retainedSize", title: WebInspector.UIString("Retained Size"), width: "120px", sortable: true, sort: WebInspector.DataGrid.Order.Descending}
633 WebInspector.HeapSnapshotSortableDataGrid.call(this, dataDisplayDelegate, columns);
636 WebInspector.HeapSnapshotContainmentDataGrid.prototype = {
638 * @param {!WebInspector.HeapSnapshotProxy} snapshot
639 * @param {number} nodeIndex
641 setDataSource: function(snapshot, nodeIndex)
643 this.snapshot = snapshot;
644 var node = { nodeIndex: nodeIndex || snapshot.rootNodeIndex };
645 var fakeEdge = { node: node };
646 this.setRootNode(this._createRootNode(snapshot, fakeEdge));
647 this.rootNode().sort();
650 _createRootNode: function(snapshot, fakeEdge)
652 return new WebInspector.HeapSnapshotObjectNode(this, snapshot, fakeEdge, null);
655 sortingChanged: function()
657 var rootNode = this.rootNode();
658 if (rootNode.hasChildren)
662 __proto__: WebInspector.HeapSnapshotSortableDataGrid.prototype
668 * @extends {WebInspector.HeapSnapshotContainmentDataGrid}
669 * @param {!WebInspector.ProfileType.DataDisplayDelegate} dataDisplayDelegate
671 WebInspector.HeapSnapshotRetainmentDataGrid = function(dataDisplayDelegate)
674 {id: "object", title: WebInspector.UIString("Object"), disclosure: true, sortable: true},
675 {id: "distance", title: WebInspector.UIString("Distance"), width: "80px", sortable: true, sort: WebInspector.DataGrid.Order.Ascending},
676 {id: "shallowSize", title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true},
677 {id: "retainedSize", title: WebInspector.UIString("Retained Size"), width: "120px", sortable: true}
679 WebInspector.HeapSnapshotContainmentDataGrid.call(this, dataDisplayDelegate, columns);
682 WebInspector.HeapSnapshotRetainmentDataGrid.Events = {
683 ExpandRetainersComplete: "ExpandRetainersComplete"
686 WebInspector.HeapSnapshotRetainmentDataGrid.prototype = {
687 _createRootNode: function(snapshot, fakeEdge)
689 return new WebInspector.HeapSnapshotRetainingObjectNode(this, snapshot, fakeEdge, null);
692 _sortFields: function(sortColumn, sortAscending)
695 object: ["_name", sortAscending, "_count", false],
696 count: ["_count", sortAscending, "_name", true],
697 shallowSize: ["_shallowSize", sortAscending, "_name", true],
698 retainedSize: ["_retainedSize", sortAscending, "_name", true],
699 distance: ["_distance", sortAscending, "_name", true]
705 this.rootNode().removeChildren();
706 this.resetSortingCache();
710 * @param {!WebInspector.HeapSnapshotProxy} snapshot
711 * @param {number} nodeIndex
713 setDataSource: function(snapshot, nodeIndex)
715 WebInspector.HeapSnapshotContainmentDataGrid.prototype.setDataSource.call(this, snapshot, nodeIndex);
716 this.rootNode().expand();
719 __proto__: WebInspector.HeapSnapshotContainmentDataGrid.prototype
724 * @extends {WebInspector.HeapSnapshotViewportDataGrid}
725 * @param {!WebInspector.ProfileType.DataDisplayDelegate} dataDisplayDelegate
727 WebInspector.HeapSnapshotConstructorsDataGrid = function(dataDisplayDelegate)
730 {id: "object", title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true},
731 {id: "distance", title: WebInspector.UIString("Distance"), width: "90px", sortable: true},
732 {id: "count", title: WebInspector.UIString("Objects Count"), width: "90px", sortable: true},
733 {id: "shallowSize", title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true},
734 {id: "retainedSize", title: WebInspector.UIString("Retained Size"), width: "120px", sort: WebInspector.DataGrid.Order.Descending, sortable: true}
736 WebInspector.HeapSnapshotViewportDataGrid.call(this, dataDisplayDelegate, columns);
737 this._profileIndex = -1;
739 this._objectIdToSelect = null;
742 WebInspector.HeapSnapshotConstructorsDataGrid.prototype = {
743 _sortFields: function(sortColumn, sortAscending)
746 object: ["_name", sortAscending, "_count", false],
747 distance: ["_distance", sortAscending, "_retainedSize", true],
748 count: ["_count", sortAscending, "_name", true],
749 shallowSize: ["_shallowSize", sortAscending, "_name", true],
750 retainedSize: ["_retainedSize", sortAscending, "_name", true]
756 * @param {!HeapProfilerAgent.HeapSnapshotObjectId} id
757 * @param {function(boolean)} callback
759 highlightObjectByHeapSnapshotId: function(id, callback)
761 if (!this.snapshot) {
762 this._objectIdToSelect = id;
767 * @param {?string} className
768 * @this {WebInspector.HeapSnapshotConstructorsDataGrid}
770 function didGetClassName(className)
776 var constructorNodes = this.topLevelNodes();
777 for (var i = 0; i < constructorNodes.length; i++) {
778 var parent = constructorNodes[i];
779 if (parent._name === className) {
780 parent.revealNodeBySnapshotObjectId(parseInt(id, 10), callback);
785 this.snapshot.nodeClassName(parseInt(id, 10), didGetClassName.bind(this));
790 this._nextRequestedFilter = null;
791 this._lastFilter = null;
792 this.removeTopLevelNodes();
795 setDataSource: function(snapshot)
797 this.snapshot = snapshot;
798 if (this._profileIndex === -1)
799 this._populateChildren();
801 if (this._objectIdToSelect) {
802 this.highlightObjectByHeapSnapshotId(this._objectIdToSelect, function(found) {});
803 this._objectIdToSelect = null;
808 * @param {number} minNodeId
809 * @param {number} maxNodeId
811 setSelectionRange: function(minNodeId, maxNodeId)
813 this._populateChildren(new WebInspector.HeapSnapshotCommon.NodeFilter(minNodeId, maxNodeId));
817 * @param {number} allocationNodeId
819 setAllocationNodeId: function(allocationNodeId)
821 var filter = new WebInspector.HeapSnapshotCommon.NodeFilter();
822 filter.allocationNodeId = allocationNodeId;
823 this._populateChildren(filter);
827 * @param {!WebInspector.HeapSnapshotCommon.NodeFilter} nodeFilter
828 * @param {!Object.<string, !WebInspector.HeapSnapshotCommon.Aggregate>} aggregates
830 _aggregatesReceived: function(nodeFilter, aggregates)
832 this._filterInProgress = null;
833 if (this._nextRequestedFilter) {
834 this.snapshot.aggregatesWithFilter(this._nextRequestedFilter, this._aggregatesReceived.bind(this, this._nextRequestedFilter));
835 this._filterInProgress = this._nextRequestedFilter;
836 this._nextRequestedFilter = null;
838 this.removeTopLevelNodes();
839 this.resetSortingCache();
840 for (var constructor in aggregates)
841 this.appendNode(this.rootNode(), new WebInspector.HeapSnapshotConstructorNode(this, constructor, aggregates[constructor], nodeFilter));
842 this.sortingChanged();
843 this._lastFilter = nodeFilter;
847 * @param {!WebInspector.HeapSnapshotCommon.NodeFilter=} nodeFilter
849 _populateChildren: function(nodeFilter)
851 nodeFilter = nodeFilter || new WebInspector.HeapSnapshotCommon.NodeFilter();
853 if (this._filterInProgress) {
854 this._nextRequestedFilter = this._filterInProgress.equals(nodeFilter) ? null : nodeFilter;
857 if (this._lastFilter && this._lastFilter.equals(nodeFilter))
859 this._filterInProgress = nodeFilter;
860 this.snapshot.aggregatesWithFilter(nodeFilter, this._aggregatesReceived.bind(this, nodeFilter));
863 filterSelectIndexChanged: function(profiles, profileIndex)
865 this._profileIndex = profileIndex;
868 if (profileIndex !== -1) {
869 var minNodeId = profileIndex > 0 ? profiles[profileIndex - 1].maxJSObjectId : 0;
870 var maxNodeId = profiles[profileIndex].maxJSObjectId;
871 nodeFilter = new WebInspector.HeapSnapshotCommon.NodeFilter(minNodeId, maxNodeId)
874 this._populateChildren(nodeFilter);
877 __proto__: WebInspector.HeapSnapshotViewportDataGrid.prototype
883 * @extends {WebInspector.HeapSnapshotViewportDataGrid}
884 * @param {!WebInspector.ProfileType.DataDisplayDelegate} dataDisplayDelegate
886 WebInspector.HeapSnapshotDiffDataGrid = function(dataDisplayDelegate)
889 {id: "object", title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true},
890 {id: "addedCount", title: WebInspector.UIString("# New"), width: "72px", sortable: true},
891 {id: "removedCount", title: WebInspector.UIString("# Deleted"), width: "72px", sortable: true},
892 {id: "countDelta", title: WebInspector.UIString("# Delta"), width: "64px", sortable: true},
893 {id: "addedSize", title: WebInspector.UIString("Alloc. Size"), width: "72px", sortable: true, sort: WebInspector.DataGrid.Order.Descending},
894 {id: "removedSize", title: WebInspector.UIString("Freed Size"), width: "72px", sortable: true},
895 {id: "sizeDelta", title: WebInspector.UIString("Size Delta"), width: "72px", sortable: true}
897 WebInspector.HeapSnapshotViewportDataGrid.call(this, dataDisplayDelegate, columns);
900 WebInspector.HeapSnapshotDiffDataGrid.prototype = {
905 defaultPopulateCount: function()
910 _sortFields: function(sortColumn, sortAscending)
913 object: ["_name", sortAscending, "_count", false],
914 addedCount: ["_addedCount", sortAscending, "_name", true],
915 removedCount: ["_removedCount", sortAscending, "_name", true],
916 countDelta: ["_countDelta", sortAscending, "_name", true],
917 addedSize: ["_addedSize", sortAscending, "_name", true],
918 removedSize: ["_removedSize", sortAscending, "_name", true],
919 sizeDelta: ["_sizeDelta", sortAscending, "_name", true]
923 setDataSource: function(snapshot)
925 this.snapshot = snapshot;
929 * @param {!WebInspector.HeapSnapshotProxy} baseSnapshot
931 setBaseDataSource: function(baseSnapshot)
933 this.baseSnapshot = baseSnapshot;
934 this.removeTopLevelNodes();
935 this.resetSortingCache();
936 if (this.baseSnapshot === this.snapshot) {
937 this.dispatchEventToListeners(WebInspector.HeapSnapshotSortableDataGrid.Events.SortingComplete);
940 this._populateChildren();
943 _populateChildren: function()
946 * @this {WebInspector.HeapSnapshotDiffDataGrid}
948 function aggregatesForDiffReceived(aggregatesForDiff)
950 this.snapshot.calculateSnapshotDiff(this.baseSnapshot.uid, aggregatesForDiff, didCalculateSnapshotDiff.bind(this));
953 * @this {WebInspector.HeapSnapshotDiffDataGrid}
955 function didCalculateSnapshotDiff(diffByClassName)
957 for (var className in diffByClassName) {
958 var diff = diffByClassName[className];
959 this.appendNode(this.rootNode(), new WebInspector.HeapSnapshotDiffNode(this, className, diff));
961 this.sortingChanged();
964 // Two snapshots live in different workers isolated from each other. That is why
965 // we first need to collect information about the nodes in the first snapshot and
966 // then pass it to the second snapshot to calclulate the diff.
967 this.baseSnapshot.aggregatesForDiff(aggregatesForDiffReceived.bind(this));
970 __proto__: WebInspector.HeapSnapshotViewportDataGrid.prototype
976 * @extends {WebInspector.HeapSnapshotSortableDataGrid}
977 * @param {!WebInspector.ProfileType.DataDisplayDelegate} dataDisplayDelegate
979 WebInspector.HeapSnapshotDominatorsDataGrid = function(dataDisplayDelegate)
982 {id: "object", title: WebInspector.UIString("Object"), disclosure: true, sortable: true},
983 {id: "shallowSize", title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true},
984 {id: "retainedSize", title: WebInspector.UIString("Retained Size"), width: "120px", sort: WebInspector.DataGrid.Order.Descending, sortable: true}
986 WebInspector.HeapSnapshotSortableDataGrid.call(this, dataDisplayDelegate, columns);
987 this._objectIdToSelect = null;
990 WebInspector.HeapSnapshotDominatorsDataGrid.prototype = {
995 defaultPopulateCount: function()
1000 setDataSource: function(snapshot)
1002 this.snapshot = snapshot;
1004 var fakeNode = new WebInspector.HeapSnapshotCommon.Node(-1, "", 0, this.snapshot.rootNodeIndex, 0, 0, "");
1005 this.setRootNode(new WebInspector.HeapSnapshotDominatorObjectNode(this, fakeNode));
1006 this.rootNode().sort();
1008 if (this._objectIdToSelect) {
1009 this.highlightObjectByHeapSnapshotId(this._objectIdToSelect, function(found) {});
1010 this._objectIdToSelect = null;
1014 sortingChanged: function()
1016 this.rootNode().sort();
1021 * @param {!HeapProfilerAgent.HeapSnapshotObjectId} id
1022 * @param {function(boolean)} callback
1024 highlightObjectByHeapSnapshotId: function(id, callback)
1026 if (!this.snapshot) {
1027 this._objectIdToSelect = id;
1033 * @this {WebInspector.HeapSnapshotDominatorsDataGrid}
1035 function didGetDominators(dominatorIds)
1037 if (!dominatorIds) {
1038 console.error("Cannot find corresponding heap snapshot node");
1042 var dominatorNode = this.rootNode();
1043 expandNextDominator.call(this, dominatorIds, dominatorNode);
1047 * @this {WebInspector.HeapSnapshotDominatorsDataGrid}
1049 function expandNextDominator(dominatorIds, dominatorNode)
1051 if (!dominatorNode) {
1052 console.error("Cannot find dominator node");
1056 if (!dominatorIds.length) {
1057 this.highlightNode(dominatorNode);
1058 dominatorNode.element.scrollIntoViewIfNeeded(true);
1062 var snapshotObjectId = dominatorIds.pop();
1063 dominatorNode.retrieveChildBySnapshotObjectId(snapshotObjectId, expandNextDominator.bind(this, dominatorIds));
1066 this.snapshot.dominatorIdsForNode(parseInt(id, 10), didGetDominators.bind(this));
1069 __proto__: WebInspector.HeapSnapshotSortableDataGrid.prototype
1075 * @extends {WebInspector.HeapSnapshotViewportDataGrid}
1076 * @param {!WebInspector.ProfileType.DataDisplayDelegate} dataDisplayDelegate
1078 WebInspector.AllocationDataGrid = function(dataDisplayDelegate)
1081 {id: "liveCount", title: WebInspector.UIString("Live Count"), width: "72px", sortable: true},
1082 {id: "count", title: WebInspector.UIString("Count"), width: "72px", sortable: true},
1083 {id: "liveSize", title: WebInspector.UIString("Live Size"), width: "72px", sortable: true},
1084 {id: "size", title: WebInspector.UIString("Size"), width: "72px", sortable: true, sort: WebInspector.DataGrid.Order.Descending},
1085 {id: "name", title: WebInspector.UIString("Function"), disclosure: true, sortable: true},
1087 WebInspector.HeapSnapshotViewportDataGrid.call(this, dataDisplayDelegate, columns);
1088 this._linkifier = new WebInspector.Linkifier();
1091 WebInspector.AllocationDataGrid.prototype = {
1094 this._linkifier.reset();
1097 setDataSource: function(snapshot)
1099 this.snapshot = snapshot;
1100 this.snapshot.allocationTracesTops(didReceiveAllocationTracesTops.bind(this));
1103 * @param {!Array.<!WebInspector.HeapSnapshotCommon.SerializedAllocationNode>} tops
1104 * @this {WebInspector.AllocationDataGrid}
1106 function didReceiveAllocationTracesTops(tops)
1108 this._topNodes = tops;
1109 this._populateChildren();
1113 _populateChildren: function()
1115 this.removeTopLevelNodes();
1116 var root = this.rootNode();
1117 var tops = this._topNodes;
1118 for (var i = 0; i < tops.length; i++)
1119 this.appendNode(root, new WebInspector.AllocationGridNode(this, tops[i]));
1120 this.updateVisibleNodes(true);
1123 sortingChanged: function()
1125 this._topNodes.sort(this._createComparator());
1126 this.rootNode().removeChildren();
1127 this._populateChildren();
1132 * @return {function(!Object, !Object):number}
1134 _createComparator: function()
1136 var fieldName = this.sortColumnIdentifier();
1137 var compareResult = (this.sortOrder() === WebInspector.DataGrid.Order.Ascending) ? +1 : -1;
1139 * @param {!Object} a
1140 * @param {!Object} b
1143 function compare(a, b)
1145 if (a[fieldName] > b[fieldName])
1146 return compareResult;
1147 if (a[fieldName] < b[fieldName])
1148 return -compareResult;
1154 __proto__: WebInspector.HeapSnapshotViewportDataGrid.prototype