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

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.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) 2014 Google Inc. All rights reserved. 2 * Copyright (C) 2014 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer 11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the 12 * in the documentation and/or other materials provided with the
13 * distribution. 13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its 14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from 15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission. 16 * this software without specific prior written permission.
17 * 17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30
31 /** 30 /**
32 * @constructor
33 * @implements {WebInspector.FlameChartDataProvider} 31 * @implements {WebInspector.FlameChartDataProvider}
34 * @param {!WebInspector.TimelineModel} model 32 * @unrestricted
35 * @param {!Array<!WebInspector.TimelineModel.Filter>} filters
36 */ 33 */
37 WebInspector.TimelineFlameChartDataProviderBase = function(model, filters) 34 WebInspector.TimelineFlameChartDataProviderBase = class {
38 { 35 /**
36 * @param {!WebInspector.TimelineModel} model
37 * @param {!Array<!WebInspector.TimelineModel.Filter>} filters
38 */
39 constructor(model, filters) {
39 WebInspector.FlameChartDataProvider.call(this); 40 WebInspector.FlameChartDataProvider.call(this);
40 this.reset(); 41 this.reset();
41 this._model = model; 42 this._model = model;
42 /** @type {?WebInspector.FlameChart.TimelineData} */ 43 /** @type {?WebInspector.FlameChart.TimelineData} */
43 this._timelineData; 44 this._timelineData;
44 this._font = "11px " + WebInspector.fontFamily(); 45 this._font = '11px ' + WebInspector.fontFamily();
45 this._filters = filters; 46 this._filters = filters;
46 }; 47 }
47 48
48 WebInspector.TimelineFlameChartDataProviderBase.prototype = { 49 /**
49 /** 50 * @override
50 * @override 51 * @return {number}
51 * @return {number} 52 */
52 */ 53 barHeight() {
53 barHeight: function() 54 return 17;
54 { 55 }
55 return 17; 56
56 }, 57 /**
57 58 * @override
58 /** 59 * @return {number}
59 * @override 60 */
60 * @return {number} 61 textBaseline() {
61 */ 62 return 5;
62 textBaseline: function() 63 }
63 { 64
64 return 5; 65 /**
65 }, 66 * @override
66 67 * @return {number}
67 /** 68 */
68 * @override 69 textPadding() {
69 * @return {number} 70 return 4;
70 */ 71 }
71 textPadding: function() 72
72 { 73 /**
73 return 4; 74 * @override
74 }, 75 * @param {number} entryIndex
75 76 * @return {string}
76 /** 77 */
77 * @override 78 entryFont(entryIndex) {
78 * @param {number} entryIndex 79 return this._font;
79 * @return {string} 80 }
80 */ 81
81 entryFont: function(entryIndex) 82 /**
82 { 83 * @override
83 return this._font; 84 * @param {number} entryIndex
84 }, 85 * @return {?string}
85 86 */
86 /** 87 entryTitle(entryIndex) {
87 * @override 88 return null;
88 * @param {number} entryIndex 89 }
89 * @return {?string} 90
90 */ 91 reset() {
91 entryTitle: function(entryIndex) 92 this._timelineData = null;
92 { 93 }
93 return null; 94
94 }, 95 /**
95 96 * @override
96 reset: function() 97 * @return {number}
97 { 98 */
98 this._timelineData = null; 99 minimumBoundary() {
99 }, 100 return this._minimumBoundary;
100 101 }
101 /** 102
102 * @override 103 /**
103 * @return {number} 104 * @override
104 */ 105 * @return {number}
105 minimumBoundary: function() 106 */
106 { 107 totalTime() {
107 return this._minimumBoundary; 108 return this._timeSpan;
108 }, 109 }
109 110
110 /** 111 /**
111 * @override 112 * @override
112 * @return {number} 113 * @param {number} value
113 */ 114 * @param {number=} precision
114 totalTime: function() 115 * @return {string}
115 { 116 */
116 return this._timeSpan; 117 formatValue(value, precision) {
117 }, 118 return Number.preciseMillisToString(value, precision);
118 119 }
119 /** 120
120 * @override 121 /**
121 * @param {number} value 122 * @override
122 * @param {number=} precision 123 * @return {number}
123 * @return {string} 124 */
124 */ 125 maxStackDepth() {
125 formatValue: function(value, precision) 126 return this._currentLevel;
126 { 127 }
127 return Number.preciseMillisToString(value, precision); 128
128 }, 129 /**
129 130 * @override
130 /** 131 * @param {number} entryIndex
131 * @override 132 * @return {?Element}
132 * @return {number} 133 */
133 */ 134 prepareHighlightedEntryInfo(entryIndex) {
134 maxStackDepth: function() 135 return null;
135 { 136 }
136 return this._currentLevel; 137
137 }, 138 /**
138 139 * @override
139 /** 140 * @param {number} entryIndex
140 * @override 141 * @return {boolean}
141 * @param {number} entryIndex 142 */
142 * @return {?Element} 143 canJumpToEntry(entryIndex) {
143 */ 144 return false;
144 prepareHighlightedEntryInfo: function(entryIndex) 145 }
145 { 146
146 return null; 147 /**
147 }, 148 * @override
148 149 * @param {number} entryIndex
149 /** 150 * @return {string}
150 * @override 151 */
151 * @param {number} entryIndex 152 entryColor(entryIndex) {
152 * @return {boolean} 153 return 'red';
153 */ 154 }
154 canJumpToEntry: function(entryIndex) 155
155 { 156 /**
156 return false; 157 * @override
157 }, 158 * @param {number} index
158 159 * @return {boolean}
159 /** 160 */
160 * @override 161 forceDecoration(index) {
161 * @param {number} entryIndex 162 return false;
162 * @return {string} 163 }
163 */ 164
164 entryColor: function(entryIndex) 165 /**
165 { 166 * @override
166 return "red"; 167 * @param {number} entryIndex
167 }, 168 * @param {!CanvasRenderingContext2D} context
168 169 * @param {?string} text
169 /** 170 * @param {number} barX
170 * @override 171 * @param {number} barY
171 * @param {number} index 172 * @param {number} barWidth
172 * @return {boolean} 173 * @param {number} barHeight
173 */ 174 * @param {number} unclippedBarX
174 forceDecoration: function(index) 175 * @param {number} timeToPixels
175 { 176 * @return {boolean}
176 return false; 177 */
177 }, 178 decorateEntry(entryIndex, context, text, barX, barY, barWidth, barHeight, uncl ippedBarX, timeToPixels) {
178 179 return false;
179 /** 180 }
180 * @override 181
181 * @param {number} entryIndex 182 /**
182 * @param {!CanvasRenderingContext2D} context 183 * @override
183 * @param {?string} text 184 * @return {number}
184 * @param {number} barX 185 */
185 * @param {number} barY 186 paddingLeft() {
186 * @param {number} barWidth 187 return 0;
187 * @param {number} barHeight 188 }
188 * @param {number} unclippedBarX 189
189 * @param {number} timeToPixels 190 /**
190 * @return {boolean} 191 * @override
191 */ 192 * @param {number} entryIndex
192 decorateEntry: function(entryIndex, context, text, barX, barY, barWidth, bar Height, unclippedBarX, timeToPixels) 193 * @return {string}
193 { 194 */
194 return false; 195 textColor(entryIndex) {
195 }, 196 return '#333';
196 197 }
197 /** 198
198 * @override 199 /**
199 * @return {number} 200 * @param {number} entryIndex
200 */ 201 * @return {?WebInspector.TimelineSelection}
201 paddingLeft: function() 202 */
202 { 203 createSelection(entryIndex) {
203 return 0; 204 return null;
204 }, 205 }
205 206
206 /** 207 /**
207 * @override 208 * @override
208 * @param {number} entryIndex 209 * @return {!WebInspector.FlameChart.TimelineData}
209 * @return {string} 210 */
210 */ 211 timelineData() {
211 textColor: function(entryIndex) 212 throw new Error('Not implemented');
212 { 213 }
213 return "#333"; 214
214 }, 215 /**
215 216 * @param {!WebInspector.TracingModel.Event} event
216 /** 217 * @return {boolean}
217 * @param {number} entryIndex 218 */
218 * @return {?WebInspector.TimelineSelection} 219 _isVisible(event) {
219 */ 220 return this._filters.every(function(filter) {
220 createSelection: function(entryIndex) 221 return filter.accept(event);
221 { 222 });
222 return null; 223 }
223 },
224
225 /**
226 * @override
227 * @return {!WebInspector.FlameChart.TimelineData}
228 */
229 timelineData: function()
230 {
231 throw new Error("Not implemented");
232 },
233
234 /**
235 * @param {!WebInspector.TracingModel.Event} event
236 * @return {boolean}
237 */
238 _isVisible: function(event)
239 {
240 return this._filters.every(function(filter) { return filter.accept(event ); });
241 }
242 }; 224 };
243 225
244 /** 226 /**
245 * @enum {symbol} 227 * @enum {symbol}
246 */ 228 */
247 WebInspector.TimelineFlameChartEntryType = { 229 WebInspector.TimelineFlameChartEntryType = {
248 Frame: Symbol("Frame"), 230 Frame: Symbol('Frame'),
249 Event: Symbol("Event"), 231 Event: Symbol('Event'),
250 InteractionRecord: Symbol("InteractionRecord"), 232 InteractionRecord: Symbol('InteractionRecord'),
251 }; 233 };
252 234
253 /** 235 /**
254 * @constructor 236 * @unrestricted
255 * @extends {WebInspector.TimelineFlameChartDataProviderBase}
256 * @param {!WebInspector.TimelineModel} model
257 * @param {!WebInspector.TimelineFrameModel} frameModel
258 * @param {!WebInspector.TimelineIRModel} irModel
259 * @param {!Array<!WebInspector.TimelineModel.Filter>} filters
260 */ 237 */
261 WebInspector.TimelineFlameChartDataProvider = function(model, frameModel, irMode l, filters) 238 WebInspector.TimelineFlameChartDataProvider = class extends WebInspector.Timelin eFlameChartDataProviderBase {
262 { 239 /**
263 WebInspector.TimelineFlameChartDataProviderBase.call(this, model, filters); 240 * @param {!WebInspector.TimelineModel} model
241 * @param {!WebInspector.TimelineFrameModel} frameModel
242 * @param {!WebInspector.TimelineIRModel} irModel
243 * @param {!Array<!WebInspector.TimelineModel.Filter>} filters
244 */
245 constructor(model, frameModel, irModel, filters) {
246 super(model, filters);
264 this._frameModel = frameModel; 247 this._frameModel = frameModel;
265 this._irModel = irModel; 248 this._irModel = irModel;
266 this._consoleColorGenerator = new WebInspector.FlameChart.ColorGenerator( 249 this._consoleColorGenerator =
267 { min: 30, max: 55 }, 250 new WebInspector.FlameChart.ColorGenerator({min: 30, max: 55}, {min: 70, max: 100, count: 6}, 50, 0.7);
268 { min: 70, max: 100, count: 6 },
269 50, 0.7);
270 251
271 this._headerLevel1 = { 252 this._headerLevel1 = {
272 padding: 4, 253 padding: 4,
273 height: 17, 254 height: 17,
274 collapsible: true, 255 collapsible: true,
275 color: WebInspector.themeSupport.patchColor("#222", WebInspector.ThemeSu pport.ColorUsage.Foreground), 256 color: WebInspector.themeSupport.patchColor('#222', WebInspector.ThemeSupp ort.ColorUsage.Foreground),
276 font: this._font, 257 font: this._font,
277 backgroundColor: WebInspector.themeSupport.patchColor("white", WebInspec tor.ThemeSupport.ColorUsage.Background), 258 backgroundColor: WebInspector.themeSupport.patchColor('white', WebInspecto r.ThemeSupport.ColorUsage.Background),
278 nestingLevel: 0 259 nestingLevel: 0
279 }; 260 };
280 261
281 this._headerLevel2 = { 262 this._headerLevel2 = {
282 padding: 2, 263 padding: 2,
283 height: 17, 264 height: 17,
284 collapsible: false, 265 collapsible: false,
285 font: this._font, 266 font: this._font,
286 color: WebInspector.themeSupport.patchColor("#222", WebInspector.ThemeSu pport.ColorUsage.Foreground), 267 color: WebInspector.themeSupport.patchColor('#222', WebInspector.ThemeSupp ort.ColorUsage.Foreground),
287 backgroundColor: WebInspector.themeSupport.patchColor("white", WebInspec tor.ThemeSupport.ColorUsage.Background), 268 backgroundColor: WebInspector.themeSupport.patchColor('white', WebInspecto r.ThemeSupport.ColorUsage.Background),
288 nestingLevel: 1, 269 nestingLevel: 1,
289 shareHeaderLine: true 270 shareHeaderLine: true
290 }; 271 };
291 272
292 this._interactionsHeaderLevel1 = { 273 this._interactionsHeaderLevel1 = {
293 padding: 4, 274 padding: 4,
294 height: 17, 275 height: 17,
295 collapsible: true, 276 collapsible: true,
296 color: WebInspector.themeSupport.patchColor("#222", WebInspector.ThemeSu pport.ColorUsage.Foreground), 277 color: WebInspector.themeSupport.patchColor('#222', WebInspector.ThemeSupp ort.ColorUsage.Foreground),
297 font: this._font, 278 font: this._font,
298 backgroundColor: WebInspector.themeSupport.patchColor("white", WebInspec tor.ThemeSupport.ColorUsage.Background), 279 backgroundColor: WebInspector.themeSupport.patchColor('white', WebInspecto r.ThemeSupport.ColorUsage.Background),
299 nestingLevel: 0, 280 nestingLevel: 0,
300 useFirstLineForOverview: true, 281 useFirstLineForOverview: true,
301 shareHeaderLine: true 282 shareHeaderLine: true
302 }; 283 };
303 284
304 this._interactionsHeaderLevel2 = { 285 this._interactionsHeaderLevel2 = {
305 padding: 2, 286 padding: 2,
306 height: 17, 287 height: 17,
307 collapsible: true, 288 collapsible: true,
308 color: WebInspector.themeSupport.patchColor("#222", WebInspector.ThemeSu pport.ColorUsage.Foreground), 289 color: WebInspector.themeSupport.patchColor('#222', WebInspector.ThemeSupp ort.ColorUsage.Foreground),
309 font: this._font, 290 font: this._font,
310 backgroundColor: WebInspector.themeSupport.patchColor("white", WebInspec tor.ThemeSupport.ColorUsage.Background), 291 backgroundColor: WebInspector.themeSupport.patchColor('white', WebInspecto r.ThemeSupport.ColorUsage.Background),
311 nestingLevel: 1, 292 nestingLevel: 1,
312 shareHeaderLine: true 293 shareHeaderLine: true
313 }; 294 };
314 }; 295 }
315 296
316 WebInspector.TimelineFlameChartDataProvider.InstantEventVisibleDurationMs = 0.00 1; 297 /**
317 298 * @override
318 WebInspector.TimelineFlameChartDataProvider.prototype = { 299 * @param {number} entryIndex
300 * @return {?string}
301 */
302 entryTitle(entryIndex) {
303 var entryType = this._entryType(entryIndex);
304 if (entryType === WebInspector.TimelineFlameChartEntryType.Event) {
305 var event = /** @type {!WebInspector.TracingModel.Event} */ (this._entryDa ta[entryIndex]);
306 if (event.phase === WebInspector.TracingModel.Phase.AsyncStepInto ||
307 event.phase === WebInspector.TracingModel.Phase.AsyncStepPast)
308 return event.name + ':' + event.args['step'];
309 if (event._blackboxRoot)
310 return WebInspector.UIString('Blackboxed');
311 var name = WebInspector.TimelineUIUtils.eventStyle(event).title;
312 // TODO(yurys): support event dividers
313 var detailsText =
314 WebInspector.TimelineUIUtils.buildDetailsTextForTraceEvent(event, this ._model.targetByEvent(event));
315 if (event.name === WebInspector.TimelineModel.RecordType.JSFrame && detail sText)
316 return detailsText;
317 return detailsText ? WebInspector.UIString('%s (%s)', name, detailsText) : name;
318 }
319 var title = this._entryIndexToTitle[entryIndex];
320 if (!title) {
321 title = WebInspector.UIString('Unexpected entryIndex %d', entryIndex);
322 console.error(title);
323 }
324 return title;
325 }
326
327 /**
328 * @override
329 * @param {number} index
330 * @return {string}
331 */
332 textColor(index) {
333 var event = this._entryData[index];
334 if (event && event._blackboxRoot)
335 return '#888';
336 else
337 return super.textColor(index);
338 }
339
340 /**
341 * @override
342 */
343 reset() {
344 super.reset();
345 /** @type {!Array<!WebInspector.TracingModel.Event|!WebInspector.TimelineFra me|!WebInspector.TimelineIRModel.Phases>} */
346 this._entryData = [];
347 /** @type {!Array<!WebInspector.TimelineFlameChartEntryType>} */
348 this._entryTypeByLevel = [];
349 /** @type {!Array<string>} */
350 this._entryIndexToTitle = [];
351 /** @type {!Array<!WebInspector.TimelineFlameChartMarker>} */
352 this._markers = [];
353 /** @type {!Map<!WebInspector.TimelineCategory, string>} */
354 this._asyncColorByCategory = new Map();
355 /** @type {!Map<!WebInspector.TimelineIRModel.Phases, string>} */
356 this._asyncColorByInteractionPhase = new Map();
357 }
358
359 /**
360 * @override
361 * @return {!WebInspector.FlameChart.TimelineData}
362 */
363 timelineData() {
364 if (this._timelineData)
365 return this._timelineData;
366
367 this._timelineData = new WebInspector.FlameChart.TimelineData([], [], [], [] );
368
369 this._flowEventIndexById = {};
370 this._minimumBoundary = this._model.minimumRecordTime();
371 this._timeSpan = this._model.isEmpty() ? 1000 : this._model.maximumRecordTim e() - this._minimumBoundary;
372 this._currentLevel = 0;
373 this._appendFrameBars(this._frameModel.frames());
374
375 this._appendHeader(WebInspector.UIString('Interactions'), this._interactions HeaderLevel1);
376 this._appendInteractionRecords();
377
378 var asyncEventGroups = WebInspector.TimelineModel.AsyncEventGroup;
379 var inputLatencies = this._model.mainThreadAsyncEvents().get(asyncEventGroup s.input);
380 if (inputLatencies && inputLatencies.length) {
381 var title = WebInspector.TimelineUIUtils.titleForAsyncEventGroup(asyncEven tGroups.input);
382 this._appendAsyncEventsGroup(title, inputLatencies, this._interactionsHead erLevel2);
383 }
384 var animations = this._model.mainThreadAsyncEvents().get(asyncEventGroups.an imation);
385 if (animations && animations.length) {
386 var title = WebInspector.TimelineUIUtils.titleForAsyncEventGroup(asyncEven tGroups.animation);
387 this._appendAsyncEventsGroup(title, animations, this._interactionsHeaderLe vel2);
388 }
389 var threads = this._model.virtualThreads();
390 this._appendThreadTimelineData(
391 WebInspector.UIString('Main'), this._model.mainThreadEvents(), this._mod el.mainThreadAsyncEvents(), true);
392 var compositorThreads = threads.filter(thread => thread.name.startsWith('Com positorTileWorker'));
393 var otherThreads = threads.filter(thread => !thread.name.startsWith('Composi torTileWorker'));
394 if (compositorThreads.length) {
395 this._appendHeader(WebInspector.UIString('Raster'), this._headerLevel1);
396 for (var i = 0; i < compositorThreads.length; ++i)
397 this._appendSyncEvents(
398 compositorThreads[i].events, WebInspector.UIString('Rasterizer Threa d %d', i), this._headerLevel2);
399 }
400 this._appendGPUEvents();
401
402 otherThreads.forEach(
403 thread => this._appendThreadTimelineData(thread.name, thread.events, thr ead.asyncEventsByGroup));
404
319 /** 405 /**
320 * @override 406 * @param {!WebInspector.TimelineFlameChartMarker} a
321 * @param {number} entryIndex 407 * @param {!WebInspector.TimelineFlameChartMarker} b
322 * @return {?string}
323 */ 408 */
324 entryTitle: function(entryIndex) 409 function compareStartTime(a, b) {
325 { 410 return a.startTime() - b.startTime();
326 var entryType = this._entryType(entryIndex); 411 }
327 if (entryType === WebInspector.TimelineFlameChartEntryType.Event) { 412
328 var event = /** @type {!WebInspector.TracingModel.Event} */ (this._e ntryData[entryIndex]); 413 this._markers.sort(compareStartTime);
329 if (event.phase === WebInspector.TracingModel.Phase.AsyncStepInto || event.phase === WebInspector.TracingModel.Phase.AsyncStepPast) 414 this._timelineData.markers = this._markers;
330 return event.name + ":" + event.args["step"]; 415
331 if (event._blackboxRoot) 416 this._flowEventIndexById = {};
332 return WebInspector.UIString("Blackboxed"); 417 return this._timelineData;
333 var name = WebInspector.TimelineUIUtils.eventStyle(event).title; 418 }
334 // TODO(yurys): support event dividers 419
335 var detailsText = WebInspector.TimelineUIUtils.buildDetailsTextForTr aceEvent(event, this._model.targetByEvent(event)); 420 /**
336 if (event.name === WebInspector.TimelineModel.RecordType.JSFrame && detailsText) 421 * @param {string} threadTitle
337 return detailsText; 422 * @param {!Array<!WebInspector.TracingModel.Event>} syncEvents
338 return detailsText ? WebInspector.UIString("%s (%s)", name, detailsT ext) : name; 423 * @param {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInspec tor.TracingModel.AsyncEvent>>} asyncEvents
339 } 424 * @param {boolean=} forceExpanded
340 var title = this._entryIndexToTitle[entryIndex]; 425 */
341 if (!title) { 426 _appendThreadTimelineData(threadTitle, syncEvents, asyncEvents, forceExpanded) {
342 title = WebInspector.UIString("Unexpected entryIndex %d", entryIndex ); 427 this._appendAsyncEvents(asyncEvents);
343 console.error(title); 428 this._appendSyncEvents(syncEvents, threadTitle, this._headerLevel1, forceExp anded);
344 } 429 }
345 return title; 430
346 }, 431 /**
432 * @param {!Array<!WebInspector.TracingModel.Event>} events
433 * @param {string} title
434 * @param {!WebInspector.FlameChart.GroupStyle} style
435 * @param {boolean=} forceExpanded
436 */
437 _appendSyncEvents(events, title, style, forceExpanded) {
438 var openEvents = [];
439 var flowEventsEnabled = Runtime.experiments.isEnabled('timelineFlowEvents');
440 var blackboxingEnabled = Runtime.experiments.isEnabled('blackboxJSFramesOnTi meline');
441 var maxStackDepth = 0;
442 for (var i = 0; i < events.length; ++i) {
443 var e = events[i];
444 if (WebInspector.TimelineModel.isMarkerEvent(e))
445 this._markers.push(new WebInspector.TimelineFlameChartMarker(
446 e.startTime, e.startTime - this._model.minimumRecordTime(),
447 WebInspector.TimelineUIUtils.markerStyleForEvent(e)));
448 if (!WebInspector.TracingModel.isFlowPhase(e.phase)) {
449 if (!e.endTime && e.phase !== WebInspector.TracingModel.Phase.Instant)
450 continue;
451 if (WebInspector.TracingModel.isAsyncPhase(e.phase))
452 continue;
453 if (!this._isVisible(e))
454 continue;
455 }
456 while (openEvents.length && openEvents.peekLast().endTime <= e.startTime)
457 openEvents.pop();
458 e._blackboxRoot = false;
459 if (blackboxingEnabled && this._isBlackboxedEvent(e)) {
460 var parent = openEvents.peekLast();
461 if (parent && parent._blackboxRoot)
462 continue;
463 e._blackboxRoot = true;
464 }
465 if (title) {
466 this._appendHeader(title, style, forceExpanded);
467 title = '';
468 }
469
470 var level = this._currentLevel + openEvents.length;
471 this._appendEvent(e, level);
472 if (flowEventsEnabled)
473 this._appendFlowEvent(e, level);
474 maxStackDepth = Math.max(maxStackDepth, openEvents.length + 1);
475 if (e.endTime)
476 openEvents.push(e);
477 }
478 this._entryTypeByLevel.length = this._currentLevel + maxStackDepth;
479 this._entryTypeByLevel.fill(WebInspector.TimelineFlameChartEntryType.Event, this._currentLevel);
480 this._currentLevel += maxStackDepth;
481 }
482
483 /**
484 * @param {!WebInspector.TracingModel.Event} event
485 * @return {boolean}
486 */
487 _isBlackboxedEvent(event) {
488 if (event.name !== WebInspector.TimelineModel.RecordType.JSFrame)
489 return false;
490 var url = event.args['data']['url'];
491 return url && this._isBlackboxedURL(url);
492 }
493
494 /**
495 * @param {string} url
496 * @return {boolean}
497 */
498 _isBlackboxedURL(url) {
499 return WebInspector.blackboxManager.isBlackboxedURL(url);
500 }
501
502 /**
503 * @param {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInspec tor.TracingModel.AsyncEvent>>} asyncEvents
504 */
505 _appendAsyncEvents(asyncEvents) {
506 var groups = WebInspector.TimelineModel.AsyncEventGroup;
507 var groupArray = Object.keys(groups).map(key => groups[key]);
508
509 groupArray.remove(groups.animation);
510 groupArray.remove(groups.input);
511
512 for (var groupIndex = 0; groupIndex < groupArray.length; ++groupIndex) {
513 var group = groupArray[groupIndex];
514 var events = asyncEvents.get(group);
515 if (!events)
516 continue;
517 var title = WebInspector.TimelineUIUtils.titleForAsyncEventGroup(group);
518 this._appendAsyncEventsGroup(title, events, this._headerLevel1);
519 }
520 }
521
522 /**
523 * @param {string} header
524 * @param {!Array<!WebInspector.TracingModel.AsyncEvent>} events
525 * @param {!WebInspector.FlameChart.GroupStyle} style
526 */
527 _appendAsyncEventsGroup(header, events, style) {
528 var lastUsedTimeByLevel = [];
529 var groupHeaderAppended = false;
530 for (var i = 0; i < events.length; ++i) {
531 var asyncEvent = events[i];
532 if (!this._isVisible(asyncEvent))
533 continue;
534 if (!groupHeaderAppended) {
535 this._appendHeader(header, style);
536 groupHeaderAppended = true;
537 }
538 var startTime = asyncEvent.startTime;
539 var level;
540 for (level = 0; level < lastUsedTimeByLevel.length && lastUsedTimeByLevel[ level] > startTime; ++level) {
541 }
542 this._appendAsyncEvent(asyncEvent, this._currentLevel + level);
543 lastUsedTimeByLevel[level] = asyncEvent.endTime;
544 }
545 this._entryTypeByLevel.length = this._currentLevel + lastUsedTimeByLevel.len gth;
546 this._entryTypeByLevel.fill(WebInspector.TimelineFlameChartEntryType.Event, this._currentLevel);
547 this._currentLevel += lastUsedTimeByLevel.length;
548 }
549
550 _appendGPUEvents() {
551 if (this._appendSyncEvents(this._model.gpuEvents(), WebInspector.UIString('G PU'), this._headerLevel1, false))
552 ++this._currentLevel;
553 }
554
555 _appendInteractionRecords() {
556 this._irModel.interactionRecords().forEach(this._appendSegment, this);
557 this._entryTypeByLevel[this._currentLevel++] = WebInspector.TimelineFlameCha rtEntryType.InteractionRecord;
558 }
559
560 /**
561 * @param {!Array.<!WebInspector.TimelineFrame>} frames
562 */
563 _appendFrameBars(frames) {
564 var style = WebInspector.TimelineUIUtils.markerStyleForFrame();
565 this._entryTypeByLevel[this._currentLevel] = WebInspector.TimelineFlameChart EntryType.Frame;
566 for (var i = 0; i < frames.length; ++i) {
567 this._markers.push(new WebInspector.TimelineFlameChartMarker(
568 frames[i].startTime, frames[i].startTime - this._model.minimumRecordTi me(), style));
569 this._appendFrame(frames[i]);
570 }
571 ++this._currentLevel;
572 }
573
574 /**
575 * @param {number} entryIndex
576 * @return {!WebInspector.TimelineFlameChartEntryType}
577 */
578 _entryType(entryIndex) {
579 return this._entryTypeByLevel[this._timelineData.entryLevels[entryIndex]];
580 }
581
582 /**
583 * @override
584 * @param {number} entryIndex
585 * @return {?Element}
586 */
587 prepareHighlightedEntryInfo(entryIndex) {
588 var time = '';
589 var title;
590 var warning;
591 var type = this._entryType(entryIndex);
592 if (type === WebInspector.TimelineFlameChartEntryType.Event) {
593 var event = /** @type {!WebInspector.TracingModel.Event} */ (this._entryDa ta[entryIndex]);
594 var totalTime = event.duration;
595 var selfTime = event.selfTime;
596 var /** @const */ eps = 1e-6;
597 if (typeof totalTime === 'number') {
598 time = Math.abs(totalTime - selfTime) > eps && selfTime > eps ?
599 WebInspector.UIString(
600 '%s (self %s)', Number.millisToString(totalTime, true), Number.m illisToString(selfTime, true)) :
601 Number.millisToString(totalTime, true);
602 }
603 title = this.entryTitle(entryIndex);
604 warning = WebInspector.TimelineUIUtils.eventWarning(event);
605 } else if (type === WebInspector.TimelineFlameChartEntryType.Frame) {
606 var frame = /** @type {!WebInspector.TimelineFrame} */ (this._entryData[en tryIndex]);
607 time = WebInspector.UIString(
608 '%s ~ %.0f\u2009fps', Number.preciseMillisToString(frame.duration, 1), (1000 / frame.duration));
609 title = frame.idle ? WebInspector.UIString('Idle Frame') : WebInspector.UI String('Frame');
610 if (frame.hasWarnings()) {
611 warning = createElement('span');
612 warning.textContent = WebInspector.UIString('Long frame');
613 }
614 } else {
615 return null;
616 }
617 var element = createElement('div');
618 var root = WebInspector.createShadowRootWithCoreStyles(element, 'timeline/ti melineFlamechartPopover.css');
619 var contents = root.createChild('div', 'timeline-flamechart-popover');
620 contents.createChild('span', 'timeline-info-time').textContent = time;
621 contents.createChild('span', 'timeline-info-title').textContent = title;
622 if (warning) {
623 warning.classList.add('timeline-info-warning');
624 contents.appendChild(warning);
625 }
626 return element;
627 }
628
629 /**
630 * @override
631 * @param {number} entryIndex
632 * @return {string}
633 */
634 entryColor(entryIndex) {
635 // This is not annotated due to closure compiler failure to properly infer c ache container's template type.
636 function patchColorAndCache(cache, key, lookupColor) {
637 var color = cache.get(key);
638 if (color)
639 return color;
640 var parsedColor = WebInspector.Color.parse(lookupColor(key));
641 color = parsedColor.setAlpha(0.7).asString(WebInspector.Color.Format.RGBA) || '';
642 cache.set(key, color);
643 return color;
644 }
645
646 var type = this._entryType(entryIndex);
647 if (type === WebInspector.TimelineFlameChartEntryType.Event) {
648 var event = /** @type {!WebInspector.TracingModel.Event} */ (this._entryDa ta[entryIndex]);
649 if (!WebInspector.TracingModel.isAsyncPhase(event.phase))
650 return WebInspector.TimelineUIUtils.eventColor(event);
651 if (event.hasCategory(WebInspector.TimelineModel.Category.Console) ||
652 event.hasCategory(WebInspector.TimelineModel.Category.UserTiming))
653 return this._consoleColorGenerator.colorForID(event.name);
654 if (event.hasCategory(WebInspector.TimelineModel.Category.LatencyInfo)) {
655 var phase =
656 WebInspector.TimelineIRModel.phaseForEvent(event) || WebInspector.Ti melineIRModel.Phases.Uncategorized;
657 return patchColorAndCache(
658 this._asyncColorByInteractionPhase, phase, WebInspector.TimelineUIUt ils.interactionPhaseColor);
659 }
660 var category = WebInspector.TimelineUIUtils.eventStyle(event).category;
661 return patchColorAndCache(this._asyncColorByCategory, category, () => cate gory.color);
662 }
663 if (type === WebInspector.TimelineFlameChartEntryType.Frame)
664 return 'white';
665 if (type === WebInspector.TimelineFlameChartEntryType.InteractionRecord)
666 return 'transparent';
667 return '';
668 }
669
670 /**
671 * @override
672 * @param {number} entryIndex
673 * @param {!CanvasRenderingContext2D} context
674 * @param {?string} text
675 * @param {number} barX
676 * @param {number} barY
677 * @param {number} barWidth
678 * @param {number} barHeight
679 * @param {number} unclippedBarX
680 * @param {number} timeToPixels
681 * @return {boolean}
682 */
683 decorateEntry(entryIndex, context, text, barX, barY, barWidth, barHeight, uncl ippedBarX, timeToPixels) {
684 var data = this._entryData[entryIndex];
685 var type = this._entryType(entryIndex);
686 if (type === WebInspector.TimelineFlameChartEntryType.Frame) {
687 var /** @const */ vPadding = 1;
688 var /** @const */ hPadding = 1;
689 var frame = /** {!WebInspector.TimelineFrame} */ (data);
690 barX += hPadding;
691 barWidth -= 2 * hPadding;
692 barY += vPadding;
693 barHeight -= 2 * vPadding + 1;
694 context.fillStyle = frame.idle ? 'white' : (frame.hasWarnings() ? '#fad1d1 ' : '#d7f0d1');
695 context.fillRect(barX, barY, barWidth, barHeight);
696 var frameDurationText = Number.preciseMillisToString(frame.duration, 1);
697 var textWidth = context.measureText(frameDurationText).width;
698 if (barWidth >= textWidth) {
699 context.fillStyle = this.textColor(entryIndex);
700 context.fillText(frameDurationText, barX + (barWidth - textWidth) / 2, b arY + barHeight - 3);
701 }
702 return true;
703 }
704
705 if (type === WebInspector.TimelineFlameChartEntryType.InteractionRecord) {
706 var color = WebInspector.TimelineUIUtils.interactionPhaseColor(
707 /** @type {!WebInspector.TimelineIRModel.Phases} */ (this._entryData[e ntryIndex]));
708 context.fillStyle = color;
709 context.fillRect(barX, barY, barWidth - 1, 2);
710 context.fillRect(barX, barY - 3, 2, 3);
711 context.fillRect(barX + barWidth - 3, barY - 3, 2, 3);
712 return false;
713 }
714
715 if (type === WebInspector.TimelineFlameChartEntryType.Event) {
716 var event = /** @type {!WebInspector.TracingModel.Event} */ (this._entryDa ta[entryIndex]);
717 if (event.hasCategory(WebInspector.TimelineModel.Category.LatencyInfo) && event.timeWaitingForMainThread) {
718 context.fillStyle = 'hsla(0, 70%, 60%, 1)';
719 var width = Math.floor(unclippedBarX - barX + event.timeWaitingForMainTh read * timeToPixels);
720 context.fillRect(barX, barY + barHeight - 3, width, 2);
721 }
722 if (event.warning)
723 paintWarningDecoration(barX, barWidth - 1.5);
724 }
347 725
348 /** 726 /**
349 * @override 727 * @param {number} x
350 * @param {number} index 728 * @param {number} width
351 * @return {string}
352 */ 729 */
353 textColor: function(index) 730 function paintWarningDecoration(x, width) {
354 { 731 var /** @const */ triangleSize = 8;
355 var event = this._entryData[index]; 732 context.save();
356 if (event && event._blackboxRoot) 733 context.beginPath();
357 return "#888"; 734 context.rect(x, barY, width, barHeight);
358 else 735 context.clip();
359 return WebInspector.TimelineFlameChartDataProviderBase.prototype.tex tColor.call(this, index); 736 context.beginPath();
360 }, 737 context.fillStyle = 'red';
361 738 context.moveTo(x + width - triangleSize, barY);
362 /** 739 context.lineTo(x + width, barY);
363 * @override 740 context.lineTo(x + width, barY + triangleSize);
364 */ 741 context.fill();
365 reset: function() 742 context.restore();
366 { 743 }
367 WebInspector.TimelineFlameChartDataProviderBase.prototype.reset.call(thi s); 744
368 /** @type {!Array<!WebInspector.TracingModel.Event|!WebInspector.Timelin eFrame|!WebInspector.TimelineIRModel.Phases>} */ 745 return false;
369 this._entryData = []; 746 }
370 /** @type {!Array<!WebInspector.TimelineFlameChartEntryType>} */ 747
371 this._entryTypeByLevel = []; 748 /**
372 /** @type {!Array<string>} */ 749 * @override
373 this._entryIndexToTitle = []; 750 * @param {number} entryIndex
374 /** @type {!Array<!WebInspector.TimelineFlameChartMarker>} */ 751 * @return {boolean}
375 this._markers = []; 752 */
376 /** @type {!Map<!WebInspector.TimelineCategory, string>} */ 753 forceDecoration(entryIndex) {
377 this._asyncColorByCategory = new Map(); 754 var type = this._entryType(entryIndex);
378 /** @type {!Map<!WebInspector.TimelineIRModel.Phases, string>} */ 755 return type === WebInspector.TimelineFlameChartEntryType.Frame ||
379 this._asyncColorByInteractionPhase = new Map(); 756 type === WebInspector.TimelineFlameChartEntryType.Event &&
380 }, 757 !!(/** @type {!WebInspector.TracingModel.Event} */ (this._entryData[entr yIndex]).warning);
381 758 }
382 /** 759
383 * @override 760 /**
384 * @return {!WebInspector.FlameChart.TimelineData} 761 * @param {string} title
385 */ 762 * @param {!WebInspector.FlameChart.GroupStyle} style
386 timelineData: function() 763 * @param {boolean=} expanded
387 { 764 */
388 if (this._timelineData) 765 _appendHeader(title, style, expanded) {
389 return this._timelineData; 766 this._timelineData.groups.push({startLevel: this._currentLevel, name: title, expanded: expanded, style: style});
390 767 }
391 this._timelineData = new WebInspector.FlameChart.TimelineData([], [], [] , []); 768
392 769 /**
393 this._flowEventIndexById = {}; 770 * @param {!WebInspector.TracingModel.Event} event
394 this._minimumBoundary = this._model.minimumRecordTime(); 771 * @param {number} level
395 this._timeSpan = this._model.isEmpty() ? 1000 : this._model.maximumReco rdTime() - this._minimumBoundary; 772 */
396 this._currentLevel = 0; 773 _appendEvent(event, level) {
397 this._appendFrameBars(this._frameModel.frames()); 774 var index = this._entryData.length;
398 775 this._entryData.push(event);
399 this._appendHeader(WebInspector.UIString("Interactions"), this._interact ionsHeaderLevel1); 776 this._timelineData.entryLevels[index] = level;
400 this._appendInteractionRecords(); 777 var duration;
401 778 if (WebInspector.TimelineModel.isMarkerEvent(event))
402 var asyncEventGroups = WebInspector.TimelineModel.AsyncEventGroup; 779 duration = undefined;
403 var inputLatencies = this._model.mainThreadAsyncEvents().get(asyncEventG roups.input); 780 else
404 if (inputLatencies && inputLatencies.length) { 781 duration = event.duration || WebInspector.TimelineFlameChartDataProvider.I nstantEventVisibleDurationMs;
405 var title = WebInspector.TimelineUIUtils.titleForAsyncEventGroup(asy ncEventGroups.input); 782 this._timelineData.entryTotalTimes[index] = duration;
406 this._appendAsyncEventsGroup(title, inputLatencies, this._interactio nsHeaderLevel2); 783 this._timelineData.entryStartTimes[index] = event.startTime;
407 } 784 }
408 var animations = this._model.mainThreadAsyncEvents().get(asyncEventGroup s.animation); 785
409 if (animations && animations.length) { 786 /**
410 var title = WebInspector.TimelineUIUtils.titleForAsyncEventGroup(asy ncEventGroups.animation); 787 * @param {!WebInspector.TracingModel.Event} event
411 this._appendAsyncEventsGroup(title, animations, this._interactionsHe aderLevel2); 788 * @param {number} level
412 } 789 */
413 var threads = this._model.virtualThreads(); 790 _appendFlowEvent(event, level) {
414 this._appendThreadTimelineData(WebInspector.UIString("Main"), this._mode l.mainThreadEvents(), this._model.mainThreadAsyncEvents(), true); 791 var timelineData = this._timelineData;
415 var compositorThreads = threads.filter(thread => thread.name.startsWith( "CompositorTileWorker"));
416 var otherThreads = threads.filter(thread => !thread.name.startsWith("Com positorTileWorker"));
417 if (compositorThreads.length) {
418 this._appendHeader(WebInspector.UIString("Raster"), this._headerLeve l1);
419 for (var i = 0; i < compositorThreads.length; ++i)
420 this._appendSyncEvents(compositorThreads[i].events, WebInspector .UIString("Rasterizer Thread %d", i), this._headerLevel2);
421 }
422 this._appendGPUEvents();
423
424 otherThreads.forEach(thread => this._appendThreadTimelineData(thread.nam e, thread.events, thread.asyncEventsByGroup));
425
426 /**
427 * @param {!WebInspector.TimelineFlameChartMarker} a
428 * @param {!WebInspector.TimelineFlameChartMarker} b
429 */
430 function compareStartTime(a, b)
431 {
432 return a.startTime() - b.startTime();
433 }
434
435 this._markers.sort(compareStartTime);
436 this._timelineData.markers = this._markers;
437
438 this._flowEventIndexById = {};
439 return this._timelineData;
440 },
441
442 /**
443 * @param {string} threadTitle
444 * @param {!Array<!WebInspector.TracingModel.Event>} syncEvents
445 * @param {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInsp ector.TracingModel.AsyncEvent>>} asyncEvents
446 * @param {boolean=} forceExpanded
447 */
448 _appendThreadTimelineData: function(threadTitle, syncEvents, asyncEvents, fo rceExpanded)
449 {
450 this._appendAsyncEvents(asyncEvents);
451 this._appendSyncEvents(syncEvents, threadTitle, this._headerLevel1, forc eExpanded);
452 },
453
454 /**
455 * @param {!Array<!WebInspector.TracingModel.Event>} events
456 * @param {string} title
457 * @param {!WebInspector.FlameChart.GroupStyle} style
458 * @param {boolean=} forceExpanded
459 */
460 _appendSyncEvents: function(events, title, style, forceExpanded)
461 {
462 var openEvents = [];
463 var flowEventsEnabled = Runtime.experiments.isEnabled("timelineFlowEvent s");
464 var blackboxingEnabled = Runtime.experiments.isEnabled("blackboxJSFrames OnTimeline");
465 var maxStackDepth = 0;
466 for (var i = 0; i < events.length; ++i) {
467 var e = events[i];
468 if (WebInspector.TimelineModel.isMarkerEvent(e))
469 this._markers.push(new WebInspector.TimelineFlameChartMarker(e.s tartTime, e.startTime - this._model.minimumRecordTime(), WebInspector.TimelineUI Utils.markerStyleForEvent(e)));
470 if (!WebInspector.TracingModel.isFlowPhase(e.phase)) {
471 if (!e.endTime && e.phase !== WebInspector.TracingModel.Phase.In stant)
472 continue;
473 if (WebInspector.TracingModel.isAsyncPhase(e.phase))
474 continue;
475 if (!this._isVisible(e))
476 continue;
477 }
478 while (openEvents.length && openEvents.peekLast().endTime <= e.start Time)
479 openEvents.pop();
480 e._blackboxRoot = false;
481 if (blackboxingEnabled && this._isBlackboxedEvent(e)) {
482 var parent = openEvents.peekLast();
483 if (parent && parent._blackboxRoot)
484 continue;
485 e._blackboxRoot = true;
486 }
487 if (title) {
488 this._appendHeader(title, style, forceExpanded);
489 title = "";
490 }
491
492 var level = this._currentLevel + openEvents.length;
493 this._appendEvent(e, level);
494 if (flowEventsEnabled)
495 this._appendFlowEvent(e, level);
496 maxStackDepth = Math.max(maxStackDepth, openEvents.length + 1);
497 if (e.endTime)
498 openEvents.push(e);
499 }
500 this._entryTypeByLevel.length = this._currentLevel + maxStackDepth;
501 this._entryTypeByLevel.fill(WebInspector.TimelineFlameChartEntryType.Eve nt, this._currentLevel);
502 this._currentLevel += maxStackDepth;
503 },
504
505 /** 792 /**
506 * @param {!WebInspector.TracingModel.Event} event 793 * @param {!WebInspector.TracingModel.Event} event
507 * @return {boolean} 794 * @return {number}
508 */ 795 */
509 _isBlackboxedEvent: function(event) 796 function pushStartFlow(event) {
510 { 797 var flowIndex = timelineData.flowStartTimes.length;
511 if (event.name !== WebInspector.TimelineModel.RecordType.JSFrame) 798 timelineData.flowStartTimes.push(event.startTime);
512 return false; 799 timelineData.flowStartLevels.push(level);
513 var url = event.args["data"]["url"]; 800 return flowIndex;
514 return url && this._isBlackboxedURL(url); 801 }
515 },
516
517 /**
518 * @param {string} url
519 * @return {boolean}
520 */
521 _isBlackboxedURL: function(url)
522 {
523 return WebInspector.blackboxManager.isBlackboxedURL(url);
524 },
525
526 /**
527 * @param {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInsp ector.TracingModel.AsyncEvent>>} asyncEvents
528 */
529 _appendAsyncEvents: function(asyncEvents)
530 {
531 var groups = WebInspector.TimelineModel.AsyncEventGroup;
532 var groupArray = Object.keys(groups).map(key => groups[key]);
533
534 groupArray.remove(groups.animation);
535 groupArray.remove(groups.input);
536
537 for (var groupIndex = 0; groupIndex < groupArray.length; ++groupIndex) {
538 var group = groupArray[groupIndex];
539 var events = asyncEvents.get(group);
540 if (!events)
541 continue;
542 var title = WebInspector.TimelineUIUtils.titleForAsyncEventGroup(gro up);
543 this._appendAsyncEventsGroup(title, events, this._headerLevel1);
544 }
545 },
546
547 /**
548 * @param {string} header
549 * @param {!Array<!WebInspector.TracingModel.AsyncEvent>} events
550 * @param {!WebInspector.FlameChart.GroupStyle} style
551 */
552 _appendAsyncEventsGroup: function(header, events, style)
553 {
554 var lastUsedTimeByLevel = [];
555 var groupHeaderAppended = false;
556 for (var i = 0; i < events.length; ++i) {
557 var asyncEvent = events[i];
558 if (!this._isVisible(asyncEvent))
559 continue;
560 if (!groupHeaderAppended) {
561 this._appendHeader(header, style);
562 groupHeaderAppended = true;
563 }
564 var startTime = asyncEvent.startTime;
565 var level;
566 for (level = 0; level < lastUsedTimeByLevel.length && lastUsedTimeBy Level[level] > startTime; ++level) {}
567 this._appendAsyncEvent(asyncEvent, this._currentLevel + level);
568 lastUsedTimeByLevel[level] = asyncEvent.endTime;
569 }
570 this._entryTypeByLevel.length = this._currentLevel + lastUsedTimeByLevel .length;
571 this._entryTypeByLevel.fill(WebInspector.TimelineFlameChartEntryType.Eve nt, this._currentLevel);
572 this._currentLevel += lastUsedTimeByLevel.length;
573 },
574
575 _appendGPUEvents: function()
576 {
577 if (this._appendSyncEvents(this._model.gpuEvents(), WebInspector.UIStrin g("GPU"), this._headerLevel1, false))
578 ++this._currentLevel;
579 },
580
581 _appendInteractionRecords: function()
582 {
583 this._irModel.interactionRecords().forEach(this._appendSegment, this);
584 this._entryTypeByLevel[this._currentLevel++] = WebInspector.TimelineFlam eChartEntryType.InteractionRecord;
585 },
586
587 /**
588 * @param {!Array.<!WebInspector.TimelineFrame>} frames
589 */
590 _appendFrameBars: function(frames)
591 {
592 var style = WebInspector.TimelineUIUtils.markerStyleForFrame();
593 this._entryTypeByLevel[this._currentLevel] = WebInspector.TimelineFlameC hartEntryType.Frame;
594 for (var i = 0; i < frames.length; ++i) {
595 this._markers.push(new WebInspector.TimelineFlameChartMarker(frames[ i].startTime, frames[i].startTime - this._model.minimumRecordTime(), style));
596 this._appendFrame(frames[i]);
597 }
598 ++this._currentLevel;
599 },
600
601 /**
602 * @param {number} entryIndex
603 * @return {!WebInspector.TimelineFlameChartEntryType}
604 */
605 _entryType: function(entryIndex)
606 {
607 return this._entryTypeByLevel[this._timelineData.entryLevels[entryIndex] ];
608 },
609
610 /**
611 * @override
612 * @param {number} entryIndex
613 * @return {?Element}
614 */
615 prepareHighlightedEntryInfo: function(entryIndex)
616 {
617 var time = "";
618 var title;
619 var warning;
620 var type = this._entryType(entryIndex);
621 if (type === WebInspector.TimelineFlameChartEntryType.Event) {
622 var event = /** @type {!WebInspector.TracingModel.Event} */ (this._e ntryData[entryIndex]);
623 var totalTime = event.duration;
624 var selfTime = event.selfTime;
625 var /** @const */ eps = 1e-6;
626 if (typeof totalTime === "number") {
627 time = Math.abs(totalTime - selfTime) > eps && selfTime > eps ?
628 WebInspector.UIString("%s (self %s)", Number.millisToString( totalTime, true), Number.millisToString(selfTime, true)) :
629 Number.millisToString(totalTime, true);
630 }
631 title = this.entryTitle(entryIndex);
632 warning = WebInspector.TimelineUIUtils.eventWarning(event);
633 } else if (type === WebInspector.TimelineFlameChartEntryType.Frame) {
634 var frame = /** @type {!WebInspector.TimelineFrame} */ (this._entryD ata[entryIndex]);
635 time = WebInspector.UIString("%s ~ %.0f\u2009fps", Number.preciseMil lisToString(frame.duration, 1), (1000 / frame.duration));
636 title = frame.idle ? WebInspector.UIString("Idle Frame") : WebInspec tor.UIString("Frame");
637 if (frame.hasWarnings()) {
638 warning = createElement("span");
639 warning.textContent = WebInspector.UIString("Long frame");
640 }
641 } else {
642 return null;
643 }
644 var element = createElement("div");
645 var root = WebInspector.createShadowRootWithCoreStyles(element, "timelin e/timelineFlamechartPopover.css");
646 var contents = root.createChild("div", "timeline-flamechart-popover");
647 contents.createChild("span", "timeline-info-time").textContent = time;
648 contents.createChild("span", "timeline-info-title").textContent = title;
649 if (warning) {
650 warning.classList.add("timeline-info-warning");
651 contents.appendChild(warning);
652 }
653 return element;
654 },
655
656 /**
657 * @override
658 * @param {number} entryIndex
659 * @return {string}
660 */
661 entryColor: function(entryIndex)
662 {
663 // This is not annotated due to closure compiler failure to properly inf er cache container's template type.
664 function patchColorAndCache(cache, key, lookupColor)
665 {
666 var color = cache.get(key);
667 if (color)
668 return color;
669 var parsedColor = WebInspector.Color.parse(lookupColor(key));
670 color = parsedColor.setAlpha(0.7).asString(WebInspector.Color.Format .RGBA) || "";
671 cache.set(key, color);
672 return color;
673 }
674
675 var type = this._entryType(entryIndex);
676 if (type === WebInspector.TimelineFlameChartEntryType.Event) {
677 var event = /** @type {!WebInspector.TracingModel.Event} */ (this._e ntryData[entryIndex]);
678 if (!WebInspector.TracingModel.isAsyncPhase(event.phase))
679 return WebInspector.TimelineUIUtils.eventColor(event);
680 if (event.hasCategory(WebInspector.TimelineModel.Category.Console) | | event.hasCategory(WebInspector.TimelineModel.Category.UserTiming))
681 return this._consoleColorGenerator.colorForID(event.name);
682 if (event.hasCategory(WebInspector.TimelineModel.Category.LatencyInf o)) {
683 var phase = WebInspector.TimelineIRModel.phaseForEvent(event) || WebInspector.TimelineIRModel.Phases.Uncategorized;
684 return patchColorAndCache(this._asyncColorByInteractionPhase, ph ase, WebInspector.TimelineUIUtils.interactionPhaseColor);
685 }
686 var category = WebInspector.TimelineUIUtils.eventStyle(event).catego ry;
687 return patchColorAndCache(this._asyncColorByCategory, category, () = > category.color);
688 }
689 if (type === WebInspector.TimelineFlameChartEntryType.Frame)
690 return "white";
691 if (type === WebInspector.TimelineFlameChartEntryType.InteractionRecord)
692 return "transparent";
693 return "";
694 },
695
696 /**
697 * @override
698 * @param {number} entryIndex
699 * @param {!CanvasRenderingContext2D} context
700 * @param {?string} text
701 * @param {number} barX
702 * @param {number} barY
703 * @param {number} barWidth
704 * @param {number} barHeight
705 * @param {number} unclippedBarX
706 * @param {number} timeToPixels
707 * @return {boolean}
708 */
709 decorateEntry: function(entryIndex, context, text, barX, barY, barWidth, bar Height, unclippedBarX, timeToPixels)
710 {
711 var data = this._entryData[entryIndex];
712 var type = this._entryType(entryIndex);
713 if (type === WebInspector.TimelineFlameChartEntryType.Frame) {
714 var /** @const */ vPadding = 1;
715 var /** @const */ hPadding = 1;
716 var frame = /** {!WebInspector.TimelineFrame} */ (data);
717 barX += hPadding;
718 barWidth -= 2 * hPadding;
719 barY += vPadding;
720 barHeight -= 2 * vPadding + 1;
721 context.fillStyle = frame.idle ? "white" : (frame.hasWarnings() ? "# fad1d1" : "#d7f0d1");
722 context.fillRect(barX, barY, barWidth, barHeight);
723 var frameDurationText = Number.preciseMillisToString(frame.duration, 1);
724 var textWidth = context.measureText(frameDurationText).width;
725 if (barWidth >= textWidth) {
726 context.fillStyle = this.textColor(entryIndex);
727 context.fillText(frameDurationText, barX + (barWidth - textWidth ) / 2, barY + barHeight - 3);
728 }
729 return true;
730 }
731
732 if (type === WebInspector.TimelineFlameChartEntryType.InteractionRecord) {
733 var color = WebInspector.TimelineUIUtils.interactionPhaseColor(/** @ type {!WebInspector.TimelineIRModel.Phases} */ (this._entryData[entryIndex]));
734 context.fillStyle = color;
735 context.fillRect(barX, barY, barWidth - 1, 2);
736 context.fillRect(barX, barY - 3, 2, 3);
737 context.fillRect(barX + barWidth - 3, barY - 3, 2, 3);
738 return false;
739 }
740
741 if (type === WebInspector.TimelineFlameChartEntryType.Event) {
742 var event = /** @type {!WebInspector.TracingModel.Event} */ (this._e ntryData[entryIndex]);
743 if (event.hasCategory(WebInspector.TimelineModel.Category.LatencyInf o) && event.timeWaitingForMainThread) {
744 context.fillStyle = "hsla(0, 70%, 60%, 1)";
745 var width = Math.floor(unclippedBarX - barX + event.timeWaitingF orMainThread * timeToPixels);
746 context.fillRect(barX, barY + barHeight - 3, width, 2);
747 }
748 if (event.warning)
749 paintWarningDecoration(barX, barWidth - 1.5);
750 }
751
752 /**
753 * @param {number} x
754 * @param {number} width
755 */
756 function paintWarningDecoration(x, width)
757 {
758 var /** @const */ triangleSize = 8;
759 context.save();
760 context.beginPath();
761 context.rect(x, barY, width, barHeight);
762 context.clip();
763 context.beginPath();
764 context.fillStyle = "red";
765 context.moveTo(x + width - triangleSize, barY);
766 context.lineTo(x + width, barY);
767 context.lineTo(x + width, barY + triangleSize);
768 context.fill();
769 context.restore();
770 }
771
772 return false;
773 },
774
775 /**
776 * @override
777 * @param {number} entryIndex
778 * @return {boolean}
779 */
780 forceDecoration: function(entryIndex)
781 {
782 var type = this._entryType(entryIndex);
783 return type === WebInspector.TimelineFlameChartEntryType.Frame ||
784 type === WebInspector.TimelineFlameChartEntryType.Event && !!(/** @t ype {!WebInspector.TracingModel.Event} */ (this._entryData[entryIndex]).warning) ;
785 },
786
787 /**
788 * @param {string} title
789 * @param {!WebInspector.FlameChart.GroupStyle} style
790 * @param {boolean=} expanded
791 */
792 _appendHeader: function(title, style, expanded)
793 {
794 this._timelineData.groups.push({startLevel: this._currentLevel, name: ti tle, expanded: expanded, style: style});
795 },
796 802
797 /** 803 /**
798 * @param {!WebInspector.TracingModel.Event} event 804 * @param {!WebInspector.TracingModel.Event} event
799 * @param {number} level 805 * @param {number} flowIndex
800 */ 806 */
801 _appendEvent: function(event, level) 807 function pushEndFlow(event, flowIndex) {
802 { 808 timelineData.flowEndTimes[flowIndex] = event.startTime;
803 var index = this._entryData.length; 809 timelineData.flowEndLevels[flowIndex] = level;
804 this._entryData.push(event); 810 }
805 this._timelineData.entryLevels[index] = level; 811
806 var duration; 812 switch (event.phase) {
807 if (WebInspector.TimelineModel.isMarkerEvent(event)) 813 case WebInspector.TracingModel.Phase.FlowBegin:
808 duration = undefined; 814 this._flowEventIndexById[event.id] = pushStartFlow(event);
809 else 815 break;
810 duration = event.duration || WebInspector.TimelineFlameChartDataProv ider.InstantEventVisibleDurationMs; 816 case WebInspector.TracingModel.Phase.FlowStep:
811 this._timelineData.entryTotalTimes[index] = duration; 817 pushEndFlow(event, this._flowEventIndexById[event.id]);
812 this._timelineData.entryStartTimes[index] = event.startTime; 818 this._flowEventIndexById[event.id] = pushStartFlow(event);
813 }, 819 break;
814 820 case WebInspector.TracingModel.Phase.FlowEnd:
815 /** 821 pushEndFlow(event, this._flowEventIndexById[event.id]);
816 * @param {!WebInspector.TracingModel.Event} event 822 delete this._flowEventIndexById[event.id];
817 * @param {number} level 823 break;
818 */ 824 }
819 _appendFlowEvent: function(event, level) 825 }
820 { 826
821 var timelineData = this._timelineData; 827 /**
822 /** 828 * @param {!WebInspector.TracingModel.AsyncEvent} asyncEvent
823 * @param {!WebInspector.TracingModel.Event} event 829 * @param {number} level
824 * @return {number} 830 */
825 */ 831 _appendAsyncEvent(asyncEvent, level) {
826 function pushStartFlow(event) 832 if (WebInspector.TracingModel.isNestableAsyncPhase(asyncEvent.phase)) {
827 { 833 // FIXME: also add steps once we support event nesting in the FlameChart.
828 var flowIndex = timelineData.flowStartTimes.length; 834 this._appendEvent(asyncEvent, level);
829 timelineData.flowStartTimes.push(event.startTime); 835 return;
830 timelineData.flowStartLevels.push(level); 836 }
831 return flowIndex; 837 var steps = asyncEvent.steps;
832 } 838 // If we have past steps, put the end event for each range rather than start one.
833 839 var eventOffset = steps.length > 1 && steps[1].phase === WebInspector.Tracin gModel.Phase.AsyncStepPast ? 1 : 0;
834 /** 840 for (var i = 0; i < steps.length - 1; ++i) {
835 * @param {!WebInspector.TracingModel.Event} event 841 var index = this._entryData.length;
836 * @param {number} flowIndex 842 this._entryData.push(steps[i + eventOffset]);
837 */ 843 var startTime = steps[i].startTime;
838 function pushEndFlow(event, flowIndex) 844 this._timelineData.entryLevels[index] = level;
839 { 845 this._timelineData.entryTotalTimes[index] = steps[i + 1].startTime - start Time;
840 timelineData.flowEndTimes[flowIndex] = event.startTime; 846 this._timelineData.entryStartTimes[index] = startTime;
841 timelineData.flowEndLevels[flowIndex] = level; 847 }
842 } 848 }
843 849
844 switch (event.phase) { 850 /**
845 case WebInspector.TracingModel.Phase.FlowBegin: 851 * @param {!WebInspector.TimelineFrame} frame
846 this._flowEventIndexById[event.id] = pushStartFlow(event); 852 */
847 break; 853 _appendFrame(frame) {
848 case WebInspector.TracingModel.Phase.FlowStep: 854 var index = this._entryData.length;
849 pushEndFlow(event, this._flowEventIndexById[event.id]); 855 this._entryData.push(frame);
850 this._flowEventIndexById[event.id] = pushStartFlow(event); 856 this._entryIndexToTitle[index] = Number.millisToString(frame.duration, true) ;
851 break; 857 this._timelineData.entryLevels[index] = this._currentLevel;
852 case WebInspector.TracingModel.Phase.FlowEnd: 858 this._timelineData.entryTotalTimes[index] = frame.duration;
853 pushEndFlow(event, this._flowEventIndexById[event.id]); 859 this._timelineData.entryStartTimes[index] = frame.startTime;
854 delete this._flowEventIndexById[event.id]; 860 }
855 break; 861
856 } 862 /**
857 }, 863 * @param {!WebInspector.Segment} segment
858 864 */
859 /** 865 _appendSegment(segment) {
860 * @param {!WebInspector.TracingModel.AsyncEvent} asyncEvent 866 var index = this._entryData.length;
861 * @param {number} level 867 this._entryData.push(/** @type {!WebInspector.TimelineIRModel.Phases} */ (se gment.data));
862 */ 868 this._entryIndexToTitle[index] = /** @type {string} */ (segment.data);
863 _appendAsyncEvent: function(asyncEvent, level) 869 this._timelineData.entryLevels[index] = this._currentLevel;
864 { 870 this._timelineData.entryTotalTimes[index] = segment.end - segment.begin;
865 if (WebInspector.TracingModel.isNestableAsyncPhase(asyncEvent.phase)) { 871 this._timelineData.entryStartTimes[index] = segment.begin;
866 // FIXME: also add steps once we support event nesting in the FlameC hart. 872 }
867 this._appendEvent(asyncEvent, level); 873
868 return; 874 /**
869 } 875 * @override
870 var steps = asyncEvent.steps; 876 * @param {number} entryIndex
871 // If we have past steps, put the end event for each range rather than s tart one. 877 * @return {?WebInspector.TimelineSelection}
872 var eventOffset = steps.length > 1 && steps[1].phase === WebInspector.Tr acingModel.Phase.AsyncStepPast ? 1 : 0; 878 */
873 for (var i = 0; i < steps.length - 1; ++i) { 879 createSelection(entryIndex) {
874 var index = this._entryData.length; 880 var type = this._entryType(entryIndex);
875 this._entryData.push(steps[i + eventOffset]); 881 var timelineSelection = null;
876 var startTime = steps[i].startTime; 882 if (type === WebInspector.TimelineFlameChartEntryType.Event)
877 this._timelineData.entryLevels[index] = level; 883 timelineSelection = WebInspector.TimelineSelection.fromTraceEvent(
878 this._timelineData.entryTotalTimes[index] = steps[i + 1].startTime - startTime; 884 /** @type {!WebInspector.TracingModel.Event} */ (this._entryData[entry Index]));
879 this._timelineData.entryStartTimes[index] = startTime; 885 else if (type === WebInspector.TimelineFlameChartEntryType.Frame)
880 } 886 timelineSelection = WebInspector.TimelineSelection.fromFrame(
881 }, 887 /** @type {!WebInspector.TimelineFrame} */ (this._entryData[entryIndex ]));
882 888 if (timelineSelection)
883 /** 889 this._lastSelection = new WebInspector.TimelineFlameChartView.Selection(ti melineSelection, entryIndex);
884 * @param {!WebInspector.TimelineFrame} frame 890 return timelineSelection;
885 */ 891 }
886 _appendFrame: function(frame) 892
887 { 893 /**
888 var index = this._entryData.length; 894 * @param {?WebInspector.TimelineSelection} selection
889 this._entryData.push(frame); 895 * @return {number}
890 this._entryIndexToTitle[index] = Number.millisToString(frame.duration, t rue); 896 */
891 this._timelineData.entryLevels[index] = this._currentLevel; 897 entryIndexForSelection(selection) {
892 this._timelineData.entryTotalTimes[index] = frame.duration; 898 if (!selection || selection.type() === WebInspector.TimelineSelection.Type.R ange)
893 this._timelineData.entryStartTimes[index] = frame.startTime; 899 return -1;
894 }, 900
895 901 if (this._lastSelection && this._lastSelection.timelineSelection.object() == = selection.object())
896 /** 902 return this._lastSelection.entryIndex;
897 * @param {!WebInspector.Segment} segment 903 var index = this._entryData.indexOf(
898 */ 904 /** @type {!WebInspector.TracingModel.Event|!WebInspector.TimelineFrame| !WebInspector.TimelineIRModel.Phases} */
899 _appendSegment: function(segment) 905 (selection.object()));
900 { 906 if (index !== -1)
901 var index = this._entryData.length; 907 this._lastSelection = new WebInspector.TimelineFlameChartView.Selection(se lection, index);
902 this._entryData.push(/** @type {!WebInspector.TimelineIRModel.Phases} */ (segment.data)); 908 return index;
903 this._entryIndexToTitle[index] = /** @type {string} */ (segment.data); 909 }
904 this._timelineData.entryLevels[index] = this._currentLevel;
905 this._timelineData.entryTotalTimes[index] = segment.end - segment.begin;
906 this._timelineData.entryStartTimes[index] = segment.begin;
907 },
908
909 /**
910 * @override
911 * @param {number} entryIndex
912 * @return {?WebInspector.TimelineSelection}
913 */
914 createSelection: function(entryIndex)
915 {
916 var type = this._entryType(entryIndex);
917 var timelineSelection = null;
918 if (type === WebInspector.TimelineFlameChartEntryType.Event)
919 timelineSelection = WebInspector.TimelineSelection.fromTraceEvent(/* * @type {!WebInspector.TracingModel.Event} */ (this._entryData[entryIndex]));
920 else if (type === WebInspector.TimelineFlameChartEntryType.Frame)
921 timelineSelection = WebInspector.TimelineSelection.fromFrame(/** @ty pe {!WebInspector.TimelineFrame} */ (this._entryData[entryIndex]));
922 if (timelineSelection)
923 this._lastSelection = new WebInspector.TimelineFlameChartView.Select ion(timelineSelection, entryIndex);
924 return timelineSelection;
925 },
926
927 /**
928 * @param {?WebInspector.TimelineSelection} selection
929 * @return {number}
930 */
931 entryIndexForSelection: function(selection)
932 {
933 if (!selection || selection.type() === WebInspector.TimelineSelection.Ty pe.Range)
934 return -1;
935
936 if (this._lastSelection && this._lastSelection.timelineSelection.object( ) === selection.object())
937 return this._lastSelection.entryIndex;
938 var index = this._entryData.indexOf(/** @type {!WebInspector.TracingMode l.Event|!WebInspector.TimelineFrame|!WebInspector.TimelineIRModel.Phases} */(sel ection.object()));
939 if (index !== -1)
940 this._lastSelection = new WebInspector.TimelineFlameChartView.Select ion(selection, index);
941 return index;
942 },
943
944 __proto__: WebInspector.TimelineFlameChartDataProviderBase.prototype
945 }; 910 };
946 911
912 WebInspector.TimelineFlameChartDataProvider.InstantEventVisibleDurationMs = 0.00 1;
913
947 /** 914 /**
948 * @constructor 915 * @unrestricted
949 * @extends {WebInspector.TimelineFlameChartDataProviderBase}
950 * @param {!WebInspector.TimelineModel} model
951 */ 916 */
952 WebInspector.TimelineFlameChartNetworkDataProvider = function(model) 917 WebInspector.TimelineFlameChartNetworkDataProvider = class extends WebInspector. TimelineFlameChartDataProviderBase {
953 { 918 /**
954 WebInspector.TimelineFlameChartDataProviderBase.call(this, model, []); 919 * @param {!WebInspector.TimelineModel} model
955 var loadingCategory = WebInspector.TimelineUIUtils.categories()["loading"]; 920 */
921 constructor(model) {
922 super(model, []);
923 var loadingCategory = WebInspector.TimelineUIUtils.categories()['loading'];
956 this._waitingColor = loadingCategory.childColor; 924 this._waitingColor = loadingCategory.childColor;
957 this._processingColor = loadingCategory.color; 925 this._processingColor = loadingCategory.color;
926 }
927
928 /**
929 * @override
930 * @return {!WebInspector.FlameChart.TimelineData}
931 */
932 timelineData() {
933 if (this._timelineData)
934 return this._timelineData;
935 /** @type {!Array<!WebInspector.TimelineModel.NetworkRequest>} */
936 this._requests = [];
937 this._timelineData = new WebInspector.FlameChart.TimelineData([], [], [], [] );
938 this._appendTimelineData(this._model.mainThreadEvents());
939 return this._timelineData;
940 }
941
942 /**
943 * @override
944 */
945 reset() {
946 super.reset();
947 /** @type {!Array<!WebInspector.TimelineModel.NetworkRequest>} */
948 this._requests = [];
949 }
950
951 /**
952 * @param {number} startTime
953 * @param {number} endTime
954 */
955 setWindowTimes(startTime, endTime) {
956 this._startTime = startTime;
957 this._endTime = endTime;
958 this._updateTimelineData();
959 }
960
961 /**
962 * @override
963 * @param {number} index
964 * @return {?WebInspector.TimelineSelection}
965 */
966 createSelection(index) {
967 if (index === -1)
968 return null;
969 var request = this._requests[index];
970 this._lastSelection = new WebInspector.TimelineFlameChartView.Selection(
971 WebInspector.TimelineSelection.fromNetworkRequest(request), index);
972 return this._lastSelection.timelineSelection;
973 }
974
975 /**
976 * @param {?WebInspector.TimelineSelection} selection
977 * @return {number}
978 */
979 entryIndexForSelection(selection) {
980 if (!selection)
981 return -1;
982
983 if (this._lastSelection && this._lastSelection.timelineSelection.object() == = selection.object())
984 return this._lastSelection.entryIndex;
985
986 if (selection.type() !== WebInspector.TimelineSelection.Type.NetworkRequest)
987 return -1;
988 var request = /** @type{!WebInspector.TimelineModel.NetworkRequest} */ (sele ction.object());
989 var index = this._requests.indexOf(request);
990 if (index !== -1)
991 this._lastSelection = new WebInspector.TimelineFlameChartView.Selection(
992 WebInspector.TimelineSelection.fromNetworkRequest(request), index);
993 return index;
994 }
995
996 /**
997 * @override
998 * @param {number} index
999 * @return {string}
1000 */
1001 entryColor(index) {
1002 var request = /** @type {!WebInspector.TimelineModel.NetworkRequest} */ (thi s._requests[index]);
1003 var category = WebInspector.TimelineUIUtils.networkRequestCategory(request);
1004 return WebInspector.TimelineUIUtils.networkCategoryColor(category);
1005 }
1006
1007 /**
1008 * @override
1009 * @param {number} index
1010 * @return {?string}
1011 */
1012 entryTitle(index) {
1013 var request = /** @type {!WebInspector.TimelineModel.NetworkRequest} */ (thi s._requests[index]);
1014 return request.url || null;
1015 }
1016
1017 /**
1018 * @override
1019 * @param {number} index
1020 * @param {!CanvasRenderingContext2D} context
1021 * @param {?string} text
1022 * @param {number} barX
1023 * @param {number} barY
1024 * @param {number} barWidth
1025 * @param {number} barHeight
1026 * @param {number} unclippedBarX
1027 * @param {number} timeToPixels
1028 * @return {boolean}
1029 */
1030 decorateEntry(index, context, text, barX, barY, barWidth, barHeight, unclipped BarX, timeToPixels) {
1031 var minTransferWidthPx = 2;
1032 var request = /** @type {!WebInspector.TimelineModel.NetworkRequest} */ (thi s._requests[index]);
1033 var startTime = request.startTime;
1034 var endTime = request.endTime;
1035 var lastX = unclippedBarX;
1036 context.fillStyle = 'hsla(0, 0%, 100%, 0.6)';
1037 for (var i = 0; i < request.children.length; ++i) {
1038 var event = request.children[i];
1039 var t0 = event.startTime;
1040 var t1 = event.endTime || event.startTime;
1041 var x0 = Math.floor(unclippedBarX + (t0 - startTime) * timeToPixels - 1);
1042 var x1 = Math.floor(unclippedBarX + (t1 - startTime) * timeToPixels + 1);
1043 if (x0 > lastX)
1044 context.fillRect(lastX, barY, x0 - lastX, barHeight);
1045 lastX = x1;
1046 }
1047 var endX = unclippedBarX + (endTime - startTime) * timeToPixels;
1048 if (endX > lastX)
1049 context.fillRect(lastX, barY, Math.min(endX - lastX, 1e5), barHeight);
1050 if (typeof request.priority === 'string') {
1051 var color = this._colorForPriority(request.priority);
1052 if (color) {
1053 context.fillStyle = 'hsl(0, 0%, 100%)';
1054 context.fillRect(barX, barY, 4, 4);
1055 context.fillStyle = color;
1056 context.fillRect(barX, barY, 3, 3);
1057 }
1058 }
1059 return false;
1060 }
1061
1062 /**
1063 * @override
1064 * @param {number} index
1065 * @return {boolean}
1066 */
1067 forceDecoration(index) {
1068 return true;
1069 }
1070
1071 /**
1072 * @override
1073 * @param {number} index
1074 * @return {?Element}
1075 */
1076 prepareHighlightedEntryInfo(index) {
1077 var /** @const */ maxURLChars = 80;
1078 var request = /** @type {!WebInspector.TimelineModel.NetworkRequest} */ (thi s._requests[index]);
1079 if (!request.url)
1080 return null;
1081 var element = createElement('div');
1082 var root = WebInspector.createShadowRootWithCoreStyles(element, 'timeline/ti melineFlamechartPopover.css');
1083 var contents = root.createChild('div', 'timeline-flamechart-popover');
1084 var duration = request.endTime - request.startTime;
1085 if (request.startTime && isFinite(duration))
1086 contents.createChild('span', 'timeline-info-network-time').textContent = N umber.millisToString(duration);
1087 if (typeof request.priority === 'string') {
1088 var div = contents.createChild('span');
1089 div.textContent =
1090 WebInspector.uiLabelForPriority(/** @type {!NetworkAgent.ResourcePrior ity} */ (request.priority));
1091 div.style.color = this._colorForPriority(request.priority) || 'black';
1092 }
1093 contents.createChild('span').textContent = request.url.trimMiddle(maxURLChar s);
1094 return element;
1095 }
1096
1097 /**
1098 * @param {string} priority
1099 * @return {?string}
1100 */
1101 _colorForPriority(priority) {
1102 switch (/** @type {!NetworkAgent.ResourcePriority} */ (priority)) {
1103 case NetworkAgent.ResourcePriority.VeryLow:
1104 return '#080';
1105 case NetworkAgent.ResourcePriority.Low:
1106 return '#6c0';
1107 case NetworkAgent.ResourcePriority.Medium:
1108 return '#fa0';
1109 case NetworkAgent.ResourcePriority.High:
1110 return '#f60';
1111 case NetworkAgent.ResourcePriority.VeryHigh:
1112 return '#f00';
1113 }
1114 return null;
1115 }
1116
1117 /**
1118 * @param {!Array.<!WebInspector.TracingModel.Event>} events
1119 */
1120 _appendTimelineData(events) {
1121 this._minimumBoundary = this._model.minimumRecordTime();
1122 this._maximumBoundary = this._model.maximumRecordTime();
1123 this._timeSpan = this._model.isEmpty() ? 1000 : this._maximumBoundary - this ._minimumBoundary;
1124 this._model.networkRequests().forEach(this._appendEntry.bind(this));
1125 this._updateTimelineData();
1126 }
1127
1128 _updateTimelineData() {
1129 if (!this._timelineData)
1130 return;
1131 var index = -1;
1132 var lastTime = Infinity;
1133 for (var i = 0; i < this._requests.length; ++i) {
1134 var r = this._requests[i];
1135 var visible = r.startTime < this._endTime && r.endTime > this._startTime;
1136 if (!visible) {
1137 this._timelineData.entryLevels[i] = -1;
1138 continue;
1139 }
1140 if (lastTime > r.startTime)
1141 ++index;
1142 lastTime = r.endTime;
1143 this._timelineData.entryLevels[i] = index;
1144 }
1145 ++index;
1146 for (var i = 0; i < this._requests.length; ++i) {
1147 if (this._timelineData.entryLevels[i] === -1)
1148 this._timelineData.entryLevels[i] = index;
1149 }
1150 this._timelineData = new WebInspector.FlameChart.TimelineData(
1151 this._timelineData.entryLevels, this._timelineData.entryTotalTimes, this ._timelineData.entryStartTimes, null);
1152 this._currentLevel = index;
1153 }
1154
1155 /**
1156 * @param {!WebInspector.TimelineModel.NetworkRequest} request
1157 */
1158 _appendEntry(request) {
1159 this._requests.push(request);
1160 this._timelineData.entryStartTimes.push(request.startTime);
1161 this._timelineData.entryTotalTimes.push(request.endTime - request.startTime) ;
1162 this._timelineData.entryLevels.push(this._requests.length - 1);
1163 }
958 }; 1164 };
959 1165
960 WebInspector.TimelineFlameChartNetworkDataProvider.prototype = {
961 /**
962 * @override
963 * @return {!WebInspector.FlameChart.TimelineData}
964 */
965 timelineData: function()
966 {
967 if (this._timelineData)
968 return this._timelineData;
969 /** @type {!Array<!WebInspector.TimelineModel.NetworkRequest>} */
970 this._requests = [];
971 this._timelineData = new WebInspector.FlameChart.TimelineData([], [], [] , []);
972 this._appendTimelineData(this._model.mainThreadEvents());
973 return this._timelineData;
974 },
975
976 /**
977 * @override
978 */
979 reset: function()
980 {
981 WebInspector.TimelineFlameChartDataProviderBase.prototype.reset.call(thi s);
982 /** @type {!Array<!WebInspector.TimelineModel.NetworkRequest>} */
983 this._requests = [];
984 },
985
986 /**
987 * @param {number} startTime
988 * @param {number} endTime
989 */
990 setWindowTimes: function(startTime, endTime)
991 {
992 this._startTime = startTime;
993 this._endTime = endTime;
994 this._updateTimelineData();
995 },
996
997 /**
998 * @override
999 * @param {number} index
1000 * @return {?WebInspector.TimelineSelection}
1001 */
1002 createSelection: function(index)
1003 {
1004 if (index === -1)
1005 return null;
1006 var request = this._requests[index];
1007 this._lastSelection = new WebInspector.TimelineFlameChartView.Selection( WebInspector.TimelineSelection.fromNetworkRequest(request), index);
1008 return this._lastSelection.timelineSelection;
1009 },
1010
1011 /**
1012 * @param {?WebInspector.TimelineSelection} selection
1013 * @return {number}
1014 */
1015 entryIndexForSelection: function(selection)
1016 {
1017 if (!selection)
1018 return -1;
1019
1020 if (this._lastSelection && this._lastSelection.timelineSelection.object( ) === selection.object())
1021 return this._lastSelection.entryIndex;
1022
1023 if (selection.type() !== WebInspector.TimelineSelection.Type.NetworkRequ est)
1024 return -1;
1025 var request = /** @type{!WebInspector.TimelineModel.NetworkRequest} */ ( selection.object());
1026 var index = this._requests.indexOf(request);
1027 if (index !== -1)
1028 this._lastSelection = new WebInspector.TimelineFlameChartView.Select ion(WebInspector.TimelineSelection.fromNetworkRequest(request), index);
1029 return index;
1030 },
1031
1032 /**
1033 * @override
1034 * @param {number} index
1035 * @return {string}
1036 */
1037 entryColor: function(index)
1038 {
1039 var request = /** @type {!WebInspector.TimelineModel.NetworkRequest} */ (this._requests[index]);
1040 var category = WebInspector.TimelineUIUtils.networkRequestCategory(reque st);
1041 return WebInspector.TimelineUIUtils.networkCategoryColor(category);
1042 },
1043
1044 /**
1045 * @override
1046 * @param {number} index
1047 * @return {?string}
1048 */
1049 entryTitle: function(index)
1050 {
1051 var request = /** @type {!WebInspector.TimelineModel.NetworkRequest} */ (this._requests[index]);
1052 return request.url || null;
1053 },
1054
1055 /**
1056 * @override
1057 * @param {number} index
1058 * @param {!CanvasRenderingContext2D} context
1059 * @param {?string} text
1060 * @param {number} barX
1061 * @param {number} barY
1062 * @param {number} barWidth
1063 * @param {number} barHeight
1064 * @param {number} unclippedBarX
1065 * @param {number} timeToPixels
1066 * @return {boolean}
1067 */
1068 decorateEntry: function(index, context, text, barX, barY, barWidth, barHeigh t, unclippedBarX, timeToPixels)
1069 {
1070 var minTransferWidthPx = 2;
1071 var request = /** @type {!WebInspector.TimelineModel.NetworkRequest} */ (this._requests[index]);
1072 var startTime = request.startTime;
1073 var endTime = request.endTime;
1074 var lastX = unclippedBarX;
1075 context.fillStyle = "hsla(0, 0%, 100%, 0.6)";
1076 for (var i = 0; i < request.children.length; ++i) {
1077 var event = request.children[i];
1078 var t0 = event.startTime;
1079 var t1 = event.endTime || event.startTime;
1080 var x0 = Math.floor(unclippedBarX + (t0 - startTime) * timeToPixels - 1);
1081 var x1 = Math.floor(unclippedBarX + (t1 - startTime) * timeToPixels + 1);
1082 if (x0 > lastX)
1083 context.fillRect(lastX, barY, x0 - lastX, barHeight);
1084 lastX = x1;
1085 }
1086 var endX = unclippedBarX + (endTime - startTime) * timeToPixels;
1087 if (endX > lastX)
1088 context.fillRect(lastX, barY, Math.min(endX - lastX, 1e5), barHeight );
1089 if (typeof request.priority === "string") {
1090 var color = this._colorForPriority(request.priority);
1091 if (color) {
1092 context.fillStyle = "hsl(0, 0%, 100%)";
1093 context.fillRect(barX, barY, 4, 4);
1094 context.fillStyle = color;
1095 context.fillRect(barX, barY, 3, 3);
1096 }
1097 }
1098 return false;
1099 },
1100
1101 /**
1102 * @override
1103 * @param {number} index
1104 * @return {boolean}
1105 */
1106 forceDecoration: function(index)
1107 {
1108 return true;
1109 },
1110
1111 /**
1112 * @override
1113 * @param {number} index
1114 * @return {?Element}
1115 */
1116 prepareHighlightedEntryInfo: function(index)
1117 {
1118 var /** @const */ maxURLChars = 80;
1119 var request = /** @type {!WebInspector.TimelineModel.NetworkRequest} */ (this._requests[index]);
1120 if (!request.url)
1121 return null;
1122 var element = createElement("div");
1123 var root = WebInspector.createShadowRootWithCoreStyles(element, "timelin e/timelineFlamechartPopover.css");
1124 var contents = root.createChild("div", "timeline-flamechart-popover");
1125 var duration = request.endTime - request.startTime;
1126 if (request.startTime && isFinite(duration))
1127 contents.createChild("span", "timeline-info-network-time").textConte nt = Number.millisToString(duration);
1128 if (typeof request.priority === "string") {
1129 var div = contents.createChild("span");
1130 div.textContent = WebInspector.uiLabelForPriority(/** @type {!Networ kAgent.ResourcePriority} */ (request.priority));
1131 div.style.color = this._colorForPriority(request.priority) || "black ";
1132 }
1133 contents.createChild("span").textContent = request.url.trimMiddle(maxURL Chars);
1134 return element;
1135 },
1136
1137 /**
1138 * @param {string} priority
1139 * @return {?string}
1140 */
1141 _colorForPriority: function(priority)
1142 {
1143 switch (/** @type {!NetworkAgent.ResourcePriority} */ (priority)) {
1144 case NetworkAgent.ResourcePriority.VeryLow: return "#080";
1145 case NetworkAgent.ResourcePriority.Low: return "#6c0";
1146 case NetworkAgent.ResourcePriority.Medium: return "#fa0";
1147 case NetworkAgent.ResourcePriority.High: return "#f60";
1148 case NetworkAgent.ResourcePriority.VeryHigh: return "#f00";
1149 }
1150 return null;
1151 },
1152
1153 /**
1154 * @param {!Array.<!WebInspector.TracingModel.Event>} events
1155 */
1156 _appendTimelineData: function(events)
1157 {
1158 this._minimumBoundary = this._model.minimumRecordTime();
1159 this._maximumBoundary = this._model.maximumRecordTime();
1160 this._timeSpan = this._model.isEmpty() ? 1000 : this._maximumBoundary - this._minimumBoundary;
1161 this._model.networkRequests().forEach(this._appendEntry.bind(this));
1162 this._updateTimelineData();
1163 },
1164
1165 _updateTimelineData: function()
1166 {
1167 if (!this._timelineData)
1168 return;
1169 var index = -1;
1170 var lastTime = Infinity;
1171 for (var i = 0; i < this._requests.length; ++i) {
1172 var r = this._requests[i];
1173 var visible = r.startTime < this._endTime && r.endTime > this._start Time;
1174 if (!visible) {
1175 this._timelineData.entryLevels[i] = -1;
1176 continue;
1177 }
1178 if (lastTime > r.startTime)
1179 ++index;
1180 lastTime = r.endTime;
1181 this._timelineData.entryLevels[i] = index;
1182 }
1183 ++index;
1184 for (var i = 0; i < this._requests.length; ++i) {
1185 if (this._timelineData.entryLevels[i] === -1)
1186 this._timelineData.entryLevels[i] = index;
1187 }
1188 this._timelineData = new WebInspector.FlameChart.TimelineData(
1189 this._timelineData.entryLevels,
1190 this._timelineData.entryTotalTimes,
1191 this._timelineData.entryStartTimes,
1192 null);
1193 this._currentLevel = index;
1194 },
1195
1196 /**
1197 * @param {!WebInspector.TimelineModel.NetworkRequest} request
1198 */
1199 _appendEntry: function(request)
1200 {
1201 this._requests.push(request);
1202 this._timelineData.entryStartTimes.push(request.startTime);
1203 this._timelineData.entryTotalTimes.push(request.endTime - request.startT ime);
1204 this._timelineData.entryLevels.push(this._requests.length - 1);
1205 },
1206
1207 __proto__: WebInspector.TimelineFlameChartDataProviderBase.prototype
1208 };
1209
1210 /** 1166 /**
1211 * @constructor
1212 * @implements {WebInspector.FlameChartMarker} 1167 * @implements {WebInspector.FlameChartMarker}
1213 * @param {number} startTime 1168 * @unrestricted
1214 * @param {number} startOffset
1215 * @param {!WebInspector.TimelineMarkerStyle} style
1216 */ 1169 */
1217 WebInspector.TimelineFlameChartMarker = function(startTime, startOffset, style) 1170 WebInspector.TimelineFlameChartMarker = class {
1218 { 1171 /**
1172 * @param {number} startTime
1173 * @param {number} startOffset
1174 * @param {!WebInspector.TimelineMarkerStyle} style
1175 */
1176 constructor(startTime, startOffset, style) {
1219 this._startTime = startTime; 1177 this._startTime = startTime;
1220 this._startOffset = startOffset; 1178 this._startOffset = startOffset;
1221 this._style = style; 1179 this._style = style;
1180 }
1181
1182 /**
1183 * @override
1184 * @return {number}
1185 */
1186 startTime() {
1187 return this._startTime;
1188 }
1189
1190 /**
1191 * @override
1192 * @return {string}
1193 */
1194 color() {
1195 return this._style.color;
1196 }
1197
1198 /**
1199 * @override
1200 * @return {string}
1201 */
1202 title() {
1203 var startTime = Number.millisToString(this._startOffset);
1204 return WebInspector.UIString('%s at %s', this._style.title, startTime);
1205 }
1206
1207 /**
1208 * @override
1209 * @param {!CanvasRenderingContext2D} context
1210 * @param {number} x
1211 * @param {number} height
1212 * @param {number} pixelsPerMillisecond
1213 */
1214 draw(context, x, height, pixelsPerMillisecond) {
1215 var lowPriorityVisibilityThresholdInPixelsPerMs = 4;
1216
1217 if (this._style.lowPriority && pixelsPerMillisecond < lowPriorityVisibilityT hresholdInPixelsPerMs)
1218 return;
1219 context.save();
1220
1221 if (!this._style.lowPriority) {
1222 context.strokeStyle = this._style.color;
1223 context.lineWidth = 2;
1224 context.beginPath();
1225 context.moveTo(x, 0);
1226 context.lineTo(x, height);
1227 context.stroke();
1228 }
1229
1230 if (this._style.tall) {
1231 context.strokeStyle = this._style.color;
1232 context.lineWidth = this._style.lineWidth;
1233 context.translate(this._style.lineWidth < 1 || (this._style.lineWidth & 1) ? 0.5 : 0, 0.5);
1234 context.beginPath();
1235 context.moveTo(x, height);
1236 context.setLineDash(this._style.dashStyle);
1237 context.lineTo(x, context.canvas.height);
1238 context.stroke();
1239 }
1240 context.restore();
1241 }
1222 }; 1242 };
1223 1243
1224 WebInspector.TimelineFlameChartMarker.prototype = {
1225 /**
1226 * @override
1227 * @return {number}
1228 */
1229 startTime: function()
1230 {
1231 return this._startTime;
1232 },
1233
1234 /**
1235 * @override
1236 * @return {string}
1237 */
1238 color: function()
1239 {
1240 return this._style.color;
1241 },
1242
1243 /**
1244 * @override
1245 * @return {string}
1246 */
1247 title: function()
1248 {
1249 var startTime = Number.millisToString(this._startOffset);
1250 return WebInspector.UIString("%s at %s", this._style.title, startTime);
1251 },
1252
1253 /**
1254 * @override
1255 * @param {!CanvasRenderingContext2D} context
1256 * @param {number} x
1257 * @param {number} height
1258 * @param {number} pixelsPerMillisecond
1259 */
1260 draw: function(context, x, height, pixelsPerMillisecond)
1261 {
1262 var lowPriorityVisibilityThresholdInPixelsPerMs = 4;
1263
1264 if (this._style.lowPriority && pixelsPerMillisecond < lowPriorityVisibil ityThresholdInPixelsPerMs)
1265 return;
1266 context.save();
1267
1268 if (!this._style.lowPriority) {
1269 context.strokeStyle = this._style.color;
1270 context.lineWidth = 2;
1271 context.beginPath();
1272 context.moveTo(x, 0);
1273 context.lineTo(x, height);
1274 context.stroke();
1275 }
1276
1277 if (this._style.tall) {
1278 context.strokeStyle = this._style.color;
1279 context.lineWidth = this._style.lineWidth;
1280 context.translate(this._style.lineWidth < 1 || (this._style.lineWidt h & 1) ? 0.5 : 0, 0.5);
1281 context.beginPath();
1282 context.moveTo(x, height);
1283 context.setLineDash(this._style.dashStyle);
1284 context.lineTo(x, context.canvas.height);
1285 context.stroke();
1286 }
1287 context.restore();
1288 }
1289 };
1290
1291 /** 1244 /**
1292 * @constructor
1293 * @extends {WebInspector.VBox}
1294 * @implements {WebInspector.TimelineModeView} 1245 * @implements {WebInspector.TimelineModeView}
1295 * @implements {WebInspector.FlameChartDelegate} 1246 * @implements {WebInspector.FlameChartDelegate}
1296 * @param {!WebInspector.TimelineModeViewDelegate} delegate 1247 * @unrestricted
1297 * @param {!WebInspector.TimelineModel} timelineModel
1298 * @param {!WebInspector.TimelineFrameModel} frameModel
1299 * @param {!WebInspector.TimelineIRModel} irModel
1300 * @param {!Array<!WebInspector.TimelineModel.Filter>} filters
1301 */ 1248 */
1302 WebInspector.TimelineFlameChartView = function(delegate, timelineModel, frameMod el, irModel, filters) 1249 WebInspector.TimelineFlameChartView = class extends WebInspector.VBox {
1303 { 1250 /**
1304 WebInspector.VBox.call(this); 1251 * @param {!WebInspector.TimelineModeViewDelegate} delegate
1305 this.element.classList.add("timeline-flamechart"); 1252 * @param {!WebInspector.TimelineModel} timelineModel
1253 * @param {!WebInspector.TimelineFrameModel} frameModel
1254 * @param {!WebInspector.TimelineIRModel} irModel
1255 * @param {!Array<!WebInspector.TimelineModel.Filter>} filters
1256 */
1257 constructor(delegate, timelineModel, frameModel, irModel, filters) {
1258 super();
1259 this.element.classList.add('timeline-flamechart');
1306 this._delegate = delegate; 1260 this._delegate = delegate;
1307 this._model = timelineModel; 1261 this._model = timelineModel;
1308 1262
1309 this._splitWidget = new WebInspector.SplitWidget(false, false, "timelineFlam echartMainView", 150); 1263 this._splitWidget = new WebInspector.SplitWidget(false, false, 'timelineFlam echartMainView', 150);
1310 1264
1311 this._dataProvider = new WebInspector.TimelineFlameChartDataProvider(this._m odel, frameModel, irModel, filters); 1265 this._dataProvider = new WebInspector.TimelineFlameChartDataProvider(this._m odel, frameModel, irModel, filters);
1312 var mainViewGroupExpansionSetting = WebInspector.settings.createSetting("tim elineFlamechartMainViewGroupExpansion", {}); 1266 var mainViewGroupExpansionSetting =
1267 WebInspector.settings.createSetting('timelineFlamechartMainViewGroupExpa nsion', {});
1313 this._mainView = new WebInspector.FlameChart(this._dataProvider, this, mainV iewGroupExpansionSetting); 1268 this._mainView = new WebInspector.FlameChart(this._dataProvider, this, mainV iewGroupExpansionSetting);
1314 1269
1315 this._networkDataProvider = new WebInspector.TimelineFlameChartNetworkDataPr ovider(this._model); 1270 this._networkDataProvider = new WebInspector.TimelineFlameChartNetworkDataPr ovider(this._model);
1316 this._networkView = new WebInspector.FlameChart(this._networkDataProvider, t his); 1271 this._networkView = new WebInspector.FlameChart(this._networkDataProvider, t his);
1317 1272
1318 this._splitWidget.setMainWidget(this._mainView); 1273 this._splitWidget.setMainWidget(this._mainView);
1319 this._splitWidget.setSidebarWidget(this._networkView); 1274 this._splitWidget.setSidebarWidget(this._networkView);
1320 this._splitWidget.show(this.element); 1275 this._splitWidget.show(this.element);
1321 1276
1322 this._onMainEntrySelected = this._onEntrySelected.bind(this, this._dataProvi der); 1277 this._onMainEntrySelected = this._onEntrySelected.bind(this, this._dataProvi der);
1323 this._onNetworkEntrySelected = this._onEntrySelected.bind(this, this._networ kDataProvider); 1278 this._onNetworkEntrySelected = this._onEntrySelected.bind(this, this._networ kDataProvider);
1324 this._mainView.addEventListener(WebInspector.FlameChart.Events.EntrySelected , this._onMainEntrySelected, this); 1279 this._mainView.addEventListener(WebInspector.FlameChart.Events.EntrySelected , this._onMainEntrySelected, this);
1325 this._networkView.addEventListener(WebInspector.FlameChart.Events.EntrySelec ted, this._onNetworkEntrySelected, this); 1280 this._networkView.addEventListener(
1281 WebInspector.FlameChart.Events.EntrySelected, this._onNetworkEntrySelect ed, this);
1326 WebInspector.blackboxManager.addChangeListener(this.refreshRecords, this); 1282 WebInspector.blackboxManager.addChangeListener(this.refreshRecords, this);
1327 }; 1283 }
1328 1284
1329 WebInspector.TimelineFlameChartView.prototype = { 1285 /**
1330 /** 1286 * @override
1331 * @override 1287 */
1332 */ 1288 dispose() {
1333 dispose: function() 1289 this._mainView.removeEventListener(WebInspector.FlameChart.Events.EntrySelec ted, this._onMainEntrySelected, this);
1334 { 1290 this._networkView.removeEventListener(
1335 this._mainView.removeEventListener(WebInspector.FlameChart.Events.EntryS elected, this._onMainEntrySelected, this); 1291 WebInspector.FlameChart.Events.EntrySelected, this._onNetworkEntrySelect ed, this);
1336 this._networkView.removeEventListener(WebInspector.FlameChart.Events.Ent rySelected, this._onNetworkEntrySelected, this); 1292 WebInspector.blackboxManager.removeChangeListener(this.refreshRecords, this) ;
1337 WebInspector.blackboxManager.removeChangeListener(this.refreshRecords, t his); 1293 }
1338 },
1339 1294
1340 /** 1295 /**
1341 * @override 1296 * @override
1342 * @return {?Element} 1297 * @return {?Element}
1343 */ 1298 */
1344 resizerElement: function() 1299 resizerElement() {
1345 { 1300 return null;
1346 return null; 1301 }
1347 },
1348 1302
1349 /** 1303 /**
1350 * @override 1304 * @override
1351 * @param {number} windowStartTime 1305 * @param {number} windowStartTime
1352 * @param {number} windowEndTime 1306 * @param {number} windowEndTime
1353 */ 1307 */
1354 requestWindowTimes: function(windowStartTime, windowEndTime) 1308 requestWindowTimes(windowStartTime, windowEndTime) {
1355 { 1309 this._delegate.requestWindowTimes(windowStartTime, windowEndTime);
1356 this._delegate.requestWindowTimes(windowStartTime, windowEndTime); 1310 }
1357 },
1358 1311
1359 /** 1312 /**
1360 * @override 1313 * @override
1361 * @param {number} startTime 1314 * @param {number} startTime
1362 * @param {number} endTime 1315 * @param {number} endTime
1363 */ 1316 */
1364 updateRangeSelection: function(startTime, endTime) 1317 updateRangeSelection(startTime, endTime) {
1365 { 1318 this._delegate.select(WebInspector.TimelineSelection.fromRange(startTime, en dTime));
1366 this._delegate.select(WebInspector.TimelineSelection.fromRange(startTime , endTime)); 1319 }
1367 },
1368 1320
1369 /** 1321 /**
1370 * @override 1322 * @override
1371 */ 1323 */
1372 refreshRecords: function() 1324 refreshRecords() {
1373 { 1325 this._dataProvider.reset();
1374 this._dataProvider.reset(); 1326 this._mainView.scheduleUpdate();
1375 this._mainView.scheduleUpdate(); 1327 this._networkDataProvider.reset();
1376 this._networkDataProvider.reset(); 1328 this._networkView.scheduleUpdate();
1377 this._networkView.scheduleUpdate(); 1329 }
1378 },
1379 1330
1380 /** 1331 /**
1381 * @override 1332 * @override
1382 * @param {?WebInspector.TracingModel.Event} event 1333 * @param {?WebInspector.TracingModel.Event} event
1383 */ 1334 */
1384 highlightEvent: function(event) 1335 highlightEvent(event) {
1385 { 1336 var entryIndex =
1386 var entryIndex = event ? this._dataProvider.entryIndexForSelection(WebIn spector.TimelineSelection.fromTraceEvent(event)) : -1; 1337 event ? this._dataProvider.entryIndexForSelection(WebInspector.TimelineS election.fromTraceEvent(event)) : -1;
1387 if (entryIndex >= 0) 1338 if (entryIndex >= 0)
1388 this._mainView.highlightEntry(entryIndex); 1339 this._mainView.highlightEntry(entryIndex);
1389 else 1340 else
1390 this._mainView.hideHighlight(); 1341 this._mainView.hideHighlight();
1391 }, 1342 }
1392 1343
1393 /** 1344 /**
1394 * @override 1345 * @override
1395 */ 1346 */
1396 wasShown: function() 1347 wasShown() {
1397 { 1348 this._mainView.scheduleUpdate();
1398 this._mainView.scheduleUpdate(); 1349 this._networkView.scheduleUpdate();
1399 this._networkView.scheduleUpdate(); 1350 }
1400 },
1401 1351
1402 /** 1352 /**
1403 * @override 1353 * @override
1404 * @return {!WebInspector.Widget} 1354 * @return {!WebInspector.Widget}
1405 */ 1355 */
1406 view: function() 1356 view() {
1407 { 1357 return this;
1408 return this; 1358 }
1409 },
1410 1359
1411 /** 1360 /**
1412 * @override 1361 * @override
1413 */ 1362 */
1414 reset: function() 1363 reset() {
1415 { 1364 this._dataProvider.reset();
1416 this._dataProvider.reset(); 1365 this._mainView.reset();
1417 this._mainView.reset(); 1366 this._mainView.setWindowTimes(0, Infinity);
1418 this._mainView.setWindowTimes(0, Infinity); 1367 this._networkDataProvider.reset();
1419 this._networkDataProvider.reset(); 1368 this._networkView.reset();
1420 this._networkView.reset(); 1369 this._networkView.setWindowTimes(0, Infinity);
1421 this._networkView.setWindowTimes(0, Infinity); 1370 }
1422 },
1423 1371
1424 /** 1372 /**
1425 * @override 1373 * @override
1426 * @param {number} startTime 1374 * @param {number} startTime
1427 * @param {number} endTime 1375 * @param {number} endTime
1428 */ 1376 */
1429 setWindowTimes: function(startTime, endTime) 1377 setWindowTimes(startTime, endTime) {
1430 { 1378 this._mainView.setWindowTimes(startTime, endTime);
1431 this._mainView.setWindowTimes(startTime, endTime); 1379 this._networkView.setWindowTimes(startTime, endTime);
1432 this._networkView.setWindowTimes(startTime, endTime); 1380 this._networkDataProvider.setWindowTimes(startTime, endTime);
1433 this._networkDataProvider.setWindowTimes(startTime, endTime); 1381 }
1434 },
1435 1382
1436 /** 1383 /**
1437 * @override 1384 * @override
1438 * @param {?WebInspector.TracingModel.Event} event 1385 * @param {?WebInspector.TracingModel.Event} event
1439 * @param {string=} regex 1386 * @param {string=} regex
1440 * @param {boolean=} select 1387 * @param {boolean=} select
1441 */ 1388 */
1442 highlightSearchResult: function(event, regex, select) 1389 highlightSearchResult(event, regex, select) {
1443 { 1390 if (!event) {
1444 if (!event) { 1391 this._delegate.select(null);
1445 this._delegate.select(null); 1392 return;
1446 return; 1393 }
1447 } 1394 var entryIndex = this._dataProvider._entryData.indexOf(event);
1448 var entryIndex = this._dataProvider._entryData.indexOf(event); 1395 var timelineSelection = this._dataProvider.createSelection(entryIndex);
1449 var timelineSelection = this._dataProvider.createSelection(entryIndex); 1396 if (timelineSelection)
1450 if (timelineSelection) 1397 this._delegate.select(timelineSelection);
1451 this._delegate.select(timelineSelection); 1398 }
1452 },
1453 1399
1454 /** 1400 /**
1455 * @override 1401 * @override
1456 * @param {?WebInspector.TimelineSelection} selection 1402 * @param {?WebInspector.TimelineSelection} selection
1457 */ 1403 */
1458 setSelection: function(selection) 1404 setSelection(selection) {
1459 { 1405 var index = this._dataProvider.entryIndexForSelection(selection);
1460 var index = this._dataProvider.entryIndexForSelection(selection); 1406 this._mainView.setSelectedEntry(index);
1461 this._mainView.setSelectedEntry(index); 1407 index = this._networkDataProvider.entryIndexForSelection(selection);
1462 index = this._networkDataProvider.entryIndexForSelection(selection); 1408 this._networkView.setSelectedEntry(index);
1463 this._networkView.setSelectedEntry(index); 1409 }
1464 },
1465 1410
1466 /** 1411 /**
1467 * @param {!WebInspector.FlameChartDataProvider} dataProvider 1412 * @param {!WebInspector.FlameChartDataProvider} dataProvider
1468 * @param {!WebInspector.Event} event 1413 * @param {!WebInspector.Event} event
1469 */ 1414 */
1470 _onEntrySelected: function(dataProvider, event) 1415 _onEntrySelected(dataProvider, event) {
1471 { 1416 var entryIndex = /** @type{number} */ (event.data);
1472 var entryIndex = /** @type{number} */ (event.data); 1417 this._delegate.select(dataProvider.createSelection(entryIndex));
1473 this._delegate.select(dataProvider.createSelection(entryIndex)); 1418 }
1474 },
1475 1419
1476 /** 1420 /**
1477 * @param {boolean} enable 1421 * @param {boolean} enable
1478 * @param {boolean=} animate 1422 * @param {boolean=} animate
1479 */ 1423 */
1480 enableNetworkPane: function(enable, animate) 1424 enableNetworkPane(enable, animate) {
1481 { 1425 if (enable)
1482 if (enable) 1426 this._splitWidget.showBoth(animate);
1483 this._splitWidget.showBoth(animate); 1427 else
1484 else 1428 this._splitWidget.hideSidebar(animate);
1485 this._splitWidget.hideSidebar(animate); 1429 }
1486 },
1487
1488 __proto__: WebInspector.VBox.prototype
1489 }; 1430 };
1490 1431
1491 /** 1432 /**
1492 * @constructor 1433 * @unrestricted
1493 * @param {!WebInspector.TimelineSelection} selection 1434 */
1494 * @param {number} entryIndex 1435 WebInspector.TimelineFlameChartView.Selection = class {
1495 */ 1436 /**
1496 WebInspector.TimelineFlameChartView.Selection = function(selection, entryIndex) 1437 * @param {!WebInspector.TimelineSelection} selection
1497 { 1438 * @param {number} entryIndex
1439 */
1440 constructor(selection, entryIndex) {
1498 this.timelineSelection = selection; 1441 this.timelineSelection = selection;
1499 this.entryIndex = entryIndex; 1442 this.entryIndex = entryIndex;
1443 }
1500 }; 1444 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698