ProfilesPanel.js 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405
  1. /*
  2. * Copyright (C) 2008 Apple Inc. All Rights Reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
  17. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  20. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  21. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  23. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
  26. /**
  27. * @constructor
  28. * @extends {WebInspector.Object}
  29. * @param {string} id
  30. * @param {string} name
  31. */
  32. WebInspector.ProfileType = function(id, name)
  33. {
  34. this._id = id;
  35. this._name = name;
  36. /** @type {!Array.<!WebInspector.ProfileHeader>} */
  37. this._profiles = [];
  38. this._profilesIdMap = {};
  39. /** @type {WebInspector.SidebarSectionTreeElement} */
  40. this.treeElement = null;
  41. }
  42. WebInspector.ProfileType.Events = {
  43. AddProfileHeader: "add-profile-header",
  44. RemoveProfileHeader: "remove-profile-header",
  45. ProgressUpdated: "progress-updated",
  46. ViewUpdated: "view-updated"
  47. }
  48. WebInspector.ProfileType.prototype = {
  49. /**
  50. * @return {boolean}
  51. */
  52. hasTemporaryView: function()
  53. {
  54. return false;
  55. },
  56. /**
  57. * @return {string|null}
  58. */
  59. fileExtension: function()
  60. {
  61. return null;
  62. },
  63. get statusBarItems()
  64. {
  65. return [];
  66. },
  67. get buttonTooltip()
  68. {
  69. return "";
  70. },
  71. get id()
  72. {
  73. return this._id;
  74. },
  75. get treeItemTitle()
  76. {
  77. return this._name;
  78. },
  79. get name()
  80. {
  81. return this._name;
  82. },
  83. /**
  84. * @return {boolean}
  85. */
  86. buttonClicked: function()
  87. {
  88. return false;
  89. },
  90. get description()
  91. {
  92. return "";
  93. },
  94. /**
  95. * @return {boolean}
  96. */
  97. isInstantProfile: function()
  98. {
  99. return false;
  100. },
  101. /**
  102. * @return {boolean}
  103. */
  104. isEnabled: function()
  105. {
  106. return true;
  107. },
  108. /**
  109. * @return {!Array.<!WebInspector.ProfileHeader>}
  110. */
  111. getProfiles: function()
  112. {
  113. return this._profiles.filter(function(profile) { return !profile.isTemporary; });
  114. },
  115. /**
  116. * @return {Element}
  117. */
  118. decorationElement: function()
  119. {
  120. return null;
  121. },
  122. /**
  123. * @nosideeffects
  124. * @param {number} uid
  125. * @return {WebInspector.ProfileHeader}
  126. */
  127. getProfile: function(uid)
  128. {
  129. return this._profilesIdMap[this._makeKey(uid)];
  130. },
  131. // Must be implemented by subclasses.
  132. /**
  133. * @param {string=} title
  134. * @return {!WebInspector.ProfileHeader}
  135. */
  136. createTemporaryProfile: function(title)
  137. {
  138. throw new Error("Needs implemented.");
  139. },
  140. /**
  141. * @param {ProfilerAgent.ProfileHeader} profile
  142. * @return {!WebInspector.ProfileHeader}
  143. */
  144. createProfile: function(profile)
  145. {
  146. throw new Error("Not supported for " + this._name + " profiles.");
  147. },
  148. /**
  149. * @nosideeffects
  150. * @param {number} id
  151. * @return {string}
  152. */
  153. _makeKey: function(id)
  154. {
  155. return id + '/' + escape(this.id);
  156. },
  157. /**
  158. * @param {!WebInspector.ProfileHeader} profile
  159. */
  160. addProfile: function(profile)
  161. {
  162. this._profiles.push(profile);
  163. // FIXME: uid only based key should be enough.
  164. this._profilesIdMap[this._makeKey(profile.uid)] = profile;
  165. this.dispatchEventToListeners(WebInspector.ProfileType.Events.AddProfileHeader, profile);
  166. },
  167. /**
  168. * @param {!WebInspector.ProfileHeader} profile
  169. */
  170. removeProfile: function(profile)
  171. {
  172. for (var i = 0; i < this._profiles.length; ++i) {
  173. if (this._profiles[i].uid === profile.uid) {
  174. this._profiles.splice(i, 1);
  175. break;
  176. }
  177. }
  178. delete this._profilesIdMap[this._makeKey(profile.uid)];
  179. },
  180. /**
  181. * @nosideeffects
  182. * @return {WebInspector.ProfileHeader}
  183. */
  184. findTemporaryProfile: function()
  185. {
  186. for (var i = 0; i < this._profiles.length; ++i) {
  187. if (this._profiles[i].isTemporary)
  188. return this._profiles[i];
  189. }
  190. return null;
  191. },
  192. _reset: function()
  193. {
  194. var profiles = this._profiles.slice(0);
  195. for (var i = 0; i < profiles.length; ++i) {
  196. var profile = profiles[i];
  197. var view = profile.existingView();
  198. if (view) {
  199. view.detach();
  200. if ("dispose" in view)
  201. view.dispose();
  202. }
  203. this.dispatchEventToListeners(WebInspector.ProfileType.Events.RemoveProfileHeader, profile);
  204. }
  205. this.treeElement.removeChildren();
  206. this._profiles = [];
  207. this._profilesIdMap = {};
  208. },
  209. /**
  210. * @param {function(this:WebInspector.ProfileType, ?string, !Array.<!ProfilerAgent.ProfileHeader>)} populateCallback
  211. */
  212. _requestProfilesFromBackend: function(populateCallback)
  213. {
  214. },
  215. _populateProfiles: function()
  216. {
  217. /**
  218. * @param {?string} error
  219. * @param {!Array.<!ProfilerAgent.ProfileHeader>} profileHeaders
  220. */
  221. function populateCallback(error, profileHeaders) {
  222. if (error)
  223. return;
  224. profileHeaders.sort(function(a, b) { return a.uid - b.uid; });
  225. var count = profileHeaders.length;
  226. for (var i = 0; i < count; ++i)
  227. this.addProfile(this.createProfile(profileHeaders[i]));
  228. }
  229. this._requestProfilesFromBackend(populateCallback.bind(this));
  230. },
  231. __proto__: WebInspector.Object.prototype
  232. }
  233. /**
  234. * @constructor
  235. * @param {!WebInspector.ProfileType} profileType
  236. * @param {string} title
  237. * @param {number=} uid
  238. */
  239. WebInspector.ProfileHeader = function(profileType, title, uid)
  240. {
  241. this._profileType = profileType;
  242. this.title = title;
  243. this.isTemporary = uid === undefined;
  244. this.uid = this.isTemporary ? -1 : uid;
  245. this._fromFile = false;
  246. }
  247. WebInspector.ProfileHeader.prototype = {
  248. /**
  249. * @return {!WebInspector.ProfileType}
  250. */
  251. profileType: function()
  252. {
  253. return this._profileType;
  254. },
  255. /**
  256. * Must be implemented by subclasses.
  257. * @return {WebInspector.ProfileSidebarTreeElement}
  258. */
  259. createSidebarTreeElement: function()
  260. {
  261. throw new Error("Needs implemented.");
  262. },
  263. /**
  264. * @return {?WebInspector.View}
  265. */
  266. existingView: function()
  267. {
  268. return this._view;
  269. },
  270. /**
  271. * @param {!WebInspector.ProfilesPanel} panel
  272. * @return {!WebInspector.View}
  273. */
  274. view: function(panel)
  275. {
  276. if (!this._view)
  277. this._view = this.createView(panel);
  278. return this._view;
  279. },
  280. /**
  281. * @param {!WebInspector.ProfilesPanel} panel
  282. * @return {!WebInspector.View}
  283. */
  284. createView: function(panel)
  285. {
  286. throw new Error("Not implemented.");
  287. },
  288. dispose: function()
  289. {
  290. },
  291. /**
  292. * @param {Function} callback
  293. */
  294. load: function(callback)
  295. {
  296. },
  297. /**
  298. * @return {boolean}
  299. */
  300. canSaveToFile: function()
  301. {
  302. return false;
  303. },
  304. saveToFile: function()
  305. {
  306. throw new Error("Needs implemented");
  307. },
  308. /**
  309. * @param {File} file
  310. */
  311. loadFromFile: function(file)
  312. {
  313. throw new Error("Needs implemented");
  314. },
  315. /**
  316. * @return {boolean}
  317. */
  318. fromFile: function()
  319. {
  320. return this._fromFile;
  321. },
  322. setFromFile: function()
  323. {
  324. this._fromFile = true;
  325. this.uid = -2;
  326. }
  327. }
  328. /**
  329. * @constructor
  330. * @extends {WebInspector.Panel}
  331. * @implements {WebInspector.ContextMenu.Provider}
  332. * @param {string=} name
  333. * @param {WebInspector.ProfileType=} type
  334. */
  335. WebInspector.ProfilesPanel = function(name, type)
  336. {
  337. // If the name is not specified the ProfilesPanel works in multi-profile mode.
  338. var singleProfileMode = typeof name !== "undefined";
  339. name = name || "profiles";
  340. WebInspector.Panel.call(this, name);
  341. this.registerRequiredCSS("panelEnablerView.css");
  342. this.registerRequiredCSS("heapProfiler.css");
  343. this.registerRequiredCSS("profilesPanel.css");
  344. this.createSidebarViewWithTree();
  345. this.profilesItemTreeElement = new WebInspector.ProfilesSidebarTreeElement(this);
  346. this.sidebarTree.appendChild(this.profilesItemTreeElement);
  347. this._singleProfileMode = singleProfileMode;
  348. this._profileTypesByIdMap = {};
  349. this.profileViews = document.createElement("div");
  350. this.profileViews.id = "profile-views";
  351. this.splitView.mainElement.appendChild(this.profileViews);
  352. this._statusBarButtons = [];
  353. this.recordButton = new WebInspector.StatusBarButton("", "record-profile-status-bar-item");
  354. this.recordButton.addEventListener("click", this.toggleRecordButton, this);
  355. this._statusBarButtons.push(this.recordButton);
  356. this.clearResultsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear all profiles."), "clear-status-bar-item");
  357. this.clearResultsButton.addEventListener("click", this._clearProfiles, this);
  358. this._statusBarButtons.push(this.clearResultsButton);
  359. this._profileTypeStatusBarItemsContainer = document.createElement("div");
  360. this._profileTypeStatusBarItemsContainer.className = "status-bar-items";
  361. this._profileViewStatusBarItemsContainer = document.createElement("div");
  362. this._profileViewStatusBarItemsContainer.className = "status-bar-items";
  363. if (singleProfileMode) {
  364. this._launcherView = this._createLauncherView();
  365. this._registerProfileType(/** @type {!WebInspector.ProfileType} */ (type));
  366. this._selectedProfileType = type;
  367. this._updateProfileTypeSpecificUI();
  368. } else {
  369. this._launcherView = new WebInspector.MultiProfileLauncherView(this);
  370. this._launcherView.addEventListener(WebInspector.MultiProfileLauncherView.EventTypes.ProfileTypeSelected, this._onProfileTypeSelected, this);
  371. this._registerProfileType(new WebInspector.CPUProfileType());
  372. this._registerProfileType(new WebInspector.HeapSnapshotProfileType());
  373. this._registerProfileType(new WebInspector.TrackingHeapSnapshotProfileType(this));
  374. if (!WebInspector.WorkerManager.isWorkerFrontend() && WebInspector.experimentsSettings.canvasInspection.isEnabled())
  375. this._registerProfileType(new WebInspector.CanvasProfileType());
  376. }
  377. this._profilesWereRequested = false;
  378. this._reset();
  379. this._createFileSelectorElement();
  380. this.element.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
  381. this._registerShortcuts();
  382. WebInspector.ContextMenu.registerProvider(this);
  383. }
  384. WebInspector.ProfilesPanel.prototype = {
  385. _createFileSelectorElement: function()
  386. {
  387. if (this._fileSelectorElement)
  388. this.element.removeChild(this._fileSelectorElement);
  389. this._fileSelectorElement = WebInspector.createFileSelectorElement(this._loadFromFile.bind(this));
  390. this.element.appendChild(this._fileSelectorElement);
  391. },
  392. /**
  393. * @return {!WebInspector.ProfileLauncherView}
  394. */
  395. _createLauncherView: function()
  396. {
  397. return new WebInspector.ProfileLauncherView(this);
  398. },
  399. _findProfileTypeByExtension: function(fileName)
  400. {
  401. for (var id in this._profileTypesByIdMap) {
  402. var type = this._profileTypesByIdMap[id];
  403. var extension = type.fileExtension();
  404. if (!extension)
  405. continue;
  406. if (fileName.endsWith(type.fileExtension()))
  407. return type;
  408. }
  409. return null;
  410. },
  411. _registerShortcuts: function()
  412. {
  413. this.registerShortcuts(WebInspector.ProfilesPanelDescriptor.ShortcutKeys.StartStopRecording, this.toggleRecordButton.bind(this));
  414. },
  415. /**
  416. * @param {!File} file
  417. */
  418. _loadFromFile: function(file)
  419. {
  420. this._createFileSelectorElement();
  421. var profileType = this._findProfileTypeByExtension(file.name);
  422. if (!profileType) {
  423. var extensions = [];
  424. for (var id in this._profileTypesByIdMap) {
  425. var extension = this._profileTypesByIdMap[id].fileExtension();
  426. if (!extension)
  427. continue;
  428. extensions.push(extension);
  429. }
  430. WebInspector.log(WebInspector.UIString("Can't load file. Only files with extensions '%s' can be loaded.", extensions.join("', '")));
  431. return;
  432. }
  433. if (!!profileType.findTemporaryProfile()) {
  434. WebInspector.log(WebInspector.UIString("Can't load profile when other profile is recording."));
  435. return;
  436. }
  437. var temporaryProfile = profileType.createTemporaryProfile(WebInspector.ProfilesPanelDescriptor.UserInitiatedProfileName + "." + file.name);
  438. temporaryProfile.setFromFile();
  439. profileType.addProfile(temporaryProfile);
  440. temporaryProfile.loadFromFile(file);
  441. },
  442. get statusBarItems()
  443. {
  444. return this._statusBarButtons.select("element").concat(this._profileTypeStatusBarItemsContainer, this._profileViewStatusBarItemsContainer);
  445. },
  446. /**
  447. * @param {WebInspector.Event|Event=} event
  448. * @return {boolean}
  449. */
  450. toggleRecordButton: function(event)
  451. {
  452. var isProfiling = this._selectedProfileType.buttonClicked();
  453. this.setRecordingProfile(this._selectedProfileType.id, isProfiling);
  454. return true;
  455. },
  456. _populateAllProfiles: function()
  457. {
  458. if (this._profilesWereRequested)
  459. return;
  460. this._profilesWereRequested = true;
  461. for (var typeId in this._profileTypesByIdMap)
  462. this._profileTypesByIdMap[typeId]._populateProfiles();
  463. },
  464. wasShown: function()
  465. {
  466. WebInspector.Panel.prototype.wasShown.call(this);
  467. this._populateAllProfiles();
  468. },
  469. /**
  470. * @param {WebInspector.Event} event
  471. */
  472. _onProfileTypeSelected: function(event)
  473. {
  474. this._selectedProfileType = /** @type {!WebInspector.ProfileType} */ (event.data);
  475. this._updateProfileTypeSpecificUI();
  476. },
  477. _updateProfileTypeSpecificUI: function()
  478. {
  479. this.recordButton.title = this._selectedProfileType.buttonTooltip;
  480. this._launcherView.updateProfileType(this._selectedProfileType);
  481. this._profileTypeStatusBarItemsContainer.removeChildren();
  482. var statusBarItems = this._selectedProfileType.statusBarItems;
  483. if (statusBarItems) {
  484. for (var i = 0; i < statusBarItems.length; ++i)
  485. this._profileTypeStatusBarItemsContainer.appendChild(statusBarItems[i]);
  486. }
  487. this._resize(this.splitView.sidebarWidth());
  488. },
  489. _reset: function()
  490. {
  491. WebInspector.Panel.prototype.reset.call(this);
  492. for (var typeId in this._profileTypesByIdMap)
  493. this._profileTypesByIdMap[typeId]._reset();
  494. delete this.visibleView;
  495. delete this.currentQuery;
  496. this.searchCanceled();
  497. this._profileGroups = {};
  498. this.recordButton.toggled = false;
  499. if (this._selectedProfileType)
  500. this.recordButton.title = this._selectedProfileType.buttonTooltip;
  501. this._launcherView.profileFinished();
  502. this.sidebarTreeElement.removeStyleClass("some-expandable");
  503. this.profileViews.removeChildren();
  504. this._profileViewStatusBarItemsContainer.removeChildren();
  505. this.removeAllListeners();
  506. this.recordButton.visible = true;
  507. this._profileViewStatusBarItemsContainer.removeStyleClass("hidden");
  508. this.clearResultsButton.element.removeStyleClass("hidden");
  509. this.profilesItemTreeElement.select();
  510. this._showLauncherView();
  511. },
  512. _showLauncherView: function()
  513. {
  514. this.closeVisibleView();
  515. this._profileViewStatusBarItemsContainer.removeChildren();
  516. this._launcherView.show(this.splitView.mainElement);
  517. this.visibleView = this._launcherView;
  518. },
  519. _clearProfiles: function()
  520. {
  521. ProfilerAgent.clearProfiles();
  522. HeapProfilerAgent.clearProfiles();
  523. this._reset();
  524. },
  525. _garbageCollectButtonClicked: function()
  526. {
  527. HeapProfilerAgent.collectGarbage();
  528. },
  529. /**
  530. * @param {!WebInspector.ProfileType} profileType
  531. */
  532. _registerProfileType: function(profileType)
  533. {
  534. this._profileTypesByIdMap[profileType.id] = profileType;
  535. this._launcherView.addProfileType(profileType);
  536. profileType.treeElement = new WebInspector.SidebarSectionTreeElement(profileType.treeItemTitle, null, true);
  537. profileType.treeElement.hidden = !this._singleProfileMode;
  538. this.sidebarTree.appendChild(profileType.treeElement);
  539. profileType.treeElement.childrenListElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
  540. function onAddProfileHeader(event)
  541. {
  542. this._addProfileHeader(event.data);
  543. }
  544. function onRemoveProfileHeader(event)
  545. {
  546. this._removeProfileHeader(event.data);
  547. }
  548. function onProgressUpdated(event)
  549. {
  550. this._reportProfileProgress(event.data.profile, event.data.done, event.data.total);
  551. }
  552. profileType.addEventListener(WebInspector.ProfileType.Events.ViewUpdated, this._updateProfileTypeSpecificUI, this);
  553. profileType.addEventListener(WebInspector.ProfileType.Events.AddProfileHeader, onAddProfileHeader, this);
  554. profileType.addEventListener(WebInspector.ProfileType.Events.RemoveProfileHeader, onRemoveProfileHeader, this);
  555. profileType.addEventListener(WebInspector.ProfileType.Events.ProgressUpdated, onProgressUpdated, this);
  556. },
  557. /**
  558. * @param {Event} event
  559. */
  560. _handleContextMenuEvent: function(event)
  561. {
  562. var element = event.srcElement;
  563. while (element && !element.treeElement && element !== this.element)
  564. element = element.parentElement;
  565. if (!element)
  566. return;
  567. if (element.treeElement && element.treeElement.handleContextMenuEvent) {
  568. element.treeElement.handleContextMenuEvent(event, this);
  569. return;
  570. }
  571. var contextMenu = new WebInspector.ContextMenu(event);
  572. if (this.visibleView instanceof WebInspector.HeapSnapshotView) {
  573. this.visibleView.populateContextMenu(contextMenu, event);
  574. }
  575. if (element !== this.element || event.srcElement === this.sidebarElement) {
  576. contextMenu.appendItem(WebInspector.UIString("Load\u2026"), this._fileSelectorElement.click.bind(this._fileSelectorElement));
  577. }
  578. contextMenu.show();
  579. },
  580. /**
  581. * @nosideeffects
  582. * @param {string} text
  583. * @param {string} profileTypeId
  584. * @return {string}
  585. */
  586. _makeTitleKey: function(text, profileTypeId)
  587. {
  588. return escape(text) + '/' + escape(profileTypeId);
  589. },
  590. /**
  591. * @param {!WebInspector.ProfileHeader} profile
  592. */
  593. _addProfileHeader: function(profile)
  594. {
  595. var profileType = profile.profileType();
  596. var typeId = profileType.id;
  597. var sidebarParent = profileType.treeElement;
  598. sidebarParent.hidden = false;
  599. var small = false;
  600. var alternateTitle;
  601. if (!WebInspector.ProfilesPanelDescriptor.isUserInitiatedProfile(profile.title) && !profile.isTemporary) {
  602. var profileTitleKey = this._makeTitleKey(profile.title, typeId);
  603. if (!(profileTitleKey in this._profileGroups))
  604. this._profileGroups[profileTitleKey] = [];
  605. var group = this._profileGroups[profileTitleKey];
  606. group.push(profile);
  607. if (group.length === 2) {
  608. // Make a group TreeElement now that there are 2 profiles.
  609. group._profilesTreeElement = new WebInspector.ProfileGroupSidebarTreeElement(this, profile.title);
  610. // Insert at the same index for the first profile of the group.
  611. var index = sidebarParent.children.indexOf(group[0]._profilesTreeElement);
  612. sidebarParent.insertChild(group._profilesTreeElement, index);
  613. // Move the first profile to the group.
  614. var selected = group[0]._profilesTreeElement.selected;
  615. sidebarParent.removeChild(group[0]._profilesTreeElement);
  616. group._profilesTreeElement.appendChild(group[0]._profilesTreeElement);
  617. if (selected)
  618. group[0]._profilesTreeElement.revealAndSelect();
  619. group[0]._profilesTreeElement.small = true;
  620. group[0]._profilesTreeElement.mainTitle = WebInspector.UIString("Run %d", 1);
  621. this.sidebarTreeElement.addStyleClass("some-expandable");
  622. }
  623. if (group.length >= 2) {
  624. sidebarParent = group._profilesTreeElement;
  625. alternateTitle = WebInspector.UIString("Run %d", group.length);
  626. small = true;
  627. }
  628. }
  629. var profileTreeElement = profile.createSidebarTreeElement();
  630. profile.sidebarElement = profileTreeElement;
  631. profileTreeElement.small = small;
  632. if (alternateTitle)
  633. profileTreeElement.mainTitle = alternateTitle;
  634. profile._profilesTreeElement = profileTreeElement;
  635. var temporaryProfile = profileType.findTemporaryProfile();
  636. if (profile.isTemporary || !temporaryProfile)
  637. sidebarParent.appendChild(profileTreeElement);
  638. else {
  639. if (temporaryProfile) {
  640. sidebarParent.insertBeforeChild(profileTreeElement, temporaryProfile._profilesTreeElement);
  641. this._removeTemporaryProfile(profile.profileType().id);
  642. }
  643. if (!this.visibleView || this.visibleView === this._launcherView)
  644. this._showProfile(profile);
  645. this.dispatchEventToListeners("profile added", {
  646. type: typeId
  647. });
  648. }
  649. },
  650. /**
  651. * @param {!WebInspector.ProfileHeader} profile
  652. */
  653. _removeProfileHeader: function(profile)
  654. {
  655. profile.dispose();
  656. profile.profileType().removeProfile(profile);
  657. var sidebarParent = profile.profileType().treeElement;
  658. var profileTitleKey = this._makeTitleKey(profile.title, profile.profileType().id);
  659. var group = this._profileGroups[profileTitleKey];
  660. if (group) {
  661. group.splice(group.indexOf(profile), 1);
  662. if (group.length === 1) {
  663. // Move the last profile out of its group and remove the group.
  664. var index = sidebarParent.children.indexOf(group._profilesTreeElement);
  665. sidebarParent.insertChild(group[0]._profilesTreeElement, index);
  666. group[0]._profilesTreeElement.small = false;
  667. group[0]._profilesTreeElement.mainTitle = group[0].title;
  668. sidebarParent.removeChild(group._profilesTreeElement);
  669. }
  670. if (group.length !== 0)
  671. sidebarParent = group._profilesTreeElement;
  672. else
  673. delete this._profileGroups[profileTitleKey];
  674. }
  675. sidebarParent.removeChild(profile._profilesTreeElement);
  676. // No other item will be selected if there aren't any other profiles, so
  677. // make sure that view gets cleared when the last profile is removed.
  678. if (!sidebarParent.children.length) {
  679. this.profilesItemTreeElement.select();
  680. this._showLauncherView();
  681. sidebarParent.hidden = !this._singleProfileMode;
  682. }
  683. },
  684. /**
  685. * @param {!WebInspector.ProfileHeader} profile
  686. * @return {WebInspector.View}
  687. */
  688. _showProfile: function(profile)
  689. {
  690. if (!profile || (profile.isTemporary && !profile.profileType().hasTemporaryView()))
  691. return null;
  692. var view = profile.view(this);
  693. if (view === this.visibleView)
  694. return view;
  695. this.closeVisibleView();
  696. view.show(this.profileViews);
  697. profile._profilesTreeElement._suppressOnSelect = true;
  698. profile._profilesTreeElement.revealAndSelect();
  699. delete profile._profilesTreeElement._suppressOnSelect;
  700. this.visibleView = view;
  701. this._profileViewStatusBarItemsContainer.removeChildren();
  702. var statusBarItems = view.statusBarItems;
  703. if (statusBarItems)
  704. for (var i = 0; i < statusBarItems.length; ++i)
  705. this._profileViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
  706. return view;
  707. },
  708. /**
  709. * @param {HeapProfilerAgent.HeapSnapshotObjectId} snapshotObjectId
  710. * @param {string} viewName
  711. */
  712. showObject: function(snapshotObjectId, viewName)
  713. {
  714. var heapProfiles = this.getProfileType(WebInspector.HeapSnapshotProfileType.TypeId).getProfiles();
  715. for (var i = 0; i < heapProfiles.length; i++) {
  716. var profile = heapProfiles[i];
  717. // FIXME: allow to choose snapshot if there are several options.
  718. if (profile.maxJSObjectId >= snapshotObjectId) {
  719. this._showProfile(profile);
  720. var view = profile.view(this);
  721. view.changeView(viewName, function() {
  722. view.dataGrid.highlightObjectByHeapSnapshotId(snapshotObjectId);
  723. });
  724. break;
  725. }
  726. }
  727. },
  728. /**
  729. * @param {string} typeId
  730. */
  731. _createTemporaryProfile: function(typeId)
  732. {
  733. var type = this.getProfileType(typeId);
  734. if (!type.findTemporaryProfile())
  735. type.addProfile(type.createTemporaryProfile());
  736. },
  737. /**
  738. * @param {string} typeId
  739. */
  740. _removeTemporaryProfile: function(typeId)
  741. {
  742. var temporaryProfile = this.getProfileType(typeId).findTemporaryProfile();
  743. if (!!temporaryProfile)
  744. this._removeProfileHeader(temporaryProfile);
  745. },
  746. /**
  747. * @param {string} typeId
  748. * @param {number} uid
  749. */
  750. getProfile: function(typeId, uid)
  751. {
  752. return this.getProfileType(typeId).getProfile(uid);
  753. },
  754. /**
  755. * @param {WebInspector.View} view
  756. */
  757. showView: function(view)
  758. {
  759. this._showProfile(view.profile);
  760. },
  761. /**
  762. * @param {string} typeId
  763. */
  764. getProfileType: function(typeId)
  765. {
  766. return this._profileTypesByIdMap[typeId];
  767. },
  768. /**
  769. * @param {string} typeId
  770. * @param {string} uid
  771. * @return {WebInspector.View}
  772. */
  773. showProfile: function(typeId, uid)
  774. {
  775. return this._showProfile(this.getProfile(typeId, Number(uid)));
  776. },
  777. closeVisibleView: function()
  778. {
  779. if (this.visibleView)
  780. this.visibleView.detach();
  781. delete this.visibleView;
  782. },
  783. /**
  784. * @param {string} query
  785. * @param {boolean} shouldJump
  786. */
  787. performSearch: function(query, shouldJump)
  788. {
  789. this.searchCanceled();
  790. var searchableViews = this._searchableViews();
  791. if (!searchableViews || !searchableViews.length)
  792. return;
  793. var visibleView = this.visibleView;
  794. var matchesCountUpdateTimeout = null;
  795. function updateMatchesCount()
  796. {
  797. WebInspector.searchController.updateSearchMatchesCount(this._totalSearchMatches, this);
  798. WebInspector.searchController.updateCurrentMatchIndex(this._currentSearchResultIndex, this);
  799. matchesCountUpdateTimeout = null;
  800. }
  801. function updateMatchesCountSoon()
  802. {
  803. if (matchesCountUpdateTimeout)
  804. return;
  805. // Update the matches count every half-second so it doesn't feel twitchy.
  806. matchesCountUpdateTimeout = setTimeout(updateMatchesCount.bind(this), 500);
  807. }
  808. function finishedCallback(view, searchMatches)
  809. {
  810. if (!searchMatches)
  811. return;
  812. this._totalSearchMatches += searchMatches;
  813. this._searchResults.push(view);
  814. this.searchMatchFound(view, searchMatches);
  815. updateMatchesCountSoon.call(this);
  816. if (shouldJump && view === visibleView)
  817. view.jumpToFirstSearchResult();
  818. }
  819. var i = 0;
  820. var panel = this;
  821. var boundFinishedCallback = finishedCallback.bind(this);
  822. var chunkIntervalIdentifier = null;
  823. // Split up the work into chunks so we don't block the
  824. // UI thread while processing.
  825. function processChunk()
  826. {
  827. var view = searchableViews[i];
  828. if (++i >= searchableViews.length) {
  829. if (panel._currentSearchChunkIntervalIdentifier === chunkIntervalIdentifier)
  830. delete panel._currentSearchChunkIntervalIdentifier;
  831. clearInterval(chunkIntervalIdentifier);
  832. }
  833. if (!view)
  834. return;
  835. view.currentQuery = query;
  836. view.performSearch(query, boundFinishedCallback);
  837. }
  838. processChunk();
  839. chunkIntervalIdentifier = setInterval(processChunk, 25);
  840. this._currentSearchChunkIntervalIdentifier = chunkIntervalIdentifier;
  841. },
  842. jumpToNextSearchResult: function()
  843. {
  844. if (!this.showView || !this._searchResults || !this._searchResults.length)
  845. return;
  846. var showFirstResult = false;
  847. this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
  848. if (this._currentSearchResultIndex === -1) {
  849. this._currentSearchResultIndex = 0;
  850. showFirstResult = true;
  851. }
  852. var currentView = this._searchResults[this._currentSearchResultIndex];
  853. if (currentView.showingLastSearchResult()) {
  854. if (++this._currentSearchResultIndex >= this._searchResults.length)
  855. this._currentSearchResultIndex = 0;
  856. currentView = this._searchResults[this._currentSearchResultIndex];
  857. showFirstResult = true;
  858. }
  859. WebInspector.searchController.updateCurrentMatchIndex(this._currentSearchResultIndex, this);
  860. if (currentView !== this.visibleView) {
  861. this.showView(currentView);
  862. WebInspector.searchController.showSearchField();
  863. }
  864. if (showFirstResult)
  865. currentView.jumpToFirstSearchResult();
  866. else
  867. currentView.jumpToNextSearchResult();
  868. },
  869. jumpToPreviousSearchResult: function()
  870. {
  871. if (!this.showView || !this._searchResults || !this._searchResults.length)
  872. return;
  873. var showLastResult = false;
  874. this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
  875. if (this._currentSearchResultIndex === -1) {
  876. this._currentSearchResultIndex = 0;
  877. showLastResult = true;
  878. }
  879. var currentView = this._searchResults[this._currentSearchResultIndex];
  880. if (currentView.showingFirstSearchResult()) {
  881. if (--this._currentSearchResultIndex < 0)
  882. this._currentSearchResultIndex = (this._searchResults.length - 1);
  883. currentView = this._searchResults[this._currentSearchResultIndex];
  884. showLastResult = true;
  885. }
  886. WebInspector.searchController.updateCurrentMatchIndex(this._currentSearchResultIndex, this);
  887. if (currentView !== this.visibleView) {
  888. this.showView(currentView);
  889. WebInspector.searchController.showSearchField();
  890. }
  891. if (showLastResult)
  892. currentView.jumpToLastSearchResult();
  893. else
  894. currentView.jumpToPreviousSearchResult();
  895. },
  896. /**
  897. * @return {!Array.<!WebInspector.ProfileHeader>}
  898. */
  899. _getAllProfiles: function()
  900. {
  901. var profiles = [];
  902. for (var typeId in this._profileTypesByIdMap)
  903. profiles = profiles.concat(this._profileTypesByIdMap[typeId].getProfiles());
  904. return profiles;
  905. },
  906. /**
  907. * @return {!Array.<!WebInspector.View>}
  908. */
  909. _searchableViews: function()
  910. {
  911. var profiles = this._getAllProfiles();
  912. var searchableViews = [];
  913. for (var i = 0; i < profiles.length; ++i) {
  914. var view = profiles[i].view(this);
  915. if (view.performSearch)
  916. searchableViews.push(view)
  917. }
  918. var index = searchableViews.indexOf(this.visibleView);
  919. if (index > 0) {
  920. // Move visibleView to the first position.
  921. searchableViews[index] = searchableViews[0];
  922. searchableViews[0] = this.visibleView;
  923. }
  924. return searchableViews;
  925. },
  926. searchMatchFound: function(view, matches)
  927. {
  928. view.profile._profilesTreeElement.searchMatches = matches;
  929. },
  930. searchCanceled: function()
  931. {
  932. if (this._searchResults) {
  933. for (var i = 0; i < this._searchResults.length; ++i) {
  934. var view = this._searchResults[i];
  935. if (view.searchCanceled)
  936. view.searchCanceled();
  937. delete view.currentQuery;
  938. }
  939. }
  940. WebInspector.Panel.prototype.searchCanceled.call(this);
  941. if (this._currentSearchChunkIntervalIdentifier) {
  942. clearInterval(this._currentSearchChunkIntervalIdentifier);
  943. delete this._currentSearchChunkIntervalIdentifier;
  944. }
  945. this._totalSearchMatches = 0;
  946. this._currentSearchResultIndex = 0;
  947. this._searchResults = [];
  948. var profiles = this._getAllProfiles();
  949. for (var i = 0; i < profiles.length; ++i)
  950. profiles[i]._profilesTreeElement.searchMatches = 0;
  951. },
  952. /**
  953. * @param {!WebInspector.Event} event
  954. */
  955. sidebarResized: function(event)
  956. {
  957. var sidebarWidth = /** @type {number} */ (event.data);
  958. this._resize(sidebarWidth);
  959. },
  960. onResize: function()
  961. {
  962. this._resize(this.splitView.sidebarWidth());
  963. },
  964. /**
  965. * @param {number} sidebarWidth
  966. */
  967. _resize: function(sidebarWidth)
  968. {
  969. var lastItemElement = this._statusBarButtons[this._statusBarButtons.length - 1].element;
  970. var left = lastItemElement.totalOffsetLeft() + lastItemElement.offsetWidth;
  971. this._profileTypeStatusBarItemsContainer.style.left = left + "px";
  972. left += this._profileTypeStatusBarItemsContainer.offsetWidth - 1;
  973. this._profileViewStatusBarItemsContainer.style.left = Math.max(left, sidebarWidth) + "px";
  974. },
  975. /**
  976. * @param {string} profileType
  977. * @param {boolean} isProfiling
  978. */
  979. setRecordingProfile: function(profileType, isProfiling)
  980. {
  981. var profileTypeObject = this.getProfileType(profileType);
  982. this.recordButton.toggled = isProfiling;
  983. this.recordButton.title = profileTypeObject.buttonTooltip;
  984. if (isProfiling) {
  985. this._launcherView.profileStarted();
  986. this._createTemporaryProfile(profileType);
  987. if (profileTypeObject.hasTemporaryView())
  988. this._showProfile(profileTypeObject.findTemporaryProfile());
  989. } else
  990. this._launcherView.profileFinished();
  991. },
  992. /**
  993. * @param {!WebInspector.ProfileHeader} profile
  994. * @param {number} done
  995. * @param {number} total
  996. */
  997. _reportProfileProgress: function(profile, done, total)
  998. {
  999. profile.sidebarElement.subtitle = WebInspector.UIString("%.0f%", (done / total) * 100);
  1000. profile.sidebarElement.wait = true;
  1001. },
  1002. /**
  1003. * @param {WebInspector.ContextMenu} contextMenu
  1004. * @param {Object} target
  1005. */
  1006. appendApplicableItems: function(event, contextMenu, target)
  1007. {
  1008. if (WebInspector.inspectorView.currentPanel() !== this)
  1009. return;
  1010. var object = /** @type {WebInspector.RemoteObject} */ (target);
  1011. var objectId = object.objectId;
  1012. if (!objectId)
  1013. return;
  1014. var heapProfiles = this.getProfileType(WebInspector.HeapSnapshotProfileType.TypeId).getProfiles();
  1015. if (!heapProfiles.length)
  1016. return;
  1017. function revealInView(viewName)
  1018. {
  1019. HeapProfilerAgent.getHeapObjectId(objectId, didReceiveHeapObjectId.bind(this, viewName));
  1020. }
  1021. function didReceiveHeapObjectId(viewName, error, result)
  1022. {
  1023. if (WebInspector.inspectorView.currentPanel() !== this)
  1024. return;
  1025. if (!error)
  1026. this.showObject(result, viewName);
  1027. }
  1028. contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Dominators view" : "Reveal in Dominators View"), revealInView.bind(this, "Dominators"));
  1029. contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Summary view" : "Reveal in Summary View"), revealInView.bind(this, "Summary"));
  1030. },
  1031. __proto__: WebInspector.Panel.prototype
  1032. }
  1033. /**
  1034. * @constructor
  1035. * @extends {WebInspector.SidebarTreeElement}
  1036. * @param {!WebInspector.ProfileHeader} profile
  1037. * @param {string} titleFormat
  1038. * @param {string} className
  1039. */
  1040. WebInspector.ProfileSidebarTreeElement = function(profile, titleFormat, className)
  1041. {
  1042. this.profile = profile;
  1043. this._titleFormat = titleFormat;
  1044. if (WebInspector.ProfilesPanelDescriptor.isUserInitiatedProfile(this.profile.title))
  1045. this._profileNumber = WebInspector.ProfilesPanelDescriptor.userInitiatedProfileIndex(this.profile.title);
  1046. WebInspector.SidebarTreeElement.call(this, className, "", "", profile, false);
  1047. this.refreshTitles();
  1048. }
  1049. WebInspector.ProfileSidebarTreeElement.prototype = {
  1050. onselect: function()
  1051. {
  1052. if (!this._suppressOnSelect)
  1053. this.treeOutline.panel._showProfile(this.profile);
  1054. },
  1055. ondelete: function()
  1056. {
  1057. this.treeOutline.panel._removeProfileHeader(this.profile);
  1058. return true;
  1059. },
  1060. get mainTitle()
  1061. {
  1062. if (this._mainTitle)
  1063. return this._mainTitle;
  1064. if (WebInspector.ProfilesPanelDescriptor.isUserInitiatedProfile(this.profile.title))
  1065. return WebInspector.UIString(this._titleFormat, this._profileNumber);
  1066. return this.profile.title;
  1067. },
  1068. set mainTitle(x)
  1069. {
  1070. this._mainTitle = x;
  1071. this.refreshTitles();
  1072. },
  1073. set searchMatches(matches)
  1074. {
  1075. if (!matches) {
  1076. if (!this.bubbleElement)
  1077. return;
  1078. this.bubbleElement.removeStyleClass("search-matches");
  1079. this.bubbleText = "";
  1080. return;
  1081. }
  1082. this.bubbleText = matches;
  1083. this.bubbleElement.addStyleClass("search-matches");
  1084. },
  1085. /**
  1086. * @param {!Event} event
  1087. * @param {!WebInspector.ProfilesPanel} panel
  1088. */
  1089. handleContextMenuEvent: function(event, panel)
  1090. {
  1091. var profile = this.profile;
  1092. var contextMenu = new WebInspector.ContextMenu(event);
  1093. // FIXME: use context menu provider
  1094. contextMenu.appendItem(WebInspector.UIString("Load\u2026"), panel._fileSelectorElement.click.bind(panel._fileSelectorElement));
  1095. if (profile.canSaveToFile())
  1096. contextMenu.appendItem(WebInspector.UIString("Save\u2026"), profile.saveToFile.bind(profile));
  1097. contextMenu.appendItem(WebInspector.UIString("Delete"), this.ondelete.bind(this));
  1098. contextMenu.show();
  1099. },
  1100. __proto__: WebInspector.SidebarTreeElement.prototype
  1101. }
  1102. /**
  1103. * @constructor
  1104. * @extends {WebInspector.SidebarTreeElement}
  1105. * @param {WebInspector.ProfilesPanel} panel
  1106. * @param {string} title
  1107. * @param {string=} subtitle
  1108. */
  1109. WebInspector.ProfileGroupSidebarTreeElement = function(panel, title, subtitle)
  1110. {
  1111. WebInspector.SidebarTreeElement.call(this, "profile-group-sidebar-tree-item", title, subtitle, null, true);
  1112. this._panel = panel;
  1113. }
  1114. WebInspector.ProfileGroupSidebarTreeElement.prototype = {
  1115. onselect: function()
  1116. {
  1117. if (this.children.length > 0)
  1118. this._panel._showProfile(this.children[this.children.length - 1].profile);
  1119. },
  1120. __proto__: WebInspector.SidebarTreeElement.prototype
  1121. }
  1122. /**
  1123. * @constructor
  1124. * @extends {WebInspector.SidebarTreeElement}
  1125. * @param {!WebInspector.ProfilesPanel} panel
  1126. */
  1127. WebInspector.ProfilesSidebarTreeElement = function(panel)
  1128. {
  1129. this._panel = panel;
  1130. this.small = false;
  1131. WebInspector.SidebarTreeElement.call(this, "profile-launcher-view-tree-item", WebInspector.UIString("Profiles"), "", null, false);
  1132. }
  1133. WebInspector.ProfilesSidebarTreeElement.prototype = {
  1134. onselect: function()
  1135. {
  1136. this._panel._showLauncherView();
  1137. },
  1138. get selectable()
  1139. {
  1140. return true;
  1141. },
  1142. __proto__: WebInspector.SidebarTreeElement.prototype
  1143. }
  1144. /**
  1145. * @constructor
  1146. * @extends {WebInspector.ProfilesPanel}
  1147. */
  1148. WebInspector.CPUProfilerPanel = function()
  1149. {
  1150. WebInspector.ProfilesPanel.call(this, "cpu-profiler", new WebInspector.CPUProfileType());
  1151. }
  1152. WebInspector.CPUProfilerPanel.prototype = {
  1153. __proto__: WebInspector.ProfilesPanel.prototype
  1154. }
  1155. /**
  1156. * @constructor
  1157. * @extends {WebInspector.ProfilesPanel}
  1158. */
  1159. WebInspector.HeapProfilerPanel = function()
  1160. {
  1161. var heapSnapshotProfileType = new WebInspector.HeapSnapshotProfileType();
  1162. WebInspector.ProfilesPanel.call(this, "heap-profiler", heapSnapshotProfileType);
  1163. this._singleProfileMode = false;
  1164. this._registerProfileType(new WebInspector.TrackingHeapSnapshotProfileType(this));
  1165. this._launcherView.addEventListener(WebInspector.MultiProfileLauncherView.EventTypes.ProfileTypeSelected, this._onProfileTypeSelected, this);
  1166. this._launcherView._profileTypeChanged(heapSnapshotProfileType);
  1167. }
  1168. WebInspector.HeapProfilerPanel.prototype = {
  1169. _createLauncherView: function()
  1170. {
  1171. return new WebInspector.MultiProfileLauncherView(this);
  1172. },
  1173. __proto__: WebInspector.ProfilesPanel.prototype
  1174. }
  1175. /**
  1176. * @constructor
  1177. * @extends {WebInspector.ProfilesPanel}
  1178. */
  1179. WebInspector.CanvasProfilerPanel = function()
  1180. {
  1181. WebInspector.ProfilesPanel.call(this, "canvas-profiler", new WebInspector.CanvasProfileType());
  1182. }
  1183. WebInspector.CanvasProfilerPanel.prototype = {
  1184. __proto__: WebInspector.ProfilesPanel.prototype
  1185. }
  1186. importScript("ProfileDataGridTree.js");
  1187. importScript("BottomUpProfileDataGridTree.js");
  1188. importScript("CPUProfileView.js");
  1189. importScript("FlameChart.js");
  1190. importScript("HeapSnapshot.js");
  1191. importScript("HeapSnapshotDataGrids.js");
  1192. importScript("HeapSnapshotGridNodes.js");
  1193. importScript("HeapSnapshotLoader.js");
  1194. importScript("HeapSnapshotProxy.js");
  1195. importScript("HeapSnapshotView.js");
  1196. importScript("HeapSnapshotWorkerDispatcher.js");
  1197. importScript("JSHeapSnapshot.js");
  1198. importScript("ProfileLauncherView.js");
  1199. importScript("TopDownProfileDataGridTree.js");
  1200. importScript("CanvasProfileView.js");
  1201. importScript("CanvasReplayStateView.js");