devil
Version:
Debugger, profiler and runtime with embedded WebKit DevTools client.
5,811 lines • 289 kB
JavaScript
WebInspector.ProfileType = function (id, name) {
WebInspector.Object.call(this);
this._id = id;
this._name = name;
this._profiles = [];
this._profileBeingRecorded = null;
console.trace("RESETTING SETTING PROFILE");
this._nextProfileUid = 1;
window.addEventListener("unload", this._clearTempStorage.bind(this), false);
}
WebInspector.ProfileType.Events = {AddProfileHeader: "add-profile-header", ProfileComplete: "profile-complete", RemoveProfileHeader: "remove-profile-header", ViewUpdated: "view-updated"}
WebInspector.ProfileType.prototype = {
nextProfileUid: function () {
return this._nextProfileUid;
}, hasTemporaryView: function () {
return false;
}, fileExtension: function () {
return null;
}, get statusBarItems() {
return [];
}, get buttonTooltip() {
return "";
}, get id() {
return this._id;
}, get treeItemTitle() {
return this._name;
}, get name() {
return this._name;
}, buttonClicked: function () {
return false;
}, get description() {
return "";
}, isInstantProfile: function () {
return false;
}, isEnabled: function () {
return true;
}, getProfiles: function () {
function isFinished(profile) {
return this._profileBeingRecorded !== profile;
}
return this._profiles.filter(isFinished.bind(this));
}, decorationElement: function () {
return null;
}, getProfile: function (uid) {
for (var i = 0; i < this._profiles.length; ++i) {
if (this._profiles[i].uid === uid)
return this._profiles[i];
}
return null;
}, loadFromFile: function (file) {
var name = file.name;
if (name.endsWith(this.fileExtension()))
name = name.substr(0, name.length - this.fileExtension().length);
var profile = this.createProfileLoadedFromFile(name);
profile.setFromFile();
this.setProfileBeingRecorded(profile);
this.addProfile(profile);
profile.loadFromFile(file);
}, createProfileLoadedFromFile: function (title) {
throw new Error("Needs implemented.");
}, addProfile: function (profile) {
this._profiles.push(profile);
this.dispatchEventToListeners(WebInspector.ProfileType.Events.AddProfileHeader, profile);
}, removeProfile: function (profile) {
var index = this._profiles.indexOf(profile);
if (index === -1)
return;
this._profiles.splice(index, 1);
this._disposeProfile(profile);
}, _clearTempStorage: function () {
for (var i = 0; i < this._profiles.length; ++i)
this._profiles[i].removeTempFile();
}, profileBeingRecorded: function () {
return this._profileBeingRecorded;
}, setProfileBeingRecorded: function (profile) {
console.trace("THIS SETTING PROFILE", profile);
if (this._profileBeingRecorded && this._profileBeingRecorded.target())
WebInspector.profilingLock().release();
if (profile && profile.target())
WebInspector.profilingLock().acquire();
console.trace("THIS SETTING PROFILE", profile);
this._profileBeingRecorded = profile;
}, profileBeingRecordedRemoved: function () {
}, _reset: function () {
var profiles = this._profiles.slice(0);
for (var i = 0; i < profiles.length; ++i)
this._disposeProfile(profiles[i]);
this._profiles = [];
this._nextProfileUid = 1;
}, _disposeProfile: function (profile) {
this.dispatchEventToListeners(WebInspector.ProfileType.Events.RemoveProfileHeader, profile);
profile.dispose();
if (this._profileBeingRecorded === profile) {
this.profileBeingRecordedRemoved();
this.setProfileBeingRecorded(null);
}
}, __proto__: WebInspector.Object.prototype
}
WebInspector.ProfileType.DataDisplayDelegate = function () {
}
WebInspector.ProfileType.DataDisplayDelegate.prototype = {
showProfile: function (profile) {
}, showObject: function (snapshotObjectId, perspectiveName) {
}
}
WebInspector.ProfileHeader = function (target, profileType, title) {
this._weakTarget = target ? target.weakReference() : new WeakReference(null);
this._profileType = profileType;
this.title = title;
this.uid = profileType._nextProfileUid++;
this._fromFile = false;
}
WebInspector.ProfileHeader.StatusUpdate = function (subtitle, wait) {
this.subtitle = subtitle;
this.wait = wait;
}
WebInspector.ProfileHeader.Events = {UpdateStatus: "UpdateStatus", ProfileReceived: "ProfileReceived"}
WebInspector.ProfileHeader.prototype = {
target: function () {
return this._weakTarget.get();
}, weakTarget: function () {
return this._weakTarget;
}, profileType: function () {
return this._profileType;
}, updateStatus: function (subtitle, wait) {
this.dispatchEventToListeners(WebInspector.ProfileHeader.Events.UpdateStatus, new WebInspector.ProfileHeader.StatusUpdate(subtitle, wait));
}, createSidebarTreeElement: function (dataDisplayDelegate) {
throw new Error("Needs implemented.");
}, createView: function (dataDisplayDelegate) {
throw new Error("Not implemented.");
}, removeTempFile: function () {
if (this._tempFile)
this._tempFile.remove();
}, dispose: function () {
}, load: function (callback) {
}, canSaveToFile: function () {
return false;
}, saveToFile: function () {
throw new Error("Needs implemented");
}, loadFromFile: function (file) {
throw new Error("Needs implemented");
}, fromFile: function () {
return this._fromFile;
}, setFromFile: function () {
this._fromFile = true;
}, __proto__: WebInspector.Object.prototype
}
WebInspector.ProfilesPanel = function () {
WebInspector.PanelWithSidebarTree.call(this, "profiles");
this.registerRequiredCSS("panelEnablerView.css");
this.registerRequiredCSS("heapProfiler.css");
this.registerRequiredCSS("profilesPanel.css");
this._searchableView = new WebInspector.SearchableView(this);
var mainView = new WebInspector.VBox();
this._searchableView.show(mainView.element);
mainView.show(this.mainElement());
this.profilesItemTreeElement = new WebInspector.ProfilesSidebarTreeElement(this);
this.sidebarTree.appendChild(this.profilesItemTreeElement);
this.profileViews = document.createElement("div");
this.profileViews.id = "profile-views";
this.profileViews.classList.add("vbox");
this._searchableView.element.appendChild(this.profileViews);
var statusBarContainer = document.createElementWithClass("div", "profiles-status-bar");
mainView.element.insertBefore(statusBarContainer, mainView.element.firstChild);
this._statusBarElement = statusBarContainer.createChild("div", "status-bar");
this.sidebarElement().classList.add("profiles-sidebar-tree-box");
var statusBarContainerLeft = document.createElementWithClass("div", "profiles-status-bar");
this.sidebarElement().insertBefore(statusBarContainerLeft, this.sidebarElement().firstChild);
this._statusBarButtons = statusBarContainerLeft.createChild("div", "status-bar");
this.recordButton = new WebInspector.StatusBarButton("", "record-profile-status-bar-item");
this.recordButton.addEventListener("click", this.toggleRecordButton, this);
this._statusBarButtons.appendChild(this.recordButton.element);
this.clearResultsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear all profiles."), "clear-status-bar-item");
this.clearResultsButton.addEventListener("click", this._reset, this);
this._statusBarButtons.appendChild(this.clearResultsButton.element);
this._profileTypeStatusBarItemsContainer = this._statusBarElement.createChild("div");
this._profileViewStatusBarItemsContainer = this._statusBarElement.createChild("div");
this._profileGroups = {};
this._launcherView = new WebInspector.MultiProfileLauncherView(this);
this._launcherView.addEventListener(WebInspector.MultiProfileLauncherView.EventTypes.ProfileTypeSelected, this._onProfileTypeSelected, this);
this._profileToView = [];
this._typeIdToSidebarSection = {};
var types = WebInspector.ProfileTypeRegistry.instance.profileTypes();
for (var i = 0; i < types.length; i++)
this._registerProfileType(types[i]);
this._launcherView.restoreSelectedProfileType();
this.profilesItemTreeElement.select();
this._showLauncherView();
this._createFileSelectorElement();
this.element.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
this._registerShortcuts();
WebInspector.profilingLock().addEventListener(WebInspector.Lock.Events.StateChanged, this._onProfilingStateChanged, this);
}
WebInspector.ProfilesPanel.prototype = {
searchableView: function () {
return this._searchableView;
}, _createFileSelectorElement: function () {
if (this._fileSelectorElement)
this.element.removeChild(this._fileSelectorElement);
this._fileSelectorElement = WebInspector.createFileSelectorElement(this._loadFromFile.bind(this));
this.element.appendChild(this._fileSelectorElement);
}, _findProfileTypeByExtension: function (fileName) {
var types = WebInspector.ProfileTypeRegistry.instance.profileTypes();
for (var i = 0; i < types.length; i++) {
var type = types[i];
var extension = type.fileExtension();
if (!extension)
continue;
if (fileName.endsWith(type.fileExtension()))
return type;
}
return null;
}, _registerShortcuts: function () {
this.registerShortcuts(WebInspector.ShortcutsScreen.ProfilesPanelShortcuts.StartStopRecording, this.toggleRecordButton.bind(this));
}, _loadFromFile: function (file) {
this._createFileSelectorElement();
var profileType = this._findProfileTypeByExtension(file.name);
if (!profileType) {
var extensions = [];
var types = WebInspector.ProfileTypeRegistry.instance.profileTypes();
for (var i = 0; i < types.length; i++) {
var extension = types[i].fileExtension();
if (!extension || extensions.indexOf(extension) !== -1)
continue;
extensions.push(extension);
}
WebInspector.console.error(WebInspector.UIString("Can't load file. Only files with extensions '%s' can be loaded.", extensions.join("', '")));
return;
}
if (!!profileType.profileBeingRecorded()) {
WebInspector.console.error(WebInspector.UIString("Can't load profile while another profile is recording."));
return;
}
profileType.loadFromFile(file);
}, toggleRecordButton: function () {
if (!this.recordButton.enabled())
return true;
var type = this._selectedProfileType;
var isProfiling = type.buttonClicked();
this._updateRecordButton(isProfiling);
if (isProfiling) {
this._launcherView.profileStarted();
if (type.hasTemporaryView())
this.showProfile(type.profileBeingRecorded());
} else {
this._launcherView.profileFinished();
}
return true;
}, _onProfilingStateChanged: function () {
this._updateRecordButton(this.recordButton.toggled);
}, _updateRecordButton: function (toggled) {
if (WebInspector.experimentsSettings.disableAgentsWhenProfile.isEnabled())
WebInspector.inspectorView.setCurrentPanelLocked(toggled);
var isAcquiredInSomeTarget = WebInspector.profilingLock().isAcquired();
var enable = toggled || !isAcquiredInSomeTarget;
this.recordButton.setEnabled(enable);
this.recordButton.toggled = toggled;
if (enable)
this.recordButton.title = this._selectedProfileType ? this._selectedProfileType.buttonTooltip : ""; else
this.recordButton.title = WebInspector.anotherProfilerActiveLabel();
if (this._selectedProfileType)
this._launcherView.updateProfileType(this._selectedProfileType, enable);
}, _profileBeingRecordedRemoved: function () {
this._updateRecordButton(false);
this._launcherView.profileFinished();
}, _onProfileTypeSelected: function (event) {
this._selectedProfileType = (event.data);
this._updateProfileTypeSpecificUI();
}, _updateProfileTypeSpecificUI: function () {
this._updateRecordButton(this.recordButton.toggled);
this._profileTypeStatusBarItemsContainer.removeChildren();
var statusBarItems = this._selectedProfileType.statusBarItems;
if (statusBarItems) {
for (var i = 0; i < statusBarItems.length; ++i)
this._profileTypeStatusBarItemsContainer.appendChild(statusBarItems[i]);
}
}, _reset: function () {
WebInspector.Panel.prototype.reset.call(this);
var types = WebInspector.ProfileTypeRegistry.instance.profileTypes();
for (var i = 0; i < types.length; i++)
types[i]._reset();
delete this.visibleView;
delete this.currentQuery;
this.searchCanceled();
this._profileGroups = {};
this._updateRecordButton(false);
this._launcherView.profileFinished();
this.sidebarTree.element.classList.remove("some-expandable");
this._launcherView.detach();
this.profileViews.removeChildren();
this._profileViewStatusBarItemsContainer.removeChildren();
this.removeAllListeners();
this.recordButton.visible = true;
this._profileViewStatusBarItemsContainer.classList.remove("hidden");
this.clearResultsButton.element.classList.remove("hidden");
this.profilesItemTreeElement.select();
this._showLauncherView();
}, _showLauncherView: function () {
this.closeVisibleView();
this._profileViewStatusBarItemsContainer.removeChildren();
this._launcherView.show(this.profileViews);
this.visibleView = this._launcherView;
}, _registerProfileType: function (profileType) {
this._launcherView.addProfileType(profileType);
var profileTypeSection = new WebInspector.ProfileTypeSidebarSection(this, profileType);
this._typeIdToSidebarSection[profileType.id] = profileTypeSection
this.sidebarTree.appendChild(profileTypeSection);
profileTypeSection.childrenListElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
function onAddProfileHeader(event) {
this._addProfileHeader((event.data));
}
function onRemoveProfileHeader(event) {
this._removeProfileHeader((event.data));
}
function profileComplete(event) {
this.showProfile((event.data));
}
profileType.addEventListener(WebInspector.ProfileType.Events.ViewUpdated, this._updateProfileTypeSpecificUI, this);
profileType.addEventListener(WebInspector.ProfileType.Events.AddProfileHeader, onAddProfileHeader, this);
profileType.addEventListener(WebInspector.ProfileType.Events.RemoveProfileHeader, onRemoveProfileHeader, this);
profileType.addEventListener(WebInspector.ProfileType.Events.ProfileComplete, profileComplete, this);
var profiles = profileType.getProfiles();
for (var i = 0; i < profiles.length; i++)
this._addProfileHeader(profiles[i]);
}, _handleContextMenuEvent: function (event) {
var element = event.srcElement;
while (element && !element.treeElement && element !== this.element)
element = element.parentElement;
if (!element)
return;
if (element.treeElement && element.treeElement.handleContextMenuEvent) {
element.treeElement.handleContextMenuEvent(event, this);
return;
}
var contextMenu = new WebInspector.ContextMenu(event);
if (this.visibleView instanceof WebInspector.HeapSnapshotView) {
this.visibleView.populateContextMenu(contextMenu, event);
}
if (element !== this.element || event.srcElement === this.sidebarElement()) {
contextMenu.appendItem(WebInspector.UIString("Load\u2026"), this._fileSelectorElement.click.bind(this._fileSelectorElement));
}
contextMenu.show();
}, showLoadFromFileDialog: function () {
this._fileSelectorElement.click();
}, _addProfileHeader: function (profile) {
var profileType = profile.profileType();
var typeId = profileType.id;
this._typeIdToSidebarSection[typeId].addProfileHeader(profile);
if (!this.visibleView || this.visibleView === this._launcherView)
this.showProfile(profile);
}, _removeProfileHeader: function (profile) {
if (profile.profileType()._profileBeingRecorded === profile)
this._profileBeingRecordedRemoved();
var i = this._indexOfViewForProfile(profile);
if (i !== -1)
this._profileToView.splice(i, 1);
var profileType = profile.profileType();
var typeId = profileType.id;
var sectionIsEmpty = this._typeIdToSidebarSection[typeId].removeProfileHeader(profile);
if (sectionIsEmpty) {
this.profilesItemTreeElement.select();
this._showLauncherView();
}
}, showProfile: function (profile) {
if (!profile || (profile.profileType().profileBeingRecorded() === profile) && !profile.profileType().hasTemporaryView())
return null;
var view = this._viewForProfile(profile);
if (view === this.visibleView)
return view;
this.closeVisibleView();
view.show(this.profileViews);
this.visibleView = view;
var profileTypeSection = this._typeIdToSidebarSection[profile.profileType().id];
var sidebarElement = profileTypeSection.sidebarElementForProfile(profile);
sidebarElement.revealAndSelect();
this._profileViewStatusBarItemsContainer.removeChildren();
var statusBarItems = view.statusBarItems;
if (statusBarItems)
for (var i = 0; i < statusBarItems.length; ++i)
this._profileViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
return view;
}, showObject: function (snapshotObjectId, perspectiveName) {
var heapProfiles = WebInspector.ProfileTypeRegistry.instance.heapSnapshotProfileType.getProfiles();
for (var i = 0; i < heapProfiles.length; i++) {
var profile = heapProfiles[i];
if (profile.maxJSObjectId >= snapshotObjectId) {
this.showProfile(profile);
var view = this._viewForProfile(profile);
view.highlightLiveObject(perspectiveName, snapshotObjectId);
break;
}
}
}, _viewForProfile: function (profile) {
var index = this._indexOfViewForProfile(profile);
if (index !== -1)
return this._profileToView[index].view;
var view = profile.createView(this);
view.element.classList.add("profile-view");
this._profileToView.push({profile: profile, view: view});
return view;
}, _indexOfViewForProfile: function (profile) {
for (var i = 0; i < this._profileToView.length; i++) {
if (this._profileToView[i].profile === profile)
return i;
}
return -1;
}, closeVisibleView: function () {
if (this.visibleView)
this.visibleView.detach();
delete this.visibleView;
}, performSearch: function (query, shouldJump, jumpBackwards) {
this.searchCanceled();
var visibleView = this.visibleView;
if (!visibleView)
return;
function finishedCallback(view, searchMatches) {
if (!searchMatches)
return;
this._searchableView.updateSearchMatchesCount(searchMatches);
this._searchResultsView = view;
if (shouldJump) {
if (jumpBackwards)
view.jumpToLastSearchResult(); else
view.jumpToFirstSearchResult();
this._searchableView.updateCurrentMatchIndex(view.currentSearchResultIndex());
}
}
visibleView.currentQuery = query;
visibleView.performSearch(query, finishedCallback.bind(this));
}, jumpToNextSearchResult: function () {
if (!this._searchResultsView)
return;
if (this._searchResultsView !== this.visibleView)
return;
this._searchResultsView.jumpToNextSearchResult();
this._searchableView.updateCurrentMatchIndex(this._searchResultsView.currentSearchResultIndex());
}, jumpToPreviousSearchResult: function () {
if (!this._searchResultsView)
return;
if (this._searchResultsView !== this.visibleView)
return;
this._searchResultsView.jumpToPreviousSearchResult();
this._searchableView.updateCurrentMatchIndex(this._searchResultsView.currentSearchResultIndex());
}, searchCanceled: function () {
if (this._searchResultsView) {
if (this._searchResultsView.searchCanceled)
this._searchResultsView.searchCanceled();
this._searchResultsView.currentQuery = null;
this._searchResultsView = null;
}
this._searchableView.updateSearchMatchesCount(0);
}, appendApplicableItems: function (event, contextMenu, target) {
if (!(target instanceof WebInspector.RemoteObject))
return;
if (WebInspector.inspectorView.currentPanel() !== this)
return;
var object = (target);
var objectId = object.objectId;
if (!objectId)
return;
var heapProfiles = WebInspector.ProfileTypeRegistry.instance.heapSnapshotProfileType.getProfiles();
if (!heapProfiles.length)
return;
function revealInView(viewName) {
object.target().heapProfilerAgent().getHeapObjectId(objectId, didReceiveHeapObjectId.bind(this, viewName));
}
function didReceiveHeapObjectId(viewName, error, result) {
if (WebInspector.inspectorView.currentPanel() !== this)
return;
if (!error)
this.showObject(result, viewName);
}
contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Summary view" : "Reveal in Summary View"), revealInView.bind(this, "Summary"));
}, __proto__: WebInspector.PanelWithSidebarTree.prototype
}
WebInspector.ProfileTypeSidebarSection = function (dataDisplayDelegate, profileType) {
WebInspector.SidebarSectionTreeElement.call(this, profileType.treeItemTitle, null, true);
this._dataDisplayDelegate = dataDisplayDelegate;
this._profileTreeElements = [];
this._profileGroups = {};
this.hidden = true;
}
WebInspector.ProfileTypeSidebarSection.ProfileGroup = function () {
this.profileSidebarTreeElements = [];
this.sidebarTreeElement = null;
}
WebInspector.ProfileTypeSidebarSection.prototype = {
addProfileHeader: function (profile) {
this.hidden = false;
var profileType = profile.profileType();
var sidebarParent = this;
var profileTreeElement = profile.createSidebarTreeElement(this._dataDisplayDelegate);
this._profileTreeElements.push(profileTreeElement);
if (!profile.fromFile() && profileType.profileBeingRecorded() !== profile) {
var profileTitle = profile.title;
var group = this._profileGroups[profileTitle];
if (!group) {
group = new WebInspector.ProfileTypeSidebarSection.ProfileGroup();
this._profileGroups[profileTitle] = group;
}
group.profileSidebarTreeElements.push(profileTreeElement);
var groupSize = group.profileSidebarTreeElements.length;
if (groupSize === 2) {
group.sidebarTreeElement = new WebInspector.ProfileGroupSidebarTreeElement(this._dataDisplayDelegate, profile.title);
var firstProfileTreeElement = group.profileSidebarTreeElements[0];
var index = this.children.indexOf(firstProfileTreeElement);
this.insertChild(group.sidebarTreeElement, index);
var selected = firstProfileTreeElement.selected;
this.removeChild(firstProfileTreeElement);
group.sidebarTreeElement.appendChild(firstProfileTreeElement);
if (selected)
firstProfileTreeElement.revealAndSelect();
firstProfileTreeElement.small = true;
firstProfileTreeElement.mainTitle = WebInspector.UIString("Run %d", 1);
this.treeOutline.element.classList.add("some-expandable");
}
if (groupSize >= 2) {
sidebarParent = group.sidebarTreeElement;
profileTreeElement.small = true;
profileTreeElement.mainTitle = WebInspector.UIString("Run %d", groupSize);
}
}
sidebarParent.appendChild(profileTreeElement);
}, removeProfileHeader: function (profile) {
var index = this._sidebarElementIndex(profile);
if (index === -1)
return false;
var profileTreeElement = this._profileTreeElements[index];
this._profileTreeElements.splice(index, 1);
var sidebarParent = this;
var group = this._profileGroups[profile.title];
if (group) {
var groupElements = group.profileSidebarTreeElements;
groupElements.splice(groupElements.indexOf(profileTreeElement), 1);
if (groupElements.length === 1) {
var pos = sidebarParent.children.indexOf(group.sidebarTreeElement);
this.insertChild(groupElements[0], pos);
groupElements[0].small = false;
groupElements[0].mainTitle = group.sidebarTreeElement.title;
this.removeChild(group.sidebarTreeElement);
}
if (groupElements.length !== 0)
sidebarParent = group.sidebarTreeElement;
}
sidebarParent.removeChild(profileTreeElement);
profileTreeElement.dispose();
if (this.children.length)
return false;
this.hidden = true;
return true;
}, sidebarElementForProfile: function (profile) {
var index = this._sidebarElementIndex(profile);
return index === -1 ? null : this._profileTreeElements[index];
}, _sidebarElementIndex: function (profile) {
var elements = this._profileTreeElements;
for (var i = 0; i < elements.length; i++) {
if (elements[i].profile === profile)
return i;
}
return -1;
}, __proto__: WebInspector.SidebarSectionTreeElement.prototype
}
WebInspector.ProfilesPanel.ContextMenuProvider = function () {
}
WebInspector.ProfilesPanel.ContextMenuProvider.prototype = {
appendApplicableItems: function (event, contextMenu, target) {
WebInspector.inspectorView.panel("profiles").appendApplicableItems(event, contextMenu, target);
}
}
WebInspector.ProfileSidebarTreeElement = function (dataDisplayDelegate, profile, className) {
this._dataDisplayDelegate = dataDisplayDelegate;
this.profile = profile;
WebInspector.SidebarTreeElement.call(this, className, profile.title, "", profile, false);
this.refreshTitles();
profile.addEventListener(WebInspector.ProfileHeader.Events.UpdateStatus, this._updateStatus, this);
if (profile.canSaveToFile())
this._createSaveLink(); else
profile.addEventListener(WebInspector.ProfileHeader.Events.ProfileReceived, this._onProfileReceived, this);
}
WebInspector.ProfileSidebarTreeElement.prototype = {
_createSaveLink: function () {
this._saveLinkElement = this.titleContainer.createChild("span", "save-link");
this._saveLinkElement.textContent = WebInspector.UIString("Save");
this._saveLinkElement.addEventListener("click", this._saveProfile.bind(this), false);
}, _onProfileReceived: function (event) {
this._createSaveLink();
}, _updateStatus: function (event) {
var statusUpdate = event.data;
if (statusUpdate.subtitle !== null)
this.subtitle = statusUpdate.subtitle;
if (typeof statusUpdate.wait === "boolean")
this.wait = statusUpdate.wait;
this.refreshTitles();
}, dispose: function () {
this.profile.removeEventListener(WebInspector.ProfileHeader.Events.UpdateStatus, this._updateStatus, this);
this.profile.removeEventListener(WebInspector.ProfileHeader.Events.ProfileReceived, this._onProfileReceived, this);
}, onselect: function () {
this._dataDisplayDelegate.showProfile(this.profile);
}, ondelete: function () {
this.profile.profileType().removeProfile(this.profile);
return true;
}, handleContextMenuEvent: function (event, panel) {
var profile = this.profile;
var contextMenu = new WebInspector.ContextMenu(event);
contextMenu.appendItem(WebInspector.UIString("Load\u2026"), panel._fileSelectorElement.click.bind(panel._fileSelectorElement));
if (profile.canSaveToFile())
contextMenu.appendItem(WebInspector.UIString("Save\u2026"), profile.saveToFile.bind(profile));
contextMenu.appendItem(WebInspector.UIString("Delete"), this.ondelete.bind(this));
contextMenu.show();
}, _saveProfile: function (event) {
this.profile.saveToFile();
}, __proto__: WebInspector.SidebarTreeElement.prototype
}
WebInspector.ProfileGroupSidebarTreeElement = function (dataDisplayDelegate, title, subtitle) {
WebInspector.SidebarTreeElement.call(this, "profile-group-sidebar-tree-item", title, subtitle, null, true);
this._dataDisplayDelegate = dataDisplayDelegate;
}
WebInspector.ProfileGroupSidebarTreeElement.prototype = {
onselect: function () {
if (this.children.length > 0)
this._dataDisplayDelegate.showProfile(this.children[this.children.length - 1].profile);
}, __proto__: WebInspector.SidebarTreeElement.prototype
}
WebInspector.ProfilesSidebarTreeElement = function (panel) {
this._panel = panel;
this.small = false;
WebInspector.SidebarTreeElement.call(this, "profile-launcher-view-tree-item", WebInspector.UIString("Profiles"), "", null, false);
}
WebInspector.ProfilesSidebarTreeElement.prototype = {
onselect: function () {
this._panel._showLauncherView();
}, get selectable() {
return true;
}, __proto__: WebInspector.SidebarTreeElement.prototype
};
WebInspector.ProfileDataGridNode = function (profileNode, owningTree, hasChildren) {
this.profileNode = profileNode;
WebInspector.DataGridNode.call(this, null, hasChildren);
this.tree = owningTree;
this.childrenByCallUID = {};
this.lastComparator = null;
this.callUID = profileNode.callUID;
this.selfTime = profileNode.selfTime;
this.totalTime = profileNode.totalTime;
this.functionName = WebInspector.CPUProfileDataModel.beautifyFunctionName(profileNode.functionName);
this._deoptReason = (!profileNode.deoptReason || profileNode.deoptReason === "no reason") ? "" : profileNode.deoptReason;
this.url = profileNode.url;
}
WebInspector.ProfileDataGridNode.prototype = {
createCell: function (columnIdentifier) {
var cell = this._createValueCell(columnIdentifier) || WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
if (columnIdentifier === "self" && this._searchMatchedSelfColumn)
cell.classList.add("highlight"); else if (columnIdentifier === "total" && this._searchMatchedTotalColumn)
cell.classList.add("highlight");
if (columnIdentifier !== "function")
return cell;
if (this._deoptReason)
cell.classList.add("not-optimized");
if (this._searchMatchedFunctionColumn)
cell.classList.add("highlight");
if (this.profileNode.scriptId !== "0") {
var lineNumber = this.profileNode.lineNumber ? this.profileNode.lineNumber - 1 : 0;
var columnNumber = this.profileNode.columnNumber ? this.profileNode.columnNumber - 1 : 0;
var target = this.tree.profileView.target();
var urlElement = this.tree.profileView._linkifier.linkifyScriptLocation(target, this.profileNode.scriptId, this.profileNode.url, lineNumber, columnNumber, "profile-node-file");
urlElement.style.maxWidth = "75%";
cell.insertBefore(urlElement, cell.firstChild);
}
return cell;
}, _createValueCell: function (columnIdentifier) {
if (columnIdentifier !== "self" && columnIdentifier !== "total")
return null;
var cell = document.createElement("td");
cell.className = "numeric-column";
var div = document.createElement("div");
var valueSpan = document.createElement("span");
valueSpan.textContent = this.data[columnIdentifier];
div.appendChild(valueSpan);
var percentColumn = columnIdentifier + "-percent";
if (percentColumn in this.data) {
var percentSpan = document.createElement("span");
percentSpan.className = "percent-column";
percentSpan.textContent = this.data[percentColumn];
div.appendChild(percentSpan);
div.classList.add("profile-multiple-values");
}
cell.appendChild(div);
return cell;
}, buildData: function () {
function formatMilliseconds(time) {
return WebInspector.UIString("%.1f\u2009ms", time);
}
function formatPercent(value) {
return WebInspector.UIString("%.2f\u2009%", value);
}
var functionName;
if (this._deoptReason) {
var content = document.createDocumentFragment();
var marker = content.createChild("span", "profile-warn-marker");
marker.title = WebInspector.UIString("Not optimized: %s", this._deoptReason);
content.createTextChild(this.functionName);
functionName = content;
} else {
functionName = this.functionName;
}
this.data = {"function": functionName, "self-percent": formatPercent(this.selfPercent), "self": formatMilliseconds(this.selfTime), "total-percent": formatPercent(this.totalPercent), "total": formatMilliseconds(this.totalTime),};
}, select: function (supressSelectedEvent) {
WebInspector.DataGridNode.prototype.select.call(this, supressSelectedEvent);
this.tree.profileView._dataGridNodeSelected(this);
}, deselect: function (supressDeselectedEvent) {
WebInspector.DataGridNode.prototype.deselect.call(this, supressDeselectedEvent);
this.tree.profileView._dataGridNodeDeselected(this);
}, sort: function (comparator, force) {
var gridNodeGroups = [[this]];
for (var gridNodeGroupIndex = 0; gridNodeGroupIndex < gridNodeGroups.length; ++gridNodeGroupIndex) {
var gridNodes = gridNodeGroups[gridNodeGroupIndex];
var count = gridNodes.length;
for (var index = 0; index < count; ++index) {
var gridNode = gridNodes[index];
if (!force && (!gridNode.expanded || gridNode.lastComparator === comparator)) {
if (gridNode.children.length)
gridNode.shouldRefreshChildren = true;
continue;
}
gridNode.lastComparator = comparator;
var children = gridNode.children;
var childCount = children.length;
if (childCount) {
children.sort(comparator);
for (var childIndex = 0; childIndex < childCount; ++childIndex)
children[childIndex].recalculateSiblings(childIndex);
gridNodeGroups.push(children);
}
}
}
}, insertChild: function (profileDataGridNode, index) {
WebInspector.DataGridNode.prototype.insertChild.call(this, profileDataGridNode, index);
this.childrenByCallUID[profileDataGridNode.callUID] = profileDataGridNode;
}, removeChild: function (profileDataGridNode) {
WebInspector.DataGridNode.prototype.removeChild.call(this, profileDataGridNode);
delete this.childrenByCallUID[profileDataGridNode.callUID];
}, removeChildren: function () {
WebInspector.DataGridNode.prototype.removeChildren.call(this);
this.childrenByCallUID = {};
}, findChild: function (node) {
if (!node)
return null;
return this.childrenByCallUID[node.callUID];
}, get selfPercent() {
return this.selfTime / this.tree.totalTime * 100.0;
}, get totalPercent() {
return this.totalTime / this.tree.totalTime * 100.0;
}, populate: function () {
WebInspector.ProfileDataGridNode.populate(this);
}, populateChildren: function () {
}, save: function () {
if (this._savedChildren)
return;
this._savedSelfTime = this.selfTime;
this._savedTotalTime = this.totalTime;
this._savedChildren = this.children.slice();
}, restore: function () {
if (!this._savedChildren)
return;
this.selfTime = this._savedSelfTime;
this.totalTime = this._savedTotalTime;
this.removeChildren();
var children = this._savedChildren;
var count = children.length;
for (var index = 0; index < count; ++index) {
children[index].restore();
this.appendChild(children[index]);
}
}, merge: function (child, shouldAbsorb) {
WebInspector.ProfileDataGridNode.merge(this, child, shouldAbsorb);
}, __proto__: WebInspector.DataGridNode.prototype
}
WebInspector.ProfileDataGridNode.merge = function (container, child, shouldAbsorb) {
container.selfTime += child.selfTime;
if (!shouldAbsorb)
container.totalTime += child.totalTime;
var children = container.children.slice();
container.removeChildren();
var count = children.length;
for (var index = 0; index < count; ++index) {
if (!shouldAbsorb || children[index] !== child)
container.appendChild(children[index]);
}
children = child.children.slice();
count = children.length;
for (var index = 0; index < count; ++index) {
var orphanedChild = children[index];
var existingChild = container.childrenByCallUID[orphanedChild.callUID];
if (existingChild)
existingChild.merge(orphanedChild, false); else
container.appendChild(orphanedChild);
}
}
WebInspector.ProfileDataGridNode.populate = function (container) {
if (container._populated)
return;
container._populated = true;
container.populateChildren();
var currentComparator = container.tree.lastComparator;
if (currentComparator)
container.sort(currentComparator, true);
}
WebInspector.ProfileDataGridTree = function (profileView, rootProfileNode) {
this.tree = this;
this.children = [];
this.profileView = profileView;
this.totalTime = rootProfileNode.totalTime;
this.lastComparator = null;
this.childrenByCallUID = {};
}
WebInspector.ProfileDataGridTree.prototype = {
get expanded() {
return true;
}, appendChild: function (child) {
this.insertChild(child, this.children.length);
}, insertChild: function (child, index) {
this.children.splice(index, 0, child);
this.childrenByCallUID[child.callUID] = child;
}, removeChildren: function () {
this.children = [];
this.childrenByCallUID = {};
}, populateChildren: function () {
}, findChild: WebInspector.ProfileDataGridNode.prototype.findChild, sort: WebInspector.ProfileDataGridNode.prototype.sort, save: function () {
if (this._savedChildren)
return;
this._savedTotalTime = this.totalTime;
this._savedChildren = this.children.slice();
}, restore: function () {
if (!this._savedChildren)
return;
this.children = this._savedChildren;
this.totalTime = this._savedTotalTime;
var children = this.children;
var count = children.length;
for (var index = 0; index < count; ++index)
children[index].restore();
this._savedChildren = null;
}
}
WebInspector.ProfileDataGridTree.propertyComparators = [{}, {}];
WebInspector.ProfileDataGridTree.propertyComparator = function (property, isAscending) {
var comparator = WebInspector.ProfileDataGridTree.propertyComparators[(isAscending ? 1 : 0)][property];
if (!comparator) {
if (isAscending) {
comparator = function (lhs, rhs) {
if (lhs[property] < rhs[property])
return -1;
if (lhs[property] > rhs[property])
return 1;
return 0;
}
} else {
comparator = function (lhs, rhs) {
if (lhs[property] > rhs[property])
return -1;
if (lhs[property] < rhs[property])
return 1;
return 0;
}
}
WebInspector.ProfileDataGridTree.propertyComparators[(isAscending ? 1 : 0)][property] = comparator;
}
return comparator;
};
WebInspector.BottomUpProfileDataGridNode = function (profileNode, owningTree) {
WebInspector.ProfileDataGridNode.call(this, profileNode, owningTree, this._willHaveChildren(profileNode));
this._remainingNodeInfos = [];
}
WebInspector.BottomUpProfileDataGridNode.prototype = {
_takePropertiesFromProfileDataGridNode: function (profileDataGridNode) {
this.save();
this.selfTime = profileDataGridNode.selfTime;
this.totalTime = profileDataGridNode.totalTime;
}, _keepOnlyChild: function (child) {
this.save();
this.removeChildren();
this.appendChild(child);
}, _exclude: function (aCallUID) {
if (this._remainingNodeInfos)
this.populate();
this.save();
var children = this.children;
var index = this.children.length;
while (index--)
children[index]._exclude(aCallUID);
var child = this.childrenByCallUID[aCallUID];
if (child)
this.merge(child, true);
}, restore: function () {
WebInspector.ProfileDataGridNode.prototype.restore.call(this);
if (!this.children.length)
this.hasChildren = this._willHaveChildren(this.profileNode);
}, merge: function (child, shouldAbsorb) {
this.selfTime -= child.selfTime;
WebInspector.ProfileDataGridNode.prototype.merge.call(this, child, shouldAbsorb);
}, populateChildren: function () {
WebInspector.BottomUpProfileDataGridNode._sharedPopulate(this);
}, _willHaveChildren: function (profileNode) {
return !!(profileNode.parent && profileNode.parent.parent);
}, __proto__: WebInspector.ProfileDataGridNode.prototype
}
WebInspector.BottomUpProfileDataGridNode._sharedPopulate = function (container) {
var remainingNodeInfos = container._remainingNodeInfos;
var count = remainingNodeInfos.length;
for (var index = 0; index < count; ++index) {
var nodeInfo = remainingNodeInfos[index];
var ancestor = nodeInfo.ancestor;
var focusNode = nodeInfo.focusNode;
var child = container.findChild(ancestor);
if (child) {
var totalTimeAccountedFor = nodeInfo.totalTimeAccountedFor;
child.selfTime += focusNode.selfTime;
if (!totalTimeAccountedFor)
child.totalTime += focusNode.totalTime;
} else {
child = new WebInspector.BottomUpProfileDataGridNode(ancestor, container.tree);
if (ancestor !== focusNode) {
child.selfTime = focusNode.selfTime;
child.totalTime = focusNode.totalTime;
}
container.appendChild(child);
}
var parent = ancestor.parent;
if (parent && parent.parent) {
nodeInfo.ancestor = parent;
child._remainingNodeInfos.push(nodeInfo);
}
}
for (var i = 0; i < container.children.length; ++i)
container.children[i].buildData();
delete container._remainingNodeInfos;
}
WebInspector.BottomUpProfileDataGridTree = function (profileView, rootProfileNode) {
WebInspector.ProfileDataGridTree.call(this, profileView, rootProfileNode);
var profileNodeUIDs = 0;
var profileNodeGroups = [[], [rootProfileNode]];
var visitedProfileNodesForCallUID = {};
this._remainingNodeInfos = [];
for (var profileNodeGroupIndex = 0; profileNodeGroupIndex < profileNodeGroups.length; ++profileNodeGroupIndex) {
var parentProfileNodes = profileNodeGroups[profileNodeGroupIndex];
var profileNodes = profileNodeGroups[++profileNodeGroupIndex];
var count = profileNodes.length;
for (var index = 0; index < count; ++index) {
var profileNode = profileNodes[index];
if (!profileNode.UID)
profileNode.UID = ++profileNodeUIDs;
if (profileNode.parent) {
var visitedNodes = visitedProfileNodesForCallUID[profileNode.callUID];
var totalTimeAccountedFor = false;
if (!visitedNodes) {
visitedNodes = {}
visitedProfileNodesForCallUID[profileNode.callUID] = visitedNodes;
} else {
var parentCount = parentProfileNodes.length;
for (var parentIndex = 0; parentIndex < parentCount; ++parentIndex) {
if (visitedNodes[parentProfileNodes[parentIndex].UID]) {
totalTimeAccountedFor = true;
break;
}
}
}
visitedNodes[profileNode.UID] = true;
this._remainingNodeInfos.push({ancestor: profileNode, focusNode: profileNode, totalTimeAccountedFor: totalTimeAccountedFor});
}
var children = profileNode.children;
if (children.length) {
profileNodeGroups.push(parentProfileNodes.concat([profileNode]))
profileNodeGroups.push(children);
}
}
}
WebInspector.ProfileDataGridNode.populate(this);
return this;
}
WebInspector.BottomUpProfileDataGridTree.prototype = {
focus: function (profileDataGridNode) {
if (!profileDataGridNode)
return;
this.save();
var currentNode = profileDataGridNode;
var focusNode = profileDataGridNode;
while (currentNode.parent && (currentNode instanceof WebInspector.ProfileDataGridNode)) {
currentNode._takePropertiesFromProfileDataGridNode(profileDataGridNode);
focusNode = currentNode;
currentNode = currentNode.parent;
if (currentNode instanceof WebInspector.ProfileDataGridNode)
currentNode._keepOnlyChild(focusNode);
}
this.children = [focusNode];
this.totalTime = profileDataGridNode.totalTime;
}, exclude: function (profileDataGridNode) {
if (!profileDataGridNode)
return;
this.save();
var excludedCallUID = profileDataGridNode.callUID;
var excludedTopLevelChild = this.childrenByCallUID[excludedCallUID];
if (excludedTopLevelChild)
this.children.remove(excludedTopLevelChild);
var children = this.children;
var count = children.length;
for (var index = 0; index < count; ++index)
children[index]._exclude(excludedCallUID);
if (this.lastComparator)
this.sort(this.lastComparator, true);
}, buildData: function () {
}, populateChildren: function () {
WebInspector.BottomUpProfileDataGridNode._sharedPopulate(this);
}, __proto__: WebInspector.ProfileDataGridTree.prototype
};
WebInspector.TopDownProfileDataGridNode = function (profileNode, owningTree) {
var hasChildren = !!(profileNode.children && profileNode.children.length);
WebInspector.ProfileDataGridNode.call(this, profileNode, owningTree, hasChildren);
this._remainingChildren = profileNode.children;
this.buildData();
}
WebInspector.TopDownProfileDataGridNode.prototype = {
populateChildren: function () {
WebInspector.TopDownProfileDataGridNode._sharedPopulate(this);
}, __proto__: WebInspector.ProfileDataGridNode.prototype
}
WebInspector.TopDownProfileDataGridNode._sharedPopulate = function (container) {
var children = container._remainingChildren;
var childrenLength = children.length;
for (var i = 0; i < childrenLength; ++i)
container.appendChild(new WebInspector.TopDownProfileDataGridNode(children[i], (container.tree)));
container._remainingChildren = null;
}
WebInspector.TopDownProfileDataGridNode._excludeRecursively = function (container, aCallUID) {
if (container._remainingChildren)
container.populate();
container.save();
var children = container.children;
var index = container.children.length;
while (index--)
WebInspector.TopDownProfileDataGridNode._excludeRecursively(children[index], aCallUID);
var child = container.childrenByCallUID[aCallUID];
if (child)
WebInspector.ProfileDataGridNode.merge(container, child, true);
}
WebInspector.TopDownProfileDataGridTree = function (profileView, rootProfileNode) {
WebInspector.ProfileDataGridTree.call(this, profileView, rootProfileNode);
this._remainingChildren = rootProfileNode.children;
WebInspector.ProfileDataGridNode.populate(this);
}
WebInspector.TopDownProfileDataGridTree.prototype = {
focus: function (profileDataGridNode) {
if (!profileDataGridNode)
return;
this.save();
profileDataGridNode.savePosition();
this.children = [profileDataGridNode];
this.totalTime = profileDataGridNode.totalTime;
}, exclude: function (profileDataGridNode) {
if (!profileDataGridNode)
return;
this.save();
WebInspector.TopDownProfileDataGridNode._excludeRecursively(this, profileDataGridNode.callUID);
if (this.lastComparator)
this.sort(this.lastComparator, true);
}, restore: function () {
if (!this._savedChildren)
return;
this.children[0].restorePosition();
WebInspector.ProfileDataGridTree.prototype.restore.call(this);
}, populateChildren: function () {
WebInspector.TopDownProfileDataGridNode._sharedPopulate(this);
}, __proto__: WebInspector.ProfileDataGridTree.prototype
};
WebInspector.CPUFlameChartDataProvider = function (cpuProfile, weakTarget) {
WebInspector.FlameChartDataProvider.call(this);
this._cpuProfile = cpuProfile;
this._weakTarget = weakTarget;
this._colorGenerator = WebInspector.CPUFlameChartDataProvider.colorGenerator();
}
WebInspector.CPUFlameChartDataProvider.prototype = {
barHeight: function () {
return 15;
}, textBaseline: function () {
return 4;
}, textPadding: function () {
return 2;
}, dividerOffsets: function (startTime, endTime) {
return null;
}, minimumBoundary: function () {
return this._cpuProfile.profileStartTime;
}, totalTime: function () {
return this._cpuProfile.profileHead.totalTime;
}, maxStackDepth: function () {
return this._maxStackDepth;
}, timelineData: function () {
return this._timelineData || this._calculateTimelineData();
}, markerColor: function (index) {
throw new Error("Unreachable.");
}, markerTitle: function (index) {
throw new Error("Unreachable.");
}, _calculateTimelineData: function () {
function ChartEntry(depth, duration, startTime, selfTime, node) {
this.depth = depth;
this.duration = duration;
this.startTime = startTime;
this.selfTime = selfTime;
this.node = node;
}
var entries = [];
var stack = [];
var maxDepth = 5;
function onOpenFrame() {
stack.push(entries.length);
entries.push(null);
}
function onCloseFrame(depth, node, startTime, totalTime, selfTime) {
var index = stack.pop();
entries[index] = new ChartEntry(depth, totalTime, startTime, selfTime, node);
maxDepth = Math.max(maxDepth, depth);
}
this._cpuProfile.forEachFrame(onOpenFrame, onCloseFrame);
var entryNodes = new Array(entries.length);
var entryLevels = new Uint8Array(entries.length);
var entryTotalTimes = new Float32Array(entries.length);
var entrySelfTimes = new Float32Array(entries.length);
var entryStartTimes = new Float64Array(entries.length);
var minimumBoundary = this.minimumBoundary();
for (var i = 0; i < entries.length; ++i) {
var entry = entries[i];
entryNodes[i] = entry.node;
entryLevels[i] = entry.depth;
entryTotalTimes[i] = entry.duration;
entryStartTimes[i] = entry.startTime;
entrySelfTimes[i] = entry.selfTime;
}
this._maxStackDepth = maxDepth;
this._timelineData = new WebInspector.FlameChart.TimelineData(entryLevels, entryTotalTimes, entryStartTimes);
this._entryNodes = entryNodes;
this._entrySelfTimes = entrySelfTimes;
return this._timelineData;
}, _millisecondsToString: function (ms) {
if (ms === 0)
return "0";
if (ms < 1000)
return WebInspector.UIString("%.1f\u2009ms", ms);
return Number.secondsToString(ms / 1000, true);
}, prepareHighlightedEntryInfo: function (entryIndex) {
var timelineData = this._timelineData;
var node = this._entryNodes[entryIndex];
if (!node)
return null;
var entryInfo = [];
function pushEntryInfoRow(title, text) {
var row = {};
row.title = title;
row.text = text;
entryInfo.push(row);
}
var name = WebInspector.CPUProfileDataModel.beautifyFunctionName(node.functionName);
pushEntryInfoRow(WebInspector.UIString("Name"), name);
var selfTime = this._millisecondsToString(this._entrySelfTimes[entryIndex]);
var totalTime = this._millisecondsToString(timelineData.entryTotalTimes[entryIndex]);
pushEntryInfoRow(WebInspector.UIString("Self time"), selfTime);
pushEntryInfoRow(WebInspector.UIString("Total time"), totalTime);
var target = this._weakTarget.get();
var text = target ? WebInspector.Linkifier.liveLocationText(target, node.scriptId, node.lineNumber, node.columnNumber) : node.url;
pushEntryInfoRow(WebInspector.UIString("URL"), text);
pushEntryInfoRow(WebInspector.UIString("Aggregated self time"), Number.secondsToString(node.selfTime / 1000, true));
pushEntryInfoRow(WebInspector.UIString("Aggregated total time"), Number.secondsToString(node.totalTime / 1000, true));
if (node.deoptReason && node.deoptReason !== "no reason")
pushEntryInfoRow(WebInspector.UIString("Not optimized"), node.deoptReason);
return entryInfo;
}, canJumpToEntry: function (entryIndex) {
return this._entryNodes[entryIndex].scriptId !== "0";
}, entryTitle: function (entryIndex) {
var node = this._entryNodes[entryIndex];
return WebInspector.CPUProfileDataModel.beautifyFunctionName(node.functionName);
}, entryFont: function (entryIndex) {
if (!this._font) {
this._font = (this.barHeight() - 4) + "px " + WebInspector.fontFamily();
this._boldFont = "bold " + this._font;
}
var node = this._entryNodes[entryIndex];
var reason = node.deoptReason;
return (reason && reason !== "no reason") ? this._boldFont : this._font;
}, entryColor: function (entryIndex) {
var node = this._entryNodes[entryIndex];
return this._colorGenerator.colorForID(node.functionName + ":" + node.url);
}, decorateEntry: function (entryIndex, context, text, barX, barY, barWidth, barHeight, timeToPosition) {
return false;
}, forceDecoration: function (entryIndex) {
return false;
}, highlightTimeRange: function (entryIndex) {
var startTime = this._timelineData.entryStartTimes[entryIndex];
return {startTime: startTime, endTime: startTime + this._timelineData.entryTotalTimes[entryIndex]};
}, paddingLeft: function () {
return 15;
}, textColor: function (entryIndex) {
return "#333";
}
}
WebInspector.CPUFlameChartDataProvider.colorGenerator = function () {
if (!WebInspector.CPUFlameChartDataProvider._colorGenerator) {
var colorGenerator = new WebInspector.FlameChart.ColorGenerator({min: 180, max: 310, count: 7}, {min: 50, max: 80, count: 5}, {min: 80, max: 90, count: 3});
colorGenerator.setColorForID("(idle):", "hsl(0, 0%, 94%)");
colorGenerator.setColorForID("(program):", "hsl(0, 0%, 80%)");
colorGenerator.setColorForID("(garbage collector):", "hsl(0, 0%, 80%)");
WebInspector.CPUFlameChartDataProvider._colorGenerator = colorGenerator;
}
return WebInspector.CPUFlameChartDataProvider._colorGenerator;
}
WebInspector.CPUProfileFlameChart = function (dataProvider) {
WebInspector.VBox.call(this);
this.registerRequiredCSS("flameChart.css");
this.element.id = "cpu-flame-chart";
this._overviewPane = new WebInspector.CPUProfileFlameChart.OverviewPane(dataProvider);
this._overviewPane.show(this.element);
this._mainPane = new WebInspector.FlameChart(dataProvider, this._overviewPane, true);
this._mainPane.show(this.element);
this._mainPane.addEventListener(WebInspector.FlameChart.Events.EntrySelected, this._onEntrySelected, this);
this._overviewPane.addEventListener(WebInspector.OverviewGrid.Events.WindowChanged, this._onWindowChanged, this);
}
WebInspector.CPUProfileFlameChart.prototype = {
_onWindowChanged: function (event) {
var windowLeft = event.data.windowTimeLeft;
var windowRight = event.data.windowTimeRight;
this._mainPane.setWindowTimes(windowLeft, windowRight);
}, selectRange: function (timeLeft, timeRight) {
this._overviewPane._selectRange(timeLeft, timeRight);
}, _onEntrySelected: function (event) {
this.dispatchEventToListeners(WebInspector.FlameChart.Events.EntrySelected, event.data);
}, update: function () {
this._overviewPane.update();
this._mainPane.update();
}, __proto__: WebInspector.VBox.prototype
};
WebInspector.CPUProfileFlameChart.OverviewCalculator = function () {
}
WebInspector.CPUProfileFlameChart.OverviewCalculator.prototype = {
paddingLeft: function () {
return 0;
}, _updateBoundaries: function (overviewPane) {
this._minimumBoundaries = overviewPane._dataProvider.minimumBoundary();
var totalTime = overviewPane._dataProvider.totalTime();
this._maximumBoundaries = this._minimumBoundaries + totalTime;
this._xScaleFactor = overviewPane._overviewContainer.clientWidth / totalTime;
}, computePosition: function (time) {
return (time - this._minimumBoundaries) * this._xScaleFactor;
}, formatTime: function (value, precision) {
return Number.secondsToString((value - this._minimumBoundaries) / 1000);
}, maximumBoundary: function () {
return this._maximumBoundaries;
}, minimumBoundary: function () {
return this._minimumBoundaries;
}, zeroTime: function () {
return this._minimumBoundaries;
}, boundarySpan: function () {
return this._maximumBoundaries - this._minimumBoundaries;
}
}
WebInspector.CPUProfileFlameChart.OverviewPane = function (dataProvider) {
WebInspector.VBox.call(this);
this.element.classList.add("flame-chart-overview-pane");
this._overviewContainer = this.element.createChild("div", "overview-container");
this._overviewGrid = new WebInspector.OverviewGrid("flame-chart");
this._overviewGrid.element.classList.add("fill");
this._overviewCanvas = this._overviewContainer.createChild("canvas", "flame-chart-overview-canvas");
this._overviewContainer.appendChild(this._overviewGrid.element);
this._overviewCalculator = new WebInspector.CPUProfileFlameChart.OverviewCalculator();
this._dataProvider = dataProvider;
this._overviewGrid.addEventListener(WebInspector.OverviewGrid.Events.WindowChanged, this._onWindowChanged, this);
}
WebInspector.CPUProfileFlameChart.OverviewPane.prototype = {
requestWindowTimes: function (windowStartTime, windowEndTime) {
this._selectRange(windowStartTime, windowEndTime);
}, _selectRange: function (timeLeft, timeRight) {
var startTime = this._dataProvider.minimumBoundary();
var totalTime = this._dataProvider.totalTime();
this._overviewGrid.setWindow((timeLeft - startTime) / totalTime, (timeRight - startTime) / totalTime);
}, _onWindowChanged: function (event) {
var startTime = this._dataProvider.minimumBoundary();
var totalTime = this._dataProvider.totalTime();
var data = {windowTimeLeft: startTime + this._overviewGrid.windowLeft() * totalTime, windowTimeRight: startTime + this._overviewGrid.windowRight() * totalTime};
this.dispatchEventToListeners(WebInspector.OverviewGrid.Events.WindowChanged, data);
}, _timelineData: function () {
return this._dataProvider.timelineData();
}, onResize: function () {
this._scheduleUpdate();
}, _scheduleUpdate: function () {
if (this._updateTimerId)
return;
this._updateTimerId = requestAnimationFrame(this.update.bind(this));
}, update: function () {
this._updateTimerId = 0;
var timelineData = this._timelineData();
if (!timelineData)
return;
this._resetCanvas(this._overviewContainer.clientWidth, this._overviewContainer.clientHeight - WebInspector.FlameChart.DividersBarHeight);
this._overviewCalculator._updateBoundaries(this);
this._overviewGrid.updateDividers(this._overviewCalculator);
this._drawOverviewCanvas();
}, _drawOverviewCanvas: function () {
var canvasWidth = this._overviewCanvas.width;
var canvasHeight = this._overviewCanvas.height;
var drawData = this._calculateDrawData(canvasWidth);
var context = this._overviewCanvas.getContext("2d");
var ratio = window.devicePixelRatio;
var offsetFromBottom = ratio;
var lineWidth = 1;
var yScaleFactor = canvasHeight / (this._dataProvider.maxStackDepth() * 1.1);
context.lineWidth = lineWidth;
context.translate(0.5, 0.5);
context.strokeStyle = "rgba(20,0,0,0.4)";
context.fillStyle = "rgba(214,225,254,0.8)";
context.moveTo(-lineWidth, canvasHeight + lineWidth);
context.lineTo(-lineWidth, Math.round(canvasHeight - drawData[0] * yScaleFactor - offsetFromBottom));
var value;
for (var x = 0; x < canvasWidth; ++x) {
value = Math.round(canvasHeight - drawData[x] * yScaleFactor - offsetFromBottom);
context.lineTo(x, value);
}
context.lineTo(canvasWidth + lineWidth, value);
context.lineTo(canvasWidth + lineWidth, canvasHeight + lineWidth);
context.fill();
context.stroke();
context.closePath();
}, _calculateDrawData: function (width) {
var dataProvider = this._dataProvider;
var timelineData = this._timelineData();
var entryStartTimes = timelineData.entryStartTimes;
var entryTotalTimes = timelineData.entryTotalTimes;
var entryLevels = timelineData.entryLevels;
var length = entryStartTimes.length;
var minimumBoundary = this._dataProvider.minimumBoundary();
var drawData = new Uint8Array(width);
var scaleFactor = width / dataProvider.totalTime();
for (var entryIndex = 0; entryIndex < length; ++entryIndex) {
var start = Math.floor((entryStartTimes[entryIndex] - minimumBoundary) * scaleFactor);
var finish = Math.floor((entryStartTimes[entryIndex] - minimumBoundary + entryTotalTimes[entryIndex]) * scaleFactor);
for (var x = start; x <= finish; ++x)
drawData[x] = Math.max(drawData[x], entryLevels[entryIndex] + 1);
}
return drawData;
}, _resetCanvas: function (width, height) {
var ratio = window.devicePixelRatio;
this._overviewCanvas.width = width * ratio;
this._overviewCanvas.height = height * ratio;
this._overviewCanvas.style.width = width + "px";
this._overviewCanvas.style.height = height + "px";
}, __proto__: WebInspector.VBox.prototype
};
WebInspector.CPUProfileView = function (profileHeader) {
WebInspector.VBox.call(this);
this.element.classList.add("cpu-profile-view");
this._viewType = WebInspector.settings.createSetting("cpuProfilerView", WebInspector.CPUProfileView._TypeHeavy);
var columns = [];
columns.push({id: "self", title: WebInspector.UIString("Self"), width: "120px", sort: WebInspector.DataGrid.Order.Descending, sortable: true});
columns.push({id: "total", title: WebInspector.UIString("Total"), width: "120px", sortable: true});
columns.push({id: "function", title: WebInspector.UIString("Function"), disclosure: true, sortable: true});
this.dataGrid = new WebInspector.DataGrid(columns);
this.dataGrid.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this._sortProfile, this);
this.dataGrid.show(this.element);
this.viewSelectComboBox = new WebInspector.StatusBarComboBox(this._changeView.bind(this));
var options = {};
options[WebInspector.CPUProfileView._TypeFlame] = this.viewSelectComboBox.createOption(WebInspector.UIString("Chart"), "", WebInspector.CPUProfileView._TypeFlame);
options[WebInspector.CPUProfileView._TypeHeavy] = this.viewSelectComboBox.createOption(WebInspector.UIString("Heavy (Bottom Up)"), "", WebInspector.CPUProfileView._TypeHeavy);
options[WebInspector.CPUProfileView._TypeTree] = this.viewSelectComboBox.createOption(WebInspector.UIString("Tree (Top Down)"), "", WebInspector.CPUProfileView._TypeTree);
var optionName = this._viewType.get() || WebInspector.CPUProfileView._TypeFlame;
var option = options[optionName] || options[WebInspector.CPUProfileView._TypeFlame];
this.viewSelectComboBox.select(option);
this._statusBarButtonsElement = document.createElement("span");
this.focusButton = new WebInspector.StatusBarButton(WebInspector.UIString("Focus selected function."), "focus-profile-node-status-bar-item");
this.focusButton.setEnabled(false);
this.focusButton.addEventListener("click", this._focusClicked, this);
this._statusBarButtonsElement.appendChild(this.focusButton.element);
this.excludeButton = new WebInspector.StatusBarButton(WebInspector.UIString("Exclude selected function."), "exclude-profile-node-status-bar-item");
this.excludeButton.setEnabled(false);
this.excludeButton.addEventListener("click", this._excludeClicked, this);
this._statusBarButtonsElement.appendChild(this.excludeButton.element);
this.resetButton = new WebInspector.StatusBarButton(WebInspector.UIString("Restore all functions."), "reset-profile-status-bar-item");
this.resetButton.visible = false;
this.resetButton.addEventListener("click", this._resetClicked, this);
this._statusBarButtonsElement.appendChild(this.resetButton.element);
this._profileHeader = profileHeader;
this._linkifier = new WebInspector.Linkifier(new WebInspector.Linkifier.DefaultFormatter(30));
this.profile = new WebInspector.CPUProfileDataModel(profileHeader._profile || profileHeader.protocolProfile());
this._changeView();
if (this._flameChart)
this._flameChart.update();
}
WebInspector.CPUProfileView._TypeFlame = "Flame";
WebInspector.CPUProfileView._TypeTree = "Tree";
WebInspector.CPUProfileView._TypeHeavy = "Heavy";
WebInspector.CPUProfileView.prototype = {
target: function () {
return this._profileHeader.target();
}, selectRange: function (timeLeft, timeRight) {
if (!this._flameChart)
return;
this._flameChart.selectRange(timeLeft, timeRight);
}, get statusBarItems() {
return [this.viewSelectComboBox.element, this._statusBarButtonsElement];
}, _getBottomUpProfileDataGridTree: function () {
if (!this._bottomUpProfileDataGridTree)
this._bottomUpProfileDataGridTree = new WebInspector.BottomUpProfileDataGridTree(this, (this.profile.profileHead));
return this._bottomUpProfileDataGridTree;
}, _getTopDownProfileDataGridTree: function () {
if (!this._topDownProfileDataGridTree)
this._topDownProfileDataGridTree = new WebInspector.TopDownProfileDataGridTree(this, (this.profile.profileHead));
return this._topDownProfileDataGridTree;
}, willHide: function () {
this._currentSearchResultIndex = -1;
}, refresh: function () {
var selectedProfileNode = this.dataGrid.selectedNode ? this.dataGrid.selectedNode.profileNode : null;
this.dataGrid.rootNode().removeChildren();
var children = this.profileDataGridTree.children;
var count = children.length;
for (var index = 0; index < count; ++index)
this.dataGrid.rootNode().appendChild(children[index]);
if (selectedProfileNode)
selectedProfileNode.selected = true;
}, refreshVisibleData: function () {
var child = this.dataGrid.rootNode().children[0];
while (child) {
child.refresh();
child = child.traverseNextNode(false, null, true);
}
}, searchCanceled: function () {
if (this._searchResults) {
for (var i = 0; i < this._searchResults.length; ++i) {
var profileNode = this._searchResults[i].profileNode;
delete profileNode._searchMatchedSelfColumn;
delete profileNode._searchMatchedTotalColumn;
delete profileNode._searchMatchedFunctionColumn;
profileNode.refresh();
}
}
delete this._searchFinishedCallback;
this._currentSearchResultIndex = -1;
this._searchResults = [];
}, performSearch: function (query, finishedCallback) {
this.searchCanceled();
query = query.trim();
if (!query.length)
return;
this._searchFinishedCallback = finishedCallback;
var greaterThan = (query.startsWith(">"));
var lessThan = (query.startsWith("<"));
var equalTo = (query.startsWith("=") || ((greaterThan || lessThan) && query.indexOf("=") === 1));
var percentUnits = (query.lastIndexOf("%") === (query.length - 1));
var millisecondsUnits = (query.length > 2 && query.lastIndexOf("ms") === (query.length - 2));
var secondsUnits = (!millisecondsUnits && query.lastIndexOf("s") === (query.length - 1));
var queryNumber = parseFloat(query);
if (greaterThan || lessThan || equalTo) {
if (equalTo && (greaterThan || lessThan))
queryNumber = parseFloat(query.substring(2)); else
queryNumber = parseFloat(query.substring(1));
}
var queryNumberMilliseconds = (secondsUnits ? (queryNumber * 1000) : queryNumber);
if (!isNaN(queryNumber) && !(greaterThan || lessThan))
equalTo = true;
var matcher = createPlainTextSearchRegex(query, "i");
function matchesQuery(profileDataGridNode) {
delete profileDataGridNode._searchMatchedSelfColumn;
delete profileDataGridNode._searchMatchedTotalColumn;
delete profileDataGridNode._searchMatchedFunctionColumn;
if (percentUnits) {
if (lessThan) {
if (profileDataGridNode.selfPercent < queryNumber)
profileDataGridNode._searchMatchedSelfColumn = true;
if (profileDataGridNode.totalPercent < queryNumber)
profileDataGridNode._searchMatchedTotalColumn = true;
} else if (greaterThan) {
if (profileDataGridNode.selfPercent > queryNumber)
profileDataGridNode._searchMatchedSelfColumn = true;
if (profileDataGridNode.totalPercent > queryNumber)
profileDataGridNode._searchMatchedTotalColumn = true;
}
if (equalTo) {
if (profileDataGridNode.selfPercent == queryNumber)
profileDataGridNode._searchMatchedSelfColumn = true;
if (profileDataGridNode.totalPercent == queryNumber)
profileDataGridNode._searchMatchedTotalColumn = true;
}
} else if (millisecondsUnits || secondsUnits) {
if (lessThan) {
if (profileDataGridNode.selfTime < queryNumberMilliseconds)
profileDataGridNode._searchMatchedSelfColumn = true;
if (profileDataGridNode.totalTime < queryNumberMilliseconds)
profileDataGridNode._searchMatchedTotalColumn = true;
} else if (greaterThan) {
if (profileDataGridNode.selfTime > queryNumberMilliseconds)
profileDataGridNode._searchMatchedSelfColumn = true;
if (profileDataGridNode.totalTime > queryNumberMilliseconds)
profileDataGridNode._searchMatchedTotalColumn = true;
}
if (equalTo) {
if (profileDataGridNode.selfTime == queryNumberMilliseconds)
profileDataGridNode._searchMatchedSelfColumn = true;
if (profileDataGridNode.totalTime == queryNumberMilliseconds)
profileDataGridNode._searchMatchedTotalColumn = true;
}
}
if (profileDataGridNode.functionName.match(matcher) || (profileDataGridNode.url && profileDataGridNode.url.match(matcher)))
profileDataGridNode._searchMatchedFunctionColumn = true;
if (profileDataGridNode._searchMatchedSelfColumn || profileDataGridNode._searchMatchedTotalColumn || profileDataGridNode._searchMatchedFunctionColumn) {
profileDataGridNode.refresh();
return true;
}
return false;
}
var current = this.profileDataGridTree.children[0];
while (current) {
if (matchesQuery(current)) {
this._searchResults.push({profileNode: current});
}
current = current.traverseNextNode(false, null, false);
}
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));
}, currentSearchResultIndex: function () {
return this._currentSearchResultIndex;
}, _jumpToSearchResult: function (index) {
var searchResult = this._searchResults[index];
if (!searchResult)
return;
var profileNode = searchResult.profileNode;
profileNode.revealAndSelect();
}, _ensureFlameChartCreated: function () {
if (this._flameChart)
return;
this._dataProvider = new WebInspector.CPUFlameChartDataProvider(this.profile, this._profileHeader.weakTarget());
this._flameChart = new WebInspector.CPUProfileFlameChart(this._dataProvider);
this._flameChart.addEventListener(WebInspector.FlameChart.Events.EntrySelected, this._onEntrySelected.bind(this));
}, _onEntrySelected: function (event) {
var entryIndex = event.data;
var node = this._dataProvider._entryNodes[entryIndex];
var target = this._profileHeader.target();
if (!node || !node.scriptId || !target)
return;
var script = target.debuggerModel.scriptForId(node.scriptId)
if (!script)
return;
var location = (script.target().debuggerModel.createRawLocation(script, node.lineNumber, 0));
WebInspector.Revealer.reveal(WebInspector.debuggerWorkspaceBinding.rawLocationToUILocation(location));
}, _changeView: function () {
if (!this.profile)
return;
switch (this.viewSelectComboBox.selectedOption().value) {
case WebInspector.CPUProfileView._TypeFlame:
this._ensureFlameChartCreated();
this.dataGrid.detach();
this._flameChart.show(this.element);
this._viewType.set(WebInspector.CPUProfileView._TypeFlame);
this._statusBarButtonsElement.classList.toggle("hidden", true);
return;
case WebInspector.CPUProfileView._TypeTree:
this.profileDataGridTree = this._getTopDownProfileDataGridTree();
this._sortProfile();
this._viewType.set(WebInspector.CPUProfileView._TypeTree);
break;
case WebInspector.CPUProfileView._TypeHeavy:
this.profileDataGridTree = this._getBottomUpProfileDataGridTree();
this._sortProfile();
this._viewType.set(WebInspector.CPUProfileView._TypeHeavy);
break;
}
this._statusBarButtonsElement.classList.toggle("hidden", false);
if (this._flameChart)
this._flameChart.detach();
this.dataGrid.show(this.element);
if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
return;
this._searchFinishedCallback(this, -this._searchResults.length);
this.performSearch(this.currentQuery, this._searchFinishedCallback);
}, _focusClicked: function (event) {
if (!this.dataGrid.selectedNode)
return;
this.resetButton.visible = true;
this.profileDataGridTree.focus(this.dataGrid.selectedNode);
this.refresh();
this.refreshVisibleData();
}, _excludeClicked: function (event) {
var selectedNode = this.dataGrid.selectedNode
if (!selectedNode)
return;
selectedNode.deselect();
this.resetButton.visible = true;
this.profileDataGridTree.exclude(selectedNode);
this.refresh();
this.refreshVisibleData();
}, _resetClicked: function (event) {
this.resetButton.visible = false;
this.profileDataGridTree.restore();
this._linkifier.reset();
this.refresh();
this.refreshVisibleData();
}, _dataGridNodeSelected: function (node) {
this.focusButton.setEnabled(true);
this.excludeButton.setEnabled(true);
}, _dataGridNodeDeselected: function (node) {
this.focusButton.setEnabled(false);
this.excludeButton.setEnabled(false);
}, _sortProfile: function () {
var sortAscending = this.dataGrid.isSortOrderAscending();
var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier();
var sortProperty = {"self": "selfTime", "total": "totalTime", "function": "functionName"}[sortColumnIdentifier];
this.profileDataGridTree.sort(WebInspector.ProfileDataGridTree.propertyComparator(sortProperty, sortAscending));
this.refresh();
}, __proto__: WebInspector.VBox.prototype
}
WebInspector.CPUProfileType = function () {
WebInspector.ProfileType.call(this, WebInspector.CPUProfileType.TypeId, WebInspector.UIString("Collect JavaScript CPU Profile"));
this._recording = false;
this._nextAnonymousConsoleProfileNumber = 1;
this._anonymousConsoleProfileIdToTitle = {};
WebInspector.CPUProfileType.instance = this;
WebInspector.targetManager.addModelListener(WebInspector.CPUProfilerModel, WebInspector.CPUProfilerModel.EventTypes.ConsoleProfileStarted, this._consoleProfileStarted, this);
WebInspector.targetManager.addModelListener(WebInspector.CPUProfilerModel, WebInspector.CPUProfilerModel.EventTypes.ConsoleProfileFinished, this._consoleProfileFinished, this);
}
WebInspector.CPUProfileType.TypeId = "CPU";
WebInspector.CPUProfileType.prototype = {
fileExtension: function () {
return ".cpuprofile";
}, get buttonTooltip() {
return this._recording ? WebInspector.UIString("Stop CPU profiling.") : WebInspector.UIString("Start CPU profiling.");
}, buttonClicked: function () {
if (this._recording) {
this.stopRecordingProfile();
return false;
} else {
this.startRecordingProfile();
return true;
}
}, get treeItemTitle() {
return WebInspector.UIString("CPU PROFILES");
}, get description() {
return WebInspector.UIString("CPU profiles show where the execution time is spent in your page's JavaScript functions.");
}, _consoleProfileStarted: function (event) {
var protocolId = (event.data.protocolId);
var scriptLocation = (event.data.scriptLocation);
var resolvedTitle = (event.data.title);
if (!resolvedTitle) {
resolvedTitle = WebInspector.UIString("Profile %s", this._nextAnonymousConsoleProfileNumber++);
this._anonymousConsoleProfileIdToTitle[protocolId] = resolvedTitle;
}
this._addMessageToConsole(WebInspector.ConsoleMessage.MessageType.Profile, scriptLocation, WebInspector.UIString("Profile '%s' started.", resolvedTitle));
}, _consoleProfileFinished: function (event) {
var protocolId = (event.data.protocolId);
var scriptLocation = (event.data.scriptLocation);
var cpuProfile = (event.data.cpuProfile);
var resolvedTitle = (event.data.title);
if (typeof resolvedTitle === "undefined") {
resolvedTitle = this._anonymousConsoleProfileIdToTitle[protocolId];
delete this._anonymousConsoleProfileIdToTitle[protocolId];
}
var profile = new WebInspector.CPUProfileHeader(scriptLocation.target(), this, resolvedTitle);
profile.setProtocolProfile(cpuProfile);
this.addProfile(profile);
this._addMessageToConsole(WebInspector.ConsoleMessage.MessageType.ProfileEnd, scriptLocation, WebInspector.UIString("Profile '%s' finished.", resolvedTitle));
}, _addMessageToConsole: function (type, scriptLocation, messageText) {
var script = scriptLocation.script();
var target = scriptLocation.target();
var message = new WebInspector.ConsoleMessage(target, WebInspector.ConsoleMessage.MessageSource.ConsoleAPI, WebInspector.ConsoleMessage.MessageLevel.Debug, messageText, type, undefined, undefined, undefined, undefined, undefined, [{
functionName: "",
scriptId: scriptLocation.scriptId,
url: script ? script.contentURL() : "",
lineNumber: scriptLocation.lineNumber,
columnNumber: scriptLocation.columnNumber || 0
}]);
target.consoleModel.addMessage(message);
}, startRecordingProfile: function () {
var target = WebInspector.context.flavor(WebInspector.Target);
if (this._profileBeingRecorded || !target)
return;
var profile = new WebInspector.CPUProfileHeader(target, this);
this.setProfileBeingRecorded(profile);
this.addProfile(profile);
profile.updateStatus(WebInspector.UIString("Recording\u2026"));
this._recording = true;
target.cpuProfilerModel.startRecording();
}, stopRecordingProfile: function () {
this._recording = false;
if (!this._profileBeingRecorded || !this._profileBeingRecorded.target())
return;
function didStopProfiling(error, profile) {
if (!this._profileBeingRecorded)
return;
this._profileBeingRecorded.setProtocolProfile(profile);
this._profileBeingRecorded.updateStatus("");
var recordedProfile = this._profileBeingRecorded;
this.setProfileBeingRecorded(null);
this.dispatchEventToListeners(WebInspector.ProfileType.Events.ProfileComplete, recordedProfile);
}
this._profileBeingRecorded.target().cpuProfilerModel.stopRecording(didStopProfiling.bind(this));
}, createProfileLoadedFromFile: function (title) {
return new WebInspector.CPUProfileHeader(null, this, title);
}, profileBeingRecordedRemoved: function () {
this.stopRecordingProfile();
}, __proto__: WebInspector.ProfileType.prototype
}
WebInspector.CPUProfileHeader = function (target, type, title) {
WebInspector.ProfileHeader.call(this, target, type, title || WebInspector.UIString("Profile %d", type.nextProfileUid()));
this._tempFile = null;
}
WebInspector.CPUProfileHeader.prototype = {
onTransferStarted: function () {
this._jsonifiedProfile = "";
this.updateStatus(WebInspector.UIString("Loading\u2026 %s", Number.bytesToString(this._jsonifiedProfile.length)), true);
}, onChunkTransferred: function (reader) {
this.updateStatus(WebInspector.UIString("Loading\u2026 %d\%", Number.bytesToString(this._jsonifiedProfile.length)));
}, onTransferFinished: function () {
this.updateStatus(WebInspector.UIString("Parsing\u2026"), true);
this._profile = JSON.parse(this._jsonifiedProfile);
this._jsonifiedProfile = null;
this.updateStatus(WebInspector.UIString("Loaded"), false);
if (this._profileType.profileBeingRecorded() === this)
this._profileType.setProfileBeingRecorded(null);
}, onError: function (reader, e) {
var subtitle;
switch (e.target.error.code) {
case e.target.error.NOT_FOUND_ERR:
subtitle = WebInspector.UIString("'%s' not found.", reader.fileName());
break;
case e.target.error.NOT_READABLE_ERR:
subtitle = WebInspector.UIString("'%s' is not readable", reader.fileName());
break;
case e.target.error.ABORT_ERR:
return;
default:
subtitle = WebInspector.UIString("'%s' error %d", reader.fileName(), e.target.error.code);
}
this.updateStatus(subtitle);
}, write: function (text) {
this._jsonifiedProfile += text;
}, close: function () {
}, dispose: function () {
this.removeTempFile();
}, createSidebarTreeElement: function (panel) {
return new WebInspector.ProfileSidebarTreeElement(panel, this, "profile-sidebar-tree-item");
}, createView: function () {
return new WebInspector.CPUProfileView(this);
}, canSaveToFile: function () {
return !this.fromFile() && this._protocolProfile;
}, saveToFile: function () {
var fileOutputStream = new WebInspector.FileOutputStream();
function onOpenForSave(accepted) {
if (!accepted)
return;
function didRead(data) {
if (data)
fileOutputStream.write(data, fileOutputStream.close.bind(fileOutputStream)); else
fileOutputStream.close();
}
if (this._failedToCreateTempFile) {
WebInspector.console.error("Failed to open temp file with heap snapshot");
fileOutputStream.close();
} else if (this._tempFile) {
this._tempFile.read(didRead);
} else {
this._onTempFileReady = onOpenForSave.bind(this, accepted);
}
}
this._fileName = this._fileName || "CPU-" + new Date().toISO8601Compact() + this._profileType.fileExtension();
fileOutputStream.open(this._fileName, onOpenForSave.bind(this));
}, loadFromFile: function (file) {
this.updateStatus(WebInspector.UIString("Loading\u2026"), true);
var fileReader = new WebInspector.ChunkedFileReader(file, 10000000, this);
fileReader.start(this);
}, protocolProfile: function () {
return this._protocolProfile;
}, setProtocolProfile: function (cpuProfile) {
this._protocolProfile = cpuProfile;
this._saveProfileDataToTempFile(cpuProfile);
if (this.canSaveToFile())
this.dispatchEventToListeners(WebInspector.ProfileHeader.Events.ProfileReceived);
}, _saveProfileDataToTempFile: function (data) {
var serializedData = JSON.stringify(data);
function didCreateTempFile(tempFile) {
this._writeToTempFile(tempFile, serializedData);
}
new WebInspector.TempFile("cpu-profiler", this.uid, didCreateTempFile.bind(this));
}, _writeToTempFile: function (tempFile, serializedData) {
this._tempFile = tempFile;
if (!tempFile) {
this._failedToCreateTempFile = true;
this._notifyTempFileReady();
return;
}
function didWriteToTempFile(success) {
if (!success)
this._failedToCreateTempFile = true;
tempFile.finishWriting();
this._notifyTempFileReady();
}
tempFile.write(serializedData, didWriteToTempFile.bind(this));
}, _notifyTempFileReady: function () {
if (this._onTempFileReady) {
this._onTempFileReady();
this._onTempFileReady = null;
}
}, __proto__: WebInspector.ProfileHeader.prototype
};
WebInspector.HeapSnapshotProgressEvent = {Update: "ProgressUpdate"};
WebInspector.HeapSnapshotCommon = {}
WebInspector.HeapSnapshotCommon.baseSystemDistance = 100000000;
WebInspector.HeapSnapshotCommon.AllocationNodeCallers = function (nodesWithSingleCaller, branchingCallers) {
this.nodesWithSingleCaller = nodesWithSingleCaller;
this.branchingCallers = branchingCallers;
}
WebInspector.HeapSnapshotCommon.SerializedAllocationNode = function (nodeId, functionName, scriptName, scriptId, line, column, count, size, liveCount, liveSize, hasChildren) {
this.id = nodeId;
this.name = functionName;
this.scriptName = scriptName;
this.scriptId = scriptId;
this.line = line;
this.column = column;
this.count = count;
this.size = size;
this.liveCount = liveCount;
this.liveSize = liveSize;
this.hasChildren = hasChildren;
}
WebInspector.HeapSnapshotCommon.AllocationStackFrame = function (functionName, scriptName, scriptId, line, column) {
this.functionName = functionName;
this.scriptName = scriptName;
this.scriptId = scriptId;
this.line = line;
this.column = column;
}
WebInspector.HeapSnapshotCommon.Node = function (id, name, distance, nodeIndex, retainedSize, selfSize, type) {
this.id = id;
this.name = name;
this.distance = distance;
this.nodeIndex = nodeIndex;
this.retainedSize = retainedSize;
this.selfSize = selfSize;
this.type = type;
this.canBeQueried = false;
this.detachedDOMTreeNode = false;
}
WebInspector.HeapSnapshotCommon.Edge = function (name, node, type, edgeIndex) {
this.name = name;
this.node = node;
this.type = type;
this.edgeIndex = edgeIndex;
};
WebInspector.HeapSnapshotCommon.Aggregate = function () {
this.count;
this.distance;
this.self;
this.maxRet;
this.type;
this.name;
this.idxs;
}
WebInspector.HeapSnapshotCommon.AggregateForDiff = function () {
this.indexes = [];
this.ids = [];
this.selfSizes = [];
}
WebInspector.HeapSnapshotCommon.Diff = function () {
this.addedCount = 0;
this.removedCount = 0;
this.addedSize = 0;
this.removedSize = 0;
this.deletedIndexes = [];
this.addedIndexes = [];
}
WebInspector.HeapSnapshotCommon.DiffForClass = function () {
this.addedCount;
this.removedCount;
this.addedSize;
this.removedSize;
this.deletedIndexes;
this.addedIndexes;
this.countDelta;
this.sizeDelta;
}
WebInspector.HeapSnapshotCommon.ComparatorConfig = function () {
this.fieldName1;
this.ascending1;
this.fieldName2;
this.ascending2;
}
WebInspector.HeapSnapshotCommon.WorkerCommand = function () {
this.callId;
this.disposition;
this.objectId;
this.newObjectId;
this.methodName;
this.methodArguments;
this.source;
}
WebInspector.HeapSnapshotCommon.ItemsRange = function (startPosition, endPosition, totalLength, items) {
this.startPosition = startPosition;
this.endPosition = endPosition;
this.totalLength = totalLength;
this.items = items;
}
WebInspector.HeapSnapshotCommon.StaticData = function (nodeCount, rootNodeIndex, totalSize, maxJSObjectId) {
this.nodeCount = nodeCount;
this.rootNodeIndex = rootNodeIndex;
this.totalSize = totalSize;
this.maxJSObjectId = maxJSObjectId;
}
WebInspector.HeapSnapshotCommon.Statistics = function () {
this.total;
this.v8heap;
this.native;
this.code;
this.jsArrays;
this.strings;
}
WebInspector.HeapSnapshotCommon.NodeFilter = function (minNodeId, maxNodeId) {
this.minNodeId = minNodeId;
this.maxNodeId = maxNodeId;
this.allocationNodeId;
}
WebInspector.HeapSnapshotCommon.NodeFilter.prototype = {
equals: function (o) {
return this.minNodeId === o.minNodeId && this.maxNodeId === o.maxNodeId && this.allocationNodeId === o.allocationNodeId;
}
};
WebInspector.HeapSnapshotWorkerProxy = function (eventHandler) {
this._eventHandler = eventHandler;
this._nextObjectId = 1;
this._nextCallId = 1;
this._callbacks = [];
this._previousCallbacks = [];
this._worker = Runtime.startWorker("heap_snapshot_worker");
this._worker.onmessage = this._messageReceived.bind(this);
}
WebInspector.HeapSnapshotWorkerProxy.prototype = {
createLoader: function (profileUid, snapshotReceivedCallback) {
var objectId = this._nextObjectId++;
var proxy = new WebInspector.HeapSnapshotLoaderProxy(this, objectId, profileUid, snapshotReceivedCallback);
this._postMessage({callId: this._nextCallId++, disposition: "create", objectId: objectId, methodName: "WebInspector.HeapSnapshotLoader"});
return proxy;
}, dispose: function () {
this._worker.terminate();
if (this._interval)
clearInterval(this._interval);
}, disposeObject: function (objectId) {
this._postMessage({callId: this._nextCallId++, disposition: "dispose", objectId: objectId});
}, evaluateForTest: function (script, callback) {
var callId = this._nextCallId++;
this._callbacks[callId] = callback;
this._postMessage({callId: callId, disposition: "evaluateForTest", source: script});
}, callFactoryMethod: function (callback, objectId, methodName, proxyConstructor) {
var callId = this._nextCallId++;
var methodArguments = Array.prototype.slice.call(arguments, 4);
var newObjectId = this._nextObjectId++;
function wrapCallback(remoteResult) {
callback(remoteResult ? new proxyConstructor(this, newObjectId) : null);
}
if (callback) {
this._callbacks[callId] = wrapCallback.bind(this);
this._postMessage({callId: callId, disposition: "factory", objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId});
return null;
} else {
this._postMessage({callId: callId, disposition: "factory", objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId});
return new proxyConstructor(this, newObjectId);
}
}, callMethod: function (callback, objectId, methodName) {
var callId = this._nextCallId++;
var methodArguments = Array.prototype.slice.call(arguments, 3);
if (callback)
this._callbacks[callId] = callback;
this._postMessage({callId: callId, disposition: "method", objectId: objectId, methodName: methodName, methodArguments: methodArguments});
}, startCheckingForLongRunningCalls: function () {
if (this._interval)
return;
this._checkLongRunningCalls();
this._interval = setInterval(this._checkLongRunningCalls.bind(this), 300);
}, _checkLongRunningCalls: function () {
for (var callId in this._previousCallbacks)
if (!(callId in this._callbacks))
delete this._previousCallbacks[callId];
var hasLongRunningCalls = false;
for (callId in this._previousCallbacks) {
hasLongRunningCalls = true;
break;
}
this.dispatchEventToListeners("wait", hasLongRunningCalls);
for (callId in this._callbacks)
this._previousCallbacks[callId] = true;
}, _messageReceived: function (event) {
var data = event.data;
if (data.eventName) {
if (this._eventHandler)
this._eventHandler(data.eventName, data.data);
return;
}
if (data.error) {
if (data.errorMethodName)
WebInspector.console.error(WebInspector.UIString("An error occurred when a call to method '%s' was requested", data.errorMethodName));
WebInspector.console.error(data["errorCallStack"]);
delete this._callbacks[data.callId];
return;
}
if (!this._callbacks[data.callId])
return;
var callback = this._callbacks[data.callId];
delete this._callbacks[data.callId];
callback(data.result);
}, _postMessage: function (message) {
this._worker.postMessage(message);
}, __proto__: WebInspector.Object.prototype
}
WebInspector.HeapSnapshotProxyObject = function (worker, objectId) {
this._worker = worker;
this._objectId = objectId;
}
WebInspector.HeapSnapshotProxyObject.prototype = {
_callWorker: function (workerMethodName, args) {
args.splice(1, 0, this._objectId);
return this._worker[workerMethodName].apply(this._worker, args);
}, dispose: function () {
this._worker.disposeObject(this._objectId);
}, disposeWorker: function () {
this._worker.dispose();
}, callFactoryMethod: function (callback, methodName, proxyConstructor, var_args) {
return this._callWorker("callFactoryMethod", Array.prototype.slice.call(arguments, 0));
}, callMethod: function (callback, methodName, var_args) {
return this._callWorker("callMethod", Array.prototype.slice.call(arguments, 0));
}
};
WebInspector.HeapSnapshotLoaderProxy = function (worker, objectId, profileUid, snapshotReceivedCallback) {
WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
this._profileUid = profileUid;
this._snapshotReceivedCallback = snapshotReceivedCallback;
}
WebInspector.HeapSnapshotLoaderProxy.prototype = {
write: function (chunk, callback) {
this.callMethod(callback, "write", chunk);
}, close: function (callback) {
function buildSnapshot() {
if (callback)
callback();
var showHiddenData = WebInspector.settings.showAdvancedHeapSnapshotProperties.get();
this.callFactoryMethod(updateStaticData.bind(this), "buildSnapshot", WebInspector.HeapSnapshotProxy, showHiddenData);
}
function updateStaticData(snapshotProxy) {
this.dispose();
snapshotProxy.setProfileUid(this._profileUid);
snapshotProxy.updateStaticData(this._snapshotReceivedCallback.bind(this));
}
this.callMethod(buildSnapshot.bind(this), "close");
}, __proto__: WebInspector.HeapSnapshotProxyObject.prototype
}
WebInspector.HeapSnapshotProxy = function (worker, objectId) {
WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
this._staticData = null;
}
WebInspector.HeapSnapshotProxy.prototype = {
aggregatesWithFilter: function (filter, callback) {
this.callMethod(callback, "aggregatesWithFilter", filter);
}, aggregatesForDiff: function (callback) {
this.callMethod(callback, "aggregatesForDiff");
}, calculateSnapshotDiff: function (baseSnapshotId, baseSnapshotAggregates, callback) {
this.callMethod(callback, "calculateSnapshotDiff", baseSnapshotId, baseSnapshotAggregates);
}, nodeClassName: function (snapshotObjectId, callback) {
this.callMethod(callback, "nodeClassName", snapshotObjectId);
}, createEdgesProvider: function (nodeIndex) {
return this.callFactoryMethod(null, "createEdgesProvider", WebInspector.HeapSnapshotProviderProxy, nodeIndex);
}, createRetainingEdgesProvider: function (nodeIndex) {
return this.callFactoryMethod(null, "createRetainingEdgesProvider", WebInspector.HeapSnapshotProviderProxy, nodeIndex);
}, createAddedNodesProvider: function (baseSnapshotId, className) {
return this.callFactoryMethod(null, "createAddedNodesProvider", WebInspector.HeapSnapshotProviderProxy, baseSnapshotId, className);
}, createDeletedNodesProvider: function (nodeIndexes) {
return this.callFactoryMethod(null, "createDeletedNodesProvider", WebInspector.HeapSnapshotProviderProxy, nodeIndexes);
}, createNodesProvider: function (filter) {
return this.callFactoryMethod(null, "createNodesProvider", WebInspector.HeapSnapshotProviderProxy, filter);
}, createNodesProviderForClass: function (className, nodeFilter) {
return this.callFactoryMethod(null, "createNodesProviderForClass", WebInspector.HeapSnapshotProviderProxy, className, nodeFilter);
}, allocationTracesTops: function (callback) {
this.callMethod(callback, "allocationTracesTops");
}, allocationNodeCallers: function (nodeId, callback) {
this.callMethod(callback, "allocationNodeCallers", nodeId);
}, allocationStack: function (nodeIndex, callback) {
this.callMethod(callback, "allocationStack", nodeIndex);
}, dispose: function () {
throw new Error("Should never be called");
}, get nodeCount() {
return this._staticData.nodeCount;
}, get rootNodeIndex() {
return this._staticData.rootNodeIndex;
}, updateStaticData: function (callback) {
function dataReceived(staticData) {
this._staticData = staticData;
callback(this);
}
this.callMethod(dataReceived.bind(this), "updateStaticData");
}, getStatistics: function (callback) {
this.callMethod(callback, "getStatistics");
}, get totalSize() {
return this._staticData.totalSize;
}, get uid() {
return this._profileUid;
}, setProfileUid: function (profileUid) {
this._profileUid = profileUid;
}, maxJSObjectId: function () {
return this._staticData.maxJSObjectId;
}, __proto__: WebInspector.HeapSnapshotProxyObject.prototype
}
WebInspector.HeapSnapshotProviderProxy = function (worker, objectId) {
WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
}
WebInspector.HeapSnapshotProviderProxy.prototype = {
nodePosition: function (snapshotObjectId, callback) {
this.callMethod(callback, "nodePosition", snapshotObjectId);
}, isEmpty: function (callback) {
this.callMethod(callback, "isEmpty");
}, serializeItemsRange: function (startPosition, endPosition, callback) {
this.callMethod(callback, "serializeItemsRange", startPosition, endPosition);
}, sortAndRewind: function (comparator, callback) {
this.callMethod(callback, "sortAndRewind", comparator);
}, __proto__: WebInspector.HeapSnapshotProxyObject.prototype
};
WebInspector.HeapSnapshotSortableDataGrid = function (dataDisplayDelegate, columns) {
WebInspector.DataGrid.call(this, columns);
this._dataDisplayDelegate = dataDisplayDelegate;
this._recursiveSortingDepth = 0;
this._highlightedNode = null;
this._populatedAndSorted = false;
this._nameFilter = null;
this.addEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.SortingComplete, this._sortingComplete, this);
this.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this.sortingChanged, this);
}
WebInspector.HeapSnapshotSortableDataGrid.Events = {ContentShown: "ContentShown", SortingComplete: "SortingComplete"}
WebInspector.HeapSnapshotSortableDataGrid.prototype = {
setNameFilter: function (nameFilter) {
this._nameFilter = nameFilter;
}, defaultPopulateCount: function () {
return 100;
}, _disposeAllNodes: function () {
var children = this.topLevelNodes();
for (var i = 0, l = children.length; i < l; ++i)
children[i].dispose();
}, wasShown: function () {
if (this._nameFilter) {
this._nameFilter.addEventListener(WebInspector.StatusBarInput.Event.TextChanged, this._onNameFilterChanged, this);
this.updateVisibleNodes(true);
}
if (this._populatedAndSorted)
this.dispatchEventToListeners(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, this);
}, _sortingComplete: function () {
this.removeEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.SortingComplete, this._sortingComplete, this);
this._populatedAndSorted = true;
this.dispatchEventToListeners(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, this);
}, willHide: function () {
if (this._nameFilter)
this._nameFilter.removeEventListener(WebInspector.StatusBarInput.Event.TextChanged, this._onNameFilterChanged, this);
this._clearCurrentHighlight();
}, populateContextMenu: function (contextMenu, event) {
var td = event.target.enclosingNodeOrSelfWithNodeName("td");
if (!td)
return;
var node = td.heapSnapshotNode;
function revealInSummaryView() {
this._dataDisplayDelegate.showObject(node.snapshotNodeId, "Summary");
}
if (node instanceof WebInspector.HeapSnapshotRetainingObjectNode)
contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Summary view" : "Reveal in Summary View"), revealInSummaryView.bind(this));
}, resetSortingCache: function () {
delete this._lastSortColumnIdentifier;
delete this._lastSortAscending;
}, topLevelNodes: function () {
return this.rootNode().children;
}, highlightObjectByHeapSnapshotId: function (heapSnapshotObjectId, callback) {
}, highlightNode: function (node) {
var prevNode = this._highlightedNode;
this._clearCurrentHighlight();
this._highlightedNode = node;
WebInspector.runCSSAnimationOnce(this._highlightedNode.element(), "highlighted-row");
}, nodeWasDetached: function (node) {
if (this._highlightedNode === node)
this._clearCurrentHighlight();
}, _clearCurrentHighlight: function () {
if (!this._highlightedNode)
return
this._highlightedNode.element().classList.remove("highlighted-row");
this._highlightedNode = null;
}, resetNameFilter: function () {
this._nameFilter.setValue("");
this._onNameFilterChanged();
}, _onNameFilterChanged: function () {
this.updateVisibleNodes(true);
}, sortingChanged: function () {
var sortAscending = this.isSortOrderAscending();
var sortColumnIdentifier = this.sortColumnIdentifier();
if (this._lastSortColumnIdentifier === sortColumnIdentifier && this._lastSortAscending === sortAscending)
return;
this._lastSortColumnIdentifier = sortColumnIdentifier;
this._lastSortAscending = sortAscending;
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) {
this.recursiveSortingEnter();
var children = this.allChildren(this.rootNode());
this.rootNode().removeChildren();
children.sort(sortFunction);
for (var i = 0, l = children.length; i < l; ++i) {
var child = children[i];
this.appendChildAfterSorting(child);
if (child.expanded)
child.sort();
}
this.recursiveSortingLeave();
}, appendChildAfterSorting: function (child) {
var revealed = child.revealed;
this.rootNode().appendChild(child);
child.revealed = revealed;
}, recursiveSortingEnter: function () {
++this._recursiveSortingDepth;
}, recursiveSortingLeave: function () {
if (!this._recursiveSortingDepth)
return;
if (--this._recursiveSortingDepth)
return;
this.updateVisibleNodes(true);
this.dispatchEventToListeners(WebInspector.HeapSnapshotSortableDataGrid.Events.SortingComplete);
}, updateVisibleNodes: function (force) {
}, allChildren: function (parent) {
return parent.children;
}, insertChild: function (parent, node, index) {
parent.insertChild(node, index);
}, removeChildByIndex: function (parent, index) {
parent.removeChild(parent.children[index]);
}, removeAllChildren: function (parent) {
parent.removeChildren();
}, __proto__: WebInspector.DataGrid.prototype
}
WebInspector.HeapSnapshotViewportDataGrid = function (dataDisplayDelegate, columns) {
WebInspector.HeapSnapshotSortableDataGrid.call(this, dataDisplayDelegate, columns);
this.scrollContainer.addEventListener("scroll", this._onScroll.bind(this), true);
this._nodeToHighlightAfterScroll = null;
this._topPaddingHeight = 0;
this._bottomPaddingHeight = 0;
}
WebInspector.HeapSnapshotViewportDataGrid.prototype = {
topLevelNodes: function () {
return this.allChildren(this.rootNode());
}, appendChildAfterSorting: function (child) {
}, updateVisibleNodes: function (force, pathToReveal) {
var guardZoneHeight = 40;
var scrollHeight = this.scrollContainer.scrollHeight;
var scrollTop = this.scrollContainer.scrollTop;
var scrollBottom = scrollHeight - scrollTop - this.scrollContainer.offsetHeight;
scrollTop = Math.max(0, scrollTop - guardZoneHeight);
scrollBottom = Math.max(0, scrollBottom - guardZoneHeight);
var viewPortHeight = scrollHeight - scrollTop - scrollBottom;
if (!pathToReveal) {
if (!force && scrollTop >= this._topPaddingHeight && scrollBottom >= this._bottomPaddingHeight)
return;
var hysteresisHeight = 500;
scrollTop -= hysteresisHeight;
viewPortHeight += 2 * hysteresisHeight;
}
var selectedNode = this.selectedNode;
this.rootNode().removeChildren();
this._topPaddingHeight = 0;
this._bottomPaddingHeight = 0;
this._addVisibleNodes(this.rootNode(), scrollTop, scrollTop + viewPortHeight, pathToReveal || null);
this.setVerticalPadding(this._topPaddingHeight, this._bottomPaddingHeight);
if (selectedNode) {
if (selectedNode.parent)
selectedNode.select(true); else
this.selectedNode = selectedNode;
}
}, _addVisibleNodes: function (parentNode, topBound, bottomBound, pathToReveal) {
if (!parentNode.expanded)
return 0;
var nodeToReveal = pathToReveal ? pathToReveal[0] : null;
var restPathToReveal = pathToReveal && pathToReveal.length > 1 ? pathToReveal.slice(1) : null;
var children = this.allChildren(parentNode);
var topPadding = 0;
var nameFilterValue = this._nameFilter ? this._nameFilter.value().toLowerCase() : "";
for (var i = 0; i < children.length; ++i) {
var child = children[i];
if (nameFilterValue && child.filteredOut && child.filteredOut(nameFilterValue))
continue;
var newTop = topPadding + this._nodeHeight(child);
if (nodeToReveal === child || (!nodeToReveal && newTop > topBound))
break;
topPadding = newTop;
}
var position = topPadding;
for (; i < children.length && (nodeToReveal || position < bottomBound); ++i) {
var child = children[i];
if (nameFilterValue && child.filteredOut && child.filteredOut(nameFilterValue))
continue;
var hasChildren = child.hasChildren;
child.removeChildren();
child.hasChildren = hasChildren;
child.revealed = true;
parentNode.appendChild(child);
position += child.nodeSelfHeight();
position += this._addVisibleNodes(child, topBound - position, bottomBound - position, restPathToReveal);
if (nodeToReveal === child)
break;
}
var bottomPadding = 0;
for (; i < children.length; ++i) {
var child = children[i];
if (nameFilterValue && child.filteredOut && child.filteredOut(nameFilterValue))
continue;
bottomPadding += this._nodeHeight(child);
}
this._topPaddingHeight += topPadding;
this._bottomPaddingHeight += bottomPadding;
return position + bottomPadding;
}, _nodeHeight: function (node) {
if (!node.revealed)
return 0;
var result = node.nodeSelfHeight();
if (!node.expanded)
return result;
var children = this.allChildren(node);
for (var i = 0; i < children.length; i++)
result += this._nodeHeight(children[i]);
return result;
}, revealTreeNode: function (pathToReveal) {
this.updateVisibleNodes(true, pathToReveal);
}, allChildren: function (parent) {
return parent._allChildren || (parent._allChildren = []);
}, appendNode: function (parent, node) {
this.allChildren(parent).push(node);
}, insertChild: function (parent, node, index) {
this.allChildren(parent).splice(index, 0, node);
}, removeChildByIndex: function (parent, index) {
this.allChildren(parent).splice(index, 1);
}, removeAllChildren: function (parent) {
parent._allChildren = [];
}, removeTopLevelNodes: function () {
this._disposeAllNodes();
this.rootNode().removeChildren();
this.rootNode()._allChildren = [];
}, highlightNode: function (node) {
if (this._isScrolledIntoView(node.element())) {
this.updateVisibleNodes(true);
WebInspector.HeapSnapshotSortableDataGrid.prototype.highlightNode.call(this, node);
} else {
node.element().scrollIntoViewIfNeeded(true);
this._nodeToHighlightAfterScroll = node;
}
}, _isScrolledIntoView: function (element) {
var viewportTop = this.scrollContainer.scrollTop;
var viewportBottom = viewportTop + this.scrollContainer.clientHeight;
var elemTop = element.offsetTop
var elemBottom = elemTop + element.offsetHeight;
return elemBottom <= viewportBottom && elemTop >= viewportTop;
}, onResize: function () {
WebInspector.HeapSnapshotSortableDataGrid.prototype.onResize.call(this);
this.updateVisibleNodes(false);
}, _onScroll: function (event) {
this.updateVisibleNodes(false);
if (this._nodeToHighlightAfterScroll) {
WebInspector.HeapSnapshotSortableDataGrid.prototype.highlightNode.call(this, this._nodeToHighlightAfterScroll);
this._nodeToHighlightAfterScroll = null;
}
}, __proto__: WebInspector.HeapSnapshotSortableDataGrid.prototype
}
WebInspector.HeapSnapshotContainmentDataGrid = function (dataDisplayDelegate, columns) {
columns = columns || [{id: "object", title: WebInspector.UIString("Object"), disclosure: true, sortable: true}, {id: "distance", title: WebInspector.UIString("Distance"), width: "80px", sortable: true}, {
id: "shallowSize",
title: WebInspector.UIString("Shallow Size"),
width: "120px",
sortable: true
}, {id: "retainedSize", title: WebInspector.UIString("Retained Size"), width: "120px", sortable: true, sort: WebInspector.DataGrid.Order.Descending}];
WebInspector.HeapSnapshotSortableDataGrid.call(this, dataDisplayDelegate, columns);
}
WebInspector.HeapSnapshotContainmentDataGrid.prototype = {
setDataSource: function (snapshot, nodeIndex) {
this.snapshot = snapshot;
var node = {nodeIndex: nodeIndex || snapshot.rootNodeIndex};
var fakeEdge = {node: node};
this.setRootNode(this._createRootNode(snapshot, fakeEdge));
this.rootNode().sort();
}, _createRootNode: function (snapshot, fakeEdge) {
return new WebInspector.HeapSnapshotObjectNode(this, snapshot, fakeEdge, null);
}, sortingChanged: function () {
var rootNode = this.rootNode();
if (rootNode.hasChildren)
rootNode.sort();
}, __proto__: WebInspector.HeapSnapshotSortableDataGrid.prototype
}
WebInspector.HeapSnapshotRetainmentDataGrid = function (dataDisplayDelegate) {
var columns = [{id: "object", title: WebInspector.UIString("Object"), disclosure: true, sortable: true}, {
id: "distance",
title: WebInspector.UIString("Distance"),
width: "80px",
sortable: true,
sort: WebInspector.DataGrid.Order.Ascending
}, {id: "shallowSize", title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true}, {id: "retainedSize", title: WebInspector.UIString("Retained Size"), width: "120px", sortable: true}];
WebInspector.HeapSnapshotContainmentDataGrid.call(this, dataDisplayDelegate, columns);
}
WebInspector.HeapSnapshotRetainmentDataGrid.Events = {ExpandRetainersComplete: "ExpandRetainersComplete"}
WebInspector.HeapSnapshotRetainmentDataGrid.prototype = {
_createRootNode: function (snapshot, fakeEdge) {
return new WebInspector.HeapSnapshotRetainingObjectNode(this, snapshot, fakeEdge, null);
}, _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],
distance: ["_distance", sortAscending, "_name", true]
}[sortColumn];
}, reset: function () {
this.rootNode().removeChildren();
this.resetSortingCache();
}, setDataSource: function (snapshot, nodeIndex) {
WebInspector.HeapSnapshotContainmentDataGrid.prototype.setDataSource.call(this, snapshot, nodeIndex);
this.rootNode().expand();
}, __proto__: WebInspector.HeapSnapshotContainmentDataGrid.prototype
}
WebInspector.HeapSnapshotConstructorsDataGrid = function (dataDisplayDelegate) {
var columns = [{id: "object", title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true}, {id: "distance", title: WebInspector.UIString("Distance"), width: "90px", sortable: true}, {
id: "count",
title: WebInspector.UIString("Objects Count"),
width: "90px",
sortable: true
}, {id: "shallowSize", title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true}, {
id: "retainedSize",
title: WebInspector.UIString("Retained Size"),
width: "120px",
sort: WebInspector.DataGrid.Order.Descending,
sortable: true
}];
WebInspector.HeapSnapshotViewportDataGrid.call(this, dataDisplayDelegate, columns);
this._profileIndex = -1;
this._objectIdToSelect = null;
}
WebInspector.HeapSnapshotConstructorsDataGrid.prototype = {
_sortFields: function (sortColumn, sortAscending) {
return {
object: ["_name", sortAscending, "_count", false],
distance: ["_distance", sortAscending, "_retainedSize", true],
count: ["_count", sortAscending, "_name", true],
shallowSize: ["_shallowSize", sortAscending, "_name", true],
retainedSize: ["_retainedSize", sortAscending, "_name", true]
}[sortColumn];
}, highlightObjectByHeapSnapshotId: function (id, callback) {
if (!this.snapshot) {
this._objectIdToSelect = id;
return;
}
function didGetClassName(className) {
if (!className) {
callback(false);
return;
}
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), callback);
return;
}
}
}
this.snapshot.nodeClassName(parseInt(id, 10), didGetClassName.bind(this));
}, clear: function () {
this._nextRequestedFilter = null;
this._lastFilter = null;
this.removeTopLevelNodes();
}, setDataSource: function (snapshot) {
this.snapshot = snapshot;
if (this._profileIndex === -1)
this._populateChildren();
if (this._objectIdToSelect) {
this.highlightObjectByHeapSnapshotId(this._objectIdToSelect, function (found) {
});
this._objectIdToSelect = null;
}
}, setSelectionRange: function (minNodeId, maxNodeId) {
this._populateChildren(new WebInspector.HeapSnapshotCommon.NodeFilter(minNodeId, maxNodeId));
}, setAllocationNodeId: function (allocationNodeId) {
var filter = new WebInspector.HeapSnapshotCommon.NodeFilter();
filter.allocationNodeId = allocationNodeId;
this._populateChildren(filter);
}, _aggregatesReceived: function (nodeFilter, aggregates) {
this._filterInProgress = null;
if (this._nextRequestedFilter) {
this.snapshot.aggregatesWithFilter(this._nextRequestedFilter, this._aggregatesReceived.bind(this, this._nextRequestedFilter));
this._filterInProgress = this._nextRequestedFilter;
this._nextRequestedFilter = null;
}
this.removeTopLevelNodes();
this.resetSortingCache();
for (var constructor in aggregates)
this.appendNode(this.rootNode(), new WebInspector.HeapSnapshotConstructorNode(this, constructor, aggregates[constructor], nodeFilter));
this.sortingChanged();
this._lastFilter = nodeFilter;
}, _populateChildren: function (nodeFilter) {
nodeFilter = nodeFilter || new WebInspector.HeapSnapshotCommon.NodeFilter();
if (this._filterInProgress) {
this._nextRequestedFilter = this._filterInProgress.equals(nodeFilter) ? null : nodeFilter;
return;
}
if (this._lastFilter && this._lastFilter.equals(nodeFilter))
return;
this._filterInProgress = nodeFilter;
this.snapshot.aggregatesWithFilter(nodeFilter, this._aggregatesReceived.bind(this, nodeFilter));
}, filterSelectIndexChanged: function (profiles, profileIndex) {
this._profileIndex = profileIndex;
var nodeFilter;
if (profileIndex !== -1) {
var minNodeId = profileIndex > 0 ? profiles[profileIndex - 1].maxJSObjectId : 0;
var maxNodeId = profiles[profileIndex].maxJSObjectId;
nodeFilter = new WebInspector.HeapSnapshotCommon.NodeFilter(minNodeId, maxNodeId)
}
this._populateChildren(nodeFilter);
}, __proto__: WebInspector.HeapSnapshotViewportDataGrid.prototype
}
WebInspector.HeapSnapshotDiffDataGrid = function (dataDisplayDelegate) {
var columns = [{id: "object", title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true}, {id: "addedCount", title: WebInspector.UIString("# New"), width: "72px", sortable: true}, {
id: "removedCount",
title: WebInspector.UIString("# Deleted"),
width: "72px",
sortable: true
}, {id: "countDelta", title: WebInspector.UIString("# Delta"), width: "64px", sortable: true}, {
id: "addedSize",
title: WebInspector.UIString("Alloc. Size"),
width: "72px",
sortable: true,
sort: WebInspector.DataGrid.Order.Descending
}, {id: "removedSize", title: WebInspector.UIString("Freed Size"), width: "72px", sortable: true}, {id: "sizeDelta", title: WebInspector.UIString("Size Delta"), width: "72px", sortable: true}];
WebInspector.HeapSnapshotViewportDataGrid.call(this, dataDisplayDelegate, columns);
}
WebInspector.HeapSnapshotDiffDataGrid.prototype = {
defaultPopulateCount: function () {
return 50;
}, _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 (snapshot) {
this.snapshot = snapshot;
}, setBaseDataSource: function (baseSnapshot) {
this.baseSnapshot = baseSnapshot;
this.removeTopLevelNodes();
this.resetSortingCache();
if (this.baseSnapshot === this.snapshot) {
this.dispatchEventToListeners(WebInspector.HeapSnapshotSortableDataGrid.Events.SortingComplete);
return;
}
this._populateChildren();
}, _populateChildren: function () {
function aggregatesForDiffReceived(aggregatesForDiff) {
this.snapshot.calculateSnapshotDiff(this.baseSnapshot.uid, aggregatesForDiff, didCalculateSnapshotDiff.bind(this));
function didCalculateSnapshotDiff(diffByClassName) {
for (var className in diffByClassName) {
var diff = diffByClassName[className];
this.appendNode(this.rootNode(), new WebInspector.HeapSnapshotDiffNode(this, className, diff));
}
this.sortingChanged();
}
}
this.baseSnapshot.aggregatesForDiff(aggregatesForDiffReceived.bind(this));
}, __proto__: WebInspector.HeapSnapshotViewportDataGrid.prototype
}
WebInspector.AllocationDataGrid = function (weakTarget, dataDisplayDelegate) {
var columns = [{id: "liveCount", title: WebInspector.UIString("Live Count"), width: "72px", sortable: true}, {id: "count", title: WebInspector.UIString("Count"), width: "72px", sortable: true}, {
id: "liveSize",
title: WebInspector.UIString("Live Size"),
width: "72px",
sortable: true
}, {id: "size", title: WebInspector.UIString("Size"), width: "72px", sortable: true, sort: WebInspector.DataGrid.Order.Descending}, {id: "name", title: WebInspector.UIString("Function"), disclosure: true, sortable: true},];
WebInspector.HeapSnapshotViewportDataGrid.call(this, dataDisplayDelegate, columns);
this._weakTarget = weakTarget;
this._linkifier = new WebInspector.Linkifier();
}
WebInspector.AllocationDataGrid.prototype = {
target: function () {
return this._weakTarget.get();
}, dispose: function () {
this._linkifier.reset();
}, setDataSource: function (snapshot) {
this.snapshot = snapshot;
this.snapshot.allocationTracesTops(didReceiveAllocationTracesTops.bind(this));
function didReceiveAllocationTracesTops(tops) {
this._topNodes = tops;
this._populateChildren();
}
}, _populateChildren: function () {
this.removeTopLevelNodes();
var root = this.rootNode();
var tops = this._topNodes;
for (var i = 0; i < tops.length; i++)
this.appendNode(root, new WebInspector.AllocationGridNode(this, tops[i]));
this.updateVisibleNodes(true);
}, sortingChanged: function () {
this._topNodes.sort(this._createComparator());
this.rootNode().removeChildren();
this._populateChildren();
}, _createComparator: function () {
var fieldName = this.sortColumnIdentifier();
var compareResult = (this.sortOrder() === WebInspector.DataGrid.Order.Ascending) ? +1 : -1;
function compare(a, b) {
if (a[fieldName] > b[fieldName])
return compareResult;
if (a[fieldName] < b[fieldName])
return -compareResult;
return 0;
}
return compare;
}, __proto__: WebInspector.HeapSnapshotViewportDataGrid.prototype
};
WebInspector.HeapSnapshotGridNode = function (tree, hasChildren) {
WebInspector.DataGridNode.call(this, null, hasChildren);
this._dataGrid = tree;
this._instanceCount = 0;
this._savedChildren = null;
this._retrievedChildrenRanges = [];
this._providerObject = null;
}
WebInspector.HeapSnapshotGridNode.Events = {PopulateComplete: "PopulateComplete"}
WebInspector.HeapSnapshotGridNode.createComparator = function (fieldNames) {
return ({fieldName1: fieldNames[0], ascending1: fieldNames[1], fieldName2: fieldNames[2], ascending2: fieldNames[3]});
}
WebInspector.HeapSnapshotGridNode.ChildrenProvider = function () {
}
WebInspector.HeapSnapshotGridNode.ChildrenProvider.prototype = {
dispose: function () {
}, nodePosition: function (snapshotObjectId, callback) {
}, isEmpty: function (callback) {
}, serializeItemsRange: function (startPosition, endPosition, callback) {
}, sortAndRewind: function (comparator, callback) {
}
}
WebInspector.HeapSnapshotGridNode.prototype = {
createProvider: function () {
throw new Error("Not implemented.");
}, retainersDataSource: function () {
return null;
}, _provider: function () {
if (!this._providerObject)
this._providerObject = this.createProvider();
return this._providerObject;
}, createCell: function (columnIdentifier) {
var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
if (this._searchMatched)
cell.classList.add("highlight");
return cell;
}, collapse: function () {
WebInspector.DataGridNode.prototype.collapse.call(this);
this._dataGrid.updateVisibleNodes(true);
}, expand: function () {
WebInspector.DataGridNode.prototype.expand.call(this);
this._dataGrid.updateVisibleNodes(true);
}, dispose: function () {
if (this._providerObject)
this._providerObject.dispose();
for (var node = this.children[0]; node; node = node.traverseNextNode(true, this, true))
if (node.dispose)
node.dispose();
}, _reachableFromWindow: false, queryObjectContent: function (callback) {
}, wasDetached: function () {
this._dataGrid.nodeWasDetached(this);
}, _toPercentString: function (num) {
return num.toFixed(0) + "\u2009%";
}, _toUIDistance: function (distance) {
var baseSystemDistance = WebInspector.HeapSnapshotCommon.baseSystemDistance;
return distance >= 0 && distance < baseSystemDistance ? WebInspector.UIString("%d", distance) : WebInspector.UIString("\u2212");
}, allChildren: function () {
return this._dataGrid.allChildren(this);
}, removeChildByIndex: function (index) {
this._dataGrid.removeChildByIndex(this, index);
}, childForPosition: function (nodePosition) {
var indexOfFirstChildInRange = 0;
for (var i = 0; i < this._retrievedChildrenRanges.length; i++) {
var range = this._retrievedChildrenRanges[i];
if (range.from <= nodePosition && nodePosition < range.to) {
var childIndex = indexOfFirstChildInRange + nodePosition - range.from;
return this.allChildren()[childIndex];
}
indexOfFirstChildInRange += range.to - range.from + 1;
}
return null;
}, _createValueCell: function (columnIdentifier) {
var cell = document.createElement("td");
cell.className = "numeric-column";
if (this.dataGrid.snapshot.totalSize !== 0) {
var div = document.createElement("div");
var valueSpan = document.createElement("span");
valueSpan.textContent = this.data[columnIdentifier];
div.appendChild(valueSpan);
var percentColumn = columnIdentifier + "-percent";
if (percentColumn in this.data) {
var percentSpan = document.createElement("span");
percentSpan.className = "percent-column";
percentSpan.textContent = this.data[percentColumn];
div.appendChild(percentSpan);
div.classList.add("profile-multiple-values");
}
cell.appendChild(div);
}
return cell;
}, populate: function (event) {
if (this._populated)
return;
this._populated = true;
function sorted() {
this._populateChildren();
}
this._provider().sortAndRewind(this.comparator(), sorted.bind(this));
}, expandWithoutPopulate: function (callback) {
this._populated = true;
this.expand();
this._provider().sortAndRewind(this.comparator(), callback);
}, _populateChildren: function (fromPosition, toPosition, afterPopulate) {
fromPosition = fromPosition || 0;
toPosition = toPosition || fromPosition + this._dataGrid.defaultPopulateCount();
var firstNotSerializedPosition = fromPosition;
function serializeNextChunk() {
if (firstNotSerializedPosition >= toPosition)
return;
var end = Math.min(firstNotSerializedPosition + this._dataGrid.defaultPopulateCount(), toPosition);
this._provider().serializeItemsRange(firstNotSerializedPosition, end, childrenRetrieved.bind(this));
firstNotSerializedPosition = end;
}
function insertRetrievedChild(item, insertionIndex) {
if (this._savedChildren) {
var hash = this._childHashForEntity(item);
if (hash in this._savedChildren) {
this._dataGrid.insertChild(this, this._savedChildren[hash], insertionIndex);
return;
}
}
this._dataGrid.insertChild(this, this._createChildNode(item), insertionIndex);
}
function insertShowMoreButton(from, to, insertionIndex) {
var button = new WebInspector.ShowMoreDataGridNode(this._populateChildren.bind(this), from, to, this._dataGrid.defaultPopulateCount());
this._dataGrid.insertChild(this, button, insertionIndex);
}
function childrenRetrieved(itemsRange) {
var itemIndex = 0;
var itemPosition = itemsRange.startPosition;
var items = itemsRange.items;
var insertionIndex = 0;
if (!this._retrievedChildrenRanges.length) {
if (itemsRange.startPosition > 0) {
this._retrievedChildrenRanges.push({from: 0, to: 0});
insertShowMoreButton.call(this, 0, itemsRange.startPosition, insertionIndex++);
}
this._retrievedChildrenRanges.push({from: itemsRange.startPosition, to: itemsRange.endPosition});
for (var i = 0, l = items.length; i < l; ++i)
insertRetrievedChild.call(this, items[i], insertionIndex++);
if (itemsRange.endPosition < itemsRange.totalLength)
insertShowMoreButton.call(this, itemsRange.endPosition, itemsRange.totalLength, insertionIndex++);
} else {
var rangeIndex = 0;
var found = false;
var range;
while (rangeIndex < this._retrievedChildrenRanges.length) {
range = this._retrievedChildrenRanges[rangeIndex];
if (range.to >= itemPosition) {
found = true;
break;
}
insertionIndex += range.to - range.from;
if (range.to < itemsRange.totalLength)
insertionIndex += 1;
++rangeIndex;
}
if (!found || itemsRange.startPosition < range.from) {
this.allChildren()[insertionIndex - 1].setEndPosition(itemsRange.startPosition);
insertShowMoreButton.call(this, itemsRange.startPosition, found ? range.from : itemsRange.totalLength, insertionIndex);
range = {from: itemsRange.startPosition, to: itemsRange.startPosition};
if (!found)
rangeIndex = this._retrievedChildrenRanges.length;
this._retrievedChildrenRanges.splice(rangeIndex, 0, range);
} else {
insertionIndex += itemPosition - range.from;
}
while (range.to < itemsRange.endPosition) {
var skipCount = range.to - itemPosition;
insertionIndex += skipCount;
itemIndex += skipCount;
itemPosition = range.to;
var nextRange = this._retrievedChildrenRanges[rangeIndex + 1];
var newEndOfRange = nextRange ? nextRange.from : itemsRange.totalLength;
if (newEndOfRange > itemsRange.endPosition)
newEndOfRange = itemsRange.endPosition;
while (itemPosition < newEndOfRange) {
insertRetrievedChild.call(this, items[itemIndex++], insertionIndex++);
++itemPosition;
}
if (nextRange && newEndOfRange === nextRange.from) {
range.to = nextRange.to;
this.removeChildByIndex(insertionIndex);
this._retrievedChildrenRanges.splice(rangeIndex + 1, 1);
} else {
range.to = newEndOfRange;
if (newEndOfRange === itemsRange.totalLength)
this.removeChildByIndex(insertionIndex); else
this.allChildren()[insertionIndex].setStartPosition(itemsRange.endPosition);
}
}
}
this._instanceCount += items.length;
if (firstNotSerializedPosition < toPosition) {
serializeNextChunk.call(this);
return;
}
if (this.expanded)
this._dataGrid.updateVisibleNodes(true);
if (afterPopulate)
afterPopulate();
this.dispatchEventToListeners(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete);
}
serializeNextChunk.call(this);
}, _saveChildren: function () {
this._savedChildren = null;
var children = this.allChildren();
for (var i = 0, l = children.length; i < l; ++i) {
var child = children[i];
if (!child.expanded)
continue;
if (!this._savedChildren)
this._savedChildren = {};
this._savedChildren[this._childHashForNode(child)] = child;
}
}, sort: function () {
this._dataGrid.recursiveSortingEnter();
function afterSort() {
this._saveChildren();
this._dataGrid.removeAllChildren(this);
this._retrievedChildrenRanges = [];
function afterPopulate() {
var children = this.allChildren();
for (var i = 0, l = children.length; i < l; ++i) {
var child = children[i];
if (child.expanded)
child.sort();
}
this._dataGrid.recursiveSortingLeave();
}
var instanceCount = this._instanceCount;
this._instanceCount = 0;
this._populateChildren(0, instanceCount, afterPopulate.bind(this));
}
this._provider().sortAndRewind(this.comparator(), afterSort.bind(this));
}, __proto__: WebInspector.DataGridNode.prototype
}
WebInspector.HeapSnapshotGenericObjectNode = function (dataGrid, node) {
WebInspector.HeapSnapshotGridNode.call(this, dataGrid, false);
if (!node)
return;
this._name = node.name;
this._type = node.type;
this._distance = node.distance;
this._shallowSize = node.selfSize;
this._retainedSize = node.retainedSize;
this.snapshotNodeId = node.id;
this.snapshotNodeIndex = node.nodeIndex;
if (this._type === "string")
this._reachableFromWindow = true; else if (this._type === "object" && this._name.startsWith("Window")) {
this._name = this.shortenWindowURL(this._name, false);
this._reachableFromWindow = true;
} else if (node.canBeQueried)
this._reachableFromWindow = true;
if (node.detachedDOMTreeNode)
this.detachedDOMTreeNode = true;
var snapshot = dataGrid.snapshot;
var shallowSizePercent = this._shallowSize / snapshot.totalSize * 100.0;
var retainedSizePercent = this._retainedSize / snapshot.totalSize * 100.0;
this.data = {
"distance": this._toUIDistance(this._distance),
"shallowSize": Number.withThousandsSeparator(this._shallowSize),
"retainedSize": Number.withThousandsSeparator(this._retainedSize),
"shallowSize-percent": this._toPercentString(shallowSizePercent),
"retainedSize-percent": this._toPercentString(retainedSizePercent)
};
};
WebInspector.HeapSnapshotGenericObjectNode.prototype = {
retainersDataSource: function () {
return {snapshot: this._dataGrid.snapshot, snapshotNodeIndex: this.snapshotNodeIndex};
}, createCell: function (columnIdentifier) {
var cell = columnIdentifier !== "object" ? this._createValueCell(columnIdentifier) : this._createObjectCell();
if (this._searchMatched)
cell.classList.add("highlight");
return cell;
}, _createObjectCell: function () {
var value = this._name;
var valueStyle = "object";
switch (this._type) {
case"concatenated string":
case"string":
value = "\"" + value + "\"";
valueStyle = "string";
break;
case"regexp":
value = "/" + value + "/";
valueStyle = "string";
break;
case"closure":
value = "function" + (value ? " " : "") + value + "()";
valueStyle = "function";
break;
case"number":
valueStyle = "number";
break;
case"hidden":
valueStyle = "null";
break;
case"array":
if (!value)
value = "[]"; else
value += "[]";
break;
}
;
if (this._reachableFromWindow)
valueStyle += " highlight";
if (value === "Object")
value = "";
if (this.detachedDOMTreeNode)
valueStyle += " detached-dom-tree-node";
return this._createObjectCellWithValue(valueStyle, value);
}, _createObjectCellWithValue: function (valueStyle, value) {
var cell = document.createElement("td");
cell.className = "object-column";
var div = document.createElement("div");
div.className = "source-code event-properties";
div.style.overflow = "visible";
this._prefixObjectCell(div);
var valueSpan = document.createElement("span");
valueSpan.className = "value console-formatted-" + valueStyle;
valueSpan.textContent = value;
div.appendChild(valueSpan);
var idSpan = document.createElement("span");
idSpan.className = "console-formatted-id";
idSpan.textContent = " @" + this.snapshotNodeId;
div.appendChild(idSpan);
cell.appendChild(div);
cell.classList.add("disclosure");
if (this.depth)
cell.style.setProperty("padding-left", (this.depth * this.dataGrid.indentWidth) + "px");
cell.heapSnapshotNode = this;
return cell;
}, _prefixObjectCell: function (div) {
}, queryObjectContent: function (target, callback, objectGroupName) {
function formatResult(error, object) {
if (!error && object.type)
callback(target.runtimeModel.createRemoteObject(object)); else
callback(target.runtimeModel.createRemoteObjectFromPrimitiveValue(WebInspector.UIString("Preview is not available")));
}
if (this._type === "string")
callback(target.runtimeModel.createRemoteObjectFromPrimitiveValue(this._name)); else
target.heapProfilerAgent().getObjectByHeapObjectId(String(this.snapshotNodeId), objectGroupName, formatResult);
}, updateHasChildren: function () {
function isEmptyCallback(isEmpty) {
this.hasChildren = !isEmpty;
}
this._provider().isEmpty(isEmptyCallback.bind(this));
}, shortenWindowURL: function (fullName, hasObjectId) {
var startPos = fullName.indexOf("/");
var endPos = hasObjectId ? fullName.indexOf("@") : fullName.length;
if (startPos !== -1 && endPos !== -1) {
var fullURL = fullName.substring(startPos + 1, endPos).trimLeft();
var url = fullURL.trimURL();
if (url.length > 40)
url = url.trimMiddle(40);
return fullName.substr(0, startPos + 2) + url + fullName.substr(endPos);
} else
return fullName;
}, __proto__: WebInspector.HeapSnapshotGridNode.prototype
}
WebInspector.HeapSnapshotObjectNode = function (dataGrid, snapshot, edge, parentObjectNode) {
WebInspector.HeapSnapshotGenericObjectNode.call(this, dataGrid, edge.node);
this._referenceName = edge.name;
this._referenceType = edge.type;
this._edgeIndex = edge.edgeIndex;
this._snapshot = snapshot;
this._parentObjectNode = parentObjectNode;
this._cycledWithAncestorGridNode = this._findAncestorWithSameSnapshotNodeId();
if (!this._cycledWithAncestorGridNode)
this.updateHasChildren();
var data = this.data;
data["count"] = "";
data["addedCount"] = "";
data["removedCount"] = "";
data["countDelta"] = "";
data["addedSize"] = "";
data["removedSize"] = "";
data["sizeDelta"] = "";
}
WebInspector.HeapSnapshotObjectNode.prototype = {
retainersDataSource: function () {
return {snapshot: this._snapshot, snapshotNodeIndex: this.snapshotNodeIndex};
}, createProvider: function () {
return this._snapshot.createEdgesProvider(this.snapshotNodeIndex);
}, _findAncestorWithSameSnapshotNodeId: function () {
var ancestor = this._parentObjectNode;
while (ancestor) {
if (ancestor.snapshotNodeId === this.snapshotNodeId)
return ancestor;
ancestor = ancestor._parentObjectNode;
}
return null;
}, _createChildNode: function (item) {
return new WebInspector.HeapSnapshotObjectNode(this._dataGrid, this._snapshot, item, this);
}, _childHashForEntity: function (edge) {
return edge.edgeIndex;
}, _childHashForNode: function (childNode) {
return childNode._edgeIndex;
}, comparator: function () {
var sortAscending = this._dataGrid.isSortOrderAscending();
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],
distance: ["distance", sortAscending, "_name", true]
}[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
}, _prefixObjectCell: function (div) {
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":
case"weak":
nameClass = "console-formatted-null";
break;
case"element":
name = "[" + name + "]";
break;
}
if (this._cycledWithAncestorGridNode)
div.className += " cycled-ancessor-node";
var nameSpan = document.createElement("span");
nameSpan.className = nameClass;
nameSpan.textContent = name;
div.appendChild(nameSpan);
var separatorSpan = document.createElement("span");
separatorSpan.className = "grayed";
separatorSpan.textContent = this._edgeNodeSeparator();
div.appendChild(separatorSpan);
}, _edgeNodeSeparator: function () {
return " :: ";
}, __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
}
WebInspector.HeapSnapshotRetainingObjectNode = function (dataGrid, snapshot, edge, parentRetainingObjectNode) {
WebInspector.HeapSnapshotObjectNode.call(this, dataGrid, snapshot, edge, parentRetainingObjectNode);
}
WebInspector.HeapSnapshotRetainingObjectNode.prototype = {
createProvider: function () {
return this._snapshot.createRetainingEdgesProvider(this.snapshotNodeIndex);
}, _createChildNode: function (item) {
return new WebInspector.HeapSnapshotRetainingObjectNode(this._dataGrid, this._snapshot, item, this);
}, _edgeNodeSeparator: function () {
return " in ";
}, expand: function () {
this._expandRetainersChain(20);
}, _expandRetainersChain: function (maxExpandLevels) {
function populateComplete() {
this.removeEventListener(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete, populateComplete, this);
this._expandRetainersChain(maxExpandLevels);
}
if (!this._populated) {
this.addEventListener(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete, populateComplete, this);
this.populate();
return;
}
WebInspector.HeapSnapshotGenericObjectNode.prototype.expand.call(this);
if (--maxExpandLevels > 0 && this.children.length > 0) {
var retainer = this.children[0];
if (retainer._distance > 1) {
retainer._expandRetainersChain(maxExpandLevels);
return;
}
}
this._dataGrid.dispatchEventToListeners(WebInspector.HeapSnapshotRetainmentDataGrid.Events.ExpandRetainersComplete);
}, __proto__: WebInspector.HeapSnapshotObjectNode.prototype
}
WebInspector.HeapSnapshotInstanceNode = function (dataGrid, snapshot, node, isDeletedNode) {
WebInspector.HeapSnapshotGenericObjectNode.call(this, dataGrid, node);
this._baseSnapshotOrSnapshot = snapshot;
this._isDeletedNode = isDeletedNode;
this.updateHasChildren();
var data = this.data;
data["count"] = "";
data["countDelta"] = "";
data["sizeDelta"] = "";
if (this._isDeletedNode) {
data["addedCount"] = "";
data["addedSize"] = "";
data["removedCount"] = "\u2022";
data["removedSize"] = Number.withThousandsSeparator(this._shallowSize);
} else {
data["addedCount"] = "\u2022";
data["addedSize"] = Number.withThousandsSeparator(this._shallowSize);
data["removedCount"] = "";
data["removedSize"] = "";
}
};
WebInspector.HeapSnapshotInstanceNode.prototype = {
retainersDataSource: function () {
return {snapshot: this._baseSnapshotOrSnapshot, snapshotNodeIndex: this.snapshotNodeIndex};
}, createProvider: function () {
return this._baseSnapshotOrSnapshot.createEdgesProvider(this.snapshotNodeIndex);
}, _createChildNode: function (item) {
return new WebInspector.HeapSnapshotObjectNode(this._dataGrid, this._baseSnapshotOrSnapshot, item, null);
}, _childHashForEntity: function (edge) {
return edge.edgeIndex;
}, _childHashForNode: function (childNode) {
return childNode._edgeIndex;
}, comparator: function () {
var sortAscending = this._dataGrid.isSortOrderAscending();
var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
var sortFields = {
object: ["!edgeName", sortAscending, "retainedSize", false],
distance: ["distance", 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.HeapSnapshotGridNode.createComparator(sortFields);
}, __proto__: WebInspector.HeapSnapshotGenericObjectNode.prototype
}
WebInspector.HeapSnapshotConstructorNode = function (dataGrid, className, aggregate, nodeFilter) {
WebInspector.HeapSnapshotGridNode.call(this, dataGrid, aggregate.count > 0);
this._name = className;
this._nodeFilter = nodeFilter;
this._distance = aggregate.distance;
this._count = aggregate.count;
this._shallowSize = aggregate.self;
this._retainedSize = aggregate.maxRet;
var snapshot = dataGrid.snapshot;
var countPercent = this._count / snapshot.nodeCount * 100.0;
var retainedSizePercent = this._retainedSize / snapshot.totalSize * 100.0;
var shallowSizePercent = this._shallowSize / snapshot.totalSize * 100.0;
this.data = {
"object": className,
"count": Number.withThousandsSeparator(this._count),
"distance": this._toUIDistance(this._distance),
"shallowSize": Number.withThousandsSeparator(this._shallowSize),
"retainedSize": Number.withThousandsSeparator(this._retainedSize),
"count-percent": this._toPercentString(countPercent),
"shallowSize-percent": this._toPercentString(shallowSizePercent),
"retainedSize-percent": this._toPercentString(retainedSizePercent)
};
}
WebInspector.HeapSnapshotConstructorNode.prototype = {
createProvider: function () {
return this._dataGrid.snapshot.createNodesProviderForClass(this._name, this._nodeFilter)
}, revealNodeBySnapshotObjectId: function (snapshotObjectId, callback) {
function didExpand() {
this._provider().nodePosition(snapshotObjectId, didGetNodePosition.bind(this));
}
function didGetNodePosition(nodePosition) {
if (nodePosition === -1) {
this.collapse();
callback(false);
} else {
this._populateChildren(nodePosition, null, didPopulateChildren.bind(this, nodePosition));
}
}
function didPopulateChildren(nodePosition) {
var child = this.childForPosition(nodePosition);
if (child) {
this._dataGrid.revealTreeNode([this, child]);
this._dataGrid.highlightNode((child));
}
callback(!!child);
}
this._dataGrid.resetNameFilter();
this.expandWithoutPopulate(didExpand.bind(this));
}, filteredOut: function (filterValue) {
return this._name.toLowerCase().indexOf(filterValue) === -1;
}, createCell: function (columnIdentifier) {
var cell = columnIdentifier !== "object" ? this._createValueCell(columnIdentifier) : WebInspector.HeapSnapshotGridNode.prototype.createCell.call(this, columnIdentifier);
if (this._searchMatched)
cell.classList.add("highlight");
return cell;
}, _createChildNode: function (item) {
return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, this._dataGrid.snapshot, item, false);
}, comparator: function () {
var sortAscending = this._dataGrid.isSortOrderAscending();
var sortColumnIdentifier = this._dataGrid.sortColumnIdentifier();
var sortFields = {
object: ["id", sortAscending, "retainedSize", false],
distance: ["distance", sortAscending, "retainedSize", false],
count: ["id", true, "retainedSize", false],
shallowSize: ["selfSize", sortAscending, "id", true],
retainedSize: ["retainedSize", sortAscending, "id", true]
}[sortColumnIdentifier];
return WebInspector.HeapSnapshotGridNode.createComparator(sortFields);
}, _childHashForEntity: function (node) {
return node.id;
}, _childHashForNode: function (childNode) {
return childNode.snapshotNodeId;
}, __proto__: WebInspector.HeapSnapshotGridNode.prototype
}
WebInspector.HeapSnapshotDiffNodesProvider = function (addedNodesProvider, deletedNodesProvider, addedCount, removedCount) {
this._addedNodesProvider = addedNodesProvider;
this._deletedNodesProvider = deletedNodesProvider;
this._addedCount = addedCount;
this._removedCount = removedCount;
}
WebInspector.HeapSnapshotDiffNodesProvider.prototype = {
dispose: function () {
this._addedNodesProvider.dispose();
this._deletedNodesProvider.dispose();
}, nodePosition: function (snapshotObjectId, callback) {
throw new Error("Unreachable");
}, isEmpty: function (callback) {
callback(false);
}, serializeItemsRange: function (beginPosition, endPosition, callback) {
function didReceiveAllItems(items) {
items.totalLength = this._addedCount + this._removedCount;
callback(items);
}
function didReceiveDeletedItems(addedItems, itemsRange) {
var items = itemsRange.items;
if (!addedItems.items.length)
addedItems.startPosition = this._addedCount + itemsRange.startPosition;
for (var i = 0; i < items.length; i++) {
items[i].isAddedNotRemoved = false;
addedItems.items.push(items[i]);
}
addedItems.endPosition = this._addedCount + itemsRange.endPosition;
didReceiveAllItems.call(this, addedItems);
}
function didReceiveAddedItems(itemsRange) {
var items = itemsRange.items;
for (var i = 0; i < items.length; i++)
items[i].isAddedNotRemoved = true;
if (itemsRange.endPosition < endPosition)
return this._deletedNodesProvider.serializeItemsRange(0, endPosition - itemsRange.endPosition, didReceiveDeletedItems.bind(this, itemsRange));
itemsRange.totalLength = this._addedCount + this._removedCount;
didReceiveAllItems.call(this, itemsRange);
}
if (beginPosition < this._addedCount) {
this._addedNodesProvider.serializeItemsRange(beginPosition, endPosition, didReceiveAddedItems.bind(this));
} else {
var emptyRange = new WebInspector.HeapSnapshotCommon.ItemsRange(0, 0, 0, []);
this._deletedNodesProvider.serializeItemsRange(beginPosition - this._addedCount, endPosition - this._addedCount, didReceiveDeletedItems.bind(this, emptyRange));
}
}, sortAndRewind: function (comparator, callback) {
function afterSort() {
this._deletedNodesProvider.sortAndRewind(comparator, callback);
}
this._addedNodesProvider.sortAndRewind(comparator, afterSort.bind(this));
}
};
WebInspector.HeapSnapshotDiffNode = function (dataGrid, className, diffForClass) {
WebInspector.HeapSnapshotGridNode.call(this, dataGrid, true);
this._name = className;
this._addedCount = diffForClass.addedCount;
this._removedCount = diffForClass.removedCount;
this._countDelta = diffForClass.countDelta;
this._addedSize = diffForClass.addedSize;
this._removedSize = diffForClass.removedSize;
this._sizeDelta = diffForClass.sizeDelta;
this._deletedIndexes = diffForClass.deletedIndexes;
this.data = {
"object": className,
"addedCount": Number.withThousandsSeparator(this._addedCount),
"removedCount": Number.withThousandsSeparator(this._removedCount),
"countDelta": this._signForDelta(this._countDelta) + Number.withThousandsSeparator(Math.abs(this._countDelta)),
"addedSize": Number.withThousandsSeparator(this._addedSize),
"removedSize": Number.withThousandsSeparator(this._removedSize),
"sizeDelta": this._signForDelta(this._sizeDelta) + Number.withThousandsSeparator(Math.abs(this._sizeDelta))
};
}
WebInspector.HeapSnapshotDiffNode.prototype = {
createProvider: function () {
var tree = this._dataGrid;
return new WebInspector.HeapSnapshotDiffNodesProvider(tree.snapshot.createAddedNodesProvider(tree.baseSnapshot.uid, this._name), tree.baseSnapshot.createDeletedNodesProvider(this._deletedIndexes), this._addedCount, this._removedCount);
}, createCell: function (columnIdentifier) {
var cell = WebInspector.HeapSnapshotGridNode.prototype.createCell.call(this, columnIdentifier);
if (columnIdentifier !== "object")
cell.classList.add("numeric-column");
return cell;
}, _createChildNode: function (item) {
if (item.isAddedNotRemoved)
return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, this._dataGrid.snapshot, item, false); else
return new WebInspector.HeapSnapshotInstanceNode(this._dataGrid, this._dataGrid.baseSnapshot, item, true);
}, _childHashForEntity: function (node) {
return node.id;
}, _childHashForNode: function (childNode) {
return childNode.snapshotNodeId;
}, comparator: function () {
var sortAscending = this._dataGrid.isSortOrderAscending();
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.HeapSnapshotGridNode.createComparator(sortFields);
}, filteredOut: function (filterValue) {
return this._name.toLowerCase().indexOf(filterValue) === -1;
}, _signForDelta: function (delta) {
if (delta === 0)
return "";
if (delta > 0)
return "+"; else
return "\u2212";
}, __proto__: WebInspector.HeapSnapshotGridNode.prototype
}
WebInspector.AllocationGridNode = function (dataGrid, data) {
WebInspector.HeapSnapshotGridNode.call(this, dataGrid, data.hasChildren);
this._populated = false;
this._allocationNode = data;
this.data = {
"liveCount": Number.withThousandsSeparator(data.liveCount),
"count": Number.withThousandsSeparator(data.count),
"liveSize": Number.withThousandsSeparator(data.liveSize),
"size": Number.withThousandsSeparator(data.size),
"name": data.name
};
}
WebInspector.AllocationGridNode.prototype = {
populate: function () {
if (this._populated)
return;
this._populated = true;
this._dataGrid.snapshot.allocationNodeCallers(this._allocationNode.id, didReceiveCallers.bind(this));
function didReceiveCallers(callers) {
var callersChain = callers.nodesWithSingleCaller;
var parentNode = this;
var dataGrid = (this._dataGrid);
for (var i = 0; i < callersChain.length; i++) {
var child = new WebInspector.AllocationGridNode(dataGrid, callersChain[i]);
dataGrid.appendNode(parentNode, child);
parentNode = child;
parentNode._populated = true;
if (this.expanded)
parentNode.expand();
}
var callersBranch = callers.branchingCallers;
callersBranch.sort(this._dataGrid._createComparator());
for (var i = 0; i < callersBranch.length; i++)
dataGrid.appendNode(parentNode, new WebInspector.AllocationGridNode(dataGrid, callersBranch[i]));
dataGrid.updateVisibleNodes(true);
}
}, expand: function () {
WebInspector.HeapSnapshotGridNode.prototype.expand.call(this);
if (this.children.length === 1)
this.children[0].expand();
}, createCell: function (columnIdentifier) {
if (columnIdentifier !== "name")
return this._createValueCell(columnIdentifier);
var cell = WebInspector.HeapSnapshotGridNode.prototype.createCell.call(this, columnIdentifier);
var allocationNode = this._allocationNode;
var target = this._dataGrid.target();
if (allocationNode.scriptId) {
var linkifier = this._dataGrid._linkifier;
var urlElement = linkifier.linkifyScriptLocation(target, String(allocationNode.scriptId), allocationNode.scriptName, allocationNode.line - 1, allocationNode.column - 1, "profile-node-file");
urlElement.style.maxWidth = "75%";
cell.insertBefore(urlElement, cell.firstChild);
}
return cell;
}, allocationNodeId: function () {
return this._allocationNode.id;
}, __proto__: WebInspector.HeapSnapshotGridNode.prototype
};
WebInspector.HeapSnapshotView = function (dataDisplayDelegate, profile) {
WebInspector.VBox.call(this);
this.element.classList.add("heap-snapshot-view");
profile.profileType().addEventListener(WebInspector.HeapSnapshotProfileType.SnapshotReceived, this._onReceiveSnapshot, this);
profile.profileType().addEventListener(WebInspector.ProfileType.Events.RemoveProfileHeader, this._onProfileHeaderRemoved, this);
if (profile.profileType().id === WebInspector.TrackingHeapSnapshotProfileType.TypeId) {
this._trackingOverviewGrid = new WebInspector.HeapTrackingOverviewGrid(profile);
this._trackingOverviewGrid.addEventListener(WebInspector.HeapTrackingOverviewGrid.IdsRangeChanged, this._onIdsRangeChanged.bind(this));
}
this._splitView = new WebInspector.SplitView(false, true, "heapSnapshotSplitViewState", 200, 200);
this._splitView.show(this.element);
this._containmentView = new WebInspector.VBox();
this._containmentView.setMinimumSize(50, 25);
this._containmentDataGrid = new WebInspector.HeapSnapshotContainmentDataGrid(dataDisplayDelegate);
this._containmentDataGrid.show(this._containmentView.element);
this._containmentDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this);
this._statisticsView = new WebInspector.HeapSnapshotStatisticsView();
this._constructorsView = new WebInspector.VBox();
this._constructorsView.setMinimumSize(50, 25);
this._constructorsDataGrid = new WebInspector.HeapSnapshotConstructorsDataGrid(dataDisplayDelegate);
this._constructorsDataGrid.show(this._constructorsView.element);
this._constructorsDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this);
this._diffView = new WebInspector.VBox();
this._diffView.setMinimumSize(50, 25);
this._diffDataGrid = new WebInspector.HeapSnapshotDiffDataGrid(dataDisplayDelegate);
this._diffDataGrid.show(this._diffView.element);
this._diffDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this);
if (profile._hasAllocationStacks) {
this._allocationView = new WebInspector.VBox();
this._allocationView.setMinimumSize(50, 25);
this._allocationDataGrid = new WebInspector.AllocationDataGrid(profile.weakTarget(), dataDisplayDelegate);
this._allocationDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._onSelectAllocationNode, this);
this._allocationDataGrid.show(this._allocationView.element);
this._allocationStackView = new WebInspector.HeapAllocationStackView(profile.weakTarget());
this._allocationStackView.setMinimumSize(50, 25);
this._tabbedPane = new WebInspector.TabbedPane();
this._tabbedPane.closeableTabs = false;
this._tabbedPane.headerElement().classList.add("heap-object-details-header");
}
this._retainmentView = new WebInspector.VBox();
this._retainmentView.setMinimumSize(50, 21);
this._retainmentView.element.classList.add("retaining-paths-view");
var splitViewResizer;
if (this._allocationStackView) {
this._tabbedPane = new WebInspector.TabbedPane();
this._tabbedPane.closeableTabs = false;
this._tabbedPane.headerElement().classList.add("heap-object-details-header");
this._tabbedPane.appendTab("retainers", WebInspector.UIString("Retainers"), this._retainmentView);
this._tabbedPane.appendTab("allocation-stack", WebInspector.UIString("Allocation stack"), this._allocationStackView);
splitViewResizer = this._tabbedPane.headerElement();
this._objectDetailsView = this._tabbedPane;
} else {
var retainmentViewHeader = document.createElementWithClass("div", "heap-snapshot-view-resizer");
var retainingPathsTitleDiv = retainmentViewHeader.createChild("div", "title");
var retainingPathsTitle = retainingPathsTitleDiv.createChild("span");
retainingPathsTitle.textContent = WebInspector.UIString("Retainers");
this._retainmentView.element.appendChild(retainmentViewHeader);
splitViewResizer = retainmentViewHeader;
this._objectDetailsView = this._retainmentView;
}
this._splitView.hideDefaultResizer();
this._splitView.installResizer(splitViewResizer);
this._retainmentDataGrid = new WebInspector.HeapSnapshotRetainmentDataGrid(dataDisplayDelegate);
this._retainmentDataGrid.show(this._retainmentView.element);
this._retainmentDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._inspectedObjectChanged, this);
this._retainmentDataGrid.reset();
this._perspectives = [];
this._perspectives.push(new WebInspector.HeapSnapshotView.SummaryPerspective());
if (profile.profileType() !== WebInspector.ProfileTypeRegistry.instance.trackingHeapSnapshotProfileType)
this._perspectives.push(new WebInspector.HeapSnapshotView.ComparisonPerspective());
this._perspectives.push(new WebInspector.HeapSnapshotView.ContainmentPerspective());
if (this._allocationView)
this._perspectives.push(new WebInspector.HeapSnapshotView.AllocationPerspective());
this._perspectives.push(new WebInspector.HeapSnapshotView.StatisticsPerspective());
this._perspectiveSelect = new WebInspector.StatusBarComboBox(this._onSelectedPerspectiveChanged.bind(this));
for (var i = 0; i < this._perspectives.length; ++i)
this._perspectiveSelect.createOption(this._perspectives[i].title());
this._profile = profile;
this._baseSelect = new WebInspector.StatusBarComboBox(this._changeBase.bind(this));
this._baseSelect.visible = false;
this._updateBaseOptions();
this._filterSelect = new WebInspector.StatusBarComboBox(this._changeFilter.bind(this));
this._filterSelect.visible = false;
this._updateFilterOptions();
this._classNameFilter = new WebInspector.StatusBarInput("Class filter");
this._classNameFilter.visible = false;
this._constructorsDataGrid.setNameFilter(this._classNameFilter);
this._diffDataGrid.setNameFilter(this._classNameFilter);
this._selectedSizeText = new WebInspector.StatusBarText("");
this._popoverHelper = new WebInspector.ObjectPopoverHelper(this.element, this._getHoverAnchor.bind(this), this._resolveObjectForPopover.bind(this), undefined, true);
this._currentPerspectiveIndex = 0;
this._currentPerspective = this._perspectives[0];
this._currentPerspective.activate(this);
this._dataGrid = this._currentPerspective.masterGrid(this);
this._refreshView();
}
WebInspector.HeapSnapshotView.Perspective = function (title) {
this._title = title;
}
WebInspector.HeapSnapshotView.Perspective.prototype = {
activate: function (heapSnapshotView) {
}, deactivate: function (heapSnapshotView) {
heapSnapshotView._baseSelect.visible = false;
heapSnapshotView._filterSelect.visible = false;
heapSnapshotView._classNameFilter.visible = false;
if (heapSnapshotView._trackingOverviewGrid)
heapSnapshotView._trackingOverviewGrid.detach();
if (heapSnapshotView._allocationView)
heapSnapshotView._allocationView.detach();
if (heapSnapshotView._statisticsView)
heapSnapshotView._statisticsView.detach();
heapSnapshotView._splitView.detach();
heapSnapshotView._splitView.detachChildViews();
}, masterGrid: function (heapSnapshotView) {
return null;
}, title: function () {
return this._title;
}, supportsSearch: function () {
return false;
}
}
WebInspector.HeapSnapshotView.SummaryPerspective = function () {
WebInspector.HeapSnapshotView.Perspective.call(this, WebInspector.UIString("Summary"));
}
WebInspector.HeapSnapshotView.SummaryPerspective.prototype = {
activate: function (heapSnapshotView) {
heapSnapshotView._constructorsView.show(heapSnapshotView._splitView.mainElement());
heapSnapshotView._objectDetailsView.show(heapSnapshotView._splitView.sidebarElement());
heapSnapshotView._splitView.show(heapSnapshotView.element);
heapSnapshotView._filterSelect.visible = true;
heapSnapshotView._classNameFilter.visible = true;
if (heapSnapshotView._trackingOverviewGrid) {
heapSnapshotView._trackingOverviewGrid.show(heapSnapshotView.element, heapSnapshotView._splitView.element);
heapSnapshotView._trackingOverviewGrid.update();
heapSnapshotView._trackingOverviewGrid._updateGrid();
}
}, masterGrid: function (heapSnapshotView) {
return heapSnapshotView._constructorsDataGrid;
}, supportsSearch: function () {
return true;
}, __proto__: WebInspector.HeapSnapshotView.Perspective.prototype
}
WebInspector.HeapSnapshotView.ComparisonPerspective = function () {
WebInspector.HeapSnapshotView.Perspective.call(this, WebInspector.UIString("Comparison"));
}
WebInspector.HeapSnapshotView.ComparisonPerspective.prototype = {
activate: function (heapSnapshotView) {
heapSnapshotView._diffView.show(heapSnapshotView._splitView.mainElement());
heapSnapshotView._objectDetailsView.show(heapSnapshotView._splitView.sidebarElement());
heapSnapshotView._splitView.show(heapSnapshotView.element);
heapSnapshotView._baseSelect.visible = true;
heapSnapshotView._classNameFilter.visible = true;
}, masterGrid: function (heapSnapshotView) {
return heapSnapshotView._diffDataGrid;
}, supportsSearch: function () {
return true;
}, __proto__: WebInspector.HeapSnapshotView.Perspective.prototype
}
WebInspector.HeapSnapshotView.ContainmentPerspective = function () {
WebInspector.HeapSnapshotView.Perspective.call(this, WebInspector.UIString("Containment"));
}
WebInspector.HeapSnapshotView.ContainmentPerspective.prototype = {
activate: function (heapSnapshotView) {
heapSnapshotView._containmentView.show(heapSnapshotView._splitView.mainElement());
heapSnapshotView._objectDetailsView.show(heapSnapshotView._splitView.sidebarElement());
heapSnapshotView._splitView.show(heapSnapshotView.element);
}, masterGrid: function (heapSnapshotView) {
return heapSnapshotView._containmentDataGrid;
}, __proto__: WebInspector.HeapSnapshotView.Perspective.prototype
}
WebInspector.HeapSnapshotView.AllocationPerspective = function () {
WebInspector.HeapSnapshotView.Perspective.call(this, WebInspector.UIString("Allocation"));
this._allocationSplitView = new WebInspector.SplitView(false, true, "heapSnapshotAllocationSplitViewState", 200, 200);
var resizer = document.createElementWithClass("div", "heap-snapshot-view-resizer");
var title = resizer.createChild("div", "title").createChild("span");
title.textContent = WebInspector.UIString("Live objects");
this._allocationSplitView.hideDefaultResizer();
this._allocationSplitView.installResizer(resizer);
this._allocationSplitView.sidebarElement().appendChild(resizer);
}
WebInspector.HeapSnapshotView.AllocationPerspective.prototype = {
activate: function (heapSnapshotView) {
heapSnapshotView._allocationView.show(this._allocationSplitView.mainElement());
heapSnapshotView._constructorsView.show(heapSnapshotView._splitView.mainElement());
heapSnapshotView._objectDetailsView.show(heapSnapshotView._splitView.sidebarElement());
heapSnapshotView._splitView.show(this._allocationSplitView.sidebarElement());
this._allocationSplitView.show(heapSnapshotView.element);
heapSnapshotView._constructorsDataGrid.clear();
var selectedNode = heapSnapshotView._allocationDataGrid.selectedNode;
if (selectedNode)
heapSnapshotView._constructorsDataGrid.setAllocationNodeId(selectedNode.allocationNodeId());
}, deactivate: function (heapSnapshotView) {
this._allocationSplitView.detach();
WebInspector.HeapSnapshotView.Perspective.prototype.deactivate.call(this, heapSnapshotView);
}, masterGrid: function (heapSnapshotView) {
return heapSnapshotView._allocationDataGrid;
}, __proto__: WebInspector.HeapSnapshotView.Perspective.prototype
}
WebInspector.HeapSnapshotView.StatisticsPerspective = function () {
WebInspector.HeapSnapshotView.Perspective.call(this, WebInspector.UIString("Statistics"));
}
WebInspector.HeapSnapshotView.StatisticsPerspective.prototype = {
activate: function (heapSnapshotView) {
heapSnapshotView._statisticsView.show(heapSnapshotView.element);
}, masterGrid: function (heapSnapshotView) {
return null;
}, __proto__: WebInspector.HeapSnapshotView.Perspective.prototype
}
WebInspector.HeapSnapshotView.prototype = {
_refreshView: function () {
this._profile.load(profileCallback.bind(this));
function profileCallback(heapSnapshotProxy) {
heapSnapshotProxy.getStatistics(this._gotStatistics.bind(this));
var list = this._profiles();
var profileIndex = list.indexOf(this._profile);
this._baseSelect.setSelectedIndex(Math.max(0, profileIndex - 1));
this._dataGrid.setDataSource(heapSnapshotProxy);
if (this._trackingOverviewGrid)
this._trackingOverviewGrid._updateGrid();
}
}, _gotStatistics: function (statistics) {
this._statisticsView.setTotal(statistics.total);
this._statisticsView.addRecord(statistics.code, WebInspector.UIString("Code"), "#f77");
this._statisticsView.addRecord(statistics.strings, WebInspector.UIString("Strings"), "#5e5");
this._statisticsView.addRecord(statistics.jsArrays, WebInspector.UIString("JS Arrays"), "#7af");
this._statisticsView.addRecord(statistics.native, WebInspector.UIString("Typed Arrays"), "#fc5");
this._statisticsView.addRecord(statistics.total, WebInspector.UIString("Total"));
}, _onIdsRangeChanged: function (event) {
var minId = event.data.minId;
var maxId = event.data.maxId;
this._selectedSizeText.setText(WebInspector.UIString("Selected size: %s", Number.bytesToString(event.data.size)));
if (this._constructorsDataGrid.snapshot)
this._constructorsDataGrid.setSelectionRange(minId, maxId);
}, get statusBarItems() {
var result = [this._perspectiveSelect.element, this._classNameFilter.element];
if (this._profile.profileType() !== WebInspector.ProfileTypeRegistry.instance.trackingHeapSnapshotProfileType)
result.push(this._baseSelect.element, this._filterSelect.element);
result.push(this._selectedSizeText.element);
return result;
}, wasShown: function () {
this._profile.load(profileCallback.bind(this));
function profileCallback() {
this._profile._wasShown();
if (this._baseProfile)
this._baseProfile.load(function () {
});
}
}, willHide: function () {
this._currentSearchResultIndex = -1;
this._popoverHelper.hidePopover();
if (this.helpPopover && this.helpPopover.isShowing())
this.helpPopover.hide();
}, 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) {
this.searchCanceled();
query = query.trim();
if (!query)
return;
if (!this._currentPerspective.supportsSearch())
return;
function didHighlight(found) {
finishedCallback(this, found ? 1 : 0);
}
if (query.charAt(0) === "@") {
var snapshotNodeId = parseInt(query.substring(1), 10);
if (!isNaN(snapshotNodeId))
this._dataGrid.highlightObjectByHeapSnapshotId(String(snapshotNodeId), didHighlight.bind(this)); else
finishedCallback(this, 0);
return;
}
this._searchFinishedCallback = finishedCallback;
var nameRegExp = createPlainTextSearchRegex(query, "i");
function matchesByName(gridNode) {
return ("_name"in gridNode) && nameRegExp.test(gridNode._name);
}
function matchesQuery(gridNode) {
delete gridNode._searchMatched;
if (matchesByName(gridNode)) {
gridNode._searchMatched = true;
gridNode.refresh();
return true;
}
return false;
}
var current = this._dataGrid.rootNode().children[0];
var depth = 0;
var info = {};
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));
}, currentSearchResultIndex: function () {
return this._currentSearchResultIndex;
}, _jumpToSearchResult: function (index) {
var searchResult = this._searchResults[index];
if (!searchResult)
return;
var node = searchResult.node;
node.revealAndSelect();
}, refreshVisibleData: function () {
if (!this._dataGrid)
return;
var child = this._dataGrid.rootNode().children[0];
while (child) {
child.refresh();
child = child.traverseNextNode(false, null, true);
}
}, _changeBase: function () {
if (this._baseProfile === this._profiles()[this._baseSelect.selectedIndex()])
return;
this._baseProfile = this._profiles()[this._baseSelect.selectedIndex()];
var dataGrid = (this._dataGrid);
if (dataGrid.snapshot)
this._baseProfile.load(dataGrid.setBaseDataSource.bind(dataGrid));
if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
return;
this._searchFinishedCallback(this, -this._searchResults.length);
this.performSearch(this.currentQuery, this._searchFinishedCallback);
}, _changeFilter: function () {
var profileIndex = this._filterSelect.selectedIndex() - 1;
this._dataGrid.filterSelectIndexChanged(this._profiles(), profileIndex);
WebInspector.notifications.dispatchEventToListeners(WebInspector.UserMetrics.UserAction, {action: WebInspector.UserMetrics.UserActionNames.HeapSnapshotFilterChanged, label: this._filterSelect.selectedOption().label});
if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
return;
this._searchFinishedCallback(this, -this._searchResults.length);
this.performSearch(this.currentQuery, this._searchFinishedCallback);
}, _profiles: function () {
return this._profile.profileType().getProfiles();
}, populateContextMenu: function (contextMenu, event) {
if (this._dataGrid)
this._dataGrid.populateContextMenu(contextMenu, event);
}, _selectionChanged: function (event) {
var selectedNode = event.target.selectedNode;
this._setSelectedNodeForDetailsView(selectedNode);
this._inspectedObjectChanged(event);
}, _onSelectAllocationNode: function (event) {
var selectedNode = event.target.selectedNode;
this._constructorsDataGrid.setAllocationNodeId(selectedNode.allocationNodeId());
this._setSelectedNodeForDetailsView(null);
}, _inspectedObjectChanged: function (event) {
var selectedNode = event.target.selectedNode;
var target = this._profile.target();
if (!target && selectedNode instanceof WebInspector.HeapSnapshotGenericObjectNode)
target.consoleAgent().addInspectedHeapObject(selectedNode.snapshotNodeId);
}, _setSelectedNodeForDetailsView: function (nodeItem) {
var dataSource = nodeItem && nodeItem.retainersDataSource();
if (dataSource) {
this._retainmentDataGrid.setDataSource(dataSource.snapshot, dataSource.snapshotNodeIndex);
if (this._allocationStackView)
this._allocationStackView.setAllocatedObject(dataSource.snapshot, dataSource.snapshotNodeIndex)
} else {
if (this._allocationStackView)
this._allocationStackView.clear();
this._retainmentDataGrid.reset();
}
}, _changePerspectiveAndWait: function (perspectiveTitle, callback) {
var perspectiveIndex = null;
for (var i = 0; i < this._perspectives.length; ++i) {
if (this._perspectives[i].title() === perspectiveTitle) {
perspectiveIndex = i;
break;
}
}
if (this._currentPerspectiveIndex === perspectiveIndex || perspectiveIndex === null) {
setTimeout(callback, 0);
return;
}
function dataGridContentShown(event) {
var dataGrid = event.data;
dataGrid.removeEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, dataGridContentShown, this);
if (dataGrid === this._dataGrid)
callback();
}
this._perspectives[perspectiveIndex].masterGrid(this).addEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, dataGridContentShown, this);
this._perspectiveSelect.setSelectedIndex(perspectiveIndex);
this._changePerspective(perspectiveIndex);
}, _updateDataSourceAndView: function () {
var dataGrid = this._dataGrid;
if (!dataGrid || dataGrid.snapshot)
return;
this._profile.load(didLoadSnapshot.bind(this));
function didLoadSnapshot(snapshotProxy) {
if (this._dataGrid !== dataGrid)
return;
if (dataGrid.snapshot !== snapshotProxy)
dataGrid.setDataSource(snapshotProxy);
if (dataGrid === this._diffDataGrid) {
if (!this._baseProfile)
this._baseProfile = this._profiles()[this._baseSelect.selectedIndex()];
this._baseProfile.load(didLoadBaseSnaphot.bind(this));
}
}
function didLoadBaseSnaphot(baseSnapshotProxy) {
if (this._diffDataGrid.baseSnapshot !== baseSnapshotProxy)
this._diffDataGrid.setBaseDataSource(baseSnapshotProxy);
}
}, _onSelectedPerspectiveChanged: function (event) {
this._changePerspective(event.target.selectedIndex);
this._onSelectedViewChanged(event);
}, _onSelectedViewChanged: function (event) {
}, _changePerspective: function (selectedIndex) {
if (selectedIndex === this._currentPerspectiveIndex)
return;
this._currentPerspectiveIndex = selectedIndex;
this._currentPerspective.deactivate(this);
var perspective = this._perspectives[selectedIndex];
this._currentPerspective = perspective;
this._dataGrid = perspective.masterGrid(this);
perspective.activate(this);
this.refreshVisibleData();
if (this._dataGrid)
this._dataGrid.updateWidths();
this._updateDataSourceAndView();
if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
return;
this._searchFinishedCallback(this, -this._searchResults.length);
this.performSearch(this.currentQuery, this._searchFinishedCallback);
}, highlightLiveObject: function (perspectiveName, snapshotObjectId) {
this._changePerspectiveAndWait(perspectiveName, didChangePerspective.bind(this));
function didChangePerspective() {
this._dataGrid.highlightObjectByHeapSnapshotId(snapshotObjectId, didHighlightObject);
}
function didHighlightObject(found) {
if (!found)
WebInspector.console.error("Cannot find corresponding heap snapshot node");
}
}, _getHoverAnchor: function (target) {
var span = target.enclosingNodeOrSelfWithNodeName("span");
if (!span)
return;
var row = target.enclosingNodeOrSelfWithNodeName("tr");
if (!row)
return;
span.node = row._dataGridNode;
return span;
}, _resolveObjectForPopover: function (element, showCallback, objectGroupName) {
if (!this._profile.target())
return;
element.node.queryObjectContent(this._profile.target(), showCallback, objectGroupName);
}, _updateBaseOptions: function () {
var list = this._profiles();
if (this._baseSelect.size() === list.length)
return;
for (var i = this._baseSelect.size(), n = list.length; i < n; ++i) {
var title = list[i].title;
this._baseSelect.createOption(title);
}
}, _updateFilterOptions: function () {
var list = this._profiles();
if (this._filterSelect.size() - 1 === list.length)
return;
if (!this._filterSelect.size())
this._filterSelect.createOption(WebInspector.UIString("All objects"));
for (var i = this._filterSelect.size() - 1, n = list.length; i < n; ++i) {
var title = list[i].title;
if (!i)
title = WebInspector.UIString("Objects allocated before %s", title); else
title = WebInspector.UIString("Objects allocated between %s and %s", list[i - 1].title, title);
this._filterSelect.createOption(title);
}
}, _updateControls: function () {
this._updateBaseOptions();
this._updateFilterOptions();
}, _onReceiveSnapshot: function (event) {
this._updateControls();
}, _onProfileHeaderRemoved: function (event) {
var profile = event.data;
if (this._profile === profile) {
this.detach();
this._profile.profileType().removeEventListener(WebInspector.HeapSnapshotProfileType.SnapshotReceived, this._onReceiveSnapshot, this);
this._profile.profileType().removeEventListener(WebInspector.ProfileType.Events.RemoveProfileHeader, this._onProfileHeaderRemoved, this);
this.dispose();
} else {
this._updateControls();
}
}, dispose: function () {
if (this._allocationStackView) {
this._allocationStackView.clear();
this._allocationDataGrid.dispose();
}
}, __proto__: WebInspector.VBox.prototype
}
WebInspector.HeapSnapshotProfileType = function (id, title) {
WebInspector.ProfileType.call(this, id || WebInspector.HeapSnapshotProfileType.TypeId, title || WebInspector.UIString("Take Heap Snapshot"));
WebInspector.targetManager.observeTargets(this);
WebInspector.targetManager.addModelListener(WebInspector.HeapProfilerModel, WebInspector.HeapProfilerModel.Events.ResetProfiles, this._resetProfiles, this);
WebInspector.targetManager.addModelListener(WebInspector.HeapProfilerModel, WebInspector.HeapProfilerModel.Events.AddHeapSnapshotChunk, this._addHeapSnapshotChunk, this);
WebInspector.targetManager.addModelListener(WebInspector.HeapProfilerModel, WebInspector.HeapProfilerModel.Events.ReportHeapSnapshotProgress, this._reportHeapSnapshotProgress, this);
}
WebInspector.HeapSnapshotProfileType.TypeId = "HEAP";
WebInspector.HeapSnapshotProfileType.SnapshotReceived = "SnapshotReceived";
WebInspector.HeapSnapshotProfileType.prototype = {
targetAdded: function (target) {
target.heapProfilerModel.enable();
}, targetRemoved: function (target) {
}, fileExtension: function () {
return ".heapsnapshot";
}, get buttonTooltip() {
return WebInspector.UIString("Take heap snapshot.");
}, isInstantProfile: function () {
return true;
}, buttonClicked: function () {
this._takeHeapSnapshot(function () {
});
WebInspector.userMetrics.ProfilesHeapProfileTaken.record();
return false;
}, get treeItemTitle() {
return WebInspector.UIString("HEAP SNAPSHOTS");
}, get description() {
return WebInspector.UIString("Heap snapshot profiles show memory distribution among your page's JavaScript objects and related DOM nodes.");
}, createProfileLoadedFromFile: function (title) {
return new WebInspector.HeapProfileHeader(null, this, title);
}, _takeHeapSnapshot: function (callback) {
if (this.profileBeingRecorded())
return;
var target = (WebInspector.context.flavor(WebInspector.Target));
var profile = new WebInspector.HeapProfileHeader(target, this);
console.log("SETTING THIS PROFILE", profile);
this.setProfileBeingRecorded(profile);
this.addProfile(profile);
profile.updateStatus(WebInspector.UIString("Snapshotting\u2026"));
function didTakeHeapSnapshot(error) {
var profile = this._profileBeingRecorded;
profile.title = WebInspector.UIString("Snapshot %d", profile.uid);
profile._finishLoad();
this.setProfileBeingRecorded(null);
this.dispatchEventToListeners(WebInspector.ProfileType.Events.ProfileComplete, profile);
callback();
}
target.heapProfilerAgent().takeHeapSnapshot(true, didTakeHeapSnapshot.bind(this));
}, _addHeapSnapshotChunk: function (event) {
if (!this.profileBeingRecorded())
return;
var chunk = (event.data);
this.profileBeingRecorded().transferChunk(chunk);
}, _reportHeapSnapshotProgress: function (event) {
var profile = this.profileBeingRecorded();
if (!profile) {
return;
}
var data = (event.data);
profile.updateStatus(WebInspector.UIString("%.0f%", (data.done / data.total) * 100), true);
if (data.finished) {
console.log("FINISHED LOADING");
profile._prepareToLoad();
}
}, _resetProfiles: function () {
this._reset();
}, _snapshotReceived: function (profile) {
if (this._profileBeingRecorded === profile)
this.setProfileBeingRecorded(null);
this.dispatchEventToListeners(WebInspector.HeapSnapshotProfileType.SnapshotReceived, profile);
}, __proto__: WebInspector.ProfileType.prototype
}
WebInspector.TrackingHeapSnapshotProfileType = function () {
WebInspector.HeapSnapshotProfileType.call(this, WebInspector.TrackingHeapSnapshotProfileType.TypeId, WebInspector.UIString("Record Heap Allocations"));
}
WebInspector.TrackingHeapSnapshotProfileType.TypeId = "HEAP-RECORD";
WebInspector.TrackingHeapSnapshotProfileType.HeapStatsUpdate = "HeapStatsUpdate";
WebInspector.TrackingHeapSnapshotProfileType.TrackingStarted = "TrackingStarted";
WebInspector.TrackingHeapSnapshotProfileType.TrackingStopped = "TrackingStopped";
WebInspector.TrackingHeapSnapshotProfileType.prototype = {
targetAdded: function (target) {
WebInspector.HeapSnapshotProfileType.prototype.targetAdded.call(this, target);
target.heapProfilerModel.addEventListener(WebInspector.HeapProfilerModel.Events.HeapStatsUpdate, this._heapStatsUpdate, this);
target.heapProfilerModel.addEventListener(WebInspector.HeapProfilerModel.Events.LastSeenObjectId, this._lastSeenObjectId, this);
}, targetRemoved: function (target) {
WebInspector.HeapSnapshotProfileType.prototype.targetRemoved.call(this, target);
target.heapProfilerModel.removeEventListener(WebInspector.HeapProfilerModel.Events.HeapStatsUpdate, this._heapStatsUpdate, this);
target.heapProfilerModel.removeEventListener(WebInspector.HeapProfilerModel.Events.LastSeenObjectId, this._lastSeenObjectId, this);
}, _heapStatsUpdate: function (event) {
if (!this._profileSamples)
return;
var samples = (event.data);
var index;
for (var i = 0; i < samples.length; i += 3) {
index = samples[i];
var count = samples[i + 1];
var size = samples[i + 2];
this._profileSamples.sizes[index] = size;
if (!this._profileSamples.max[index])
this._profileSamples.max[index] = size;
}
}, _lastSeenObjectId: function (event) {
var profileSamples = this._profileSamples;
if (!profileSamples)
return;
var data = (event.data);
var currentIndex = Math.max(profileSamples.ids.length, profileSamples.max.length - 1);
profileSamples.ids[currentIndex] = data.lastSeenObjectId;
if (!profileSamples.max[currentIndex]) {
profileSamples.max[currentIndex] = 0;
profileSamples.sizes[currentIndex] = 0;
}
profileSamples.timestamps[currentIndex] = data.timestamp;
if (profileSamples.totalTime < data.timestamp - profileSamples.timestamps[0])
profileSamples.totalTime *= 2;
this.dispatchEventToListeners(WebInspector.TrackingHeapSnapshotProfileType.HeapStatsUpdate, this._profileSamples);
this._profileBeingRecorded.updateStatus(null, true);
}, hasTemporaryView: function () {
return true;
}, get buttonTooltip() {
return this._recording ? WebInspector.UIString("Stop recording heap profile.") : WebInspector.UIString("Start recording heap profile.");
}, isInstantProfile: function () {
return false;
}, buttonClicked: function () {
return this._toggleRecording();
}, _startRecordingProfile: function () {
if (this.profileBeingRecorded())
return;
var recordAllocationStacks = WebInspector.settings.recordAllocationStacks.get();
this._addNewProfile(recordAllocationStacks);
this.profileBeingRecorded().target().heapProfilerAgent().startTrackingHeapObjects(recordAllocationStacks);
}, _addNewProfile: function (withAllocationStacks) {
var target = WebInspector.context.flavor(WebInspector.Target);
this.setProfileBeingRecorded(new WebInspector.HeapProfileHeader(target, this, undefined, withAllocationStacks));
this._lastSeenIndex = -1;
this._profileSamples = {'sizes': [], 'ids': [], 'timestamps': [], 'max': [], 'totalTime': 30000};
this._profileBeingRecorded._profileSamples = this._profileSamples;
this._recording = true;
this.addProfile(this._profileBeingRecorded);
this._profileBeingRecorded.updateStatus(WebInspector.UIString("Recording\u2026"));
this.dispatchEventToListeners(WebInspector.TrackingHeapSnapshotProfileType.TrackingStarted);
}, _stopRecordingProfile: function () {
this._profileBeingRecorded.updateStatus(WebInspector.UIString("Snapshotting\u2026"));
function didTakeHeapSnapshot(error) {
var profile = this.profileBeingRecorded();
if (!profile)
return;
profile._finishLoad();
this._profileSamples = null;
this.setProfileBeingRecorded(null);
this.dispatchEventToListeners(WebInspector.ProfileType.Events.ProfileComplete, profile);
}
this._profileBeingRecorded.target().heapProfilerAgent().stopTrackingHeapObjects(true, didTakeHeapSnapshot.bind(this));
this._recording = false;
this.dispatchEventToListeners(WebInspector.TrackingHeapSnapshotProfileType.TrackingStopped);
}, _toggleRecording: function () {
if (this._recording)
this._stopRecordingProfile(); else
this._startRecordingProfile();
return this._recording;
}, get treeItemTitle() {
return WebInspector.UIString("HEAP TIMELINES");
}, get description() {
return WebInspector.UIString("Record JavaScript object allocations over time. Use this profile type to isolate memory leaks.");
}, resetProfiles: function () {
var wasRecording = this._recording;
var recordingAllocationStacks = wasRecording && this.profileBeingRecorded()._hasAllocationStacks;
this.setProfileBeingRecorded(null);
WebInspector.HeapSnapshotProfileType.prototype.resetProfiles.call(this);
this._profileSamples = null;
this._lastSeenIndex = -1;
if (wasRecording)
this._addNewProfile(recordingAllocationStacks);
}, profileBeingRecordedRemoved: function () {
this._stopRecordingProfile();
this._profileSamples = null;
}, __proto__: WebInspector.HeapSnapshotProfileType.prototype
}
WebInspector.HeapProfileHeader = function (target, type, title, hasAllocationStacks) {
WebInspector.ProfileHeader.call(this, target, type, title || WebInspector.UIString("Snapshot %d", type.nextProfileUid()));
this._hasAllocationStacks = !!hasAllocationStacks;
this.maxJSObjectId = -1;
this._workerProxy = null;
this._receiver = null;
this._snapshotProxy = null;
this._loadCallbacks = [];
this._totalNumberOfChunks = 0;
this._bufferedWriter = null;
console.log("HeapProfileHeader\n\n\n\n\n\n\n");
}
WebInspector.HeapProfileHeader.prototype = {
createSidebarTreeElement: function (dataDisplayDelegate) {
return new WebInspector.ProfileSidebarTreeElement(dataDisplayDelegate, this, "heap-snapshot-sidebar-tree-item");
}, createView: function (dataDisplayDelegate) {
return new WebInspector.HeapSnapshotView(dataDisplayDelegate, this);
}, load: function (callback) {
if (this.uid === -1)
return;
if (this._snapshotProxy) {
callback(this._snapshotProxy);
return;
}
this._loadCallbacks.push(callback);
}, _prepareToLoad: function () {
console.assert(!this._receiver, "Already loading");
this._setupWorker();
console.log("_setupWorker\n\n\n");
this.updateStatus(WebInspector.UIString("Loading\u2026"), true);
}, _finishLoad: function () {
if (!this._wasDisposed)
this._receiver.close(function () {
});
if (this._bufferedWriter) {
this._bufferedWriter.close(this._didWriteToTempFile.bind(this));
this._bufferedWriter = null;
}
}, _didWriteToTempFile: function (tempFile) {
if (this._wasDisposed) {
if (tempFile)
tempFile.remove();
return;
}
this._tempFile = tempFile;
if (!tempFile)
this._failedToCreateTempFile = true;
if (this._onTempFileReady) {
this._onTempFileReady();
this._onTempFileReady = null;
}
}, _setupWorker: function () {
function setProfileWait(event) {
this.updateStatus(null, event.data);
}
console.log("_setupWorker\n\n\n");
console.assert(!this._workerProxy, "HeapSnapshotWorkerProxy already exists");
this._workerProxy = new WebInspector.HeapSnapshotWorkerProxy(this._handleWorkerEvent.bind(this));
this._workerProxy.addEventListener("wait", setProfileWait, this);
this._receiver = this._workerProxy.createLoader(this.uid, this._snapshotReceived.bind(this));
}, _handleWorkerEvent: function (eventName, data) {
if (WebInspector.HeapSnapshotProgressEvent.Update !== eventName)
return;
var subtitle = (data);
this.updateStatus(subtitle);
}, dispose: function () {
if (this._workerProxy)
this._workerProxy.dispose();
this.removeTempFile();
this._wasDisposed = true;
}, _didCompleteSnapshotTransfer: function () {
if (!this._snapshotProxy)
return;
this.updateStatus(Number.bytesToString(this._snapshotProxy.totalSize), false);
}, transferChunk: function (chunk) {
console.log("transferChunk\n\n\n\n\n\n\n");
if (!this._bufferedWriter)
this._bufferedWriter = new WebInspector.BufferedTempFileWriter("heap-profiler", this.uid);
this._bufferedWriter.write(chunk);
++this._totalNumberOfChunks;
this._receiver.write(chunk, function () {
});
}, _snapshotReceived: function (snapshotProxy) {
console.log("SNAPSHOT RECEIVED\n\n\n\n\n\n\n");
if (this._wasDisposed)
return;
this._receiver = null;
this._snapshotProxy = snapshotProxy;
this.maxJSObjectId = snapshotProxy.maxJSObjectId();
this._didCompleteSnapshotTransfer();
this._workerProxy.startCheckingForLongRunningCalls();
this.notifySnapshotReceived();
}, notifySnapshotReceived: function () {
for (var i = 0; i < this._loadCallbacks.length; i++)
this._loadCallbacks[i](this._snapshotProxy);
this._loadCallbacks = null;
this._profileType._snapshotReceived(this);
if (this.canSaveToFile())
this.dispatchEventToListeners(WebInspector.ProfileHeader.Events.ProfileReceived);
}, _wasShown: function () {
}, canSaveToFile: function () {
return !this.fromFile() && this._snapshotProxy;
}, saveToFile: function () {
var fileOutputStream = new WebInspector.FileOutputStream();
function onOpen(accepted) {
if (!accepted)
return;
if (this._failedToCreateTempFile) {
WebInspector.console.error("Failed to open temp file with heap snapshot");
fileOutputStream.close();
} else if (this._tempFile) {
var delegate = new WebInspector.SaveSnapshotOutputStreamDelegate(this);
this._tempFile.writeToOutputSteam(fileOutputStream, delegate);
} else {
this._onTempFileReady = onOpen.bind(this, accepted);
this._updateSaveProgress(0, 1);
}
}
this._fileName = this._fileName || "Heap-" + new Date().toISO8601Compact() + this._profileType.fileExtension();
fileOutputStream.open(this._fileName, onOpen.bind(this));
}, _updateSaveProgress: function (value, total) {
var percentValue = ((total ? (value / total) : 0) * 100).toFixed(0);
this.updateStatus(WebInspector.UIString("Saving\u2026 %d\%", percentValue));
}, loadFromFile: function (file) {
this.updateStatus(WebInspector.UIString("Loading\u2026"), true);
this._setupWorker();
var delegate = new WebInspector.HeapSnapshotLoadFromFileDelegate(this);
var fileReader = this._createFileReader(file, delegate);
fileReader.start(this._receiver);
}, _createFileReader: function (file, delegate) {
return new WebInspector.ChunkedFileReader(file, 10000000, delegate);
}, __proto__: WebInspector.ProfileHeader.prototype
}
WebInspector.HeapSnapshotLoadFromFileDelegate = function (snapshotHeader) {
this._snapshotHeader = snapshotHeader;
}
WebInspector.HeapSnapshotLoadFromFileDelegate.prototype = {
onTransferStarted: function () {
}, onChunkTransferred: function (reader) {
}, onTransferFinished: function () {
}, onError: function (reader, e) {
var subtitle;
switch (e.target.error.code) {
case e.target.error.NOT_FOUND_ERR:
subtitle = WebInspector.UIString("'%s' not found.", reader.fileName());
break;
case e.target.error.NOT_READABLE_ERR:
subtitle = WebInspector.UIString("'%s' is not readable", reader.fileName());
break;
case e.target.error.ABORT_ERR:
return;
default:
subtitle = WebInspector.UIString("'%s' error %d", reader.fileName(), e.target.error.code);
}
this._snapshotHeader.updateStatus(subtitle);
}
}
WebInspector.SaveSnapshotOutputStreamDelegate = function (profileHeader) {
this._profileHeader = profileHeader;
}
WebInspector.SaveSnapshotOutputStreamDelegate.prototype = {
onTransferStarted: function () {
this._profileHeader._updateSaveProgress(0, 1);
}, onTransferFinished: function () {
this._profileHeader._didCompleteSnapshotTransfer();
}, onChunkTransferred: function (reader) {
this._profileHeader._updateSaveProgress(reader.loadedSize(), reader.fileSize());
}, onError: function (reader, event) {
WebInspector.console.error("Failed to read heap snapshot from temp file: " + (event).message);
this.onTransferFinished();
}
}
WebInspector.HeapTrackingOverviewGrid = function (heapProfileHeader) {
WebInspector.VBox.call(this);
this.registerRequiredCSS("flameChart.css");
this.element.id = "heap-recording-view";
this.element.classList.add("heap-tracking-overview");
this._overviewContainer = this.element.createChild("div", "overview-container");
this._overviewGrid = new WebInspector.OverviewGrid("heap-recording");
this._overviewGrid.element.classList.add("fill");
this._overviewCanvas = this._overviewContainer.createChild("canvas", "heap-recording-overview-canvas");
this._overviewContainer.appendChild(this._overviewGrid.element);
this._overviewCalculator = new WebInspector.HeapTrackingOverviewGrid.OverviewCalculator();
this._overviewGrid.addEventListener(WebInspector.OverviewGrid.Events.WindowChanged, this._onWindowChanged, this);
this._profileSamples = heapProfileHeader._profileSamples;
if (heapProfileHeader.profileType().profileBeingRecorded() === heapProfileHeader) {
this._profileType = heapProfileHeader.profileType();
this._profileType.addEventListener(WebInspector.TrackingHeapSnapshotProfileType.HeapStatsUpdate, this._onHeapStatsUpdate, this);
this._profileType.addEventListener(WebInspector.TrackingHeapSnapshotProfileType.TrackingStopped, this._onStopTracking, this);
}
var timestamps = this._profileSamples.timestamps;
var totalTime = this._profileSamples.totalTime;
this._windowLeft = 0.0;
this._windowRight = totalTime && timestamps.length ? (timestamps[timestamps.length - 1] - timestamps[0]) / totalTime : 1.0;
this._overviewGrid.setWindow(this._windowLeft, this._windowRight);
this._yScale = new WebInspector.HeapTrackingOverviewGrid.SmoothScale();
this._xScale = new WebInspector.HeapTrackingOverviewGrid.SmoothScale();
}
WebInspector.HeapTrackingOverviewGrid.IdsRangeChanged = "IdsRangeChanged";
WebInspector.HeapTrackingOverviewGrid.prototype = {
_onStopTracking: function (event) {
this._profileType.removeEventListener(WebInspector.TrackingHeapSnapshotProfileType.HeapStatsUpdate, this._onHeapStatsUpdate, this);
this._profileType.removeEventListener(WebInspector.TrackingHeapSnapshotProfileType.TrackingStopped, this._onStopTracking, this);
}, _onHeapStatsUpdate: function (event) {
this._profileSamples = event.data;
this._scheduleUpdate();
}, _drawOverviewCanvas: function (width, height) {
if (!this._profileSamples)
return;
var profileSamples = this._profileSamples;
var sizes = profileSamples.sizes;
var topSizes = profileSamples.max;
var timestamps = profileSamples.timestamps;
var startTime = timestamps[0];
var endTime = timestamps[timestamps.length - 1];
var scaleFactor = this._xScale.nextScale(width / profileSamples.totalTime);
var maxSize = 0;
function aggregateAndCall(sizes, callback) {
var size = 0;
var currentX = 0;
for (var i = 1; i < timestamps.length; ++i) {
var x = Math.floor((timestamps[i] - startTime) * scaleFactor);
if (x !== currentX) {
if (size)
callback(currentX, size);
size = 0;
currentX = x;
}
size += sizes[i];
}
callback(currentX, size);
}
function maxSizeCallback(x, size) {
maxSize = Math.max(maxSize, size);
}
aggregateAndCall(sizes, maxSizeCallback);
var yScaleFactor = this._yScale.nextScale(maxSize ? height / (maxSize * 1.1) : 0.0);
this._overviewCanvas.width = width * window.devicePixelRatio;
this._overviewCanvas.height = height * window.devicePixelRatio;
this._overviewCanvas.style.width = width + "px";
this._overviewCanvas.style.height = height + "px";
var context = this._overviewCanvas.getContext("2d");
context.scale(window.devicePixelRatio, window.devicePixelRatio);
context.beginPath();
context.lineWidth = 2;
context.strokeStyle = "rgba(192, 192, 192, 0.6)";
var currentX = (endTime - startTime) * scaleFactor;
context.moveTo(currentX, height - 1);
context.lineTo(currentX, 0);
context.stroke();
context.closePath();
var gridY;
var gridValue;
var gridLabelHeight = 14;
if (yScaleFactor) {
const maxGridValue = (height - gridLabelHeight) / yScaleFactor;
gridValue = Math.pow(1024, Math.floor(Math.log(maxGridValue) / Math.log(1024)));
gridValue *= Math.pow(10, Math.floor(Math.log(maxGridValue / gridValue) / Math.LN10));
if (gridValue * 5 <= maxGridValue)
gridValue *= 5;
gridY = Math.round(height - gridValue * yScaleFactor - 0.5) + 0.5;
context.beginPath();
context.lineWidth = 1;
context.strokeStyle = "rgba(0, 0, 0, 0.2)";
context.moveTo(0, gridY);
context.lineTo(width, gridY);
context.stroke();
context.closePath();
}
function drawBarCallback(x, size) {
context.moveTo(x, height - 1);
context.lineTo(x, Math.round(height - size * yScaleFactor - 1));
}
context.beginPath();
context.lineWidth = 2;
context.strokeStyle = "rgba(192, 192, 192, 0.6)";
aggregateAndCall(topSizes, drawBarCallback);
context.stroke();
context.closePath();
context.beginPath();
context.lineWidth = 2;
context.strokeStyle = "rgba(0, 0, 192, 0.8)";
aggregateAndCall(sizes, drawBarCallback);
context.stroke();
context.closePath();
if (gridValue) {
var label = Number.bytesToString(gridValue);
var labelPadding = 4;
var labelX = 0;
var labelY = gridY - 0.5;
var labelWidth = 2 * labelPadding + context.measureText(label).width;
context.beginPath();
context.textBaseline = "bottom";
context.font = "10px " + window.getComputedStyle(this.element, null).getPropertyValue("font-family");
context.fillStyle = "rgba(255, 255, 255, 0.75)";
context.fillRect(labelX, labelY - gridLabelHeight, labelWidth, gridLabelHeight);
context.fillStyle = "rgb(64, 64, 64)";
context.fillText(label, labelX + labelPadding, labelY);
context.fill();
context.closePath();
}
}, onResize: function () {
this._updateOverviewCanvas = true;
this._scheduleUpdate();
}, _onWindowChanged: function () {
if (!this._updateGridTimerId)
this._updateGridTimerId = setTimeout(this._updateGrid.bind(this), 10);
}, _scheduleUpdate: function () {
if (this._updateTimerId)
return;
this._updateTimerId = setTimeout(this.update.bind(this), 10);
}, _updateBoundaries: function () {
this._windowLeft = this._overviewGrid.windowLeft();
this._windowRight = this._overviewGrid.windowRight();
this._windowWidth = this._windowRight - this._windowLeft;
}, update: function () {
this._updateTimerId = null;
if (!this.isShowing())
return;
this._updateBoundaries();
this._overviewCalculator._updateBoundaries(this);
this._overviewGrid.updateDividers(this._overviewCalculator);
this._drawOverviewCanvas(this._overviewContainer.clientWidth, this._overviewContainer.clientHeight - 20);
}, _updateGrid: function () {
this._updateGridTimerId = 0;
this._updateBoundaries();
var ids = this._profileSamples.ids;
var timestamps = this._profileSamples.timestamps;
var sizes = this._profileSamples.sizes;
var startTime = timestamps[0];
var totalTime = this._profileSamples.totalTime;
var timeLeft = startTime + totalTime * this._windowLeft;
var timeRight = startTime + totalTime * this._windowRight;
var minId = 0;
var maxId = ids[ids.length - 1] + 1;
var size = 0;
for (var i = 0; i < timestamps.length; ++i) {
if (!timestamps[i])
continue;
if (timestamps[i] > timeRight)
break;
maxId = ids[i];
if (timestamps[i] < timeLeft) {
minId = ids[i];
continue;
}
size += sizes[i];
}
this.dispatchEventToListeners(WebInspector.HeapTrackingOverviewGrid.IdsRangeChanged, {minId: minId, maxId: maxId, size: size});
}, __proto__: WebInspector.VBox.prototype
}
WebInspector.HeapTrackingOverviewGrid.SmoothScale = function () {
this._lastUpdate = 0;
this._currentScale = 0.0;
}
WebInspector.HeapTrackingOverviewGrid.SmoothScale.prototype = {
nextScale: function (target) {
target = target || this._currentScale;
if (this._currentScale) {
var now = Date.now();
var timeDeltaMs = now - this._lastUpdate;
this._lastUpdate = now;
var maxChangePerSec = 20;
var maxChangePerDelta = Math.pow(maxChangePerSec, timeDeltaMs / 1000);
var scaleChange = target / this._currentScale;
this._currentScale *= Number.constrain(scaleChange, 1 / maxChangePerDelta, maxChangePerDelta);
} else
this._currentScale = target;
return this._currentScale;
}
}
WebInspector.HeapTrackingOverviewGrid.OverviewCalculator = function () {
}
WebInspector.HeapTrackingOverviewGrid.OverviewCalculator.prototype = {
paddingLeft: function () {
return 0;
}, _updateBoundaries: function (chart) {
this._minimumBoundaries = 0;
this._maximumBoundaries = chart._profileSamples.totalTime;
this._xScaleFactor = chart._overviewContainer.clientWidth / this._maximumBoundaries;
}, computePosition: function (time) {
return (time - this._minimumBoundaries) * this._xScaleFactor;
}, formatTime: function (value, precision) {
return Number.secondsToString(value / 1000, !!precision);
}, maximumBoundary: function () {
return this._maximumBoundaries;
}, minimumBoundary: function () {
return this._minimumBoundaries;
}, zeroTime: function () {
return this._minimumBoundaries;
}, boundarySpan: function () {
return this._maximumBoundaries - this._minimumBoundaries;
}
}
WebInspector.HeapSnapshotStatisticsView = function () {
WebInspector.VBox.call(this);
this.setMinimumSize(50, 25);
this._pieChart = new WebInspector.PieChart(150);
this.element.appendChild(this._pieChart.element);
this._labels = this.element.createChild("div", "heap-snapshot-stats-legend");
}
WebInspector.HeapSnapshotStatisticsView.prototype = {
setTotal: function (value) {
this._pieChart.setTotal(value);
}, addRecord: function (value, name, color) {
if (color)
this._pieChart.addSlice(value, color);
var node = this._labels.createChild("div");
var swatchDiv = node.createChild("div", "heap-snapshot-stats-swatch");
var nameDiv = node.createChild("div", "heap-snapshot-stats-name");
var sizeDiv = node.createChild("div", "heap-snapshot-stats-size");
if (color)
swatchDiv.style.backgroundColor = color; else
swatchDiv.classList.add("heap-snapshot-stats-empty-swatch");
nameDiv.textContent = name;
sizeDiv.textContent = WebInspector.UIString("%s KB", Number.withThousandsSeparator(Math.round(value / 1024)));
}, __proto__: WebInspector.VBox.prototype
}
WebInspector.HeapAllocationStackView = function (weakTarget) {
WebInspector.View.call(this);
this._weakTarget = weakTarget;
;
this._linkifier = new WebInspector.Linkifier();
}
WebInspector.HeapAllocationStackView.prototype = {
setAllocatedObject: function (snapshot, snapshotNodeIndex) {
this.clear();
snapshot.allocationStack(snapshotNodeIndex, this._didReceiveAllocationStack.bind(this));
}, clear: function () {
this.element.removeChildren();
this._linkifier.reset();
}, _didReceiveAllocationStack: function (frames) {
if (!frames) {
var stackDiv = this.element.createChild("div", "no-heap-allocation-stack");
stackDiv.createTextChild(WebInspector.UIString("Stack was not recorded for this object because it had been allocated before this profile recording started."));
return;
}
var stackDiv = this.element.createChild("div", "heap-allocation-stack");
for (var i = 0; i < frames.length; i++) {
var frame = frames[i];
var frameDiv = stackDiv.createChild("div", "stack-frame");
var name = frameDiv.createChild("div");
name.textContent = frame.functionName;
if (frame.scriptId) {
var urlElement = this._linkifier.linkifyScriptLocation(this._weakTarget.get(), String(frame.scriptId), frame.scriptName, frame.line - 1, frame.column - 1);
frameDiv.appendChild(urlElement);
}
}
}, __proto__: WebInspector.View.prototype
};
WebInspector.ProfileLauncherView = function (profilesPanel) {
WebInspector.VBox.call(this);
this._panel = profilesPanel;
this.element.classList.add("profile-launcher-view");
this.element.classList.add("panel-enabler-view");
this._contentElement = this.element.createChild("div", "profile-launcher-view-content");
this._innerContentElement = this._contentElement.createChild("div");
var targetSpan = this._contentElement.createChild("span");
var selectTargetText = targetSpan.createChild("span");
selectTargetText.textContent = WebInspector.UIString("Target:");
var targetsSelect = targetSpan.createChild("select", "chrome-select");
new WebInspector.TargetsComboBoxController(targetsSelect, targetSpan);
this._controlButton = this._contentElement.createChild("button", "text-button control-profiling");
this._controlButton.addEventListener("click", this._controlButtonClicked.bind(this), false);
this._recordButtonEnabled = true;
this._loadButton = this._contentElement.createChild("button", "text-button load-profile");
this._loadButton.textContent = WebInspector.UIString("Load");
this._loadButton.addEventListener("click", this._loadButtonClicked.bind(this), false);
WebInspector.targetManager.observeTargets(this);
}
WebInspector.ProfileLauncherView.prototype = {
targetAdded: function (target) {
this._updateLoadButtonLayout();
}, targetRemoved: function (target) {
this._updateLoadButtonLayout();
}, _updateLoadButtonLayout: function () {
this._loadButton.classList.toggle("multi-target", WebInspector.targetManager.targets().length > 1);
}, addProfileType: function (profileType) {
var descriptionElement = this._innerContentElement.createChild("h1");
descriptionElement.textContent = profileType.description;
var decorationElement = profileType.decorationElement();
if (decorationElement)
this._innerContentElement.appendChild(decorationElement);
this._isInstantProfile = profileType.isInstantProfile();
this._isEnabled = profileType.isEnabled();
this._profileTypeId = profileType.id;
}, _controlButtonClicked: function () {
this._panel.toggleRecordButton();
}, _loadButtonClicked: function () {
this._panel.showLoadFromFileDialog();
}, _updateControls: function () {
if (this._isEnabled && this._recordButtonEnabled)
this._controlButton.removeAttribute("disabled"); else
this._controlButton.setAttribute("disabled", "");
this._controlButton.title = this._recordButtonEnabled ? "" : WebInspector.anotherProfilerActiveLabel();
if (this._isInstantProfile) {
this._controlButton.classList.remove("running");
this._controlButton.textContent = WebInspector.UIString("Take Snapshot");
} else if (this._isProfiling) {
this._controlButton.classList.add("running");
this._controlButton.textContent = WebInspector.UIString("Stop");
} else {
this._controlButton.classList.remove("running");
this._controlButton.textContent = WebInspector.UIString("Start");
}
}, profileStarted: function () {
this._isProfiling = true;
this._updateControls();
}, profileFinished: function () {
this._isProfiling = false;
this._updateControls();
}, updateProfileType: function (profileType, recordButtonEnabled) {
this._isInstantProfile = profileType.isInstantProfile();
this._recordButtonEnabled = recordButtonEnabled;
this._isEnabled = profileType.isEnabled();
this._profileTypeId = profileType.id;
this._updateControls();
}, __proto__: WebInspector.VBox.prototype
}
WebInspector.MultiProfileLauncherView = function (profilesPanel) {
WebInspector.ProfileLauncherView.call(this, profilesPanel);
WebInspector.settings.selectedProfileType = WebInspector.settings.createSetting("selectedProfileType", "CPU");
var header = this._innerContentElement.createChild("h1");
header.textContent = WebInspector.UIString("Select profiling type");
this._profileTypeSelectorForm = this._innerContentElement.createChild("form");
this._innerContentElement.createChild("div", "flexible-space");
this._typeIdToOptionElement = {};
}
WebInspector.MultiProfileLauncherView.EventTypes = {ProfileTypeSelected: "profile-type-selected"}
WebInspector.MultiProfileLauncherView.prototype = {
addProfileType: function (profileType) {
var labelElement = this._profileTypeSelectorForm.createChild("label");
labelElement.textContent = profileType.name;
var optionElement = document.createElement("input");
labelElement.insertBefore(optionElement, labelElement.firstChild);
this._typeIdToOptionElement[profileType.id] = optionElement;
optionElement._profileType = profileType;
optionElement.type = "radio";
optionElement.name = "profile-type";
optionElement.style.hidden = true;
optionElement.addEventListener("change", this._profileTypeChanged.bind(this, profileType), false);
var descriptionElement = labelElement.createChild("p");
descriptionElement.textContent = profileType.description;
var decorationElement = profileType.decorationElement();
if (decorationElement)
labelElement.appendChild(decorationElement);
}, restoreSelectedProfileType: function () {
var typeId = WebInspector.settings.selectedProfileType.get();
if (!(typeId in this._typeIdToOptionElement))
typeId = Object.keys(this._typeIdToOptionElement)[0];
this._typeIdToOptionElement[typeId].checked = true;
var type = this._typeIdToOptionElement[typeId]._profileType;
this.dispatchEventToListeners(WebInspector.MultiProfileLauncherView.EventTypes.ProfileTypeSelected, type);
}, _controlButtonClicked: function () {
this._panel.toggleRecordButton();
}, _updateControls: function () {
WebInspector.ProfileLauncherView.prototype._updateControls.call(this);
var items = this._profileTypeSelectorForm.elements;
for (var i = 0; i < items.length; ++i) {
if (items[i].type === "radio")
items[i].disabled = this._isProfiling;
}
}, _profileTypeChanged: function (profileType) {
this.dispatchEventToListeners(WebInspector.MultiProfileLauncherView.EventTypes.ProfileTypeSelected, profileType);
this._isInstantProfile = profileType.isInstantProfile();
this._isEnabled = profileType.isEnabled();
this._profileTypeId = profileType.id;
this._updateControls();
WebInspector.settings.selectedProfileType.set(profileType.id);
}, profileStarted: function () {
this._isProfiling = true;
this._updateControls();
}, profileFinished: function () {
this._isProfiling = false;
this._updateControls();
}, __proto__: WebInspector.ProfileLauncherView.prototype
};
WebInspector.CanvasProfileView = function (profile) {
WebInspector.VBox.call(this);
this.registerRequiredCSS("canvasProfiler.css");
this.element.classList.add("canvas-profile-view");
this._profile = profile;
this._traceLogId = profile.traceLogId();
this._traceLogPlayer = (profile.traceLogPlayer());
this._linkifier = new WebInspector.Linkifier();
this._replayInfoSplitView = new WebInspector.SplitView(true, true, "canvasProfileViewReplaySplitViewState", 0.34);
this._replayInfoSplitView.show(this.element);
this._imageSplitView = new WebInspector.SplitView(false, true, "canvasProfileViewSplitViewState", 300);
this._imageSplitView.show(this._replayInfoSplitView.mainElement());
var replayImageContainerView = new WebInspector.VBoxWithResizeCallback(this._onReplayImageResize.bind(this));
replayImageContainerView.setMinimumSize(50, 28);
replayImageContainerView.show(this._imageSplitView.mainElement());
var replayImageContainer = replayImageContainerView.element;
replayImageContainer.id = "canvas-replay-image-container";
var replayImageParent = replayImageContainer.createChild("div", "canvas-replay-image-parent");
replayImageParent.createChild("span");
this._replayImageElement = replayImageParent.createChild("img");
this._debugInfoElement = replayImageContainer.createChild("div", "canvas-debug-info hidden");
this._spinnerIcon = replayImageContainer.createChild("div", "spinner-icon small hidden");
var replayLogContainerView = new WebInspector.VBox();
replayLogContainerView.setMinimumSize(22, 22);
replayLogContainerView.show(this._imageSplitView.sidebarElement());
var replayLogContainer = replayLogContainerView.element;
var controlsContainer = replayLogContainer.createChild("div", "status-bar");
var logGridContainer = replayLogContainer.createChild("div", "canvas-replay-log");
this._createControlButton(controlsContainer, "canvas-replay-first-step", WebInspector.UIString("First call."), this._onReplayFirstStepClick.bind(this));
this._createControlButton(controlsContainer, "canvas-replay-prev-step", WebInspector.UIString("Previous call."), this._onReplayStepClick.bind(this, false));
this._createControlButton(controlsContainer, "canvas-replay-next-step", WebInspector.UIString("Next call."), this._onReplayStepClick.bind(this, true));
this._createControlButton(controlsContainer, "canvas-replay-prev-draw", WebInspector.UIString("Previous drawing call."), this._onReplayDrawingCallClick.bind(this, false));
this._createControlButton(controlsContainer, "canvas-replay-next-draw", WebInspector.UIString("Next drawing call."), this._onReplayDrawingCallClick.bind(this, true));
this._createControlButton(controlsContainer, "canvas-replay-last-step", WebInspector.UIString("Last call."), this._onReplayLastStepClick.bind(this));
this._replayContextSelector = new WebInspector.StatusBarComboBox(this._onReplayContextChanged.bind(this));
this._replayContextSelector.createOption(WebInspector.UIString("<screenshot auto>"), WebInspector.UIString("Show screenshot of the last replayed resource."), "");
controlsContainer.appendChild(this._replayContextSelector.element);
this._installReplayInfoSidebarWidgets(controlsContainer);
this._replayStateView = new WebInspector.CanvasReplayStateView(this._traceLogPlayer);
this._replayStateView.show(this._replayInfoSplitView.sidebarElement());
this._replayContexts = {};
var columns = [{title: "#", sortable: false, width: "5%"}, {title: WebInspector.UIString("Call"), sortable: false, width: "75%", disclosure: true}, {title: WebInspector.UIString("Location"), sortable: false, width: "20%"}];
this._logGrid = new WebInspector.DataGrid(columns);
this._logGrid.element.classList.add("fill");
this._logGrid.show(logGridContainer);
this._logGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._replayTraceLog, this);
this.element.addEventListener("mousedown", this._onMouseClick.bind(this), true);
this._popoverHelper = new WebInspector.ObjectPopoverHelper(this.element, this._popoverAnchor.bind(this), this._resolveObjectForPopover.bind(this), this._onHidePopover.bind(this), true);
this._popoverHelper.setRemoteObjectFormatter(this._hexNumbersFormatter.bind(this));
this._requestTraceLog(0);
}
WebInspector.CanvasProfileView.TraceLogPollingInterval = 500;
WebInspector.CanvasProfileView.prototype = {
dispose: function () {
this._linkifier.reset();
}, get statusBarItems() {
return [];
}, get profile() {
return this._profile;
}, _onReplayImageResize: function () {
var parent = this._replayImageElement.parentElement;
this._replayImageElement.style.maxWidth = parent.clientWidth + "px";
this._replayImageElement.style.maxHeight = parent.clientHeight + "px";
}, elementsToRestoreScrollPositionsFor: function () {
return [this._logGrid.scrollContainer];
}, _installReplayInfoSidebarWidgets: function (controlsContainer) {
this._replayInfoResizeWidgetElement = controlsContainer.createChild("div", "resizer-widget");
this._replayInfoSplitView.addEventListener(WebInspector.SplitView.Events.ShowModeChanged, this._updateReplayInfoResizeWidget, this);
this._updateReplayInfoResizeWidget();
this._replayInfoSplitView.installResizer(this._replayInfoResizeWidgetElement);
this._toggleReplayStateSidebarButton = this._replayInfoSplitView.createShowHideSidebarButton("sidebar", "canvas-sidebar-show-hide-button");
controlsContainer.appendChild(this._toggleReplayStateSidebarButton.element);
this._replayInfoSplitView.hideSidebar();
}, _updateReplayInfoResizeWidget: function () {
this._replayInfoResizeWidgetElement.classList.toggle("hidden", this._replayInfoSplitView.showMode() !== WebInspector.SplitView.ShowMode.Both);
}, _onMouseClick: function (event) {
var resourceLinkElement = event.target.enclosingNodeOrSelfWithClass("canvas-formatted-resource");
if (resourceLinkElement) {
this._replayInfoSplitView.showBoth();
this._replayStateView.selectResource(resourceLinkElement.__resourceId);
event.consume(true);
return;
}
if (event.target.enclosingNodeOrSelfWithClass("webkit-html-resource-link"))
event.consume(false);
}, _createControlButton: function (parent, className, title, clickCallback) {
var button = new WebInspector.StatusBarButton(title, className + " canvas-replay-button");
parent.appendChild(button.element);
button.makeLongClickEnabled();
button.addEventListener("click", clickCallback, this);
button.addEventListener("longClickDown", clickCallback, this);
button.addEventListener("longClickPress", clickCallback, this);
}, _onReplayContextChanged: function () {
var selectedContextId = this._replayContextSelector.selectedOption().value;
function didReceiveResourceState(resourceState) {
this._enableWaitIcon(false);
if (selectedContextId !== this._replayContextSelector.selectedOption().value)
return;
var imageURL = (resourceState && resourceState.imageURL) || "";
this._replayImageElement.src = imageURL;
this._replayImageElement.style.visibility = imageURL ? "" : "hidden";
}
this._enableWaitIcon(true);
this._traceLogPlayer.getResourceState(selectedContextId, didReceiveResourceState.bind(this));
}, _onReplayStepClick: function (forward) {
var selectedNode = this._logGrid.selectedNode;
if (!selectedNode)
return;
var nextNode = selectedNode;
do {
nextNode = forward ? nextNode.traverseNextNode(false) : nextNode.traversePreviousNode(false);
} while (nextNode && typeof nextNode.index !== "number");
(nextNode || selectedNode).revealAndSelect();
}, _onReplayDrawingCallClick: function (forward) {
var selectedNode = this._logGrid.selectedNode;
if (!selectedNode)
return;
var nextNode = selectedNode;
while (nextNode) {
var sibling = forward ? nextNode.nextSibling : nextNode.previousSibling;
if (sibling) {
nextNode = sibling;
if (nextNode.hasChildren || nextNode.call.isDrawingCall)
break;
} else {
nextNode = nextNode.parent;
if (!forward)
break;
}
}
if (!nextNode && forward)
this._onReplayLastStepClick(); else
(nextNode || selectedNode).revealAndSelect();
}, _onReplayFirstStepClick: function () {
var firstNode = this._logGrid.rootNode().children[0];
if (firstNode)
firstNode.revealAndSelect();
}, _onReplayLastStepClick: function () {
var lastNode = this._logGrid.rootNode().children.peekLast();
if (!lastNode)
return;
while (lastNode.expanded) {
var lastChild = lastNode.children.peekLast();
if (!lastChild)
break;
lastNode = lastChild;
}
lastNode.revealAndSelect();
}, _enableWaitIcon: function (enable) {
this._spinnerIcon.classList.toggle("hidden", !enable);
this._debugInfoElement.classList.toggle("hidden", enable);
}, _replayTraceLog: function () {
if (this._pendingReplayTraceLogEvent)
return;
var index = this._selectedCallIndex();
if (index === -1 || index === this._lastReplayCallIndex)
return;
this._lastReplayCallIndex = index;
this._pendingReplayTraceLogEvent = true;
function didReplayTraceLog(resourceState, replayTime) {
delete this._pendingReplayTraceLogEvent;
this._enableWaitIcon(false);
this._debugInfoElement.textContent = WebInspector.UIString("Replay time: %s", Number.secondsToString(replayTime / 1000, true));
this._onReplayContextChanged();
if (index !== this._selectedCallIndex())
this._replayTraceLog();
}
this._enableWaitIcon(true);
this._traceLogPlayer.replayTraceLog(index, didReplayTraceLog.bind(this));
}, _requestTraceLog: function (offset) {
function didReceiveTraceLog(traceLog) {
this._enableWaitIcon(false);
if (!traceLog)
return;
var callNodes = [];
var calls = traceLog.calls;
var index = traceLog.startOffset;
for (var i = 0, n = calls.length; i < n; ++i)
callNodes.push(this._createCallNode(index++, calls[i]));
var contexts = traceLog.contexts;
for (var i = 0, n = contexts.length; i < n; ++i) {
var contextId = contexts[i].resourceId || "";
var description = contexts[i].description || "";
if (this._replayContexts[contextId])
continue;
this._replayContexts[contextId] = true;
this._replayContextSelector.createOption(description, WebInspector.UIString("Show screenshot of this context's canvas."), contextId);
}
this._appendCallNodes(callNodes);
if (traceLog.alive)
setTimeout(this._requestTraceLog.bind(this, index), WebInspector.CanvasProfileView.TraceLogPollingInterval); else
this._flattenSingleFrameNode();
this._profile._updateCapturingStatus(traceLog);
this._onReplayLastStepClick();
}
this._enableWaitIcon(true);
this._traceLogPlayer.getTraceLog(offset, undefined, didReceiveTraceLog.bind(this));
}, _selectedCallIndex: function () {
var node = this._logGrid.selectedNode;
return node ? this._peekLastRecursively(node).index : -1;
}, _peekLastRecursively: function (node) {
var lastChild;
while ((lastChild = node.children.peekLast()))
node = lastChild;
return node;
}, _appendCallNodes: function (callNodes) {
var rootNode = this._logGrid.rootNode();
var frameNode = rootNode.children.peekLast();
if (frameNode && this._peekLastRecursively(frameNode).call.isFrameEndCall)
frameNode = null;
for (var i = 0, n = callNodes.length; i < n; ++i) {
if (!frameNode) {
var index = rootNode.children.length;
var data = {};
data[0] = "";
data[1] = WebInspector.UIString("Frame #%d", index + 1);
data[2] = "";
frameNode = new WebInspector.DataGridNode(data);
frameNode.selectable = true;
rootNode.appendChild(frameNode);
}
var nextFrameCallIndex = i + 1;
while (nextFrameCallIndex < n && !callNodes[nextFrameCallIndex - 1].call.isFrameEndCall)
++nextFrameCallIndex;
this._appendCallNodesToFrameNode(frameNode, callNodes, i, nextFrameCallIndex);
i = nextFrameCallIndex - 1;
frameNode = null;
}
}, _appendCallNodesToFrameNode: function (frameNode, callNodes, fromIndex, toIndex) {
var self = this;
function appendDrawCallGroup() {
var index = self._drawCallGroupsCount || 0;
var data = {};
data[0] = "";
data[1] = WebInspector.UIString("Draw call group #%d", index + 1);
data[2] = "";
var node = new WebInspector.DataGridNode(data);
node.selectable = true;
self._drawCallGroupsCount = index + 1;
frameNode.appendChild(node);
return node;
}
function splitDrawCallGroup(drawCallGroup) {
var splitIndex = 0;
var splitNode;
while ((splitNode = drawCallGroup.children[splitIndex])) {
if (splitNode.call.isDrawingCall)
break;
++splitIndex;
}
var newDrawCallGroup = appendDrawCallGroup();
var lastNode;
while ((lastNode = drawCallGroup.children[splitIndex + 1]))
newDrawCallGroup.appendChild(lastNode);
return newDrawCallGroup;
}
var drawCallGroup = frameNode.children.peekLast();
var groupHasDrawCall = false;
if (drawCallGroup) {
for (var i = 0, n = drawCallGroup.children.length; i < n; ++i) {
if (drawCallGroup.children[i].call.isDrawingCall) {
groupHasDrawCall = true;
break;
}
}
} else
drawCallGroup = appendDrawCallGroup();
for (var i = fromIndex; i < toIndex; ++i) {
var node = callNodes[i];
drawCallGroup.appendChild(node);
if (node.call.isDrawingCall) {
if (groupHasDrawCall)
drawCallGroup = splitDrawCallGroup(drawCallGroup); else
groupHasDrawCall = true;
}
}
}, _createCallNode: function (index, call) {
var callViewElement = document.createElement("div");
var data = {};
data[0] = index + 1;
data[1] = callViewElement;
data[2] = "";
if (call.sourceURL) {
var lineNumber = Math.max(0, call.lineNumber - 1) || 0;
var columnNumber = Math.max(0, call.columnNumber - 1) || 0;
data[2] = this._linkifier.linkifyScriptLocation(this.profile.target(), null, call.sourceURL, lineNumber, columnNumber);
}
callViewElement.createChild("span", "canvas-function-name").textContent = call.functionName || "context." + call.property;
if (call.arguments) {
callViewElement.createTextChild("(");
for (var i = 0, n = call.arguments.length; i < n; ++i) {
var argument = (call.arguments[i]);
if (i)
callViewElement.createTextChild(", ");
var element = WebInspector.CanvasProfileDataGridHelper.createCallArgumentElement(argument);
element.__argumentIndex = i;
callViewElement.appendChild(element);
}
callViewElement.createTextChild(")");
} else if (call.value) {
callViewElement.createTextChild(" = ");
callViewElement.appendChild(WebInspector.CanvasProfileDataGridHelper.createCallArgumentElement(call.value));
}
if (call.result) {
callViewElement.createTextChild(" => ");
callViewElement.appendChild(WebInspector.CanvasProfileDataGridHelper.createCallArgumentElement(call.result));
}
var node = new WebInspector.DataGridNode(data);
node.index = index;
node.selectable = true;
node.call = call;
return node;
}, _popoverAnchor: function (element, event) {
var argumentElement = element.enclosingNodeOrSelfWithClass("canvas-call-argument");
if (!argumentElement || argumentElement.__suppressPopover)
return;
return argumentElement;
}, _resolveObjectForPopover: function (argumentElement, showCallback, objectGroupName) {
function showObjectPopover(error, result, resourceState) {
if (error)
return;
if (!result)
return;
this._popoverAnchorElement = argumentElement.cloneNode(true);
this._popoverAnchorElement.classList.add("canvas-popover-anchor");
this._popoverAnchorElement.classList.add("source-frame-eval-expression");
argumentElement.parentElement.appendChild(this._popoverAnchorElement);
var diffLeft = this._popoverAnchorElement.boxInWindow().x - argumentElement.boxInWindow().x;
this._popoverAnchorElement.style.left = this._popoverAnchorElement.offsetLeft - diffLeft + "px";
showCallback(WebInspector.runtimeModel.createRemoteObject(result), false, this._popoverAnchorElement);
}
var evalResult = argumentElement.__evalResult;
if (evalResult)
showObjectPopover.call(this, null, evalResult); else {
var dataGridNode = this._logGrid.dataGridNodeFromNode(argumentElement);
if (!dataGridNode || typeof dataGridNode.index !== "number") {
this._popoverHelper.hidePopover();
return;
}
var callIndex = dataGridNode.index;
var argumentIndex = argumentElement.__argumentIndex;
if (typeof argumentIndex !== "number")
argumentIndex = -1;
CanvasAgent.evaluateTraceLogCallArgument(this._traceLogId, callIndex, argumentIndex, objectGroupName, showObjectPopover.bind(this));
}
}, _hexNumbersFormatter: function (object) {
if (object.type === "number") {
var str = "0000" + Number(object.description).toString(16).toUpperCase();
str = str.replace(/^0+(.{4,})$/, "$1");
return "0x" + str;
}
return object.description || "";
}, _onHidePopover: function () {
if (this._popoverAnchorElement) {
this._popoverAnchorElement.remove()
delete this._popoverAnchorElement;
}
}, _flattenSingleFrameNode: function () {
var rootNode = this._logGrid.rootNode();
if (rootNode.children.length !== 1)
return;
var frameNode = rootNode.children[0];
while (frameNode.children[0])
rootNode.appendChild(frameNode.children[0]);
rootNode.removeChild(frameNode);
}, __proto__: WebInspector.VBox.prototype
}
WebInspector.CanvasProfileType = function () {
WebInspector.ProfileType.call(this, WebInspector.CanvasProfileType.TypeId, WebInspector.UIString("Capture Canvas Frame"));
this._recording = false;
this._lastProfileHeader = null;
this._capturingModeSelector = new WebInspector.StatusBarComboBox(this._dispatchViewUpdatedEvent.bind(this));
this._capturingModeSelector.element.title = WebInspector.UIString("Canvas capture mode.");
this._capturingModeSelector.createOption(WebInspector.UIString("Single Frame"), WebInspector.UIString("Capture a single canvas frame."), "");
this._capturingModeSelector.createOption(WebInspector.UIString("Consecutive Frames"), WebInspector.UIString("Capture consecutive canvas frames."), "1");
this._frameOptions = {};
this._framesWithCanvases = {};
this._frameSelector = new WebInspector.StatusBarComboBox(this._dispatchViewUpdatedEvent.bind(this));
this._frameSelector.element.title = WebInspector.UIString("Frame containing the canvases to capture.");
this._frameSelector.element.classList.add("hidden");
this._target = (WebInspector.targetManager.mainTarget());
this._target.resourceTreeModel.frames().forEach(this._addFrame, this);
this._target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameAdded, this._frameAdded, this);
this._target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, this._frameRemoved, this);
this._dispatcher = new WebInspector.CanvasDispatcher(this);
this._canvasAgentEnabled = false;
this._decorationElement = document.createElement("div");
this._decorationElement.className = "profile-canvas-decoration";
this._updateDecorationElement();
}
WebInspector.CanvasProfileType.TypeId = "CANVAS_PROFILE";
WebInspector.CanvasProfileType.prototype = {
get statusBarItems() {
return [this._capturingModeSelector.element, this._frameSelector.element];
}, get buttonTooltip() {
if (this._isSingleFrameMode())
return WebInspector.UIString("Capture next canvas frame."); else
return this._recording ? WebInspector.UIString("Stop capturing canvas frames.") : WebInspector.UIString("Start capturing canvas frames.");
}, buttonClicked: function () {
if (!this._canvasAgentEnabled)
return false;
if (this._recording) {
this._recording = false;
this._stopFrameCapturing();
} else if (this._isSingleFrameMode()) {
this._recording = false;
this._runSingleFrameCapturing();
} else {
this._recording = true;
this._startFrameCapturing();
}
return this._recording;
}, _runSingleFrameCapturing: function () {
var frameId = this._selectedFrameId();
WebInspector.profilingLock().acquire();
CanvasAgent.captureFrame(frameId, this._didStartCapturingFrame.bind(this, frameId));
WebInspector.profilingLock().release();
}, _startFrameCapturing: function () {
var frameId = this._selectedFrameId();
WebInspector.profilingLock().acquire();
CanvasAgent.startCapturing(frameId, this._didStartCapturingFrame.bind(this, frameId));
}, _stopFrameCapturing: function () {
if (!this._lastProfileHeader) {
WebInspector.profilingLock().release();
return;
}
var profileHeader = this._lastProfileHeader;
var traceLogId = profileHeader.traceLogId();
this._lastProfileHeader = null;
function didStopCapturing() {
profileHeader._updateCapturingStatus();
}
CanvasAgent.stopCapturing(traceLogId, didStopCapturing);
WebInspector.profilingLock().release();
}, _didStartCapturingFrame: function (frameId, error, traceLogId) {
if (error || this._lastProfileHeader && this._lastProfileHeader.traceLogId() === traceLogId)
return;
var profileHeader = new WebInspector.CanvasProfileHeader(this._target, this, traceLogId, frameId);
this._lastProfileHeader = profileHeader;
this.addProfile(profileHeader);
profileHeader._updateCapturingStatus();
}, get treeItemTitle() {
return WebInspector.UIString("CANVAS PROFILE");
}, get description() {
return WebInspector.UIString("Canvas calls instrumentation");
}, decorationElement: function () {
return this._decorationElement;
}, removeProfile: function (profile) {
WebInspector.ProfileType.prototype.removeProfile.call(this, profile);
if (this._recording && profile === this._lastProfileHeader)
this._recording = false;
}, _updateDecorationElement: function (forcePageReload) {
this._decorationElement.removeChildren();
this._decorationElement.createChild("div", "warning-icon-small");
this._decorationElement.appendChild(document.createTextNode(this._canvasAgentEnabled ? WebInspector.UIString("Canvas Profiler is enabled.") : WebInspector.UIString("Canvas Profiler is disabled.")));
var button = this._decorationElement.createChild("button", "text-button");
button.type = "button";
button.textContent = this._canvasAgentEnabled ? WebInspector.UIString("Disable") : WebInspector.UIString("Enable");
button.addEventListener("click", this._onProfilerEnableButtonClick.bind(this, !this._canvasAgentEnabled), false);
var target = this._target;
function hasUninstrumentedCanvasesCallback(error, result) {
if (error || result)
target.resourceTreeModel.reloadPage();
}
if (forcePageReload) {
if (this._canvasAgentEnabled) {
CanvasAgent.hasUninstrumentedCanvases(hasUninstrumentedCanvasesCallback);
} else {
for (var frameId in this._framesWithCanvases) {
if (this._framesWithCanvases.hasOwnProperty(frameId)) {
target.resourceTreeModel.reloadPage();
break;
}
}
}
}
}, _onProfilerEnableButtonClick: function (enable) {
if (this._canvasAgentEnabled === enable)
return;
function callback(error) {
if (error)
return;
this._canvasAgentEnabled = enable;
this._updateDecorationElement(true);
this._dispatchViewUpdatedEvent();
}
if (enable)
CanvasAgent.enable(callback.bind(this)); else
CanvasAgent.disable(callback.bind(this));
}, _isSingleFrameMode: function () {
return !this._capturingModeSelector.selectedOption().value;
}, _frameAdded: function (event) {
var frame = (event.data);
this._addFrame(frame);
}, _addFrame: function (frame) {
var frameId = frame.id;
var option = document.createElement("option");
option.text = frame.displayName();
option.title = frame.url;
option.value = frameId;
this._frameOptions[frameId] = option;
if (this._framesWithCanvases[frameId]) {
this._frameSelector.addOption(option);
this._dispatchViewUpdatedEvent();
}
}, _frameRemoved: function (event) {
var frame = (event.data);
var frameId = frame.id;
var option = this._frameOptions[frameId];
if (option && this._framesWithCanvases[frameId]) {
this._frameSelector.removeOption(option);
this._dispatchViewUpdatedEvent();
}
delete this._frameOptions[frameId];
delete this._framesWithCanvases[frameId];
}, _contextCreated: function (frameId) {
if (this._framesWithCanvases[frameId])
return;
this._framesWithCanvases[frameId] = true;
var option = this._frameOptions[frameId];
if (option) {
this._frameSelector.addOption(option);
this._dispatchViewUpdatedEvent();
}
}, _traceLogsRemoved: function (frameId, traceLogId) {
var sidebarElementsToDelete = [];
var sidebarElements = ((this.treeElement && this.treeElement.children) || []);
for (var i = 0, n = sidebarElements.length; i < n; ++i) {
var header = (sidebarElements[i].profile);
if (!header)
continue;
if (frameId && frameId !== header.frameId())
continue;
if (traceLogId && traceLogId !== header.traceLogId())
continue;
sidebarElementsToDelete.push(sidebarElements[i]);
}
for (var i = 0, n = sidebarElementsToDelete.length; i < n; ++i)
sidebarElementsToDelete[i].ondelete();
}, _selectedFrameId: function () {
var option = this._frameSelector.selectedOption();
return option ? option.value : undefined;
}, _dispatchViewUpdatedEvent: function () {
this._frameSelector.element.classList.toggle("hidden", this._frameSelector.size() <= 1);
this.dispatchEventToListeners(WebInspector.ProfileType.Events.ViewUpdated);
}, isInstantProfile: function () {
return this._isSingleFrameMode();
}, isEnabled: function () {
return this._canvasAgentEnabled;
}, __proto__: WebInspector.ProfileType.prototype
}
WebInspector.CanvasDispatcher = function (profileType) {
this._profileType = profileType;
InspectorBackend.registerCanvasDispatcher(this);
}
WebInspector.CanvasDispatcher.prototype = {
contextCreated: function (frameId) {
this._profileType._contextCreated(frameId);
}, traceLogsRemoved: function (frameId, traceLogId) {
this._profileType._traceLogsRemoved(frameId, traceLogId);
}
}
WebInspector.CanvasProfileHeader = function (target, type, traceLogId, frameId) {
WebInspector.ProfileHeader.call(this, target, type, WebInspector.UIString("Trace Log %d", type.nextProfileUid()));
this._traceLogId = traceLogId || "";
this._frameId = frameId;
this._alive = true;
this._traceLogSize = 0;
this._traceLogPlayer = traceLogId ? new WebInspector.CanvasTraceLogPlayerProxy(traceLogId) : null;
}
WebInspector.CanvasProfileHeader.prototype = {
traceLogId: function () {
return this._traceLogId;
}, traceLogPlayer: function () {
return this._traceLogPlayer;
}, frameId: function () {
return this._frameId;
}, createSidebarTreeElement: function (panel) {
return new WebInspector.ProfileSidebarTreeElement(panel, this, "profile-sidebar-tree-item");
}, createView: function () {
return new WebInspector.CanvasProfileView(this);
}, dispose: function () {
if (this._traceLogPlayer)
this._traceLogPlayer.dispose();
clearTimeout(this._requestStatusTimer);
this._alive = false;
}, _updateCapturingStatus: function (traceLog) {
if (!this._traceLogId)
return;
if (traceLog) {
this._alive = traceLog.alive;
this._traceLogSize = traceLog.totalAvailableCalls;
}
var subtitle = this._alive ? WebInspector.UIString("Capturing\u2026 %d calls", this._traceLogSize) : WebInspector.UIString("Captured %d calls", this._traceLogSize);
this.updateStatus(subtitle, this._alive);
if (this._alive) {
clearTimeout(this._requestStatusTimer);
this._requestStatusTimer = setTimeout(this._requestCapturingStatus.bind(this), WebInspector.CanvasProfileView.TraceLogPollingInterval);
}
}, _requestCapturingStatus: function () {
function didReceiveTraceLog(traceLog) {
if (!traceLog)
return;
this._alive = traceLog.alive;
this._traceLogSize = traceLog.totalAvailableCalls;
this._updateCapturingStatus();
}
this._traceLogPlayer.getTraceLog(0, 0, didReceiveTraceLog.bind(this));
}, __proto__: WebInspector.ProfileHeader.prototype
}
WebInspector.CanvasProfileDataGridHelper = {
createCallArgumentElement: function (callArgument) {
if (callArgument.enumName)
return WebInspector.CanvasProfileDataGridHelper.createEnumValueElement(callArgument.enumName, +callArgument.description);
var element = document.createElement("span");
element.className = "canvas-call-argument";
var description = callArgument.description;
if (callArgument.type === "string") {
const maxStringLength = 150;
element.createTextChild("\"");
element.createChild("span", "canvas-formatted-string").textContent = description.trimMiddle(maxStringLength);
element.createTextChild("\"");
element.__suppressPopover = (description.length <= maxStringLength && !/[\r\n]/.test(description));
if (!element.__suppressPopover)
element.__evalResult = WebInspector.runtimeModel.createRemoteObjectFromPrimitiveValue(description);
} else {
var type = callArgument.subtype || callArgument.type;
if (type) {
element.classList.add("canvas-formatted-" + type);
if (["null", "undefined", "boolean", "number"].indexOf(type) >= 0)
element.__suppressPopover = true;
}
element.textContent = description;
if (callArgument.remoteObject)
element.__evalResult = WebInspector.runtimeModel.createRemoteObject(callArgument.remoteObject);
}
if (callArgument.resourceId) {
element.classList.add("canvas-formatted-resource");
element.__resourceId = callArgument.resourceId;
}
return element;
}, createEnumValueElement: function (enumName, enumValue) {
var element = document.createElement("span");
element.className = "canvas-call-argument canvas-formatted-number";
element.textContent = enumName;
element.__evalResult = WebInspector.runtimeModel.createRemoteObjectFromPrimitiveValue(enumValue);
return element;
}
}
WebInspector.CanvasTraceLogPlayerProxy = function (traceLogId) {
this._traceLogId = traceLogId;
this._currentResourceStates = {};
this._defaultResourceId = null;
}
WebInspector.CanvasTraceLogPlayerProxy.Events = {CanvasTraceLogReceived: "CanvasTraceLogReceived", CanvasReplayStateChanged: "CanvasReplayStateChanged", CanvasResourceStateReceived: "CanvasResourceStateReceived",}
WebInspector.CanvasTraceLogPlayerProxy.prototype = {
getTraceLog: function (startOffset, maxLength, userCallback) {
function callback(error, traceLog) {
if (error || !traceLog) {
userCallback(null);
return;
}
userCallback(traceLog);
this.dispatchEventToListeners(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasTraceLogReceived, traceLog);
}
CanvasAgent.getTraceLog(this._traceLogId, startOffset, maxLength, callback.bind(this));
}, dispose: function () {
this._currentResourceStates = {};
CanvasAgent.dropTraceLog(this._traceLogId);
this.dispatchEventToListeners(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasReplayStateChanged);
}, getResourceState: function (resourceId, userCallback) {
resourceId = resourceId || this._defaultResourceId;
if (!resourceId) {
userCallback(null);
return;
}
var effectiveResourceId = (resourceId);
if (this._currentResourceStates[effectiveResourceId]) {
userCallback(this._currentResourceStates[effectiveResourceId]);
return;
}
function callback(error, resourceState) {
if (error || !resourceState) {
userCallback(null);
return;
}
this._currentResourceStates[effectiveResourceId] = resourceState;
userCallback(resourceState);
this.dispatchEventToListeners(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasResourceStateReceived, resourceState);
}
CanvasAgent.getResourceState(this._traceLogId, effectiveResourceId, callback.bind(this));
}, replayTraceLog: function (index, userCallback) {
function callback(error, resourceState, replayTime) {
this._currentResourceStates = {};
if (error) {
userCallback(null, replayTime);
} else {
this._defaultResourceId = resourceState.id;
this._currentResourceStates[resourceState.id] = resourceState;
userCallback(resourceState, replayTime);
}
this.dispatchEventToListeners(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasReplayStateChanged);
if (!error)
this.dispatchEventToListeners(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasResourceStateReceived, resourceState);
}
CanvasAgent.replayTraceLog(this._traceLogId, index, callback.bind(this));
}, clearResourceStates: function () {
this._currentResourceStates = {};
this.dispatchEventToListeners(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasReplayStateChanged);
}, __proto__: WebInspector.Object.prototype
};
WebInspector.CanvasReplayStateView = function (traceLogPlayer) {
WebInspector.VBox.call(this);
this.registerRequiredCSS("canvasProfiler.css");
this.element.classList.add("canvas-replay-state-view");
this._traceLogPlayer = traceLogPlayer;
var controlsContainer = this.element.createChild("div", "status-bar");
this._prevButton = this._createControlButton(controlsContainer, "canvas-replay-state-prev", WebInspector.UIString("Previous resource."), this._onResourceNavigationClick.bind(this, false));
this._nextButton = this._createControlButton(controlsContainer, "canvas-replay-state-next", WebInspector.UIString("Next resource."), this._onResourceNavigationClick.bind(this, true));
this._createControlButton(controlsContainer, "canvas-replay-state-refresh", WebInspector.UIString("Refresh."), this._onStateRefreshClick.bind(this));
this._resourceSelector = new WebInspector.StatusBarComboBox(this._onReplayResourceChanged.bind(this));
this._currentOption = this._resourceSelector.createOption(WebInspector.UIString("<auto>"), WebInspector.UIString("Show state of the last replayed resource."), "");
controlsContainer.appendChild(this._resourceSelector.element);
this._resourceIdToDescription = {};
this._gridNodesExpandedState = {};
this._gridScrollPositions = {};
this._currentResourceId = null;
this._prevOptionsStack = [];
this._nextOptionsStack = [];
this._highlightedGridNodes = [];
var columns = [{title: WebInspector.UIString("Name"), sortable: false, width: "50%", disclosure: true}, {title: WebInspector.UIString("Value"), sortable: false, width: "50%"}];
this._stateGrid = new WebInspector.DataGrid(columns);
this._stateGrid.element.classList.add("fill");
this._stateGrid.show(this.element);
this._traceLogPlayer.addEventListener(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasReplayStateChanged, this._onReplayResourceChanged, this);
this._traceLogPlayer.addEventListener(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasTraceLogReceived, this._onCanvasTraceLogReceived, this);
this._traceLogPlayer.addEventListener(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasResourceStateReceived, this._onCanvasResourceStateReceived, this);
this._updateButtonsEnabledState();
}
WebInspector.CanvasReplayStateView.prototype = {
selectResource: function (resourceId) {
if (resourceId === this._resourceSelector.selectedOption().value)
return;
var option = this._resourceSelector.selectElement().firstChild;
for (var index = 0; option; ++index, option = option.nextSibling) {
if (resourceId === option.value) {
this._resourceSelector.setSelectedIndex(index);
this._onReplayResourceChanged();
break;
}
}
}, _createControlButton: function (parent, className, title, clickCallback) {
var button = new WebInspector.StatusBarButton(title, className + " canvas-replay-button");
parent.appendChild(button.element);
button.makeLongClickEnabled();
button.addEventListener("click", clickCallback, this);
button.addEventListener("longClickDown", clickCallback, this);
button.addEventListener("longClickPress", clickCallback, this);
return button;
}, _onResourceNavigationClick: function (forward) {
var newOption = forward ? this._nextOptionsStack.pop() : this._prevOptionsStack.pop();
if (!newOption)
return;
(forward ? this._prevOptionsStack : this._nextOptionsStack).push(this._currentOption);
this._isNavigationButton = true;
this.selectResource(newOption.value);
delete this._isNavigationButton;
this._updateButtonsEnabledState();
}, _onStateRefreshClick: function () {
this._traceLogPlayer.clearResourceStates();
}, _updateButtonsEnabledState: function () {
this._prevButton.setEnabled(this._prevOptionsStack.length > 0);
this._nextButton.setEnabled(this._nextOptionsStack.length > 0);
}, _updateCurrentOption: function () {
const maxStackSize = 256;
var selectedOption = this._resourceSelector.selectedOption();
if (this._currentOption === selectedOption)
return;
if (!this._isNavigationButton) {
this._prevOptionsStack.push(this._currentOption);
this._nextOptionsStack = [];
if (this._prevOptionsStack.length > maxStackSize)
this._prevOptionsStack.shift();
this._updateButtonsEnabledState();
}
this._currentOption = selectedOption;
}, _collectResourcesFromTraceLog: function (traceLog) {
var collectedResources = [];
var calls = traceLog.calls;
for (var i = 0, n = calls.length; i < n; ++i) {
var call = calls[i];
var args = call.arguments || [];
for (var j = 0; j < args.length; ++j)
this._collectResourceFromCallArgument(args[j], collectedResources);
this._collectResourceFromCallArgument(call.result, collectedResources);
this._collectResourceFromCallArgument(call.value, collectedResources);
}
var contexts = traceLog.contexts;
for (var i = 0, n = contexts.length; i < n; ++i)
this._collectResourceFromCallArgument(contexts[i], collectedResources);
this._addCollectedResourcesToSelector(collectedResources);
}, _collectResourcesFromResourceState: function (resourceState) {
var collectedResources = [];
this._collectResourceFromResourceStateDescriptors(resourceState.descriptors, collectedResources);
this._addCollectedResourcesToSelector(collectedResources);
}, _collectResourceFromResourceStateDescriptors: function (descriptors, output) {
if (!descriptors)
return;
for (var i = 0, n = descriptors.length; i < n; ++i) {
var descriptor = descriptors[i];
this._collectResourceFromCallArgument(descriptor.value, output);
this._collectResourceFromResourceStateDescriptors(descriptor.values, output);
}
}, _collectResourceFromCallArgument: function (argument, output) {
if (!argument)
return;
var resourceId = argument.resourceId;
if (!resourceId || this._resourceIdToDescription[resourceId])
return;
this._resourceIdToDescription[resourceId] = argument.description;
output.push(argument);
}, _addCollectedResourcesToSelector: function (collectedResources) {
if (!collectedResources.length)
return;
function comparator(arg1, arg2) {
var a = arg1.description;
var b = arg2.description;
return String.naturalOrderComparator(a, b);
}
collectedResources.sort(comparator);
var selectElement = this._resourceSelector.selectElement();
var currentOption = selectElement.firstChild;
currentOption = currentOption.nextSibling;
for (var i = 0, n = collectedResources.length; i < n; ++i) {
var argument = collectedResources[i];
while (currentOption && String.naturalOrderComparator(currentOption.text, argument.description) < 0)
currentOption = currentOption.nextSibling;
var option = this._resourceSelector.createOption(argument.description, WebInspector.UIString("Show state of this resource."), argument.resourceId);
if (currentOption)
selectElement.insertBefore(option, currentOption);
}
}, _onReplayResourceChanged: function () {
this._updateCurrentOption();
var selectedResourceId = this._resourceSelector.selectedOption().value;
function didReceiveResourceState(resourceState) {
if (selectedResourceId !== this._resourceSelector.selectedOption().value)
return;
this._showResourceState(resourceState);
}
this._traceLogPlayer.getResourceState(selectedResourceId, didReceiveResourceState.bind(this));
}, _onCanvasTraceLogReceived: function (event) {
var traceLog = (event.data);
console.assert(traceLog);
this._collectResourcesFromTraceLog(traceLog);
}, _onCanvasResourceStateReceived: function (event) {
var resourceState = (event.data);
console.assert(resourceState);
this._collectResourcesFromResourceState(resourceState);
}, _showResourceState: function (resourceState) {
this._saveExpandedState();
this._saveScrollState();
var rootNode = this._stateGrid.rootNode();
if (!resourceState) {
this._currentResourceId = null;
this._updateDataGridHighlights([]);
rootNode.removeChildren();
return;
}
var nodesToHighlight = [];
var nameToOldGridNodes = {};
function populateNameToNodesMap(map, node) {
if (!node)
return;
for (var i = 0, child; child = node.children[i]; ++i) {
var item = {node: child, children: {}};
map[child.name] = item;
populateNameToNodesMap(item.children, child);
}
}
populateNameToNodesMap(nameToOldGridNodes, rootNode);
rootNode.removeChildren();
function comparator(d1, d2) {
var hasChildren1 = !!d1.values;
var hasChildren2 = !!d2.values;
if (hasChildren1 !== hasChildren2)
return hasChildren1 ? 1 : -1;
return String.naturalOrderComparator(d1.name, d2.name);
}
function appendResourceStateDescriptors(descriptors, parent, nameToOldChildren) {
descriptors = descriptors || [];
descriptors.sort(comparator);
var oldChildren = nameToOldChildren || {};
for (var i = 0, n = descriptors.length; i < n; ++i) {
var descriptor = descriptors[i];
var childNode = this._createDataGridNode(descriptor);
parent.appendChild(childNode);
var oldChildrenItem = oldChildren[childNode.name] || {};
var oldChildNode = oldChildrenItem.node;
if (!oldChildNode || oldChildNode.element().textContent !== childNode.element().textContent)
nodesToHighlight.push(childNode);
appendResourceStateDescriptors.call(this, descriptor.values, childNode, oldChildrenItem.children);
}
}
appendResourceStateDescriptors.call(this, resourceState.descriptors, rootNode, nameToOldGridNodes);
var shouldHighlightChanges = (this._resourceKindId(this._currentResourceId) === this._resourceKindId(resourceState.id));
this._currentResourceId = resourceState.id;
this._restoreExpandedState();
this._updateDataGridHighlights(shouldHighlightChanges ? nodesToHighlight : []);
this._restoreScrollState();
}, _updateDataGridHighlights: function (nodes) {
for (var i = 0, n = this._highlightedGridNodes.length; i < n; ++i)
this._highlightedGridNodes[i].element().classList.remove("canvas-grid-node-highlighted");
this._highlightedGridNodes = nodes;
for (var i = 0, n = this._highlightedGridNodes.length; i < n; ++i) {
var node = this._highlightedGridNodes[i];
WebInspector.runCSSAnimationOnce(node.element(), "canvas-grid-node-highlighted");
node.reveal();
}
}, _resourceKindId: function (resourceId) {
var description = (resourceId && this._resourceIdToDescription[resourceId]) || "";
return description.replace(/\d+/g, "");
}, _forEachGridNode: function (callback) {
function processRecursively(node, key) {
for (var i = 0, child; child = node.children[i]; ++i) {
var childKey = key + "#" + child.name;
callback(child, childKey);
processRecursively(child, childKey);
}
}
processRecursively(this._stateGrid.rootNode(), "");
}, _saveExpandedState: function () {
if (!this._currentResourceId)
return;
var expandedState = {};
var key = this._resourceKindId(this._currentResourceId);
this._gridNodesExpandedState[key] = expandedState;
function callback(node, key) {
if (node.expanded)
expandedState[key] = true;
}
this._forEachGridNode(callback);
}, _restoreExpandedState: function () {
if (!this._currentResourceId)
return;
var key = this._resourceKindId(this._currentResourceId);
var expandedState = this._gridNodesExpandedState[key];
if (!expandedState)
return;
function callback(node, key) {
if (expandedState[key])
node.expand();
}
this._forEachGridNode(callback);
}, _saveScrollState: function () {
if (!this._currentResourceId)
return;
var key = this._resourceKindId(this._currentResourceId);
this._gridScrollPositions[key] = {scrollTop: this._stateGrid.scrollContainer.scrollTop, scrollLeft: this._stateGrid.scrollContainer.scrollLeft};
}, _restoreScrollState: function () {
if (!this._currentResourceId)
return;
var key = this._resourceKindId(this._currentResourceId);
var scrollState = this._gridScrollPositions[key];
if (!scrollState)
return;
this._stateGrid.scrollContainer.scrollTop = scrollState.scrollTop;
this._stateGrid.scrollContainer.scrollLeft = scrollState.scrollLeft;
}, _createDataGridNode: function (descriptor) {
var name = descriptor.name;
var callArgument = descriptor.value;
var valueElement = callArgument ? WebInspector.CanvasProfileDataGridHelper.createCallArgumentElement(callArgument) : "";
var nameElement = name;
if (typeof descriptor.enumValueForName !== "undefined")
nameElement = WebInspector.CanvasProfileDataGridHelper.createEnumValueElement(name, +descriptor.enumValueForName);
if (descriptor.isArray && descriptor.values) {
if (typeof nameElement === "string")
nameElement += "[" + descriptor.values.length + "]"; else {
var element = document.createElement("span");
element.appendChild(nameElement);
element.createTextChild("[" + descriptor.values.length + "]");
nameElement = element;
}
}
var data = {};
data[0] = nameElement;
data[1] = valueElement;
var node = new WebInspector.DataGridNode(data);
node.selectable = false;
node.name = name;
return node;
}, __proto__: WebInspector.VBox.prototype
};
WebInspector.ProfileTypeRegistry = function () {
this._profileTypes = [];
this.cpuProfileType = new WebInspector.CPUProfileType();
this._addProfileType(this.cpuProfileType);
this.heapSnapshotProfileType = new WebInspector.HeapSnapshotProfileType();
this._addProfileType(this.heapSnapshotProfileType);
this.trackingHeapSnapshotProfileType = new WebInspector.TrackingHeapSnapshotProfileType();
this._addProfileType(this.trackingHeapSnapshotProfileType);
if (!WebInspector.isWorkerFrontend() && WebInspector.experimentsSettings.canvasInspection.isEnabled()) {
this.canvasProfileType = new WebInspector.CanvasProfileType();
this._addProfileType(this.canvasProfileType);
}
}
WebInspector.ProfileTypeRegistry.prototype = {
_addProfileType: function (profileType) {
this._profileTypes.push(profileType);
}, profileTypes: function () {
return this._profileTypes;
}
}
WebInspector.ProfileTypeRegistry.instance = new WebInspector.ProfileTypeRegistry();
;