UNPKG

devil-windows

Version:

Debugger, profiler and runtime with embedded WebKit DevTools client (for Windows).

1,030 lines (1,021 loc) 295 kB
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(); } WebInsp