Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(256)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js

Issue 2466123002: DevTools: reformat front-end code to match chromium style. (Closed)
Patch Set: all done Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved. 2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * Copyright (C) 2012 Intel Inc. All rights reserved. 3 * Copyright (C) 2012 Intel Inc. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are 6 * modification, are permitted provided that the following conditions are
7 * met: 7 * met:
8 * 8 *
9 * * Redistributions of source code must retain the above copyright 9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 10 matching lines...) Expand all
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31
32 /** 31 /**
33 * @constructor
34 * @extends {WebInspector.Panel}
35 * @implements {WebInspector.TimelineLifecycleDelegate} 32 * @implements {WebInspector.TimelineLifecycleDelegate}
36 * @implements {WebInspector.TimelineModeViewDelegate} 33 * @implements {WebInspector.TimelineModeViewDelegate}
37 * @implements {WebInspector.Searchable} 34 * @implements {WebInspector.Searchable}
35 * @unrestricted
38 */ 36 */
39 WebInspector.TimelinePanel = function() 37 WebInspector.TimelinePanel = class extends WebInspector.Panel {
40 { 38 constructor() {
41 WebInspector.Panel.call(this, "timeline"); 39 super('timeline');
42 this.registerRequiredCSS("timeline/timelinePanel.css"); 40 this.registerRequiredCSS('timeline/timelinePanel.css');
43 this.element.addEventListener("contextmenu", this._contextMenu.bind(this), f alse); 41 this.element.addEventListener('contextmenu', this._contextMenu.bind(this), f alse);
44 this._dropTarget = new WebInspector.DropTarget(this.element, [WebInspector.D ropTarget.Types.Files, WebInspector.DropTarget.Types.URIList], WebInspector.UISt ring("Drop timeline file or URL here"), this._handleDrop.bind(this)); 42 this._dropTarget = new WebInspector.DropTarget(
43 this.element, [WebInspector.DropTarget.Types.Files, WebInspector.DropTar get.Types.URIList],
44 WebInspector.UIString('Drop timeline file or URL here'), this._handleDro p.bind(this));
45 45
46 this._state = WebInspector.TimelinePanel.State.Idle; 46 this._state = WebInspector.TimelinePanel.State.Idle;
47 this._detailsLinkifier = new WebInspector.Linkifier(); 47 this._detailsLinkifier = new WebInspector.Linkifier();
48 this._windowStartTime = 0; 48 this._windowStartTime = 0;
49 this._windowEndTime = Infinity; 49 this._windowEndTime = Infinity;
50 this._millisecondsToRecordAfterLoadEvent = 3000; 50 this._millisecondsToRecordAfterLoadEvent = 3000;
51 this._toggleRecordAction = /** @type {!WebInspector.Action }*/ (WebInspector .actionRegistry.action("timeline.toggle-recording")); 51 this._toggleRecordAction =
52 /** @type {!WebInspector.Action }*/ (WebInspector.actionRegistry.action( 'timeline.toggle-recording'));
52 this._customCPUThrottlingRate = 0; 53 this._customCPUThrottlingRate = 0;
53 54
54 /** @type {!Array<!WebInspector.TimelineModel.Filter>} */ 55 /** @type {!Array<!WebInspector.TimelineModel.Filter>} */
55 this._filters = []; 56 this._filters = [];
56 if (!Runtime.experiments.isEnabled("timelineShowAllEvents")) { 57 if (!Runtime.experiments.isEnabled('timelineShowAllEvents')) {
57 this._filters.push(WebInspector.TimelineUIUtils.visibleEventsFilter()); 58 this._filters.push(WebInspector.TimelineUIUtils.visibleEventsFilter());
58 this._filters.push(new WebInspector.ExcludeTopLevelFilter()); 59 this._filters.push(new WebInspector.ExcludeTopLevelFilter());
59 } 60 }
60 61
61 // Create models. 62 // Create models.
62 this._tracingModelBackingStorage = new WebInspector.TempFileBackingStorage(" tracing"); 63 this._tracingModelBackingStorage = new WebInspector.TempFileBackingStorage(' tracing');
63 this._tracingModel = new WebInspector.TracingModel(this._tracingModelBacking Storage); 64 this._tracingModel = new WebInspector.TracingModel(this._tracingModelBacking Storage);
64 this._model = new WebInspector.TimelineModel(WebInspector.TimelineUIUtils.vi sibleEventsFilter()); 65 this._model = new WebInspector.TimelineModel(WebInspector.TimelineUIUtils.vi sibleEventsFilter());
65 this._frameModel = new WebInspector.TimelineFrameModel(event => WebInspector .TimelineUIUtils.eventStyle(event).category.name); 66 this._frameModel =
67 new WebInspector.TimelineFrameModel(event => WebInspector.TimelineUIUtil s.eventStyle(event).category.name);
66 this._filmStripModel = new WebInspector.FilmStripModel(this._tracingModel); 68 this._filmStripModel = new WebInspector.FilmStripModel(this._tracingModel);
67 this._irModel = new WebInspector.TimelineIRModel(); 69 this._irModel = new WebInspector.TimelineIRModel();
68 70
69 this._cpuThrottlingManager = new WebInspector.CPUThrottlingManager(); 71 this._cpuThrottlingManager = new WebInspector.CPUThrottlingManager();
70 72
71 /** @type {!Array.<!WebInspector.TimelineModeView>} */ 73 /** @type {!Array.<!WebInspector.TimelineModeView>} */
72 this._currentViews = []; 74 this._currentViews = [];
73 75
74 this._captureNetworkSetting = WebInspector.settings.createSetting("timelineC aptureNetwork", false); 76 this._captureNetworkSetting = WebInspector.settings.createSetting('timelineC aptureNetwork', false);
75 this._captureJSProfileSetting = WebInspector.settings.createSetting("timelin eEnableJSSampling", true); 77 this._captureJSProfileSetting = WebInspector.settings.createSetting('timelin eEnableJSSampling', true);
76 this._captureMemorySetting = WebInspector.settings.createSetting("timelineCa ptureMemory", false); 78 this._captureMemorySetting = WebInspector.settings.createSetting('timelineCa ptureMemory', false);
77 this._captureLayersAndPicturesSetting = WebInspector.settings.createSetting( "timelineCaptureLayersAndPictures", false); 79 this._captureLayersAndPicturesSetting =
78 this._captureFilmStripSetting = WebInspector.settings.createSetting("timelin eCaptureFilmStrip", false); 80 WebInspector.settings.createSetting('timelineCaptureLayersAndPictures', false);
79 81 this._captureFilmStripSetting = WebInspector.settings.createSetting('timelin eCaptureFilmStrip', false);
80 this._panelToolbar = new WebInspector.Toolbar("", this.element); 82
83 this._panelToolbar = new WebInspector.Toolbar('', this.element);
81 this._createToolbarItems(); 84 this._createToolbarItems();
82 85
83 var timelinePane = new WebInspector.VBox(); 86 var timelinePane = new WebInspector.VBox();
84 timelinePane.show(this.element); 87 timelinePane.show(this.element);
85 var topPaneElement = timelinePane.element.createChild("div", "hbox"); 88 var topPaneElement = timelinePane.element.createChild('div', 'hbox');
86 topPaneElement.id = "timeline-overview-panel"; 89 topPaneElement.id = 'timeline-overview-panel';
87 90
88 // Create top overview component. 91 // Create top overview component.
89 this._overviewPane = new WebInspector.TimelineOverviewPane("timeline"); 92 this._overviewPane = new WebInspector.TimelineOverviewPane('timeline');
90 this._overviewPane.addEventListener(WebInspector.TimelineOverviewPane.Events .WindowChanged, this._onWindowChanged.bind(this)); 93 this._overviewPane.addEventListener(
94 WebInspector.TimelineOverviewPane.Events.WindowChanged, this._onWindowCh anged.bind(this));
91 this._overviewPane.show(topPaneElement); 95 this._overviewPane.show(topPaneElement);
92 this._statusPaneContainer = timelinePane.element.createChild("div", "status- pane-container fill"); 96 this._statusPaneContainer = timelinePane.element.createChild('div', 'status- pane-container fill');
93 97
94 this._createFileSelector(); 98 this._createFileSelector();
95 99
96 WebInspector.targetManager.addEventListener(WebInspector.TargetManager.Event s.PageReloadRequested, this._pageReloadRequested, this); 100 WebInspector.targetManager.addEventListener(
101 WebInspector.TargetManager.Events.PageReloadRequested, this._pageReloadR equested, this);
97 WebInspector.targetManager.addEventListener(WebInspector.TargetManager.Event s.Load, this._loadEventFired, this); 102 WebInspector.targetManager.addEventListener(WebInspector.TargetManager.Event s.Load, this._loadEventFired, this);
98 103
99 // Create top level properties splitter. 104 // Create top level properties splitter.
100 this._detailsSplitWidget = new WebInspector.SplitWidget(false, true, "timeli nePanelDetailsSplitViewState"); 105 this._detailsSplitWidget = new WebInspector.SplitWidget(false, true, 'timeli nePanelDetailsSplitViewState');
101 this._detailsSplitWidget.element.classList.add("timeline-details-split"); 106 this._detailsSplitWidget.element.classList.add('timeline-details-split');
102 this._detailsView = new WebInspector.TimelineDetailsView(this._model, this._ filters, this); 107 this._detailsView = new WebInspector.TimelineDetailsView(this._model, this._ filters, this);
103 this._detailsSplitWidget.installResizer(this._detailsView.headerElement()); 108 this._detailsSplitWidget.installResizer(this._detailsView.headerElement());
104 this._detailsSplitWidget.setSidebarWidget(this._detailsView); 109 this._detailsSplitWidget.setSidebarWidget(this._detailsView);
105 110
106 this._searchableView = new WebInspector.SearchableView(this); 111 this._searchableView = new WebInspector.SearchableView(this);
107 this._searchableView.setMinimumSize(0, 100); 112 this._searchableView.setMinimumSize(0, 100);
108 this._searchableView.element.classList.add("searchable-view"); 113 this._searchableView.element.classList.add('searchable-view');
109 this._detailsSplitWidget.setMainWidget(this._searchableView); 114 this._detailsSplitWidget.setMainWidget(this._searchableView);
110 115
111 this._stackView = new WebInspector.StackView(false); 116 this._stackView = new WebInspector.StackView(false);
112 this._stackView.element.classList.add("timeline-view-stack"); 117 this._stackView.element.classList.add('timeline-view-stack');
113 118
114 this._stackView.show(this._searchableView.element); 119 this._stackView.show(this._searchableView.element);
115 this._onModeChanged(); 120 this._onModeChanged();
116 121
117 this._detailsSplitWidget.show(timelinePane.element); 122 this._detailsSplitWidget.show(timelinePane.element);
118 this._detailsSplitWidget.hideSidebar(); 123 this._detailsSplitWidget.hideSidebar();
119 WebInspector.targetManager.addEventListener(WebInspector.TargetManager.Event s.SuspendStateChanged, this._onSuspendStateChanged, this); 124 WebInspector.targetManager.addEventListener(
125 WebInspector.TargetManager.Events.SuspendStateChanged, this._onSuspendSt ateChanged, this);
120 this._showRecordingHelpMessage(); 126 this._showRecordingHelpMessage();
121 127
122 /** @type {!WebInspector.TracingModel.Event}|undefined */ 128 /** @type {!WebInspector.TracingModel.Event}|undefined */
123 this._selectedSearchResult; 129 this._selectedSearchResult;
124 /** @type {!Array<!WebInspector.TracingModel.Event>}|undefined */ 130 /** @type {!Array<!WebInspector.TracingModel.Event>}|undefined */
125 this._searchResults; 131 this._searchResults;
132 }
133
134 /**
135 * @return {!WebInspector.TimelinePanel}
136 */
137 static instance() {
138 return /** @type {!WebInspector.TimelinePanel} */ (self.runtime.sharedInstan ce(WebInspector.TimelinePanel));
139 }
140
141 /**
142 * @override
143 * @return {?WebInspector.SearchableView}
144 */
145 searchableView() {
146 return this._searchableView;
147 }
148
149 /**
150 * @override
151 */
152 wasShown() {
153 WebInspector.context.setFlavor(WebInspector.TimelinePanel, this);
154 }
155
156 /**
157 * @override
158 */
159 willHide() {
160 WebInspector.context.setFlavor(WebInspector.TimelinePanel, null);
161 }
162
163 /**
164 * @return {number}
165 */
166 windowStartTime() {
167 if (this._windowStartTime)
168 return this._windowStartTime;
169 return this._model.minimumRecordTime();
170 }
171
172 /**
173 * @return {number}
174 */
175 windowEndTime() {
176 if (this._windowEndTime < Infinity)
177 return this._windowEndTime;
178 return this._model.maximumRecordTime() || Infinity;
179 }
180
181 /**
182 * @param {!WebInspector.Event} event
183 */
184 _onWindowChanged(event) {
185 this._windowStartTime = event.data.startTime;
186 this._windowEndTime = event.data.endTime;
187
188 for (var i = 0; i < this._currentViews.length; ++i)
189 this._currentViews[i].setWindowTimes(this._windowStartTime, this._windowEn dTime);
190
191 if (!this._selection || this._selection.type() === WebInspector.TimelineSele ction.Type.Range)
192 this.select(null);
193 }
194
195 /**
196 * @param {!WebInspector.Event} event
197 */
198 _onOverviewSelectionChanged(event) {
199 var selection = /** @type {!WebInspector.TimelineSelection} */ (event.data);
200 this.select(selection);
201 }
202
203 /**
204 * @override
205 * @param {number} windowStartTime
206 * @param {number} windowEndTime
207 */
208 requestWindowTimes(windowStartTime, windowEndTime) {
209 this._overviewPane.requestWindowTimes(windowStartTime, windowEndTime);
210 }
211
212 /**
213 * @return {!WebInspector.Widget}
214 */
215 _layersView() {
216 if (this._lazyLayersView)
217 return this._lazyLayersView;
218 this._lazyLayersView =
219 new WebInspector.TimelineLayersView(this._model, this._showSnapshotInPai ntProfiler.bind(this));
220 return this._lazyLayersView;
221 }
222
223 _paintProfilerView() {
224 if (this._lazyPaintProfilerView)
225 return this._lazyPaintProfilerView;
226 this._lazyPaintProfilerView = new WebInspector.TimelinePaintProfilerView(thi s._frameModel);
227 return this._lazyPaintProfilerView;
228 }
229
230 /**
231 * @param {!WebInspector.TimelineModeView} modeView
232 */
233 _addModeView(modeView) {
234 modeView.setWindowTimes(this.windowStartTime(), this.windowEndTime());
235 modeView.refreshRecords();
236 var splitWidget =
237 this._stackView.appendView(modeView.view(), 'timelinePanelTimelineStackS plitViewState', undefined, 112);
238 var resizer = modeView.resizerElement();
239 if (splitWidget && resizer) {
240 splitWidget.hideDefaultResizer();
241 splitWidget.installResizer(resizer);
242 }
243 this._currentViews.push(modeView);
244 }
245
246 _removeAllModeViews() {
247 this._currentViews.forEach(view => view.dispose());
248 this._currentViews = [];
249 this._stackView.detachChildWidgets();
250 }
251
252 /**
253 * @param {!WebInspector.TimelinePanel.State} state
254 */
255 _setState(state) {
256 this._state = state;
257 this._updateTimelineControls();
258 }
259
260 /**
261 * @param {string} name
262 * @param {!WebInspector.Setting} setting
263 * @param {string} tooltip
264 * @return {!WebInspector.ToolbarItem}
265 */
266 _createSettingCheckbox(name, setting, tooltip) {
267 if (!this._recordingOptionUIControls)
268 this._recordingOptionUIControls = [];
269 var checkboxItem = new WebInspector.ToolbarCheckbox(name, tooltip, setting);
270 this._recordingOptionUIControls.push(checkboxItem);
271 return checkboxItem;
272 }
273
274 _createToolbarItems() {
275 this._panelToolbar.removeToolbarItems();
276
277 var perspectiveSetting =
278 WebInspector.settings.createSetting('timelinePerspective', WebInspector. TimelinePanel.Perspectives.Load);
279 if (Runtime.experiments.isEnabled('timelineRecordingPerspectives')) {
280 /**
281 * @this {!WebInspector.TimelinePanel}
282 */
283 function onPerspectiveChanged() {
284 perspectiveSetting.set(perspectiveCombobox.selectElement().value);
285 this._createToolbarItems();
286 }
287
288 /**
289 * @param {string} id
290 * @param {string} title
291 */
292 function addPerspectiveOption(id, title) {
293 var option = perspectiveCombobox.createOption(title, '', id);
294 perspectiveCombobox.addOption(option);
295 if (id === perspectiveSetting.get())
296 perspectiveCombobox.select(option);
297 }
298
299 var perspectiveCombobox = new WebInspector.ToolbarComboBox(onPerspectiveCh anged.bind(this));
300 addPerspectiveOption(WebInspector.TimelinePanel.Perspectives.Load, WebInsp ector.UIString('Page Load'));
301 addPerspectiveOption(
302 WebInspector.TimelinePanel.Perspectives.Responsiveness, WebInspector.U IString('Responsiveness'));
303 addPerspectiveOption(WebInspector.TimelinePanel.Perspectives.Custom, WebIn spector.UIString('Custom'));
304 this._panelToolbar.appendToolbarItem(perspectiveCombobox);
305
306 switch (perspectiveSetting.get()) {
307 case WebInspector.TimelinePanel.Perspectives.Load:
308 this._captureNetworkSetting.set(true);
309 this._captureJSProfileSetting.set(true);
310 this._captureMemorySetting.set(false);
311 this._captureLayersAndPicturesSetting.set(false);
312 this._captureFilmStripSetting.set(true);
313 break;
314 case WebInspector.TimelinePanel.Perspectives.Responsiveness:
315 this._captureNetworkSetting.set(true);
316 this._captureJSProfileSetting.set(true);
317 this._captureMemorySetting.set(false);
318 this._captureLayersAndPicturesSetting.set(false);
319 this._captureFilmStripSetting.set(false);
320 break;
321 }
322 }
323 if (Runtime.experiments.isEnabled('timelineRecordingPerspectives') &&
324 perspectiveSetting.get() === WebInspector.TimelinePanel.Perspectives.Loa d) {
325 this._reloadButton =
326 new WebInspector.ToolbarButton(WebInspector.UIString('Record & Reload' ), 'refresh-toolbar-item');
327 this._reloadButton.addEventListener('click', () => WebInspector.targetMana ger.reloadPage());
328 this._panelToolbar.appendToolbarItem(this._reloadButton);
329 } else {
330 this._panelToolbar.appendToolbarItem(WebInspector.Toolbar.createActionButt on(this._toggleRecordAction));
331 }
332
333 this._updateTimelineControls();
334 var clearButton = new WebInspector.ToolbarButton(WebInspector.UIString('Clea r recording'), 'clear-toolbar-item');
335 clearButton.addEventListener('click', this._clear, this);
336 this._panelToolbar.appendToolbarItem(clearButton);
337
338 this._panelToolbar.appendSeparator();
339
340 this._panelToolbar.appendText(WebInspector.UIString('Capture:'));
341
342 var screenshotCheckbox = this._createSettingCheckbox(
343 WebInspector.UIString('Screenshots'), this._captureFilmStripSetting,
344 WebInspector.UIString('Capture screenshots while recording. (Has small p erformance overhead)'));
345
346 if (!Runtime.experiments.isEnabled('timelineRecordingPerspectives') ||
347 perspectiveSetting.get() === WebInspector.TimelinePanel.Perspectives.Cus tom) {
348 this._panelToolbar.appendToolbarItem(this._createSettingCheckbox(
349 WebInspector.UIString('Network'), this._captureNetworkSetting,
350 WebInspector.UIString('Show network requests information')));
351 this._panelToolbar.appendToolbarItem(this._createSettingCheckbox(
352 WebInspector.UIString('JS Profile'), this._captureJSProfileSetting,
353 WebInspector.UIString('Capture JavaScript stacks with sampling profile r. (Has small performance overhead)')));
354 this._panelToolbar.appendToolbarItem(screenshotCheckbox);
355 this._panelToolbar.appendToolbarItem(this._createSettingCheckbox(
356 WebInspector.UIString('Memory'), this._captureMemorySetting,
357 WebInspector.UIString('Capture memory information on every timeline ev ent.')));
358 this._panelToolbar.appendToolbarItem(this._createSettingCheckbox(
359 WebInspector.UIString('Paint'), this._captureLayersAndPicturesSetting,
360 WebInspector.UIString(
361 'Capture graphics layer positions and rasterization draw calls. (H as large performance overhead)')));
362 } else {
363 this._panelToolbar.appendToolbarItem(screenshotCheckbox);
364 }
365
366 this._captureNetworkSetting.addChangeListener(this._onNetworkChanged, this);
367 this._captureMemorySetting.addChangeListener(this._onModeChanged, this);
368 this._captureFilmStripSetting.addChangeListener(this._onModeChanged, this);
369
370 this._panelToolbar.appendSeparator();
371 var garbageCollectButton =
372 new WebInspector.ToolbarButton(WebInspector.UIString('Collect garbage'), 'garbage-collect-toolbar-item');
373 garbageCollectButton.addEventListener('click', this._garbageCollectButtonCli cked, this);
374 this._panelToolbar.appendToolbarItem(garbageCollectButton);
375
376 this._panelToolbar.appendSeparator();
377 this._cpuThrottlingCombobox = new WebInspector.ToolbarComboBox(this._onCPUTh rottlingChanged.bind(this));
378 this._panelToolbar.appendToolbarItem(this._cpuThrottlingCombobox);
379 this._populateCPUThrottingCombobox();
380 }
381
382 _populateCPUThrottingCombobox() {
383 var cpuThrottlingCombobox = this._cpuThrottlingCombobox;
384 cpuThrottlingCombobox.removeOptions();
385 var currentRate = this._cpuThrottlingManager.rate();
386 var hasSelection = false;
387 /**
388 * @param {string} name
389 * @param {number} value
390 */
391 function addGroupingOption(name, value) {
392 var option = cpuThrottlingCombobox.createOption(name, '', String(value));
393 cpuThrottlingCombobox.addOption(option);
394 if (hasSelection || (value && value !== currentRate))
395 return;
396 cpuThrottlingCombobox.select(option);
397 hasSelection = true;
398 }
399 var predefinedRates = new Map([
400 [1, WebInspector.UIString('No CPU throttling')], [2, WebInspector.UIString ('High end device (2\xD7 slowdown)')],
401 [5, WebInspector.UIString('Low end device (5\xD7 slowdown)')]
402 ]);
403 for (var rate of predefinedRates)
404 addGroupingOption(rate[1], rate[0]);
405 if (this._customCPUThrottlingRate && !predefinedRates.has(this._customCPUThr ottlingRate))
406 addGroupingOption(
407 WebInspector.UIString('Custom rate (%d\xD7 slowdown)', this._customCPU ThrottlingRate),
408 this._customCPUThrottlingRate);
409 addGroupingOption(WebInspector.UIString('Set custom rate\u2026'), 0);
410 }
411
412 _prepareToLoadTimeline() {
413 console.assert(this._state === WebInspector.TimelinePanel.State.Idle);
414 this._setState(WebInspector.TimelinePanel.State.Loading);
415 }
416
417 _createFileSelector() {
418 if (this._fileSelectorElement)
419 this._fileSelectorElement.remove();
420 this._fileSelectorElement = WebInspector.createFileSelectorElement(this._loa dFromFile.bind(this));
421 this.element.appendChild(this._fileSelectorElement);
422 }
423
424 /**
425 * @param {!Event} event
426 */
427 _contextMenu(event) {
428 var contextMenu = new WebInspector.ContextMenu(event);
429 contextMenu.appendItemsAtLocation('timelineMenu');
430 contextMenu.show();
431 }
432
433 /**
434 * @return {boolean}
435 */
436 _saveToFile() {
437 if (this._state !== WebInspector.TimelinePanel.State.Idle)
438 return true;
439 if (this._model.isEmpty())
440 return true;
441
442 var now = new Date();
443 var fileName = 'TimelineRawData-' + now.toISO8601Compact() + '.json';
444 var stream = new WebInspector.FileOutputStream();
445
446 /**
447 * @param {boolean} accepted
448 * @this {WebInspector.TimelinePanel}
449 */
450 function callback(accepted) {
451 if (!accepted)
452 return;
453 var saver = new WebInspector.TracingTimelineSaver();
454 this._tracingModelBackingStorage.writeToStream(stream, saver);
455 }
456 stream.open(fileName, callback.bind(this));
457 return true;
458 }
459
460 /**
461 * @return {boolean}
462 */
463 _selectFileToLoad() {
464 this._fileSelectorElement.click();
465 return true;
466 }
467
468 /**
469 * @param {!File} file
470 */
471 _loadFromFile(file) {
472 if (this._state !== WebInspector.TimelinePanel.State.Idle)
473 return;
474 this._prepareToLoadTimeline();
475 this._loader = WebInspector.TimelineLoader.loadFromFile(this._tracingModel, file, this);
476 this._createFileSelector();
477 }
478
479 /**
480 * @param {string} url
481 */
482 _loadFromURL(url) {
483 if (this._state !== WebInspector.TimelinePanel.State.Idle)
484 return;
485 this._prepareToLoadTimeline();
486 this._loader = WebInspector.TimelineLoader.loadFromURL(this._tracingModel, u rl, this);
487 }
488
489 _refreshViews() {
490 for (var i = 0; i < this._currentViews.length; ++i) {
491 var view = this._currentViews[i];
492 view.refreshRecords();
493 }
494 this._updateSelectionDetails();
495 }
496
497 _onModeChanged() {
498 // Set up overview controls.
499 this._overviewControls = [];
500 this._overviewControls.push(new WebInspector.TimelineEventOverviewResponsive ness(this._model, this._frameModel));
501 if (Runtime.experiments.isEnabled('inputEventsOnTimelineOverview'))
502 this._overviewControls.push(new WebInspector.TimelineEventOverviewInput(th is._model));
503 this._overviewControls.push(new WebInspector.TimelineEventOverviewFrames(thi s._model, this._frameModel));
504 this._overviewControls.push(new WebInspector.TimelineEventOverviewCPUActivit y(this._model));
505 this._overviewControls.push(new WebInspector.TimelineEventOverviewNetwork(th is._model));
506 if (this._captureFilmStripSetting.get())
507 this._overviewControls.push(new WebInspector.TimelineFilmStripOverview(thi s._model, this._filmStripModel));
508 if (this._captureMemorySetting.get())
509 this._overviewControls.push(new WebInspector.TimelineEventOverviewMemory(t his._model));
510 this._overviewPane.setOverviewControls(this._overviewControls);
511
512 // Set up the main view.
513 this._removeAllModeViews();
514 this._flameChart =
515 new WebInspector.TimelineFlameChartView(this, this._model, this._frameMo del, this._irModel, this._filters);
516 this._flameChart.enableNetworkPane(this._captureNetworkSetting.get());
517 this._addModeView(this._flameChart);
518
519 if (this._captureMemorySetting.get())
520 this._addModeView(new WebInspector.MemoryCountersGraph(
521 this, this._model, [WebInspector.TimelineUIUtils.visibleEventsFilter() ]));
522
523 this.doResize();
524 this.select(null);
525 }
526
527 _onNetworkChanged() {
528 if (this._flameChart)
529 this._flameChart.enableNetworkPane(this._captureNetworkSetting.get(), true );
530 }
531
532 _onCPUThrottlingChanged() {
533 if (!this._cpuThrottlingManager)
534 return;
535 var value = this._cpuThrottlingCombobox.selectedOption().value;
536 var isLastOption = this._cpuThrottlingCombobox.selectedIndex() === this._cpu ThrottlingCombobox.size() - 1;
537 this._populateCPUThrottingCombobox();
538 var resultPromise = isLastOption ?
539 WebInspector.TimelinePanel.CustomCPUThrottlingRateDialog.show(this._cpuT hrottlingCombobox.element) :
540 Promise.resolve(value);
541 resultPromise.then(text => {
542 var value = Number.parseFloat(text);
543 if (value >= 1) {
544 if (isLastOption)
545 this._customCPUThrottlingRate = value;
546 this._cpuThrottlingManager.setRate(value);
547 this._populateCPUThrottingCombobox();
548 }
549 });
550 }
551
552 /**
553 * @param {boolean} enabled
554 */
555 _setUIControlsEnabled(enabled) {
556 /**
557 * @param {!WebInspector.ToolbarButton} toolbarButton
558 */
559 function handler(toolbarButton) {
560 toolbarButton.setEnabled(enabled);
561 }
562 this._recordingOptionUIControls.forEach(handler);
563 }
564
565 /**
566 * @param {boolean} userInitiated
567 */
568 _startRecording(userInitiated) {
569 console.assert(!this._statusPane, 'Status pane is already opened.');
570 var mainTarget = WebInspector.targetManager.mainTarget();
571 if (!mainTarget)
572 return;
573 this._setState(WebInspector.TimelinePanel.State.StartPending);
574 this._showRecordingStarted();
575
576 this._autoRecordGeneration = userInitiated ? null : Symbol('Generation');
577 this._controller = new WebInspector.TimelineController(mainTarget, this, thi s._tracingModel);
578 this._controller.startRecording(
579 true, this._captureJSProfileSetting.get(), this._captureMemorySetting.ge t(),
580 this._captureLayersAndPicturesSetting.get(),
581 this._captureFilmStripSetting && this._captureFilmStripSetting.get());
582
583 for (var i = 0; i < this._overviewControls.length; ++i)
584 this._overviewControls[i].timelineStarted();
585
586 if (userInitiated)
587 WebInspector.userMetrics.actionTaken(WebInspector.UserMetrics.Action.Timel ineStarted);
588 this._setUIControlsEnabled(false);
589 this._hideRecordingHelpMessage();
590 }
591
592 _stopRecording() {
593 if (this._statusPane) {
594 this._statusPane.finish();
595 this._statusPane.updateStatus(WebInspector.UIString('Stopping timeline\u20 26'));
596 this._statusPane.updateProgressBar(WebInspector.UIString('Received'), 0);
597 }
598 this._setState(WebInspector.TimelinePanel.State.StopPending);
599 this._autoRecordGeneration = null;
600 this._controller.stopRecording();
601 this._controller = null;
602 this._setUIControlsEnabled(true);
603 }
604
605 _onSuspendStateChanged() {
606 this._updateTimelineControls();
607 }
608
609 _updateTimelineControls() {
610 var state = WebInspector.TimelinePanel.State;
611 this._toggleRecordAction.setToggled(this._state === state.Recording);
612 this._toggleRecordAction.setEnabled(this._state === state.Recording || this. _state === state.Idle);
613 this._panelToolbar.setEnabled(this._state !== state.Loading);
614 this._dropTarget.setEnabled(this._state === state.Idle);
615 }
616
617 _toggleRecording() {
618 if (this._state === WebInspector.TimelinePanel.State.Idle)
619 this._startRecording(true);
620 else if (this._state === WebInspector.TimelinePanel.State.Recording)
621 this._stopRecording();
622 }
623
624 _garbageCollectButtonClicked() {
625 var targets = WebInspector.targetManager.targets();
626 for (var i = 0; i < targets.length; ++i)
627 targets[i].heapProfilerAgent().collectGarbage();
628 }
629
630 _clear() {
631 WebInspector.LineLevelProfile.instance().reset();
632 this._tracingModel.reset();
633 this._model.reset();
634 this._showRecordingHelpMessage();
635
636 this.requestWindowTimes(0, Infinity);
637 delete this._selection;
638 this._frameModel.reset();
639 this._filmStripModel.reset(this._tracingModel);
640 this._overviewPane.reset();
641 for (var i = 0; i < this._currentViews.length; ++i)
642 this._currentViews[i].reset();
643 for (var i = 0; i < this._overviewControls.length; ++i)
644 this._overviewControls[i].reset();
645 this.select(null);
646 this._detailsSplitWidget.hideSidebar();
647 }
648
649 /**
650 * @override
651 */
652 recordingStarted() {
653 this._clear();
654 this._setState(WebInspector.TimelinePanel.State.Recording);
655 this._showRecordingStarted();
656 this._statusPane.updateStatus(WebInspector.UIString('Recording\u2026'));
657 this._statusPane.updateProgressBar(WebInspector.UIString('Buffer usage'), 0) ;
658 this._statusPane.startTimer();
659 this._hideRecordingHelpMessage();
660 }
661
662 /**
663 * @override
664 * @param {number} usage
665 */
666 recordingProgress(usage) {
667 this._statusPane.updateProgressBar(WebInspector.UIString('Buffer usage'), us age * 100);
668 }
669
670 _showRecordingHelpMessage() {
671 /**
672 * @param {string} tagName
673 * @param {string} contents
674 * @return {!Element}
675 */
676 function encloseWithTag(tagName, contents) {
677 var e = createElement(tagName);
678 e.textContent = contents;
679 return e;
680 }
681
682 var recordNode = encloseWithTag(
683 'b', WebInspector.shortcutRegistry.shortcutDescriptorsForAction('timelin e.toggle-recording')[0].name);
684 var reloadNode =
685 encloseWithTag('b', WebInspector.shortcutRegistry.shortcutDescriptorsFor Action('main.reload')[0].name);
686 var navigateNode = encloseWithTag('b', WebInspector.UIString('WASD (ZQSD)')) ;
687 var hintText = createElementWithClass('div');
688 hintText.appendChild(WebInspector.formatLocalized(
689 'To capture a new timeline, click the record toolbar button or hit %s.', [recordNode]));
690 hintText.createChild('br');
691 hintText.appendChild(
692 WebInspector.formatLocalized('To evaluate page load performance, hit %s to record the reload.', [reloadNode]));
693 hintText.createChild('p');
694 hintText.appendChild(
695 WebInspector.formatLocalized('After recording, select an area of interes t in the overview by dragging.', []));
696 hintText.createChild('br');
697 hintText.appendChild(WebInspector.formatLocalized(
698 'Then, zoom and pan the timeline with the mousewheel and %s keys.', [nav igateNode]));
699 this._hideRecordingHelpMessage();
700 this._helpMessageElement =
701 this._searchableView.element.createChild('div', 'full-widget-dimmed-bann er timeline-status-pane');
702 this._helpMessageElement.appendChild(hintText);
703 }
704
705 _hideRecordingHelpMessage() {
706 if (this._helpMessageElement)
707 this._helpMessageElement.remove();
708 delete this._helpMessageElement;
709 }
710
711 /**
712 * @override
713 */
714 loadingStarted() {
715 this._hideRecordingHelpMessage();
716
717 if (this._statusPane)
718 this._statusPane.hide();
719 this._statusPane = new WebInspector.TimelinePanel.StatusPane(false, this._ca ncelLoading.bind(this));
720 this._statusPane.showPane(this._statusPaneContainer);
721 this._statusPane.updateStatus(WebInspector.UIString('Loading timeline\u2026' ));
722 // FIXME: make loading from backend cancelable as well.
723 if (!this._loader)
724 this._statusPane.finish();
725 this.loadingProgress(0);
726 }
727
728 /**
729 * @override
730 * @param {number=} progress
731 */
732 loadingProgress(progress) {
733 if (typeof progress === 'number')
734 this._statusPane.updateProgressBar(WebInspector.UIString('Received'), prog ress * 100);
735 }
736
737 /**
738 * @override
739 * @param {boolean} success
740 */
741 loadingComplete(success) {
742 var loadedFromFile = !!this._loader;
743 delete this._loader;
744 this._setState(WebInspector.TimelinePanel.State.Idle);
745
746 if (!success) {
747 this._statusPane.hide();
748 delete this._statusPane;
749 this._clear();
750 return;
751 }
752
753 if (this._statusPane)
754 this._statusPane.updateStatus(WebInspector.UIString('Processing timeline\u 2026'));
755 this._model.setEvents(this._tracingModel, loadedFromFile);
756 this._frameModel.reset();
757 this._frameModel.addTraceEvents(
758 WebInspector.targetManager.mainTarget(), this._model.inspectedTargetEven ts(), this._model.sessionId() || '');
759 this._filmStripModel.reset(this._tracingModel);
760 var groups = WebInspector.TimelineModel.AsyncEventGroup;
761 var asyncEventsByGroup = this._model.mainThreadAsyncEvents();
762 this._irModel.populate(asyncEventsByGroup.get(groups.input), asyncEventsByGr oup.get(groups.animation));
763 this._model.cpuProfiles().forEach(profile => WebInspector.LineLevelProfile.i nstance().appendCPUProfile(profile));
764 if (this._statusPane)
765 this._statusPane.hide();
766 delete this._statusPane;
767 this._overviewPane.reset();
768 this._overviewPane.setBounds(this._model.minimumRecordTime(), this._model.ma ximumRecordTime());
769 this._setAutoWindowTimes();
770 this._refreshViews();
771 for (var i = 0; i < this._overviewControls.length; ++i)
772 this._overviewControls[i].timelineStopped();
773 this._setMarkers();
774 this._overviewPane.scheduleUpdate();
775 this._updateSearchHighlight(false, true);
776 this._detailsSplitWidget.showBoth();
777 }
778
779 _showRecordingStarted() {
780 if (this._statusPane)
781 return;
782 this._statusPane = new WebInspector.TimelinePanel.StatusPane(true, this._sto pRecording.bind(this));
783 this._statusPane.showPane(this._statusPaneContainer);
784 this._statusPane.updateStatus(WebInspector.UIString('Initializing recording\ u2026'));
785 }
786
787 _cancelLoading() {
788 if (this._loader)
789 this._loader.cancel();
790 }
791
792 _setMarkers() {
793 var markers = new Map();
794 var recordTypes = WebInspector.TimelineModel.RecordType;
795 var zeroTime = this._model.minimumRecordTime();
796 for (var record of this._model.eventDividerRecords()) {
797 if (record.type() === recordTypes.TimeStamp || record.type() === recordTyp es.ConsoleTime)
798 continue;
799 markers.set(record.startTime(), WebInspector.TimelineUIUtils.createDivider ForRecord(record, zeroTime, 0));
800 }
801 this._overviewPane.setMarkers(markers);
802 }
803
804 /**
805 * @param {!WebInspector.Event} event
806 */
807 _pageReloadRequested(event) {
808 if (this._state !== WebInspector.TimelinePanel.State.Idle || !this.isShowing ())
809 return;
810 this._startRecording(false);
811 }
812
813 /**
814 * @param {!WebInspector.Event} event
815 */
816 _loadEventFired(event) {
817 if (this._state !== WebInspector.TimelinePanel.State.Recording || !this._aut oRecordGeneration)
818 return;
819 setTimeout(stopRecordingOnReload.bind(this, this._autoRecordGeneration), thi s._millisecondsToRecordAfterLoadEvent);
820
821 /**
822 * @this {WebInspector.TimelinePanel}
823 * @param {!Object} recordGeneration
824 */
825 function stopRecordingOnReload(recordGeneration) {
826 // Check if we're still in the same recording session.
827 if (this._state !== WebInspector.TimelinePanel.State.Recording || this._au toRecordGeneration !== recordGeneration)
828 return;
829 this._stopRecording();
830 }
831 }
832
833 // WebInspector.Searchable implementation
834
835 /**
836 * @override
837 */
838 jumpToNextSearchResult() {
839 if (!this._searchResults || !this._searchResults.length)
840 return;
841 var index = this._selectedSearchResult ? this._searchResults.indexOf(this._s electedSearchResult) : -1;
842 this._jumpToSearchResult(index + 1);
843 }
844
845 /**
846 * @override
847 */
848 jumpToPreviousSearchResult() {
849 if (!this._searchResults || !this._searchResults.length)
850 return;
851 var index = this._selectedSearchResult ? this._searchResults.indexOf(this._s electedSearchResult) : 0;
852 this._jumpToSearchResult(index - 1);
853 }
854
855 /**
856 * @override
857 * @return {boolean}
858 */
859 supportsCaseSensitiveSearch() {
860 return false;
861 }
862
863 /**
864 * @override
865 * @return {boolean}
866 */
867 supportsRegexSearch() {
868 return false;
869 }
870
871 /**
872 * @param {number} index
873 */
874 _jumpToSearchResult(index) {
875 this._selectSearchResult((index + this._searchResults.length) % this._search Results.length);
876 this._currentViews[0].highlightSearchResult(this._selectedSearchResult, this ._searchRegex, true);
877 }
878
879 /**
880 * @param {number} index
881 */
882 _selectSearchResult(index) {
883 this._selectedSearchResult = this._searchResults[index];
884 this._searchableView.updateCurrentMatchIndex(index);
885 }
886
887 _clearHighlight() {
888 this._currentViews[0].highlightSearchResult(null);
889 }
890
891 /**
892 * @param {boolean} revealRecord
893 * @param {boolean} shouldJump
894 * @param {boolean=} jumpBackwards
895 */
896 _updateSearchHighlight(revealRecord, shouldJump, jumpBackwards) {
897 if (!this._searchRegex) {
898 this._clearHighlight();
899 return;
900 }
901
902 if (!this._searchResults)
903 this._updateSearchResults(shouldJump, jumpBackwards);
904 this._currentViews[0].highlightSearchResult(this._selectedSearchResult, this ._searchRegex, revealRecord);
905 }
906
907 /**
908 * @param {boolean} shouldJump
909 * @param {boolean=} jumpBackwards
910 */
911 _updateSearchResults(shouldJump, jumpBackwards) {
912 if (!this._searchRegex)
913 return;
914
915 // FIXME: search on all threads.
916 var events = this._model.mainThreadEvents();
917 var filters = this._filters.concat([new WebInspector.TimelineTextFilter(this ._searchRegex)]);
918 var matches = [];
919 for (var index = events.lowerBound(this._windowStartTime, (time, event) => t ime - event.startTime);
920 index < events.length; ++index) {
921 var event = events[index];
922 if (event.startTime > this._windowEndTime)
923 break;
924 if (WebInspector.TimelineModel.isVisible(filters, event))
925 matches.push(event);
926 }
927
928 var matchesCount = matches.length;
929 if (matchesCount) {
930 this._searchResults = matches;
931 this._searchableView.updateSearchMatchesCount(matchesCount);
932
933 var selectedIndex = matches.indexOf(this._selectedSearchResult);
934 if (shouldJump && selectedIndex === -1)
935 selectedIndex = jumpBackwards ? this._searchResults.length - 1 : 0;
936 this._selectSearchResult(selectedIndex);
937 } else {
938 this._searchableView.updateSearchMatchesCount(0);
939 delete this._selectedSearchResult;
940 }
941 }
942
943 /**
944 * @override
945 */
946 searchCanceled() {
947 this._clearHighlight();
948 delete this._searchResults;
949 delete this._selectedSearchResult;
950 delete this._searchRegex;
951 }
952
953 /**
954 * @override
955 * @param {!WebInspector.SearchableView.SearchConfig} searchConfig
956 * @param {boolean} shouldJump
957 * @param {boolean=} jumpBackwards
958 */
959 performSearch(searchConfig, shouldJump, jumpBackwards) {
960 var query = searchConfig.query;
961 this._searchRegex = createPlainTextSearchRegex(query, 'i');
962 delete this._searchResults;
963 this._updateSearchHighlight(true, shouldJump, jumpBackwards);
964 }
965
966 _updateSelectionDetails() {
967 switch (this._selection.type()) {
968 case WebInspector.TimelineSelection.Type.TraceEvent:
969 var event = /** @type {!WebInspector.TracingModel.Event} */ (this._selec tion.object());
970 WebInspector.TimelineUIUtils.buildTraceEventDetails(
971 event, this._model, this._detailsLinkifier, true,
972 this._appendDetailsTabsForTraceEventAndShowDetails.bind(this, event) );
973 break;
974 case WebInspector.TimelineSelection.Type.Frame:
975 var frame = /** @type {!WebInspector.TimelineFrame} */ (this._selection. object());
976 var screenshotTime = frame.idle ?
977 frame.startTime :
978 frame.endTime; // For idle frames, look at the state at the beginni ng of the frame.
979 var filmStripFrame = filmStripFrame = this._filmStripModel.frameByTimest amp(screenshotTime);
980 if (filmStripFrame && filmStripFrame.timestamp - frame.endTime > 10)
981 filmStripFrame = null;
982 this.showInDetails(
983 WebInspector.TimelineUIUtils.generateDetailsContentForFrame(this._fr ameModel, frame, filmStripFrame));
984 if (frame.layerTree) {
985 var layersView = this._layersView();
986 layersView.showLayerTree(frame.layerTree);
987 if (!this._detailsView.hasTab(WebInspector.TimelinePanel.DetailsTab.La yerViewer))
988 this._detailsView.appendTab(
989 WebInspector.TimelinePanel.DetailsTab.LayerViewer, WebInspector. UIString('Layers'), layersView);
990 }
991 break;
992 case WebInspector.TimelineSelection.Type.NetworkRequest:
993 var request = /** @type {!WebInspector.TimelineModel.NetworkRequest} */ (this._selection.object());
994 WebInspector.TimelineUIUtils.buildNetworkRequestDetails(request, this._m odel, this._detailsLinkifier)
995 .then(this.showInDetails.bind(this));
996 break;
997 case WebInspector.TimelineSelection.Type.Range:
998 this._updateSelectedRangeStats(this._selection._startTime, this._selecti on._endTime);
999 break;
1000 }
1001
1002 this._detailsView.updateContents(this._selection);
1003 }
1004
1005 /**
1006 * @param {!WebInspector.TimelineSelection} selection
1007 * @return {?WebInspector.TimelineFrame}
1008 */
1009 _frameForSelection(selection) {
1010 switch (selection.type()) {
1011 case WebInspector.TimelineSelection.Type.Frame:
1012 return /** @type {!WebInspector.TimelineFrame} */ (selection.object());
1013 case WebInspector.TimelineSelection.Type.Range:
1014 return null;
1015 case WebInspector.TimelineSelection.Type.TraceEvent:
1016 return this._frameModel.filteredFrames(selection._endTime, selection._en dTime)[0];
1017 default:
1018 console.assert(false, 'Should never be reached');
1019 return null;
1020 }
1021 }
1022
1023 /**
1024 * @param {number} offset
1025 */
1026 _jumpToFrame(offset) {
1027 var currentFrame = this._frameForSelection(this._selection);
1028 if (!currentFrame)
1029 return;
1030 var frames = this._frameModel.frames();
1031 var index = frames.indexOf(currentFrame);
1032 console.assert(index >= 0, 'Can\'t find current frame in the frame list');
1033 index = Number.constrain(index + offset, 0, frames.length - 1);
1034 var frame = frames[index];
1035 this._revealTimeRange(frame.startTime, frame.endTime);
1036 this.select(WebInspector.TimelineSelection.fromFrame(frame));
1037 return true;
1038 }
1039
1040 /**
1041 * @param {!WebInspector.PaintProfilerSnapshot} snapshot
1042 */
1043 _showSnapshotInPaintProfiler(snapshot) {
1044 var paintProfilerView = this._paintProfilerView();
1045 var hasProfileData = paintProfilerView.setSnapshot(snapshot);
1046 if (!this._detailsView.hasTab(WebInspector.TimelinePanel.DetailsTab.PaintPro filer))
1047 this._detailsView.appendTab(
1048 WebInspector.TimelinePanel.DetailsTab.PaintProfiler, WebInspector.UISt ring('Paint Profiler'),
1049 paintProfilerView, undefined, undefined, true);
1050 this._detailsView.selectTab(WebInspector.TimelinePanel.DetailsTab.PaintProfi ler, true);
1051 }
1052
1053 /**
1054 * @param {!WebInspector.TracingModel.Event} event
1055 * @param {!Node} content
1056 */
1057 _appendDetailsTabsForTraceEventAndShowDetails(event, content) {
1058 this.showInDetails(content);
1059 if (event.name === WebInspector.TimelineModel.RecordType.Paint ||
1060 event.name === WebInspector.TimelineModel.RecordType.RasterTask)
1061 this._showEventInPaintProfiler(event);
1062 }
1063
1064 /**
1065 * @param {!WebInspector.TracingModel.Event} event
1066 */
1067 _showEventInPaintProfiler(event) {
1068 var target = WebInspector.targetManager.mainTarget();
1069 if (!target)
1070 return;
1071 var paintProfilerView = this._paintProfilerView();
1072 var hasProfileData = paintProfilerView.setEvent(target, event);
1073 if (!hasProfileData)
1074 return;
1075 if (!this._detailsView.hasTab(WebInspector.TimelinePanel.DetailsTab.PaintPro filer))
1076 this._detailsView.appendTab(
1077 WebInspector.TimelinePanel.DetailsTab.PaintProfiler, WebInspector.UISt ring('Paint Profiler'),
1078 paintProfilerView, undefined, undefined, false);
1079 }
1080
1081 /**
1082 * @param {number} startTime
1083 * @param {number} endTime
1084 */
1085 _updateSelectedRangeStats(startTime, endTime) {
1086 this.showInDetails(WebInspector.TimelineUIUtils.buildRangeStats(this._model, startTime, endTime));
1087 }
1088
1089 /**
1090 * @override
1091 * @param {?WebInspector.TimelineSelection} selection
1092 * @param {!WebInspector.TimelinePanel.DetailsTab=} preferredTab
1093 */
1094 select(selection, preferredTab) {
1095 if (!selection)
1096 selection = WebInspector.TimelineSelection.fromRange(this._windowStartTime , this._windowEndTime);
1097 this._selection = selection;
1098 this._detailsLinkifier.reset();
1099 if (preferredTab)
1100 this._detailsView.setPreferredTab(preferredTab);
1101
1102 for (var view of this._currentViews)
1103 view.setSelection(selection);
1104 this._updateSelectionDetails();
1105 }
1106
1107 /**
1108 * @override
1109 * @param {number} time
1110 */
1111 selectEntryAtTime(time) {
1112 var events = this._model.mainThreadEvents();
1113 // Find best match, then backtrack to the first visible entry.
1114 for (var index = events.upperBound(time, (time, event) => time - event.start Time) - 1; index >= 0; --index) {
1115 var event = events[index];
1116 var endTime = event.endTime || event.startTime;
1117 if (WebInspector.TracingModel.isTopLevelEvent(event) && endTime < time)
1118 break;
1119 if (WebInspector.TimelineModel.isVisible(this._filters, event) && endTime >= time) {
1120 this.select(WebInspector.TimelineSelection.fromTraceEvent(event));
1121 return;
1122 }
1123 }
1124 this.select(null);
1125 }
1126
1127 /**
1128 * @override
1129 * @param {?WebInspector.TracingModel.Event} event
1130 */
1131 highlightEvent(event) {
1132 for (var view of this._currentViews)
1133 view.highlightEvent(event);
1134 }
1135
1136 /**
1137 * @param {number} startTime
1138 * @param {number} endTime
1139 */
1140 _revealTimeRange(startTime, endTime) {
1141 var timeShift = 0;
1142 if (this._windowEndTime < endTime)
1143 timeShift = endTime - this._windowEndTime;
1144 else if (this._windowStartTime > startTime)
1145 timeShift = startTime - this._windowStartTime;
1146 if (timeShift)
1147 this.requestWindowTimes(this._windowStartTime + timeShift, this._windowEnd Time + timeShift);
1148 }
1149
1150 /**
1151 * @override
1152 * @param {!Node} node
1153 */
1154 showInDetails(node) {
1155 this._detailsView.setContent(node);
1156 }
1157
1158 /**
1159 * @param {!DataTransfer} dataTransfer
1160 */
1161 _handleDrop(dataTransfer) {
1162 var items = dataTransfer.items;
1163 if (!items.length)
1164 return;
1165 var item = items[0];
1166 if (item.kind === 'string') {
1167 var url = dataTransfer.getData('text/uri-list');
1168 if (new WebInspector.ParsedURL(url).isValid)
1169 this._loadFromURL(url);
1170 } else if (item.kind === 'file') {
1171 var entry = items[0].webkitGetAsEntry();
1172 if (!entry.isFile)
1173 return;
1174 entry.file(this._loadFromFile.bind(this));
1175 }
1176 }
1177
1178 _setAutoWindowTimes() {
1179 var tasks = this._model.mainThreadTasks();
1180 if (!tasks.length) {
1181 this.requestWindowTimes(this._tracingModel.minimumRecordTime(), this._trac ingModel.maximumRecordTime());
1182 return;
1183 }
1184 /**
1185 * @param {number} startIndex
1186 * @param {number} stopIndex
1187 * @return {number}
1188 */
1189 function findLowUtilizationRegion(startIndex, stopIndex) {
1190 var /** @const */ threshold = 0.1;
1191 var cutIndex = startIndex;
1192 var cutTime = (tasks[cutIndex].startTime() + tasks[cutIndex].endTime()) / 2;
1193 var usedTime = 0;
1194 var step = Math.sign(stopIndex - startIndex);
1195 for (var i = startIndex; i !== stopIndex; i += step) {
1196 var task = tasks[i];
1197 var taskTime = (task.startTime() + task.endTime()) / 2;
1198 var interval = Math.abs(cutTime - taskTime);
1199 if (usedTime < threshold * interval) {
1200 cutIndex = i;
1201 cutTime = taskTime;
1202 usedTime = 0;
1203 }
1204 usedTime += task.endTime() - task.startTime();
1205 }
1206 return cutIndex;
1207 }
1208 var rightIndex = findLowUtilizationRegion(tasks.length - 1, 0);
1209 var leftIndex = findLowUtilizationRegion(0, rightIndex);
1210 var leftTime = tasks[leftIndex].startTime();
1211 var rightTime = tasks[rightIndex].endTime();
1212 var span = rightTime - leftTime;
1213 var totalSpan = this._tracingModel.maximumRecordTime() - this._tracingModel. minimumRecordTime();
1214 if (span < totalSpan * 0.1) {
1215 leftTime = this._tracingModel.minimumRecordTime();
1216 rightTime = this._tracingModel.maximumRecordTime();
1217 } else {
1218 leftTime = Math.max(leftTime - 0.05 * span, this._tracingModel.minimumReco rdTime());
1219 rightTime = Math.min(rightTime + 0.05 * span, this._tracingModel.maximumRe cordTime());
1220 }
1221 this.requestWindowTimes(leftTime, rightTime);
1222 }
126 }; 1223 };
127 1224
128 /** 1225 /**
129 * @enum {string} 1226 * @enum {string}
130 */ 1227 */
131 WebInspector.TimelinePanel.Perspectives = { 1228 WebInspector.TimelinePanel.Perspectives = {
132 Load: "Load", 1229 Load: 'Load',
133 Responsiveness: "Responsiveness", 1230 Responsiveness: 'Responsiveness',
134 Custom: "Custom" 1231 Custom: 'Custom'
135 }; 1232 };
136 1233
137 /** 1234 /**
138 * @enum {string} 1235 * @enum {string}
139 */ 1236 */
140 WebInspector.TimelinePanel.DetailsTab = { 1237 WebInspector.TimelinePanel.DetailsTab = {
141 Details: "Details", 1238 Details: 'Details',
142 Events: "Events", 1239 Events: 'Events',
143 CallTree: "CallTree", 1240 CallTree: 'CallTree',
144 BottomUp: "BottomUp", 1241 BottomUp: 'BottomUp',
145 PaintProfiler: "PaintProfiler", 1242 PaintProfiler: 'PaintProfiler',
146 LayerViewer: "LayerViewer" 1243 LayerViewer: 'LayerViewer'
147 }; 1244 };
148 1245
149 /** 1246 /**
150 * @enum {symbol} 1247 * @enum {symbol}
151 */ 1248 */
152 WebInspector.TimelinePanel.State = { 1249 WebInspector.TimelinePanel.State = {
153 Idle: Symbol("Idle"), 1250 Idle: Symbol('Idle'),
154 StartPending: Symbol("StartPending"), 1251 StartPending: Symbol('StartPending'),
155 Recording: Symbol("Recording"), 1252 Recording: Symbol('Recording'),
156 StopPending: Symbol("StopPending"), 1253 StopPending: Symbol('StopPending'),
157 Loading: Symbol("Loading") 1254 Loading: Symbol('Loading')
158 }; 1255 };
159 1256
160 // Define row and header height, should be in sync with styles for timeline grap hs. 1257 // Define row and header height, should be in sync with styles for timeline grap hs.
161 WebInspector.TimelinePanel.rowHeight = 18; 1258 WebInspector.TimelinePanel.rowHeight = 18;
162 WebInspector.TimelinePanel.headerHeight = 20; 1259 WebInspector.TimelinePanel.headerHeight = 20;
163 1260
164 WebInspector.TimelinePanel.prototype = {
165 /**
166 * @override
167 * @return {?WebInspector.SearchableView}
168 */
169 searchableView: function()
170 {
171 return this._searchableView;
172 },
173
174 wasShown: function()
175 {
176 WebInspector.context.setFlavor(WebInspector.TimelinePanel, this);
177 },
178
179 willHide: function()
180 {
181 WebInspector.context.setFlavor(WebInspector.TimelinePanel, null);
182 },
183
184 /**
185 * @return {number}
186 */
187 windowStartTime: function()
188 {
189 if (this._windowStartTime)
190 return this._windowStartTime;
191 return this._model.minimumRecordTime();
192 },
193
194 /**
195 * @return {number}
196 */
197 windowEndTime: function()
198 {
199 if (this._windowEndTime < Infinity)
200 return this._windowEndTime;
201 return this._model.maximumRecordTime() || Infinity;
202 },
203
204 /**
205 * @param {!WebInspector.Event} event
206 */
207 _onWindowChanged: function(event)
208 {
209 this._windowStartTime = event.data.startTime;
210 this._windowEndTime = event.data.endTime;
211
212 for (var i = 0; i < this._currentViews.length; ++i)
213 this._currentViews[i].setWindowTimes(this._windowStartTime, this._wi ndowEndTime);
214
215 if (!this._selection || this._selection.type() === WebInspector.Timeline Selection.Type.Range)
216 this.select(null);
217 },
218
219 /**
220 * @param {!WebInspector.Event} event
221 */
222 _onOverviewSelectionChanged: function(event)
223 {
224 var selection = /** @type {!WebInspector.TimelineSelection} */ (event.da ta);
225 this.select(selection);
226 },
227
228 /**
229 * @override
230 * @param {number} windowStartTime
231 * @param {number} windowEndTime
232 */
233 requestWindowTimes: function(windowStartTime, windowEndTime)
234 {
235 this._overviewPane.requestWindowTimes(windowStartTime, windowEndTime);
236 },
237
238 /**
239 * @return {!WebInspector.Widget}
240 */
241 _layersView: function()
242 {
243 if (this._lazyLayersView)
244 return this._lazyLayersView;
245 this._lazyLayersView = new WebInspector.TimelineLayersView(this._model, this._showSnapshotInPaintProfiler.bind(this));
246 return this._lazyLayersView;
247 },
248
249 _paintProfilerView: function()
250 {
251 if (this._lazyPaintProfilerView)
252 return this._lazyPaintProfilerView;
253 this._lazyPaintProfilerView = new WebInspector.TimelinePaintProfilerView (this._frameModel);
254 return this._lazyPaintProfilerView;
255 },
256
257 /**
258 * @param {!WebInspector.TimelineModeView} modeView
259 */
260 _addModeView: function(modeView)
261 {
262 modeView.setWindowTimes(this.windowStartTime(), this.windowEndTime());
263 modeView.refreshRecords();
264 var splitWidget = this._stackView.appendView(modeView.view(), "timelineP anelTimelineStackSplitViewState", undefined, 112);
265 var resizer = modeView.resizerElement();
266 if (splitWidget && resizer) {
267 splitWidget.hideDefaultResizer();
268 splitWidget.installResizer(resizer);
269 }
270 this._currentViews.push(modeView);
271 },
272
273 _removeAllModeViews: function()
274 {
275 this._currentViews.forEach(view => view.dispose());
276 this._currentViews = [];
277 this._stackView.detachChildWidgets();
278 },
279
280 /**
281 * @param {!WebInspector.TimelinePanel.State} state
282 */
283 _setState: function(state)
284 {
285 this._state = state;
286 this._updateTimelineControls();
287 },
288
289 /**
290 * @param {string} name
291 * @param {!WebInspector.Setting} setting
292 * @param {string} tooltip
293 * @return {!WebInspector.ToolbarItem}
294 */
295 _createSettingCheckbox: function(name, setting, tooltip)
296 {
297 if (!this._recordingOptionUIControls)
298 this._recordingOptionUIControls = [];
299 var checkboxItem = new WebInspector.ToolbarCheckbox(name, tooltip, setti ng);
300 this._recordingOptionUIControls.push(checkboxItem);
301 return checkboxItem;
302 },
303
304 _createToolbarItems: function()
305 {
306 this._panelToolbar.removeToolbarItems();
307
308 var perspectiveSetting = WebInspector.settings.createSetting("timelinePe rspective", WebInspector.TimelinePanel.Perspectives.Load);
309 if (Runtime.experiments.isEnabled("timelineRecordingPerspectives")) {
310 /**
311 * @this {!WebInspector.TimelinePanel}
312 */
313 function onPerspectiveChanged()
314 {
315 perspectiveSetting.set(perspectiveCombobox.selectElement().value );
316 this._createToolbarItems();
317 }
318
319 /**
320 * @param {string} id
321 * @param {string} title
322 */
323 function addPerspectiveOption(id, title)
324 {
325 var option = perspectiveCombobox.createOption(title, "", id);
326 perspectiveCombobox.addOption(option);
327 if (id === perspectiveSetting.get())
328 perspectiveCombobox.select(option);
329 }
330
331 var perspectiveCombobox = new WebInspector.ToolbarComboBox(onPerspec tiveChanged.bind(this));
332 addPerspectiveOption(WebInspector.TimelinePanel.Perspectives.Load, W ebInspector.UIString("Page Load"));
333 addPerspectiveOption(WebInspector.TimelinePanel.Perspectives.Respons iveness, WebInspector.UIString("Responsiveness"));
334 addPerspectiveOption(WebInspector.TimelinePanel.Perspectives.Custom, WebInspector.UIString("Custom"));
335 this._panelToolbar.appendToolbarItem(perspectiveCombobox);
336
337 switch (perspectiveSetting.get()) {
338 case WebInspector.TimelinePanel.Perspectives.Load:
339 this._captureNetworkSetting.set(true);
340 this._captureJSProfileSetting.set(true);
341 this._captureMemorySetting.set(false);
342 this._captureLayersAndPicturesSetting.set(false);
343 this._captureFilmStripSetting.set(true);
344 break;
345 case WebInspector.TimelinePanel.Perspectives.Responsiveness:
346 this._captureNetworkSetting.set(true);
347 this._captureJSProfileSetting.set(true);
348 this._captureMemorySetting.set(false);
349 this._captureLayersAndPicturesSetting.set(false);
350 this._captureFilmStripSetting.set(false);
351 break;
352 }
353 }
354 if (Runtime.experiments.isEnabled("timelineRecordingPerspectives") && pe rspectiveSetting.get() === WebInspector.TimelinePanel.Perspectives.Load) {
355 this._reloadButton = new WebInspector.ToolbarButton(WebInspector.UIS tring("Record & Reload"), "refresh-toolbar-item");
356 this._reloadButton.addEventListener("click", () => WebInspector.targ etManager.reloadPage());
357 this._panelToolbar.appendToolbarItem(this._reloadButton);
358 } else {
359 this._panelToolbar.appendToolbarItem(WebInspector.Toolbar.createActi onButton(this._toggleRecordAction));
360 }
361
362 this._updateTimelineControls();
363 var clearButton = new WebInspector.ToolbarButton(WebInspector.UIString(" Clear recording"), "clear-toolbar-item");
364 clearButton.addEventListener("click", this._clear, this);
365 this._panelToolbar.appendToolbarItem(clearButton);
366
367 this._panelToolbar.appendSeparator();
368
369 this._panelToolbar.appendText(WebInspector.UIString("Capture:"));
370
371 var screenshotCheckbox = this._createSettingCheckbox(
372 WebInspector.UIString("Screenshots"), this._captureFilmStripSetting, WebInspector.UIString("Capture screenshots while recording. (Has small performa nce overhead)"));
373
374 if (!Runtime.experiments.isEnabled("timelineRecordingPerspectives") || p erspectiveSetting.get() === WebInspector.TimelinePanel.Perspectives.Custom) {
375 this._panelToolbar.appendToolbarItem(this._createSettingCheckbox(
376 WebInspector.UIString("Network"), this._captureNetworkSetting, W ebInspector.UIString("Show network requests information")));
377 this._panelToolbar.appendToolbarItem(this._createSettingCheckbox(
378 WebInspector.UIString("JS Profile"), this._captureJSProfileSetti ng, WebInspector.UIString("Capture JavaScript stacks with sampling profiler. (Ha s small performance overhead)")));
379 this._panelToolbar.appendToolbarItem(screenshotCheckbox);
380 this._panelToolbar.appendToolbarItem(this._createSettingCheckbox(
381 WebInspector.UIString("Memory"), this._captureMemorySetting, Web Inspector.UIString("Capture memory information on every timeline event.")));
382 this._panelToolbar.appendToolbarItem(this._createSettingCheckbox(
383 WebInspector.UIString("Paint"), this._captureLayersAndPicturesSe tting, WebInspector.UIString("Capture graphics layer positions and rasterization draw calls. (Has large performance overhead)")));
384 } else {
385 this._panelToolbar.appendToolbarItem(screenshotCheckbox);
386 }
387
388 this._captureNetworkSetting.addChangeListener(this._onNetworkChanged, th is);
389 this._captureMemorySetting.addChangeListener(this._onModeChanged, this);
390 this._captureFilmStripSetting.addChangeListener(this._onModeChanged, thi s);
391
392 this._panelToolbar.appendSeparator();
393 var garbageCollectButton = new WebInspector.ToolbarButton(WebInspector.U IString("Collect garbage"), "garbage-collect-toolbar-item");
394 garbageCollectButton.addEventListener("click", this._garbageCollectButto nClicked, this);
395 this._panelToolbar.appendToolbarItem(garbageCollectButton);
396
397 this._panelToolbar.appendSeparator();
398 this._cpuThrottlingCombobox = new WebInspector.ToolbarComboBox(this._onC PUThrottlingChanged.bind(this));
399 this._panelToolbar.appendToolbarItem(this._cpuThrottlingCombobox);
400 this._populateCPUThrottingCombobox();
401 },
402
403 _populateCPUThrottingCombobox: function()
404 {
405 var cpuThrottlingCombobox = this._cpuThrottlingCombobox;
406 cpuThrottlingCombobox.removeOptions();
407 var currentRate = this._cpuThrottlingManager.rate();
408 var hasSelection = false;
409 /**
410 * @param {string} name
411 * @param {number} value
412 */
413 function addGroupingOption(name, value)
414 {
415 var option = cpuThrottlingCombobox.createOption(name, "", String(val ue));
416 cpuThrottlingCombobox.addOption(option);
417 if (hasSelection || (value && value !== currentRate))
418 return;
419 cpuThrottlingCombobox.select(option);
420 hasSelection = true;
421 }
422 var predefinedRates = new Map([
423 [1, WebInspector.UIString("No CPU throttling")],
424 [2, WebInspector.UIString("High end device (2\xD7 slowdown)")],
425 [5, WebInspector.UIString("Low end device (5\xD7 slowdown)")]
426 ]);
427 for (var rate of predefinedRates)
428 addGroupingOption(rate[1], rate[0]);
429 if (this._customCPUThrottlingRate && !predefinedRates.has(this._customCP UThrottlingRate))
430 addGroupingOption(WebInspector.UIString("Custom rate (%d\xD7 slowdow n)", this._customCPUThrottlingRate), this._customCPUThrottlingRate);
431 addGroupingOption(WebInspector.UIString("Set custom rate\u2026"), 0);
432 },
433
434 _prepareToLoadTimeline: function()
435 {
436 console.assert(this._state === WebInspector.TimelinePanel.State.Idle);
437 this._setState(WebInspector.TimelinePanel.State.Loading);
438 },
439
440 _createFileSelector: function()
441 {
442 if (this._fileSelectorElement)
443 this._fileSelectorElement.remove();
444 this._fileSelectorElement = WebInspector.createFileSelectorElement(this. _loadFromFile.bind(this));
445 this.element.appendChild(this._fileSelectorElement);
446 },
447
448 /**
449 * @param {!Event} event
450 */
451 _contextMenu: function(event)
452 {
453 var contextMenu = new WebInspector.ContextMenu(event);
454 contextMenu.appendItemsAtLocation("timelineMenu");
455 contextMenu.show();
456 },
457
458 /**
459 * @return {boolean}
460 */
461 _saveToFile: function()
462 {
463 if (this._state !== WebInspector.TimelinePanel.State.Idle)
464 return true;
465 if (this._model.isEmpty())
466 return true;
467
468 var now = new Date();
469 var fileName = "TimelineRawData-" + now.toISO8601Compact() + ".json";
470 var stream = new WebInspector.FileOutputStream();
471
472 /**
473 * @param {boolean} accepted
474 * @this {WebInspector.TimelinePanel}
475 */
476 function callback(accepted)
477 {
478 if (!accepted)
479 return;
480 var saver = new WebInspector.TracingTimelineSaver();
481 this._tracingModelBackingStorage.writeToStream(stream, saver);
482 }
483 stream.open(fileName, callback.bind(this));
484 return true;
485 },
486
487 /**
488 * @return {boolean}
489 */
490 _selectFileToLoad: function()
491 {
492 this._fileSelectorElement.click();
493 return true;
494 },
495
496 /**
497 * @param {!File} file
498 */
499 _loadFromFile: function(file)
500 {
501 if (this._state !== WebInspector.TimelinePanel.State.Idle)
502 return;
503 this._prepareToLoadTimeline();
504 this._loader = WebInspector.TimelineLoader.loadFromFile(this._tracingMod el, file, this);
505 this._createFileSelector();
506 },
507
508 /**
509 * @param {string} url
510 */
511 _loadFromURL: function(url)
512 {
513 if (this._state !== WebInspector.TimelinePanel.State.Idle)
514 return;
515 this._prepareToLoadTimeline();
516 this._loader = WebInspector.TimelineLoader.loadFromURL(this._tracingMode l, url, this);
517 },
518
519 _refreshViews: function()
520 {
521 for (var i = 0; i < this._currentViews.length; ++i) {
522 var view = this._currentViews[i];
523 view.refreshRecords();
524 }
525 this._updateSelectionDetails();
526 },
527
528 _onModeChanged: function()
529 {
530 // Set up overview controls.
531 this._overviewControls = [];
532 this._overviewControls.push(new WebInspector.TimelineEventOverview.Respo nsiveness(this._model, this._frameModel));
533 if (Runtime.experiments.isEnabled("inputEventsOnTimelineOverview"))
534 this._overviewControls.push(new WebInspector.TimelineEventOverview.I nput(this._model));
535 this._overviewControls.push(new WebInspector.TimelineEventOverview.Frame s(this._model, this._frameModel));
536 this._overviewControls.push(new WebInspector.TimelineEventOverview.CPUAc tivity(this._model));
537 this._overviewControls.push(new WebInspector.TimelineEventOverview.Netwo rk(this._model));
538 if (this._captureFilmStripSetting.get())
539 this._overviewControls.push(new WebInspector.TimelineFilmStripOvervi ew(this._model, this._filmStripModel));
540 if (this._captureMemorySetting.get())
541 this._overviewControls.push(new WebInspector.TimelineEventOverview.M emory(this._model));
542 this._overviewPane.setOverviewControls(this._overviewControls);
543
544 // Set up the main view.
545 this._removeAllModeViews();
546 this._flameChart = new WebInspector.TimelineFlameChartView(this, this._m odel, this._frameModel, this._irModel, this._filters);
547 this._flameChart.enableNetworkPane(this._captureNetworkSetting.get());
548 this._addModeView(this._flameChart);
549
550 if (this._captureMemorySetting.get())
551 this._addModeView(new WebInspector.MemoryCountersGraph(this, this._m odel, [WebInspector.TimelineUIUtils.visibleEventsFilter()]));
552
553 this.doResize();
554 this.select(null);
555 },
556
557 _onNetworkChanged: function()
558 {
559 if (this._flameChart)
560 this._flameChart.enableNetworkPane(this._captureNetworkSetting.get() , true);
561 },
562
563 _onCPUThrottlingChanged: function()
564 {
565 if (!this._cpuThrottlingManager)
566 return;
567 var value = this._cpuThrottlingCombobox.selectedOption().value;
568 var isLastOption = this._cpuThrottlingCombobox.selectedIndex() === this. _cpuThrottlingCombobox.size() - 1;
569 this._populateCPUThrottingCombobox();
570 var resultPromise = isLastOption
571 ? WebInspector.TimelinePanel.CustomCPUThrottlingRateDialog.show(this ._cpuThrottlingCombobox.element)
572 : Promise.resolve(value);
573 resultPromise.then(text => {
574 var value = Number.parseFloat(text);
575 if (value >= 1) {
576 if (isLastOption)
577 this._customCPUThrottlingRate = value;
578 this._cpuThrottlingManager.setRate(value);
579 this._populateCPUThrottingCombobox();
580 }
581 });
582 },
583
584 /**
585 * @param {boolean} enabled
586 */
587 _setUIControlsEnabled: function(enabled)
588 {
589 /**
590 * @param {!WebInspector.ToolbarButton} toolbarButton
591 */
592 function handler(toolbarButton)
593 {
594 toolbarButton.setEnabled(enabled);
595 }
596 this._recordingOptionUIControls.forEach(handler);
597 },
598
599 /**
600 * @param {boolean} userInitiated
601 */
602 _startRecording: function(userInitiated)
603 {
604 console.assert(!this._statusPane, "Status pane is already opened.");
605 var mainTarget = WebInspector.targetManager.mainTarget();
606 if (!mainTarget)
607 return;
608 this._setState(WebInspector.TimelinePanel.State.StartPending);
609 this._showRecordingStarted();
610
611 this._autoRecordGeneration = userInitiated ? null : Symbol("Generation") ;
612 this._controller = new WebInspector.TimelineController(mainTarget, this, this._tracingModel);
613 this._controller.startRecording(true, this._captureJSProfileSetting.get( ), this._captureMemorySetting.get(), this._captureLayersAndPicturesSetting.get() , this._captureFilmStripSetting && this._captureFilmStripSetting.get());
614
615 for (var i = 0; i < this._overviewControls.length; ++i)
616 this._overviewControls[i].timelineStarted();
617
618 if (userInitiated)
619 WebInspector.userMetrics.actionTaken(WebInspector.UserMetrics.Action .TimelineStarted);
620 this._setUIControlsEnabled(false);
621 this._hideRecordingHelpMessage();
622 },
623
624 _stopRecording: function()
625 {
626 if (this._statusPane) {
627 this._statusPane.finish();
628 this._statusPane.updateStatus(WebInspector.UIString("Stopping timeli ne\u2026"));
629 this._statusPane.updateProgressBar(WebInspector.UIString("Received") , 0);
630 }
631 this._setState(WebInspector.TimelinePanel.State.StopPending);
632 this._autoRecordGeneration = null;
633 this._controller.stopRecording();
634 this._controller = null;
635 this._setUIControlsEnabled(true);
636 },
637
638 _onSuspendStateChanged: function()
639 {
640 this._updateTimelineControls();
641 },
642
643 _updateTimelineControls: function()
644 {
645 var state = WebInspector.TimelinePanel.State;
646 this._toggleRecordAction.setToggled(this._state === state.Recording);
647 this._toggleRecordAction.setEnabled(this._state === state.Recording || t his._state === state.Idle);
648 this._panelToolbar.setEnabled(this._state !== state.Loading);
649 this._dropTarget.setEnabled(this._state === state.Idle);
650 },
651
652 _toggleRecording: function()
653 {
654 if (this._state === WebInspector.TimelinePanel.State.Idle)
655 this._startRecording(true);
656 else if (this._state === WebInspector.TimelinePanel.State.Recording)
657 this._stopRecording();
658 },
659
660 _garbageCollectButtonClicked: function()
661 {
662 var targets = WebInspector.targetManager.targets();
663 for (var i = 0; i < targets.length; ++i)
664 targets[i].heapProfilerAgent().collectGarbage();
665 },
666
667 _clear: function()
668 {
669 WebInspector.LineLevelProfile.instance().reset();
670 this._tracingModel.reset();
671 this._model.reset();
672 this._showRecordingHelpMessage();
673
674 this.requestWindowTimes(0, Infinity);
675 delete this._selection;
676 this._frameModel.reset();
677 this._filmStripModel.reset(this._tracingModel);
678 this._overviewPane.reset();
679 for (var i = 0; i < this._currentViews.length; ++i)
680 this._currentViews[i].reset();
681 for (var i = 0; i < this._overviewControls.length; ++i)
682 this._overviewControls[i].reset();
683 this.select(null);
684 this._detailsSplitWidget.hideSidebar();
685 },
686
687 /**
688 * @override
689 */
690 recordingStarted: function()
691 {
692 this._clear();
693 this._setState(WebInspector.TimelinePanel.State.Recording);
694 this._showRecordingStarted();
695 this._statusPane.updateStatus(WebInspector.UIString("Recording\u2026"));
696 this._statusPane.updateProgressBar(WebInspector.UIString("Buffer usage") , 0);
697 this._statusPane.startTimer();
698 this._hideRecordingHelpMessage();
699 },
700
701 /**
702 * @override
703 * @param {number} usage
704 */
705 recordingProgress: function(usage)
706 {
707 this._statusPane.updateProgressBar(WebInspector.UIString("Buffer usage") , usage * 100);
708 },
709
710 _showRecordingHelpMessage: function()
711 {
712 /**
713 * @param {string} tagName
714 * @param {string} contents
715 * @return {!Element}
716 */
717 function encloseWithTag(tagName, contents)
718 {
719 var e = createElement(tagName);
720 e.textContent = contents;
721 return e;
722 }
723
724 var recordNode = encloseWithTag("b", WebInspector.shortcutRegistry.short cutDescriptorsForAction("timeline.toggle-recording")[0].name);
725 var reloadNode = encloseWithTag("b", WebInspector.shortcutRegistry.short cutDescriptorsForAction("main.reload")[0].name);
726 var navigateNode = encloseWithTag("b", WebInspector.UIString("WASD (ZQSD )"));
727 var hintText = createElementWithClass("div");
728 hintText.appendChild(WebInspector.formatLocalized("To capture a new time line, click the record toolbar button or hit %s.", [recordNode]));
729 hintText.createChild("br");
730 hintText.appendChild(WebInspector.formatLocalized("To evaluate page load performance, hit %s to record the reload.", [reloadNode]));
731 hintText.createChild("p");
732 hintText.appendChild(WebInspector.formatLocalized("After recording, sele ct an area of interest in the overview by dragging.", []));
733 hintText.createChild("br");
734 hintText.appendChild(WebInspector.formatLocalized("Then, zoom and pan th e timeline with the mousewheel and %s keys.", [navigateNode]));
735 this._hideRecordingHelpMessage();
736 this._helpMessageElement = this._searchableView.element.createChild("div ", "full-widget-dimmed-banner timeline-status-pane");
737 this._helpMessageElement.appendChild(hintText);
738 },
739
740 _hideRecordingHelpMessage: function()
741 {
742 if (this._helpMessageElement)
743 this._helpMessageElement.remove();
744 delete this._helpMessageElement;
745 },
746
747 /**
748 * @override
749 */
750 loadingStarted: function()
751 {
752 this._hideRecordingHelpMessage();
753
754 if (this._statusPane)
755 this._statusPane.hide();
756 this._statusPane = new WebInspector.TimelinePanel.StatusPane(false, this ._cancelLoading.bind(this));
757 this._statusPane.showPane(this._statusPaneContainer);
758 this._statusPane.updateStatus(WebInspector.UIString("Loading timeline\u2 026"));
759 // FIXME: make loading from backend cancelable as well.
760 if (!this._loader)
761 this._statusPane.finish();
762 this.loadingProgress(0);
763 },
764
765 /**
766 * @override
767 * @param {number=} progress
768 */
769 loadingProgress: function(progress)
770 {
771 if (typeof progress === "number")
772 this._statusPane.updateProgressBar(WebInspector.UIString("Received") , progress * 100);
773 },
774
775 /**
776 * @override
777 * @param {boolean} success
778 */
779 loadingComplete: function(success)
780 {
781 var loadedFromFile = !!this._loader;
782 delete this._loader;
783 this._setState(WebInspector.TimelinePanel.State.Idle);
784
785 if (!success) {
786 this._statusPane.hide();
787 delete this._statusPane;
788 this._clear();
789 return;
790 }
791
792 if (this._statusPane)
793 this._statusPane.updateStatus(WebInspector.UIString("Processing time line\u2026"));
794 this._model.setEvents(this._tracingModel, loadedFromFile);
795 this._frameModel.reset();
796 this._frameModel.addTraceEvents(WebInspector.targetManager.mainTarget(), this._model.inspectedTargetEvents(), this._model.sessionId() || "");
797 this._filmStripModel.reset(this._tracingModel);
798 var groups = WebInspector.TimelineModel.AsyncEventGroup;
799 var asyncEventsByGroup = this._model.mainThreadAsyncEvents();
800 this._irModel.populate(asyncEventsByGroup.get(groups.input), asyncEvents ByGroup.get(groups.animation));
801 this._model.cpuProfiles().forEach(profile => WebInspector.LineLevelProfi le.instance().appendCPUProfile(profile));
802 if (this._statusPane)
803 this._statusPane.hide();
804 delete this._statusPane;
805 this._overviewPane.reset();
806 this._overviewPane.setBounds(this._model.minimumRecordTime(), this._mode l.maximumRecordTime());
807 this._setAutoWindowTimes();
808 this._refreshViews();
809 for (var i = 0; i < this._overviewControls.length; ++i)
810 this._overviewControls[i].timelineStopped();
811 this._setMarkers();
812 this._overviewPane.scheduleUpdate();
813 this._updateSearchHighlight(false, true);
814 this._detailsSplitWidget.showBoth();
815 },
816
817 _showRecordingStarted: function()
818 {
819 if (this._statusPane)
820 return;
821 this._statusPane = new WebInspector.TimelinePanel.StatusPane(true, this. _stopRecording.bind(this));
822 this._statusPane.showPane(this._statusPaneContainer);
823 this._statusPane.updateStatus(WebInspector.UIString("Initializing record ing\u2026"));
824 },
825
826 _cancelLoading: function()
827 {
828 if (this._loader)
829 this._loader.cancel();
830 },
831
832 _setMarkers: function()
833 {
834 var markers = new Map();
835 var recordTypes = WebInspector.TimelineModel.RecordType;
836 var zeroTime = this._model.minimumRecordTime();
837 for (var record of this._model.eventDividerRecords()) {
838 if (record.type() === recordTypes.TimeStamp || record.type() === rec ordTypes.ConsoleTime)
839 continue;
840 markers.set(record.startTime(), WebInspector.TimelineUIUtils.createD ividerForRecord(record, zeroTime, 0));
841 }
842 this._overviewPane.setMarkers(markers);
843 },
844
845 /**
846 * @param {!WebInspector.Event} event
847 */
848 _pageReloadRequested: function(event)
849 {
850 if (this._state !== WebInspector.TimelinePanel.State.Idle || !this.isSho wing())
851 return;
852 this._startRecording(false);
853 },
854
855 /**
856 * @param {!WebInspector.Event} event
857 */
858 _loadEventFired: function(event)
859 {
860 if (this._state !== WebInspector.TimelinePanel.State.Recording || !this. _autoRecordGeneration)
861 return;
862 setTimeout(stopRecordingOnReload.bind(this, this._autoRecordGeneration), this._millisecondsToRecordAfterLoadEvent);
863
864 /**
865 * @this {WebInspector.TimelinePanel}
866 * @param {!Object} recordGeneration
867 */
868 function stopRecordingOnReload(recordGeneration)
869 {
870 // Check if we're still in the same recording session.
871 if (this._state !== WebInspector.TimelinePanel.State.Recording || th is._autoRecordGeneration !== recordGeneration)
872 return;
873 this._stopRecording();
874 }
875 },
876
877 // WebInspector.Searchable implementation
878
879 /**
880 * @override
881 */
882 jumpToNextSearchResult: function()
883 {
884 if (!this._searchResults || !this._searchResults.length)
885 return;
886 var index = this._selectedSearchResult ? this._searchResults.indexOf(thi s._selectedSearchResult) : -1;
887 this._jumpToSearchResult(index + 1);
888 },
889
890 /**
891 * @override
892 */
893 jumpToPreviousSearchResult: function()
894 {
895 if (!this._searchResults || !this._searchResults.length)
896 return;
897 var index = this._selectedSearchResult ? this._searchResults.indexOf(thi s._selectedSearchResult) : 0;
898 this._jumpToSearchResult(index - 1);
899 },
900
901 /**
902 * @override
903 * @return {boolean}
904 */
905 supportsCaseSensitiveSearch: function()
906 {
907 return false;
908 },
909
910 /**
911 * @override
912 * @return {boolean}
913 */
914 supportsRegexSearch: function()
915 {
916 return false;
917 },
918
919 /**
920 * @param {number} index
921 */
922 _jumpToSearchResult: function(index)
923 {
924 this._selectSearchResult((index + this._searchResults.length) % this._se archResults.length);
925 this._currentViews[0].highlightSearchResult(this._selectedSearchResult, this._searchRegex, true);
926 },
927
928 /**
929 * @param {number} index
930 */
931 _selectSearchResult: function(index)
932 {
933 this._selectedSearchResult = this._searchResults[index];
934 this._searchableView.updateCurrentMatchIndex(index);
935 },
936
937 _clearHighlight: function()
938 {
939 this._currentViews[0].highlightSearchResult(null);
940 },
941
942 /**
943 * @param {boolean} revealRecord
944 * @param {boolean} shouldJump
945 * @param {boolean=} jumpBackwards
946 */
947 _updateSearchHighlight: function(revealRecord, shouldJump, jumpBackwards)
948 {
949 if (!this._searchRegex) {
950 this._clearHighlight();
951 return;
952 }
953
954 if (!this._searchResults)
955 this._updateSearchResults(shouldJump, jumpBackwards);
956 this._currentViews[0].highlightSearchResult(this._selectedSearchResult, this._searchRegex, revealRecord);
957 },
958
959 /**
960 * @param {boolean} shouldJump
961 * @param {boolean=} jumpBackwards
962 */
963 _updateSearchResults: function(shouldJump, jumpBackwards)
964 {
965 if (!this._searchRegex)
966 return;
967
968 // FIXME: search on all threads.
969 var events = this._model.mainThreadEvents();
970 var filters = this._filters.concat([new WebInspector.TimelineTextFilter( this._searchRegex)]);
971 var matches = [];
972 for (var index = events.lowerBound(this._windowStartTime, (time, event) => time - event.startTime); index < events.length; ++index) {
973 var event = events[index];
974 if (event.startTime > this._windowEndTime)
975 break;
976 if (WebInspector.TimelineModel.isVisible(filters, event))
977 matches.push(event);
978 }
979
980 var matchesCount = matches.length;
981 if (matchesCount) {
982 this._searchResults = matches;
983 this._searchableView.updateSearchMatchesCount(matchesCount);
984
985 var selectedIndex = matches.indexOf(this._selectedSearchResult);
986 if (shouldJump && selectedIndex === -1)
987 selectedIndex = jumpBackwards ? this._searchResults.length - 1 : 0;
988 this._selectSearchResult(selectedIndex);
989 } else {
990 this._searchableView.updateSearchMatchesCount(0);
991 delete this._selectedSearchResult;
992 }
993 },
994
995 /**
996 * @override
997 */
998 searchCanceled: function()
999 {
1000 this._clearHighlight();
1001 delete this._searchResults;
1002 delete this._selectedSearchResult;
1003 delete this._searchRegex;
1004 },
1005
1006 /**
1007 * @override
1008 * @param {!WebInspector.SearchableView.SearchConfig} searchConfig
1009 * @param {boolean} shouldJump
1010 * @param {boolean=} jumpBackwards
1011 */
1012 performSearch: function(searchConfig, shouldJump, jumpBackwards)
1013 {
1014 var query = searchConfig.query;
1015 this._searchRegex = createPlainTextSearchRegex(query, "i");
1016 delete this._searchResults;
1017 this._updateSearchHighlight(true, shouldJump, jumpBackwards);
1018 },
1019
1020 _updateSelectionDetails: function()
1021 {
1022 switch (this._selection.type()) {
1023 case WebInspector.TimelineSelection.Type.TraceEvent:
1024 var event = /** @type {!WebInspector.TracingModel.Event} */ (this._s election.object());
1025 WebInspector.TimelineUIUtils.buildTraceEventDetails(event, this._mod el, this._detailsLinkifier, true, this._appendDetailsTabsForTraceEventAndShowDet ails.bind(this, event));
1026 break;
1027 case WebInspector.TimelineSelection.Type.Frame:
1028 var frame = /** @type {!WebInspector.TimelineFrame} */ (this._select ion.object());
1029 var screenshotTime = frame.idle ? frame.startTime : frame.endTime; / / For idle frames, look at the state at the beginning of the frame.
1030 var filmStripFrame = filmStripFrame = this._filmStripModel.frameByTi mestamp(screenshotTime);
1031 if (filmStripFrame && filmStripFrame.timestamp - frame.endTime > 10)
1032 filmStripFrame = null;
1033 this.showInDetails(WebInspector.TimelineUIUtils.generateDetailsConte ntForFrame(this._frameModel, frame, filmStripFrame));
1034 if (frame.layerTree) {
1035 var layersView = this._layersView();
1036 layersView.showLayerTree(frame.layerTree);
1037 if (!this._detailsView.hasTab(WebInspector.TimelinePanel.Details Tab.LayerViewer))
1038 this._detailsView.appendTab(WebInspector.TimelinePanel.Detai lsTab.LayerViewer, WebInspector.UIString("Layers"), layersView);
1039 }
1040 break;
1041 case WebInspector.TimelineSelection.Type.NetworkRequest:
1042 var request = /** @type {!WebInspector.TimelineModel.NetworkRequest} */ (this._selection.object());
1043 WebInspector.TimelineUIUtils.buildNetworkRequestDetails(request, thi s._model, this._detailsLinkifier)
1044 .then(this.showInDetails.bind(this));
1045 break;
1046 case WebInspector.TimelineSelection.Type.Range:
1047 this._updateSelectedRangeStats(this._selection._startTime, this._sel ection._endTime);
1048 break;
1049 }
1050
1051 this._detailsView.updateContents(this._selection);
1052 },
1053
1054 /**
1055 * @param {!WebInspector.TimelineSelection} selection
1056 * @return {?WebInspector.TimelineFrame}
1057 */
1058 _frameForSelection: function(selection)
1059 {
1060 switch (selection.type()) {
1061 case WebInspector.TimelineSelection.Type.Frame:
1062 return /** @type {!WebInspector.TimelineFrame} */ (selection.object( ));
1063 case WebInspector.TimelineSelection.Type.Range:
1064 return null;
1065 case WebInspector.TimelineSelection.Type.TraceEvent:
1066 return this._frameModel.filteredFrames(selection._endTime, selection ._endTime)[0];
1067 default:
1068 console.assert(false, "Should never be reached");
1069 return null;
1070 }
1071 },
1072
1073 /**
1074 * @param {number} offset
1075 */
1076 _jumpToFrame: function(offset)
1077 {
1078 var currentFrame = this._frameForSelection(this._selection);
1079 if (!currentFrame)
1080 return;
1081 var frames = this._frameModel.frames();
1082 var index = frames.indexOf(currentFrame);
1083 console.assert(index >= 0, "Can't find current frame in the frame list") ;
1084 index = Number.constrain(index + offset, 0, frames.length - 1);
1085 var frame = frames[index];
1086 this._revealTimeRange(frame.startTime, frame.endTime);
1087 this.select(WebInspector.TimelineSelection.fromFrame(frame));
1088 return true;
1089 },
1090
1091 /**
1092 * @param {!WebInspector.PaintProfilerSnapshot} snapshot
1093 */
1094 _showSnapshotInPaintProfiler: function(snapshot)
1095 {
1096 var paintProfilerView = this._paintProfilerView();
1097 var hasProfileData = paintProfilerView.setSnapshot(snapshot);
1098 if (!this._detailsView.hasTab(WebInspector.TimelinePanel.DetailsTab.Pain tProfiler))
1099 this._detailsView.appendTab(WebInspector.TimelinePanel.DetailsTab.Pa intProfiler, WebInspector.UIString("Paint Profiler"), paintProfilerView, undefin ed, undefined, true);
1100 this._detailsView.selectTab(WebInspector.TimelinePanel.DetailsTab.PaintP rofiler, true);
1101 },
1102
1103 /**
1104 * @param {!WebInspector.TracingModel.Event} event
1105 * @param {!Node} content
1106 */
1107 _appendDetailsTabsForTraceEventAndShowDetails: function(event, content)
1108 {
1109 this.showInDetails(content);
1110 if (event.name === WebInspector.TimelineModel.RecordType.Paint || event. name === WebInspector.TimelineModel.RecordType.RasterTask)
1111 this._showEventInPaintProfiler(event);
1112 },
1113
1114 /**
1115 * @param {!WebInspector.TracingModel.Event} event
1116 */
1117 _showEventInPaintProfiler: function(event)
1118 {
1119 var target = WebInspector.targetManager.mainTarget();
1120 if (!target)
1121 return;
1122 var paintProfilerView = this._paintProfilerView();
1123 var hasProfileData = paintProfilerView.setEvent(target, event);
1124 if (!hasProfileData)
1125 return;
1126 if (!this._detailsView.hasTab(WebInspector.TimelinePanel.DetailsTab.Pain tProfiler))
1127 this._detailsView.appendTab(WebInspector.TimelinePanel.DetailsTab.Pa intProfiler, WebInspector.UIString("Paint Profiler"), paintProfilerView, undefin ed, undefined, false);
1128 },
1129
1130 /**
1131 * @param {number} startTime
1132 * @param {number} endTime
1133 */
1134 _updateSelectedRangeStats: function(startTime, endTime)
1135 {
1136 this.showInDetails(WebInspector.TimelineUIUtils.buildRangeStats(this._mo del, startTime, endTime));
1137 },
1138
1139 /**
1140 * @override
1141 * @param {?WebInspector.TimelineSelection} selection
1142 * @param {!WebInspector.TimelinePanel.DetailsTab=} preferredTab
1143 */
1144 select: function(selection, preferredTab)
1145 {
1146 if (!selection)
1147 selection = WebInspector.TimelineSelection.fromRange(this._windowSta rtTime, this._windowEndTime);
1148 this._selection = selection;
1149 this._detailsLinkifier.reset();
1150 if (preferredTab)
1151 this._detailsView.setPreferredTab(preferredTab);
1152
1153 for (var view of this._currentViews)
1154 view.setSelection(selection);
1155 this._updateSelectionDetails();
1156 },
1157
1158 /**
1159 * @override
1160 * @param {number} time
1161 */
1162 selectEntryAtTime: function(time)
1163 {
1164 var events = this._model.mainThreadEvents();
1165 // Find best match, then backtrack to the first visible entry.
1166 for (var index = events.upperBound(time, (time, event) => time - event.s tartTime) - 1; index >= 0; --index) {
1167 var event = events[index];
1168 var endTime = event.endTime || event.startTime;
1169 if (WebInspector.TracingModel.isTopLevelEvent(event) && endTime < ti me)
1170 break;
1171 if (WebInspector.TimelineModel.isVisible(this._filters, event) && en dTime >= time) {
1172 this.select(WebInspector.TimelineSelection.fromTraceEvent(event) );
1173 return;
1174 }
1175 }
1176 this.select(null);
1177 },
1178
1179 /**
1180 * @override
1181 * @param {?WebInspector.TracingModel.Event} event
1182 */
1183 highlightEvent: function(event)
1184 {
1185 for (var view of this._currentViews)
1186 view.highlightEvent(event);
1187 },
1188
1189 /**
1190 * @param {number} startTime
1191 * @param {number} endTime
1192 */
1193 _revealTimeRange: function(startTime, endTime)
1194 {
1195 var timeShift = 0;
1196 if (this._windowEndTime < endTime)
1197 timeShift = endTime - this._windowEndTime;
1198 else if (this._windowStartTime > startTime)
1199 timeShift = startTime - this._windowStartTime;
1200 if (timeShift)
1201 this.requestWindowTimes(this._windowStartTime + timeShift, this._win dowEndTime + timeShift);
1202 },
1203
1204 /**
1205 * @override
1206 * @param {!Node} node
1207 */
1208 showInDetails: function(node)
1209 {
1210 this._detailsView.setContent(node);
1211 },
1212
1213 /**
1214 * @param {!DataTransfer} dataTransfer
1215 */
1216 _handleDrop: function(dataTransfer)
1217 {
1218 var items = dataTransfer.items;
1219 if (!items.length)
1220 return;
1221 var item = items[0];
1222 if (item.kind === "string") {
1223 var url = dataTransfer.getData("text/uri-list");
1224 if (new WebInspector.ParsedURL(url).isValid)
1225 this._loadFromURL(url);
1226 } else if (item.kind === "file") {
1227 var entry = items[0].webkitGetAsEntry();
1228 if (!entry.isFile)
1229 return;
1230 entry.file(this._loadFromFile.bind(this));
1231 }
1232 },
1233
1234 _setAutoWindowTimes: function()
1235 {
1236 var tasks = this._model.mainThreadTasks();
1237 if (!tasks.length) {
1238 this.requestWindowTimes(this._tracingModel.minimumRecordTime(), this ._tracingModel.maximumRecordTime());
1239 return;
1240 }
1241 /**
1242 * @param {number} startIndex
1243 * @param {number} stopIndex
1244 * @return {number}
1245 */
1246 function findLowUtilizationRegion(startIndex, stopIndex)
1247 {
1248 var /** @const */ threshold = 0.1;
1249 var cutIndex = startIndex;
1250 var cutTime = (tasks[cutIndex].startTime() + tasks[cutIndex].endTime ()) / 2;
1251 var usedTime = 0;
1252 var step = Math.sign(stopIndex - startIndex);
1253 for (var i = startIndex; i !== stopIndex; i += step) {
1254 var task = tasks[i];
1255 var taskTime = (task.startTime() + task.endTime()) / 2;
1256 var interval = Math.abs(cutTime - taskTime);
1257 if (usedTime < threshold * interval) {
1258 cutIndex = i;
1259 cutTime = taskTime;
1260 usedTime = 0;
1261 }
1262 usedTime += task.endTime() - task.startTime();
1263 }
1264 return cutIndex;
1265 }
1266 var rightIndex = findLowUtilizationRegion(tasks.length - 1, 0);
1267 var leftIndex = findLowUtilizationRegion(0, rightIndex);
1268 var leftTime = tasks[leftIndex].startTime();
1269 var rightTime = tasks[rightIndex].endTime();
1270 var span = rightTime - leftTime;
1271 var totalSpan = this._tracingModel.maximumRecordTime() - this._tracingMo del.minimumRecordTime();
1272 if (span < totalSpan * 0.1) {
1273 leftTime = this._tracingModel.minimumRecordTime();
1274 rightTime = this._tracingModel.maximumRecordTime();
1275 } else {
1276 leftTime = Math.max(leftTime - 0.05 * span, this._tracingModel.minim umRecordTime());
1277 rightTime = Math.min(rightTime + 0.05 * span, this._tracingModel.max imumRecordTime());
1278 }
1279 this.requestWindowTimes(leftTime, rightTime);
1280 },
1281
1282 __proto__: WebInspector.Panel.prototype
1283 };
1284
1285 /** 1261 /**
1286 * @interface 1262 * @interface
1287 */ 1263 */
1288 WebInspector.TimelineLifecycleDelegate = function() 1264 WebInspector.TimelineLifecycleDelegate = function() {};
1289 { 1265
1266 WebInspector.TimelineLifecycleDelegate.prototype = {
1267 recordingStarted: function() {},
1268
1269 /**
1270 * @param {number} usage
1271 */
1272 recordingProgress: function(usage) {},
1273
1274 loadingStarted: function() {},
1275
1276 /**
1277 * @param {number=} progress
1278 */
1279 loadingProgress: function(progress) {},
1280
1281 /**
1282 * @param {boolean} success
1283 */
1284 loadingComplete: function(success) {},
1290 }; 1285 };
1291 1286
1292 WebInspector.TimelineLifecycleDelegate.prototype = {
1293 recordingStarted: function() {},
1294
1295 /**
1296 * @param {number} usage
1297 */
1298 recordingProgress: function(usage) {},
1299
1300 loadingStarted: function() {},
1301
1302 /**
1303 * @param {number=} progress
1304 */
1305 loadingProgress: function(progress) {},
1306
1307 /**
1308 * @param {boolean} success
1309 */
1310 loadingComplete: function(success) {},
1311 };
1312
1313
1314 /** 1287 /**
1315 * @constructor 1288 * @unrestricted
1316 * @extends {WebInspector.TabbedPane}
1317 * @param {!WebInspector.TimelineModel} timelineModel
1318 * @param {!Array<!WebInspector.TimelineModel.Filter>} filters
1319 * @param {!WebInspector.TimelineModeViewDelegate} delegate
1320 */ 1289 */
1321 WebInspector.TimelineDetailsView = function(timelineModel, filters, delegate) 1290 WebInspector.TimelineDetailsView = class extends WebInspector.TabbedPane {
1322 { 1291 /**
1323 WebInspector.TabbedPane.call(this); 1292 * @param {!WebInspector.TimelineModel} timelineModel
1324 this.element.classList.add("timeline-details"); 1293 * @param {!Array<!WebInspector.TimelineModel.Filter>} filters
1294 * @param {!WebInspector.TimelineModeViewDelegate} delegate
1295 */
1296 constructor(timelineModel, filters, delegate) {
1297 super();
1298 this.element.classList.add('timeline-details');
1325 1299
1326 var tabIds = WebInspector.TimelinePanel.DetailsTab; 1300 var tabIds = WebInspector.TimelinePanel.DetailsTab;
1327 this._defaultDetailsWidget = new WebInspector.VBox(); 1301 this._defaultDetailsWidget = new WebInspector.VBox();
1328 this._defaultDetailsWidget.element.classList.add("timeline-details-view"); 1302 this._defaultDetailsWidget.element.classList.add('timeline-details-view');
1329 this._defaultDetailsContentElement = this._defaultDetailsWidget.element.crea teChild("div", "timeline-details-view-body vbox"); 1303 this._defaultDetailsContentElement =
1330 this.appendTab(tabIds.Details, WebInspector.UIString("Summary"), this._defau ltDetailsWidget); 1304 this._defaultDetailsWidget.element.createChild('div', 'timeline-details- view-body vbox');
1305 this.appendTab(tabIds.Details, WebInspector.UIString('Summary'), this._defau ltDetailsWidget);
1331 this.setPreferredTab(tabIds.Details); 1306 this.setPreferredTab(tabIds.Details);
1332 1307
1333 /** @type Map<string, WebInspector.TimelineTreeView> */ 1308 /** @type Map<string, WebInspector.TimelineTreeView> */
1334 this._rangeDetailViews = new Map(); 1309 this._rangeDetailViews = new Map();
1335 1310
1336 var bottomUpView = new WebInspector.BottomUpTimelineTreeView(timelineModel, filters); 1311 var bottomUpView = new WebInspector.BottomUpTimelineTreeView(timelineModel, filters);
1337 this.appendTab(tabIds.BottomUp, WebInspector.UIString("Bottom-Up"), bottomUp View); 1312 this.appendTab(tabIds.BottomUp, WebInspector.UIString('Bottom-Up'), bottomUp View);
1338 this._rangeDetailViews.set(tabIds.BottomUp, bottomUpView); 1313 this._rangeDetailViews.set(tabIds.BottomUp, bottomUpView);
1339 1314
1340 var callTreeView = new WebInspector.CallTreeTimelineTreeView(timelineModel, filters); 1315 var callTreeView = new WebInspector.CallTreeTimelineTreeView(timelineModel, filters);
1341 this.appendTab(tabIds.CallTree, WebInspector.UIString("Call Tree"), callTree View); 1316 this.appendTab(tabIds.CallTree, WebInspector.UIString('Call Tree'), callTree View);
1342 this._rangeDetailViews.set(tabIds.CallTree, callTreeView); 1317 this._rangeDetailViews.set(tabIds.CallTree, callTreeView);
1343 1318
1344 var eventsView = new WebInspector.EventsTimelineTreeView(timelineModel, filt ers, delegate); 1319 var eventsView = new WebInspector.EventsTimelineTreeView(timelineModel, filt ers, delegate);
1345 this.appendTab(tabIds.Events, WebInspector.UIString("Event Log"), eventsView ); 1320 this.appendTab(tabIds.Events, WebInspector.UIString('Event Log'), eventsView );
1346 this._rangeDetailViews.set(tabIds.Events, eventsView); 1321 this._rangeDetailViews.set(tabIds.Events, eventsView);
1347 1322
1348 this.addEventListener(WebInspector.TabbedPane.Events.TabSelected, this._tabS elected, this); 1323 this.addEventListener(WebInspector.TabbedPane.Events.TabSelected, this._tabS elected, this);
1324 }
1325
1326 /**
1327 * @param {!Node} node
1328 */
1329 setContent(node) {
1330 var allTabs = this.otherTabs(WebInspector.TimelinePanel.DetailsTab.Details);
1331 for (var i = 0; i < allTabs.length; ++i) {
1332 if (!this._rangeDetailViews.has(allTabs[i]))
1333 this.closeTab(allTabs[i]);
1334 }
1335 this._defaultDetailsContentElement.removeChildren();
1336 this._defaultDetailsContentElement.appendChild(node);
1337 }
1338
1339 /**
1340 * @param {!WebInspector.TimelineSelection} selection
1341 */
1342 updateContents(selection) {
1343 this._selection = selection;
1344 var view = this.selectedTabId ? this._rangeDetailViews.get(this.selectedTabI d) : null;
1345 if (view)
1346 view.updateContents(selection);
1347 }
1348
1349 /**
1350 * @override
1351 * @param {string} id
1352 * @param {string} tabTitle
1353 * @param {!WebInspector.Widget} view
1354 * @param {string=} tabTooltip
1355 * @param {boolean=} userGesture
1356 * @param {boolean=} isCloseable
1357 */
1358 appendTab(id, tabTitle, view, tabTooltip, userGesture, isCloseable) {
1359 super.appendTab(id, tabTitle, view, tabTooltip, userGesture, isCloseable);
1360 if (this._preferredTabId !== this.selectedTabId)
1361 this.selectTab(id);
1362 }
1363
1364 /**
1365 * @param {string} tabId
1366 */
1367 setPreferredTab(tabId) {
1368 this._preferredTabId = tabId;
1369 }
1370
1371 /**
1372 * @param {!WebInspector.Event} event
1373 */
1374 _tabSelected(event) {
1375 if (!event.data.isUserGesture)
1376 return;
1377 this.setPreferredTab(event.data.tabId);
1378 this.updateContents(this._selection);
1379 }
1349 }; 1380 };
1350 1381
1351 WebInspector.TimelineDetailsView.prototype = {
1352 /**
1353 * @param {!Node} node
1354 */
1355 setContent: function(node)
1356 {
1357 var allTabs = this.otherTabs(WebInspector.TimelinePanel.DetailsTab.Detai ls);
1358 for (var i = 0; i < allTabs.length; ++i) {
1359 if (!this._rangeDetailViews.has(allTabs[i]))
1360 this.closeTab(allTabs[i]);
1361 }
1362 this._defaultDetailsContentElement.removeChildren();
1363 this._defaultDetailsContentElement.appendChild(node);
1364 },
1365
1366 /**
1367 * @param {!WebInspector.TimelineSelection} selection
1368 */
1369 updateContents: function(selection)
1370 {
1371 this._selection = selection;
1372 var view = this.selectedTabId ? this._rangeDetailViews.get(this.selected TabId) : null;
1373 if (view)
1374 view.updateContents(selection);
1375 },
1376
1377 /**
1378 * @override
1379 * @param {string} id
1380 * @param {string} tabTitle
1381 * @param {!WebInspector.Widget} view
1382 * @param {string=} tabTooltip
1383 * @param {boolean=} userGesture
1384 * @param {boolean=} isCloseable
1385 */
1386 appendTab: function(id, tabTitle, view, tabTooltip, userGesture, isCloseable )
1387 {
1388 WebInspector.TabbedPane.prototype.appendTab.call(this, id, tabTitle, vie w, tabTooltip, userGesture, isCloseable);
1389 if (this._preferredTabId !== this.selectedTabId)
1390 this.selectTab(id);
1391 },
1392
1393 /**
1394 * @param {string} tabId
1395 */
1396 setPreferredTab: function(tabId)
1397 {
1398 this._preferredTabId = tabId;
1399 },
1400
1401 /**
1402 * @param {!WebInspector.Event} event
1403 */
1404 _tabSelected: function(event)
1405 {
1406 if (!event.data.isUserGesture)
1407 return;
1408 this.setPreferredTab(event.data.tabId);
1409 this.updateContents(this._selection);
1410 },
1411
1412 __proto__: WebInspector.TabbedPane.prototype
1413 };
1414
1415 /** 1382 /**
1416 * @constructor 1383 * @unrestricted
1417 * @param {!WebInspector.TimelineSelection.Type} type
1418 * @param {number} startTime
1419 * @param {number} endTime
1420 * @param {!Object=} object
1421 */ 1384 */
1422 WebInspector.TimelineSelection = function(type, startTime, endTime, object) 1385 WebInspector.TimelineSelection = class {
1423 { 1386 /**
1387 * @param {!WebInspector.TimelineSelection.Type} type
1388 * @param {number} startTime
1389 * @param {number} endTime
1390 * @param {!Object=} object
1391 */
1392 constructor(type, startTime, endTime, object) {
1424 this._type = type; 1393 this._type = type;
1425 this._startTime = startTime; 1394 this._startTime = startTime;
1426 this._endTime = endTime; 1395 this._endTime = endTime;
1427 this._object = object || null; 1396 this._object = object || null;
1397 }
1398
1399 /**
1400 * @param {!WebInspector.TimelineFrame} frame
1401 * @return {!WebInspector.TimelineSelection}
1402 */
1403 static fromFrame(frame) {
1404 return new WebInspector.TimelineSelection(
1405 WebInspector.TimelineSelection.Type.Frame, frame.startTime, frame.endTim e, frame);
1406 }
1407
1408 /**
1409 * @param {!WebInspector.TimelineModel.NetworkRequest} request
1410 * @return {!WebInspector.TimelineSelection}
1411 */
1412 static fromNetworkRequest(request) {
1413 return new WebInspector.TimelineSelection(
1414 WebInspector.TimelineSelection.Type.NetworkRequest, request.startTime, r equest.endTime || request.startTime,
1415 request);
1416 }
1417
1418 /**
1419 * @param {!WebInspector.TracingModel.Event} event
1420 * @return {!WebInspector.TimelineSelection}
1421 */
1422 static fromTraceEvent(event) {
1423 return new WebInspector.TimelineSelection(
1424 WebInspector.TimelineSelection.Type.TraceEvent, event.startTime, event.e ndTime || (event.startTime + 1), event);
1425 }
1426
1427 /**
1428 * @param {number} startTime
1429 * @param {number} endTime
1430 * @return {!WebInspector.TimelineSelection}
1431 */
1432 static fromRange(startTime, endTime) {
1433 return new WebInspector.TimelineSelection(WebInspector.TimelineSelection.Typ e.Range, startTime, endTime);
1434 }
1435
1436 /**
1437 * @return {!WebInspector.TimelineSelection.Type}
1438 */
1439 type() {
1440 return this._type;
1441 }
1442
1443 /**
1444 * @return {?Object}
1445 */
1446 object() {
1447 return this._object;
1448 }
1449
1450 /**
1451 * @return {number}
1452 */
1453 startTime() {
1454 return this._startTime;
1455 }
1456
1457 /**
1458 * @return {number}
1459 */
1460 endTime() {
1461 return this._endTime;
1462 }
1428 }; 1463 };
1429 1464
1430 /** 1465 /**
1431 * @enum {string} 1466 * @enum {string}
1432 */ 1467 */
1433 WebInspector.TimelineSelection.Type = { 1468 WebInspector.TimelineSelection.Type = {
1434 Frame: "Frame", 1469 Frame: 'Frame',
1435 NetworkRequest: "NetworkRequest", 1470 NetworkRequest: 'NetworkRequest',
1436 TraceEvent: "TraceEvent", 1471 TraceEvent: 'TraceEvent',
1437 Range: "Range" 1472 Range: 'Range'
1438 }; 1473 };
1439 1474
1440 /**
1441 * @param {!WebInspector.TimelineFrame} frame
1442 * @return {!WebInspector.TimelineSelection}
1443 */
1444 WebInspector.TimelineSelection.fromFrame = function(frame)
1445 {
1446 return new WebInspector.TimelineSelection(
1447 WebInspector.TimelineSelection.Type.Frame,
1448 frame.startTime, frame.endTime,
1449 frame);
1450 };
1451
1452 /**
1453 * @param {!WebInspector.TimelineModel.NetworkRequest} request
1454 * @return {!WebInspector.TimelineSelection}
1455 */
1456 WebInspector.TimelineSelection.fromNetworkRequest = function(request)
1457 {
1458 return new WebInspector.TimelineSelection(
1459 WebInspector.TimelineSelection.Type.NetworkRequest,
1460 request.startTime, request.endTime || request.startTime,
1461 request);
1462 };
1463
1464 /**
1465 * @param {!WebInspector.TracingModel.Event} event
1466 * @return {!WebInspector.TimelineSelection}
1467 */
1468 WebInspector.TimelineSelection.fromTraceEvent = function(event)
1469 {
1470 return new WebInspector.TimelineSelection(
1471 WebInspector.TimelineSelection.Type.TraceEvent,
1472 event.startTime, event.endTime || (event.startTime + 1),
1473 event);
1474 };
1475
1476 /**
1477 * @param {number} startTime
1478 * @param {number} endTime
1479 * @return {!WebInspector.TimelineSelection}
1480 */
1481 WebInspector.TimelineSelection.fromRange = function(startTime, endTime)
1482 {
1483 return new WebInspector.TimelineSelection(
1484 WebInspector.TimelineSelection.Type.Range,
1485 startTime, endTime);
1486 };
1487
1488 WebInspector.TimelineSelection.prototype = {
1489 /**
1490 * @return {!WebInspector.TimelineSelection.Type}
1491 */
1492 type: function()
1493 {
1494 return this._type;
1495 },
1496
1497 /**
1498 * @return {?Object}
1499 */
1500 object: function()
1501 {
1502 return this._object;
1503 },
1504
1505 /**
1506 * @return {number}
1507 */
1508 startTime: function()
1509 {
1510 return this._startTime;
1511 },
1512
1513 /**
1514 * @return {number}
1515 */
1516 endTime: function()
1517 {
1518 return this._endTime;
1519 }
1520 };
1521 1475
1522 /** 1476 /**
1523 * @interface 1477 * @interface
1524 * @extends {WebInspector.EventTarget} 1478 * @extends {WebInspector.EventTarget}
1525 */ 1479 */
1526 WebInspector.TimelineModeView = function() 1480 WebInspector.TimelineModeView = function() {};
1527 { 1481
1482 WebInspector.TimelineModeView.prototype = {
1483 /**
1484 * @return {!WebInspector.Widget}
1485 */
1486 view: function() {},
1487
1488 dispose: function() {},
1489
1490 /**
1491 * @return {?Element}
1492 */
1493 resizerElement: function() {},
1494
1495 reset: function() {},
1496
1497 refreshRecords: function() {},
1498
1499 /**
1500 * @param {?WebInspector.TracingModel.Event} event
1501 * @param {string=} regex
1502 * @param {boolean=} select
1503 */
1504 highlightSearchResult: function(event, regex, select) {},
1505
1506 /**
1507 * @param {number} startTime
1508 * @param {number} endTime
1509 */
1510 setWindowTimes: function(startTime, endTime) {},
1511
1512 /**
1513 * @param {?WebInspector.TimelineSelection} selection
1514 */
1515 setSelection: function(selection) {},
1516
1517 /**
1518 * @param {?WebInspector.TracingModel.Event} event
1519 */
1520 highlightEvent: function(event) {}
1528 }; 1521 };
1529 1522
1530 WebInspector.TimelineModeView.prototype = {
1531 /**
1532 * @return {!WebInspector.Widget}
1533 */
1534 view: function() {},
1535
1536 dispose: function() {},
1537
1538 /**
1539 * @return {?Element}
1540 */
1541 resizerElement: function() {},
1542
1543 reset: function() {},
1544
1545 refreshRecords: function() {},
1546
1547 /**
1548 * @param {?WebInspector.TracingModel.Event} event
1549 * @param {string=} regex
1550 * @param {boolean=} select
1551 */
1552 highlightSearchResult: function(event, regex, select) {},
1553
1554 /**
1555 * @param {number} startTime
1556 * @param {number} endTime
1557 */
1558 setWindowTimes: function(startTime, endTime) {},
1559
1560 /**
1561 * @param {?WebInspector.TimelineSelection} selection
1562 */
1563 setSelection: function(selection) {},
1564
1565 /**
1566 * @param {?WebInspector.TracingModel.Event} event
1567 */
1568 highlightEvent: function(event) { }
1569 };
1570
1571 /** 1523 /**
1572 * @interface 1524 * @interface
1573 */ 1525 */
1574 WebInspector.TimelineModeViewDelegate = function() {}; 1526 WebInspector.TimelineModeViewDelegate = function() {};
1575 1527
1576 WebInspector.TimelineModeViewDelegate.prototype = { 1528 WebInspector.TimelineModeViewDelegate.prototype = {
1577 /** 1529 /**
1578 * @param {number} startTime 1530 * @param {number} startTime
1579 * @param {number} endTime 1531 * @param {number} endTime
1580 */ 1532 */
1581 requestWindowTimes: function(startTime, endTime) {}, 1533 requestWindowTimes: function(startTime, endTime) {},
1582 1534
1583 /** 1535 /**
1584 * @param {?WebInspector.TimelineSelection} selection 1536 * @param {?WebInspector.TimelineSelection} selection
1585 * @param {!WebInspector.TimelinePanel.DetailsTab=} preferredTab 1537 * @param {!WebInspector.TimelinePanel.DetailsTab=} preferredTab
1586 */ 1538 */
1587 select: function(selection, preferredTab) {}, 1539 select: function(selection, preferredTab) {},
1588 1540
1589 /** 1541 /**
1590 * @param {number} time 1542 * @param {number} time
1591 */ 1543 */
1592 selectEntryAtTime: function(time) {}, 1544 selectEntryAtTime: function(time) {},
1593 1545
1594 /** 1546 /**
1595 * @param {!Node} node 1547 * @param {!Node} node
1596 */ 1548 */
1597 showInDetails: function(node) {}, 1549 showInDetails: function(node) {},
1598 1550
1599 /** 1551 /**
1600 * @param {?WebInspector.TracingModel.Event} event 1552 * @param {?WebInspector.TracingModel.Event} event
1601 */ 1553 */
1602 highlightEvent: function(event) {} 1554 highlightEvent: function(event) {}
1603 }; 1555 };
1604 1556
1605 /** 1557 /**
1606 * @constructor 1558 * @unrestricted
1607 * @extends {WebInspector.TimelineModel.Filter} 1559 */
1608 */ 1560 WebInspector.TimelineCategoryFilter = class extends WebInspector.TimelineModel.F ilter {
1609 WebInspector.TimelineCategoryFilter = function() 1561 constructor() {
1610 { 1562 super();
1611 WebInspector.TimelineModel.Filter.call(this); 1563 }
1612 }; 1564
1613 1565 /**
1614 WebInspector.TimelineCategoryFilter.prototype = { 1566 * @override
1615 /** 1567 * @param {!WebInspector.TracingModel.Event} event
1616 * @override 1568 * @return {boolean}
1617 * @param {!WebInspector.TracingModel.Event} event 1569 */
1618 * @return {boolean} 1570 accept(event) {
1619 */ 1571 return !WebInspector.TimelineUIUtils.eventStyle(event).category.hidden;
1620 accept: function(event) 1572 }
1621 { 1573 };
1622 return !WebInspector.TimelineUIUtils.eventStyle(event).category.hidden; 1574
1623 }, 1575 /**
1624 1576 * @unrestricted
1625 __proto__: WebInspector.TimelineModel.Filter.prototype 1577 */
1626 }; 1578 WebInspector.TimelineIsLongFilter = class extends WebInspector.TimelineModel.Fil ter {
1627 1579 constructor() {
1628 /** 1580 super();
1629 * @constructor
1630 * @extends {WebInspector.TimelineModel.Filter}
1631 */
1632 WebInspector.TimelineIsLongFilter = function()
1633 {
1634 WebInspector.TimelineModel.Filter.call(this);
1635 this._minimumRecordDuration = 0; 1581 this._minimumRecordDuration = 0;
1636 }; 1582 }
1637 1583
1638 WebInspector.TimelineIsLongFilter.prototype = { 1584 /**
1639 /** 1585 * @param {number} value
1640 * @param {number} value 1586 */
1641 */ 1587 setMinimumRecordDuration(value) {
1642 setMinimumRecordDuration: function(value) 1588 this._minimumRecordDuration = value;
1643 { 1589 }
1644 this._minimumRecordDuration = value; 1590
1645 }, 1591 /**
1646 1592 * @override
1647 /** 1593 * @param {!WebInspector.TracingModel.Event} event
1648 * @override 1594 * @return {boolean}
1649 * @param {!WebInspector.TracingModel.Event} event 1595 */
1650 * @return {boolean} 1596 accept(event) {
1651 */ 1597 var duration = event.endTime ? event.endTime - event.startTime : 0;
1652 accept: function(event) 1598 return duration >= this._minimumRecordDuration;
1653 { 1599 }
1654 var duration = event.endTime ? event.endTime - event.startTime : 0; 1600 };
1655 return duration >= this._minimumRecordDuration; 1601
1656 }, 1602 /**
1657 1603 * @unrestricted
1658 __proto__: WebInspector.TimelineModel.Filter.prototype 1604 */
1659 1605 WebInspector.TimelineTextFilter = class extends WebInspector.TimelineModel.Filte r {
1660 }; 1606 /**
1661 1607 * @param {!RegExp=} regExp
1662 /** 1608 */
1663 * @constructor 1609 constructor(regExp) {
1664 * @extends {WebInspector.TimelineModel.Filter} 1610 super();
1665 * @param {!RegExp=} regExp
1666 */
1667 WebInspector.TimelineTextFilter = function(regExp)
1668 {
1669 WebInspector.TimelineModel.Filter.call(this);
1670 this._setRegExp(regExp || null); 1611 this._setRegExp(regExp || null);
1671 }; 1612 }
1672 1613
1673 WebInspector.TimelineTextFilter.prototype = { 1614 /**
1674 /** 1615 * @param {?RegExp} regExp
1675 * @param {?RegExp} regExp 1616 */
1676 */ 1617 _setRegExp(regExp) {
1677 _setRegExp: function(regExp) 1618 this._regExp = regExp;
1678 { 1619 }
1679 this._regExp = regExp; 1620
1680 }, 1621 /**
1681 1622 * @override
1682 /** 1623 * @param {!WebInspector.TracingModel.Event} event
1683 * @override 1624 * @return {boolean}
1684 * @param {!WebInspector.TracingModel.Event} event 1625 */
1685 * @return {boolean} 1626 accept(event) {
1686 */ 1627 return !this._regExp || WebInspector.TimelineUIUtils.testContentMatching(eve nt, this._regExp);
1687 accept: function(event) 1628 }
1688 { 1629 };
1689 return !this._regExp || WebInspector.TimelineUIUtils.testContentMatching (event, this._regExp); 1630
1690 }, 1631 /**
1691 1632 * @unrestricted
1692 __proto__: WebInspector.TimelineModel.Filter.prototype 1633 */
1693 }; 1634 WebInspector.TimelinePanel.StatusPane = class extends WebInspector.VBox {
1694 1635 /**
1695 /** 1636 * @param {boolean} showTimer
1696 * @constructor 1637 * @param {function()} stopCallback
1697 * @extends {WebInspector.VBox} 1638 */
1698 * @param {boolean} showTimer 1639 constructor(showTimer, stopCallback) {
1699 * @param {function()} stopCallback 1640 super(true);
1700 */ 1641 this.registerRequiredCSS('timeline/timelineStatusDialog.css');
1701 WebInspector.TimelinePanel.StatusPane = function(showTimer, stopCallback) 1642 this.contentElement.classList.add('timeline-status-dialog');
1702 { 1643
1703 WebInspector.VBox.call(this, true); 1644 var statusLine = this.contentElement.createChild('div', 'status-dialog-line status');
1704 this.registerRequiredCSS("timeline/timelineStatusDialog.css"); 1645 statusLine.createChild('div', 'label').textContent = WebInspector.UIString(' Status');
1705 this.contentElement.classList.add("timeline-status-dialog"); 1646 this._status = statusLine.createChild('div', 'content');
1706
1707 var statusLine = this.contentElement.createChild("div", "status-dialog-line status");
1708 statusLine.createChild("div", "label").textContent = WebInspector.UIString(" Status");
1709 this._status = statusLine.createChild("div", "content");
1710 1647
1711 if (showTimer) { 1648 if (showTimer) {
1712 var timeLine = this.contentElement.createChild("div", "status-dialog-lin e time"); 1649 var timeLine = this.contentElement.createChild('div', 'status-dialog-line time');
1713 timeLine.createChild("div", "label").textContent = WebInspector.UIString ("Time"); 1650 timeLine.createChild('div', 'label').textContent = WebInspector.UIString(' Time');
1714 this._time = timeLine.createChild("div", "content"); 1651 this._time = timeLine.createChild('div', 'content');
1715 } 1652 }
1716 var progressLine = this.contentElement.createChild("div", "status-dialog-lin e progress"); 1653 var progressLine = this.contentElement.createChild('div', 'status-dialog-lin e progress');
1717 this._progressLabel = progressLine.createChild("div", "label"); 1654 this._progressLabel = progressLine.createChild('div', 'label');
1718 this._progressBar = progressLine.createChild("div", "indicator-container").c reateChild("div", "indicator"); 1655 this._progressBar = progressLine.createChild('div', 'indicator-container').c reateChild('div', 'indicator');
1719 1656
1720 this._stopButton = createTextButton(WebInspector.UIString("Stop"), stopCallb ack); 1657 this._stopButton = createTextButton(WebInspector.UIString('Stop'), stopCallb ack);
1721 this.contentElement.createChild("div", "stop-button").appendChild(this._stop Button); 1658 this.contentElement.createChild('div', 'stop-button').appendChild(this._stop Button);
1722 }; 1659 }
1723 1660
1724 WebInspector.TimelinePanel.StatusPane.prototype = { 1661 finish() {
1725 finish: function() 1662 this._stopTimer();
1726 { 1663 this._stopButton.disabled = true;
1727 this._stopTimer(); 1664 }
1728 this._stopButton.disabled = true; 1665
1729 }, 1666 hide() {
1730 1667 this.element.parentNode.classList.remove('tinted');
1731 hide: function() 1668 this.element.remove();
1732 { 1669 }
1733 this.element.parentNode.classList.remove("tinted"); 1670
1734 this.element.remove(); 1671 /**
1735 }, 1672 * @param {!Element} parent
1736 1673 */
1737 /** 1674 showPane(parent) {
1738 * @param {!Element} parent 1675 this.show(parent);
1739 */ 1676 parent.classList.add('tinted');
1740 showPane: function(parent) 1677 }
1741 { 1678
1742 this.show(parent); 1679 /**
1743 parent.classList.add("tinted"); 1680 * @param {string} text
1744 }, 1681 */
1745 1682 updateStatus(text) {
1746 /** 1683 this._status.textContent = text;
1747 * @param {string} text 1684 }
1748 */ 1685
1749 updateStatus: function(text) 1686 /**
1750 { 1687 * @param {string} activity
1751 this._status.textContent = text; 1688 * @param {number} percent
1752 }, 1689 */
1753 1690 updateProgressBar(activity, percent) {
1754 /** 1691 this._progressLabel.textContent = activity;
1755 * @param {string} activity 1692 this._progressBar.style.width = percent.toFixed(1) + '%';
1756 * @param {number} percent 1693 this._updateTimer();
1757 */ 1694 }
1758 updateProgressBar: function(activity, percent) 1695
1759 { 1696 startTimer() {
1760 this._progressLabel.textContent = activity; 1697 this._startTime = Date.now();
1761 this._progressBar.style.width = percent.toFixed(1) + "%"; 1698 this._timeUpdateTimer = setInterval(this._updateTimer.bind(this, false), 100 0);
1762 this._updateTimer(); 1699 this._updateTimer();
1763 }, 1700 }
1764 1701
1765 startTimer: function() 1702 _stopTimer() {
1766 { 1703 if (!this._timeUpdateTimer)
1767 this._startTime = Date.now(); 1704 return;
1768 this._timeUpdateTimer = setInterval(this._updateTimer.bind(this, false), 1000); 1705 clearInterval(this._timeUpdateTimer);
1769 this._updateTimer(); 1706 this._updateTimer(true);
1770 }, 1707 delete this._timeUpdateTimer;
1771 1708 }
1772 _stopTimer: function() 1709
1773 { 1710 /**
1774 if (!this._timeUpdateTimer) 1711 * @param {boolean=} precise
1775 return; 1712 */
1776 clearInterval(this._timeUpdateTimer); 1713 _updateTimer(precise) {
1777 this._updateTimer(true); 1714 if (!this._timeUpdateTimer)
1778 delete this._timeUpdateTimer; 1715 return;
1779 }, 1716 var elapsed = (Date.now() - this._startTime) / 1000;
1780 1717 this._time.textContent = WebInspector.UIString('%s\u2009sec', elapsed.toFixe d(precise ? 1 : 0));
1781 /** 1718 }
1782 * @param {boolean=} precise 1719 };
1783 */ 1720
1784 _updateTimer: function(precise) 1721
1785 { 1722 /**
1786 if (!this._timeUpdateTimer)
1787 return;
1788 var elapsed = (Date.now() - this._startTime) / 1000;
1789 this._time.textContent = WebInspector.UIString("%s\u2009sec", elapsed.to Fixed(precise ? 1 : 0));
1790 },
1791
1792 __proto__: WebInspector.VBox.prototype
1793 };
1794
1795 /**
1796 * @return {!WebInspector.TimelinePanel}
1797 */
1798 WebInspector.TimelinePanel.instance = function()
1799 {
1800 return /** @type {!WebInspector.TimelinePanel} */ (self.runtime.sharedInstan ce(WebInspector.TimelinePanel));
1801 };
1802
1803 /**
1804 * @constructor
1805 * @implements {WebInspector.QueryParamHandler} 1723 * @implements {WebInspector.QueryParamHandler}
1806 */ 1724 * @unrestricted
1807 WebInspector.LoadTimelineHandler = function() 1725 */
1808 { 1726 WebInspector.LoadTimelineHandler = class {
1809 }; 1727 /**
1810 1728 * @override
1811 WebInspector.LoadTimelineHandler.prototype = { 1729 * @param {string} value
1812 /** 1730 */
1813 * @override 1731 handleQueryParam(value) {
1814 * @param {string} value 1732 WebInspector.viewManager.showView('timeline').then(() => {
1815 */ 1733 WebInspector.TimelinePanel.instance()._loadFromURL(window.decodeURICompone nt(value));
1816 handleQueryParam: function(value) 1734 });
1817 { 1735 }
1818 WebInspector.viewManager.showView("timeline").then(() => { 1736 };
1819 WebInspector.TimelinePanel.instance()._loadFromURL(window.decodeURIC omponent(value)); 1737
1820 }); 1738 /**
1739 * @implements {WebInspector.ActionDelegate}
1740 * @unrestricted
1741 */
1742 WebInspector.TimelinePanel.ActionDelegate = class {
1743 /**
1744 * @override
1745 * @param {!WebInspector.Context} context
1746 * @param {string} actionId
1747 * @return {boolean}
1748 */
1749 handleAction(context, actionId) {
1750 var panel = WebInspector.context.flavor(WebInspector.TimelinePanel);
1751 console.assert(panel && panel instanceof WebInspector.TimelinePanel);
1752 switch (actionId) {
1753 case 'timeline.toggle-recording':
1754 panel._toggleRecording();
1755 return true;
1756 case 'timeline.save-to-file':
1757 panel._saveToFile();
1758 return true;
1759 case 'timeline.load-from-file':
1760 panel._selectFileToLoad();
1761 return true;
1762 case 'timeline.jump-to-previous-frame':
1763 panel._jumpToFrame(-1);
1764 return true;
1765 case 'timeline.jump-to-next-frame':
1766 panel._jumpToFrame(1);
1767 return true;
1821 } 1768 }
1822 }; 1769 return false;
1823 1770 }
1824 /** 1771 };
1825 * @constructor 1772
1826 * @implements {WebInspector.ActionDelegate} 1773 /**
1827 */ 1774 * @unrestricted
1828 WebInspector.TimelinePanel.ActionDelegate = function() 1775 */
1829 { 1776 WebInspector.TimelineFilters = class extends WebInspector.Object {
1830 }; 1777 constructor() {
1831 1778 super();
1832 WebInspector.TimelinePanel.ActionDelegate.prototype = {
1833 /**
1834 * @override
1835 * @param {!WebInspector.Context} context
1836 * @param {string} actionId
1837 * @return {boolean}
1838 */
1839 handleAction: function(context, actionId)
1840 {
1841 var panel = WebInspector.context.flavor(WebInspector.TimelinePanel);
1842 console.assert(panel && panel instanceof WebInspector.TimelinePanel);
1843 switch (actionId) {
1844 case "timeline.toggle-recording":
1845 panel._toggleRecording();
1846 return true;
1847 case "timeline.save-to-file":
1848 panel._saveToFile();
1849 return true;
1850 case "timeline.load-from-file":
1851 panel._selectFileToLoad();
1852 return true;
1853 case "timeline.jump-to-previous-frame":
1854 panel._jumpToFrame(-1);
1855 return true;
1856 case "timeline.jump-to-next-frame":
1857 panel._jumpToFrame(1);
1858 return true;
1859 }
1860 return false;
1861 }
1862 };
1863
1864 /**
1865 * @constructor
1866 * @extends {WebInspector.Object}
1867 */
1868 WebInspector.TimelineFilters = function()
1869 {
1870 WebInspector.Object.call(this);
1871 1779
1872 this._categoryFilter = new WebInspector.TimelineCategoryFilter(); 1780 this._categoryFilter = new WebInspector.TimelineCategoryFilter();
1873 this._durationFilter = new WebInspector.TimelineIsLongFilter(); 1781 this._durationFilter = new WebInspector.TimelineIsLongFilter();
1874 this._textFilter = new WebInspector.TimelineTextFilter(); 1782 this._textFilter = new WebInspector.TimelineTextFilter();
1875 this._filters = [this._categoryFilter, this._durationFilter, this._textFilte r]; 1783 this._filters = [this._categoryFilter, this._durationFilter, this._textFilte r];
1876 1784
1877 this._createFilterBar(); 1785 this._createFilterBar();
1786 }
1787
1788 /**
1789 * @return {!Array<!WebInspector.TimelineModel.Filter>}
1790 */
1791 filters() {
1792 return this._filters;
1793 }
1794
1795 /**
1796 * @return {?RegExp}
1797 */
1798 searchRegExp() {
1799 return this._textFilter._regExp;
1800 }
1801
1802 /**
1803 * @return {!WebInspector.ToolbarItem}
1804 */
1805 filterButton() {
1806 return this._filterBar.filterButton();
1807 }
1808
1809 /**
1810 * @return {!WebInspector.Widget}
1811 */
1812 filtersWidget() {
1813 return this._filterBar;
1814 }
1815
1816 _createFilterBar() {
1817 this._filterBar = new WebInspector.FilterBar('timelinePanel');
1818
1819 this._textFilterUI = new WebInspector.TextFilterUI();
1820 this._textFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterChang ed, textFilterChanged, this);
1821 this._filterBar.addFilter(this._textFilterUI);
1822
1823 var durationOptions = [];
1824 for (var durationMs of WebInspector.TimelineFilters._durationFilterPresetsMs ) {
1825 var durationOption = {};
1826 if (!durationMs) {
1827 durationOption.label = WebInspector.UIString('All');
1828 durationOption.title = WebInspector.UIString('Show all records');
1829 } else {
1830 durationOption.label = WebInspector.UIString('\u2265 %dms', durationMs);
1831 durationOption.title = WebInspector.UIString('Hide records shorter than %dms', durationMs);
1832 }
1833 durationOption.value = durationMs;
1834 durationOptions.push(durationOption);
1835 }
1836 var durationFilterUI = new WebInspector.ComboBoxFilterUI(durationOptions);
1837 durationFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterChanged , durationFilterChanged, this);
1838 this._filterBar.addFilter(durationFilterUI);
1839
1840 var categoryFiltersUI = {};
1841 var categories = WebInspector.TimelineUIUtils.categories();
1842 for (var categoryName in categories) {
1843 var category = categories[categoryName];
1844 if (!category.visible)
1845 continue;
1846 var filter = new WebInspector.CheckboxFilterUI(category.name, category.tit le);
1847 filter.setColor(category.color, 'rgba(0, 0, 0, 0.2)');
1848 categoryFiltersUI[category.name] = filter;
1849 filter.addEventListener(
1850 WebInspector.FilterUI.Events.FilterChanged, categoriesFilterChanged.bi nd(this, categoryName));
1851 this._filterBar.addFilter(filter);
1852 }
1853 return this._filterBar;
1854
1855 /**
1856 * @this {WebInspector.TimelineFilters}
1857 */
1858 function textFilterChanged() {
1859 var searchQuery = this._textFilterUI.value();
1860 this._textFilter._setRegExp(searchQuery ? createPlainTextSearchRegex(searc hQuery, 'i') : null);
1861 this._notifyFiltersChanged();
1862 }
1863
1864 /**
1865 * @this {WebInspector.TimelineFilters}
1866 */
1867 function durationFilterChanged() {
1868 var duration = durationFilterUI.value();
1869 var minimumRecordDuration = parseInt(duration, 10);
1870 this._durationFilter.setMinimumRecordDuration(minimumRecordDuration);
1871 this._notifyFiltersChanged();
1872 }
1873
1874 /**
1875 * @param {string} name
1876 * @this {WebInspector.TimelineFilters}
1877 */
1878 function categoriesFilterChanged(name) {
1879 var categories = WebInspector.TimelineUIUtils.categories();
1880 categories[name].hidden = !categoryFiltersUI[name].checked();
1881 this._notifyFiltersChanged();
1882 }
1883 }
1884
1885 _notifyFiltersChanged() {
1886 this.dispatchEventToListeners(WebInspector.TimelineFilters.Events.FilterChan ged);
1887 }
1878 }; 1888 };
1879 1889
1880 /** @enum {symbol} */ 1890 /** @enum {symbol} */
1881 WebInspector.TimelineFilters.Events = { 1891 WebInspector.TimelineFilters.Events = {
1882 FilterChanged: Symbol("FilterChanged") 1892 FilterChanged: Symbol('FilterChanged')
1883 }; 1893 };
1884 1894
1885 WebInspector.TimelineFilters._durationFilterPresetsMs = [0, 1, 15]; 1895 WebInspector.TimelineFilters._durationFilterPresetsMs = [0, 1, 15];
1886 1896
1887 WebInspector.TimelineFilters.prototype = {
1888 /**
1889 * @return {!Array<!WebInspector.TimelineModel.Filter>}
1890 */
1891 filters: function()
1892 {
1893 return this._filters;
1894 },
1895
1896 /**
1897 * @return {?RegExp}
1898 */
1899 searchRegExp: function()
1900 {
1901 return this._textFilter._regExp;
1902 },
1903
1904 /**
1905 * @return {!WebInspector.ToolbarItem}
1906 */
1907 filterButton: function()
1908 {
1909 return this._filterBar.filterButton();
1910 },
1911
1912 /**
1913 * @return {!WebInspector.Widget}
1914 */
1915 filtersWidget: function()
1916 {
1917 return this._filterBar;
1918 },
1919
1920 _createFilterBar: function()
1921 {
1922 this._filterBar = new WebInspector.FilterBar("timelinePanel");
1923
1924 this._textFilterUI = new WebInspector.TextFilterUI();
1925 this._textFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterC hanged, textFilterChanged, this);
1926 this._filterBar.addFilter(this._textFilterUI);
1927
1928 var durationOptions = [];
1929 for (var durationMs of WebInspector.TimelineFilters._durationFilterPrese tsMs) {
1930 var durationOption = {};
1931 if (!durationMs) {
1932 durationOption.label = WebInspector.UIString("All");
1933 durationOption.title = WebInspector.UIString("Show all records") ;
1934 } else {
1935 durationOption.label = WebInspector.UIString("\u2265 %dms", dura tionMs);
1936 durationOption.title = WebInspector.UIString("Hide records short er than %dms", durationMs);
1937 }
1938 durationOption.value = durationMs;
1939 durationOptions.push(durationOption);
1940 }
1941 var durationFilterUI = new WebInspector.ComboBoxFilterUI(durationOptions );
1942 durationFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterCha nged, durationFilterChanged, this);
1943 this._filterBar.addFilter(durationFilterUI);
1944
1945 var categoryFiltersUI = {};
1946 var categories = WebInspector.TimelineUIUtils.categories();
1947 for (var categoryName in categories) {
1948 var category = categories[categoryName];
1949 if (!category.visible)
1950 continue;
1951 var filter = new WebInspector.CheckboxFilterUI(category.name, catego ry.title);
1952 filter.setColor(category.color, "rgba(0, 0, 0, 0.2)");
1953 categoryFiltersUI[category.name] = filter;
1954 filter.addEventListener(WebInspector.FilterUI.Events.FilterChanged, categoriesFilterChanged.bind(this, categoryName));
1955 this._filterBar.addFilter(filter);
1956 }
1957 return this._filterBar;
1958
1959 /**
1960 * @this {WebInspector.TimelineFilters}
1961 */
1962 function textFilterChanged()
1963 {
1964 var searchQuery = this._textFilterUI.value();
1965 this._textFilter._setRegExp(searchQuery ? createPlainTextSearchRegex (searchQuery, "i") : null);
1966 this._notifyFiltersChanged();
1967 }
1968
1969 /**
1970 * @this {WebInspector.TimelineFilters}
1971 */
1972 function durationFilterChanged()
1973 {
1974 var duration = durationFilterUI.value();
1975 var minimumRecordDuration = parseInt(duration, 10);
1976 this._durationFilter.setMinimumRecordDuration(minimumRecordDuration) ;
1977 this._notifyFiltersChanged();
1978 }
1979
1980 /**
1981 * @param {string} name
1982 * @this {WebInspector.TimelineFilters}
1983 */
1984 function categoriesFilterChanged(name)
1985 {
1986 var categories = WebInspector.TimelineUIUtils.categories();
1987 categories[name].hidden = !categoryFiltersUI[name].checked();
1988 this._notifyFiltersChanged();
1989 }
1990 },
1991
1992 _notifyFiltersChanged: function()
1993 {
1994 this.dispatchEventToListeners(WebInspector.TimelineFilters.Events.Filter Changed);
1995 },
1996
1997 __proto__: WebInspector.Object.prototype
1998 };
1999
2000 /** 1897 /**
2001 * @constructor
2002 * @extends {WebInspector.Object}
2003 * @implements {WebInspector.TargetManager.Observer} 1898 * @implements {WebInspector.TargetManager.Observer}
1899 * @unrestricted
2004 */ 1900 */
2005 WebInspector.CPUThrottlingManager = function() 1901 WebInspector.CPUThrottlingManager = class extends WebInspector.Object {
2006 { 1902 constructor() {
1903 super();
2007 this._targets = []; 1904 this._targets = [];
2008 this._throttlingRate = 1.; // No throttling 1905 this._throttlingRate = 1.; // No throttling
2009 WebInspector.targetManager.observeTargets(this, WebInspector.Target.Capabili ty.Browser); 1906 WebInspector.targetManager.observeTargets(this, WebInspector.Target.Capabili ty.Browser);
2010 }; 1907 }
2011 1908
2012 WebInspector.CPUThrottlingManager.prototype = { 1909 /**
2013 /** 1910 * @param {number} value
2014 * @param {number} value 1911 */
2015 */ 1912 setRate(value) {
2016 setRate: function(value) 1913 this._throttlingRate = value;
2017 { 1914 this._targets.forEach(target => target.emulationAgent().setCPUThrottlingRate (value));
2018 this._throttlingRate = value; 1915 if (value !== 1)
2019 this._targets.forEach(target => target.emulationAgent().setCPUThrottling Rate(value)); 1916 WebInspector.inspectorView.setPanelIcon(
2020 if (value !== 1) 1917 'timeline', 'warning-icon', WebInspector.UIString('CPU throttling is e nabled'));
2021 WebInspector.inspectorView.setPanelIcon("timeline", "warning-icon", WebInspector.UIString("CPU throttling is enabled")); 1918 else
2022 else 1919 WebInspector.inspectorView.setPanelIcon('timeline', '', '');
2023 WebInspector.inspectorView.setPanelIcon("timeline", "", ""); 1920 }
2024 }, 1921
2025 1922 /**
2026 /** 1923 * @return {number}
2027 * @return {number} 1924 */
2028 */ 1925 rate() {
2029 rate: function() 1926 return this._throttlingRate;
2030 { 1927 }
2031 return this._throttlingRate; 1928
2032 }, 1929 /**
2033 1930 * @override
2034 /** 1931 * @param {!WebInspector.Target} target
2035 * @override 1932 */
2036 * @param {!WebInspector.Target} target 1933 targetAdded(target) {
2037 */ 1934 this._targets.push(target);
2038 targetAdded: function(target) 1935 target.emulationAgent().setCPUThrottlingRate(this._throttlingRate);
2039 { 1936 }
2040 this._targets.push(target); 1937
2041 target.emulationAgent().setCPUThrottlingRate(this._throttlingRate); 1938 /**
2042 }, 1939 * @override
2043 1940 * @param {!WebInspector.Target} target
2044 /** 1941 */
2045 * @override 1942 targetRemoved(target) {
2046 * @param {!WebInspector.Target} target 1943 this._targets.remove(target, true);
2047 */ 1944 }
2048 targetRemoved: function(target)
2049 {
2050 this._targets.remove(target, true);
2051 },
2052
2053 __proto__: WebInspector.Object.prototype
2054 }; 1945 };
2055 1946
2056 /** 1947 /**
2057 * @constructor 1948 * @unrestricted
2058 * @extends {WebInspector.HBox}
2059 */ 1949 */
2060 WebInspector.TimelinePanel.CustomCPUThrottlingRateDialog = function() 1950 WebInspector.TimelinePanel.CustomCPUThrottlingRateDialog = class extends WebInsp ector.HBox {
2061 { 1951 constructor() {
2062 WebInspector.HBox.call(this, true); 1952 super(true);
2063 this.registerRequiredCSS("ui_lazy/dialog.css"); 1953 this.registerRequiredCSS('ui_lazy/dialog.css');
2064 this.contentElement.createChild("label").textContent = WebInspector.UIString ("CPU Slowdown Rate: "); 1954 this.contentElement.createChild('label').textContent = WebInspector.UIString ('CPU Slowdown Rate: ');
2065 1955
2066 this._input = this.contentElement.createChild("input"); 1956 this._input = this.contentElement.createChild('input');
2067 this._input.setAttribute("type", "text"); 1957 this._input.setAttribute('type', 'text');
2068 this._input.style.width = "64px"; 1958 this._input.style.width = '64px';
2069 this._input.addEventListener("keydown", this._onKeyDown.bind(this), false); 1959 this._input.addEventListener('keydown', this._onKeyDown.bind(this), false);
2070 1960
2071 var addButton = this.contentElement.createChild("button"); 1961 var addButton = this.contentElement.createChild('button');
2072 addButton.textContent = WebInspector.UIString("Set"); 1962 addButton.textContent = WebInspector.UIString('Set');
2073 addButton.addEventListener("click", this._apply.bind(this), false); 1963 addButton.addEventListener('click', this._apply.bind(this), false);
2074 1964
2075 this.setDefaultFocusedElement(this._input); 1965 this.setDefaultFocusedElement(this._input);
2076 this.contentElement.tabIndex = 0; 1966 this.contentElement.tabIndex = 0;
2077 this._resultPromise = new Promise(fulfill => this._callback = fulfill); 1967 this._resultPromise = new Promise(fulfill => this._callback = fulfill);
2078 }; 1968 }
2079 1969
2080 /** 1970 /**
2081 * @param {!Element=} anchor 1971 * @param {!Element=} anchor
2082 * @return {!Promise<string>} 1972 * @return {!Promise<string>}
2083 */ 1973 */
2084 WebInspector.TimelinePanel.CustomCPUThrottlingRateDialog.show = function(anchor) 1974 static show(anchor) {
2085 {
2086 var dialog = new WebInspector.Dialog(); 1975 var dialog = new WebInspector.Dialog();
2087 var dialogContent = new WebInspector.TimelinePanel.CustomCPUThrottlingRateDi alog(); 1976 var dialogContent = new WebInspector.TimelinePanel.CustomCPUThrottlingRateDi alog();
2088 dialogContent.show(dialog.element); 1977 dialogContent.show(dialog.element);
2089 dialog.setWrapsContent(true); 1978 dialog.setWrapsContent(true);
2090 if (anchor) 1979 if (anchor)
2091 dialog.setPosition(anchor.totalOffsetLeft() - 32, anchor.totalOffsetTop( ) + anchor.offsetHeight); 1980 dialog.setPosition(anchor.totalOffsetLeft() - 32, anchor.totalOffsetTop() + anchor.offsetHeight);
2092 dialog.show(); 1981 dialog.show();
2093 return dialogContent.result().then(value => (dialog.detach(), value)); 1982 return dialogContent.result().then(value => (dialog.detach(), value));
2094 }; 1983 }
2095 1984
2096 WebInspector.TimelinePanel.CustomCPUThrottlingRateDialog.prototype = { 1985 /**
2097 /** 1986 * @return {!Promise<string>}
2098 * @return {!Promise<string>} 1987 */
2099 */ 1988 result() {
2100 result: function() 1989 return this._resultPromise;
2101 { 1990 }
2102 return this._resultPromise; 1991
2103 }, 1992 _apply() {
2104 1993 this._callback(this._input.value);
2105 _apply: function() 1994 }
2106 { 1995
2107 this._callback(this._input.value); 1996 /**
2108 }, 1997 * @param {!Event} event
2109 1998 */
2110 /** 1999 _onKeyDown(event) {
2111 * @param {!Event} event 2000 if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Enter.code) {
2112 */ 2001 event.preventDefault();
2113 _onKeyDown: function(event) 2002 this._apply();
2114 { 2003 }
2115 if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Enter.code) { 2004 }
2116 event.preventDefault(); 2005 };
2117 this._apply(); 2006
2118 } 2007
2119 },
2120
2121 __proto__: WebInspector.HBox.prototype
2122 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698