blob: 6b6bb3940ea17109f8b18c5197780a09889aeb72 [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371/**
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
29 */
30
Tim van der Lippebb769172020-02-12 15:32:4431import * as Common from '../common/common.js';
32import * as Host from '../host/host.js';
Jack Franklin1be909c2020-03-04 08:57:4133import * as Platform from '../platform/platform.js';
Paul Lewiscf1f8a42020-11-04 21:05:2434import * as Root from '../root/root.js';
Paul Lewisead45752020-06-23 09:51:3635import * as SDK from '../sdk/sdk.js'; // eslint-disable-line no-unused-vars
Paul Lewisca569a52020-09-09 16:11:5136import * as ThemeSupport from '../theme_support/theme_support.js';
Tim van der Lippedfbb48f2020-11-19 14:49:1537import * as TimelineModel from '../timeline_model/timeline_model.js'; // eslint-disable-line no-unused-vars
Tim van der Lippebb769172020-02-12 15:32:4438import * as UI from '../ui/ui.js';
39
Paul Lewis2cfa94e2020-01-13 10:30:1540import {ChartViewport, ChartViewportDelegate} from './ChartViewport.js'; // eslint-disable-line no-unused-vars
41import {Calculator, TimelineGrid} from './TimelineGrid.js'; // eslint-disable-line no-unused-vars
42
Blink Reformat4c46d092018-04-07 15:32:3743/**
44 * @interface
45 */
Tim van der Lippefd2b2ce2020-01-03 15:05:1846export class FlameChartDelegate {
Blink Reformat4c46d092018-04-07 15:32:3747 /**
48 * @param {number} startTime
49 * @param {number} endTime
50 * @param {boolean} animate
51 */
Tim van der Lippefd2b2ce2020-01-03 15:05:1852 windowChanged(startTime, endTime, animate) {
53 }
Blink Reformat4c46d092018-04-07 15:32:3754
55 /**
56 * @param {number} startTime
57 * @param {number} endTime
58 */
Tim van der Lippefd2b2ce2020-01-03 15:05:1859 updateRangeSelection(startTime, endTime) {
60 }
Blink Reformat4c46d092018-04-07 15:32:3761
62 /**
Tim van der Lippefd2b2ce2020-01-03 15:05:1863 * @param {!FlameChart} flameChart
Tim van der Lippe8ef250c2020-02-20 16:29:2564 * @param {?Group} group
Blink Reformat4c46d092018-04-07 15:32:3765 */
Tim van der Lippefd2b2ce2020-01-03 15:05:1866 updateSelectedGroup(flameChart, group) {
67 }
68}
Blink Reformat4c46d092018-04-07 15:32:3769
70/**
Paul Lewis2cfa94e2020-01-13 10:30:1571 * @implements {Calculator}
72 * @implements {ChartViewportDelegate}
Blink Reformat4c46d092018-04-07 15:32:3773 */
Tim van der Lippebb769172020-02-12 15:32:4474export class FlameChart extends UI.Widget.VBox {
Blink Reformat4c46d092018-04-07 15:32:3775 /**
Tim van der Lippefd2b2ce2020-01-03 15:05:1876 * @param {!FlameChartDataProvider} dataProvider
77 * @param {!FlameChartDelegate} flameChartDelegate
Paul Lewiscf1f8a42020-11-04 21:05:2478 * @param {!Common.Settings.Setting<?>=} groupExpansionSetting
Blink Reformat4c46d092018-04-07 15:32:3779 */
80 constructor(dataProvider, flameChartDelegate, groupExpansionSetting) {
81 super(true);
Jack Franklin71519f82020-11-03 12:08:5982 this.registerRequiredCSS('perf_ui/flameChart.css', {enableLegacyPatching: true});
Blink Reformat4c46d092018-04-07 15:32:3783 this.contentElement.classList.add('flame-chart-main-pane');
84 this._groupExpansionSetting = groupExpansionSetting;
85 this._groupExpansionState = groupExpansionSetting && groupExpansionSetting.get() || {};
86 this._flameChartDelegate = flameChartDelegate;
87
Tim van der Lippe99e59b82019-09-30 20:00:5988 this._useWebGL = Root.Runtime.experiments.isEnabled('timelineWebGL');
Paul Lewis2cfa94e2020-01-13 10:30:1589 this._chartViewport = new ChartViewport(this);
Blink Reformat4c46d092018-04-07 15:32:3790 this._chartViewport.show(this.contentElement);
91
92 this._dataProvider = dataProvider;
93
Paul Lewis49b16822020-02-21 14:22:0394 this._candyStripeCanvas = /** @type {!HTMLCanvasElement} */ (document.createElement('canvas'));
95 this._createCandyStripePattern();
96
Blink Reformat4c46d092018-04-07 15:32:3797 this._viewportElement = this._chartViewport.viewportElement;
Alexei Filippov57ccafb2018-08-14 20:59:0598 if (this._useWebGL) {
99 this._canvasGL = /** @type {!HTMLCanvasElement} */ (this._viewportElement.createChild('canvas', 'fill'));
100 this._initWebGL();
101 }
Paul Lewiscf1f8a42020-11-04 21:05:24102 /** @type {!HTMLCanvasElement} */
Alexei Filippov57ccafb2018-08-14 20:59:05103 this._canvas = /** @type {!HTMLCanvasElement} */ (this._viewportElement.createChild('canvas', 'fill'));
Blink Reformat4c46d092018-04-07 15:32:37104
Joel Einbinder83fc76e2018-06-11 23:19:47105 this._canvas.tabIndex = 0;
Anubha Mathur72dd5822019-06-13 23:05:19106 UI.ARIAUtils.setAccessibleName(this._canvas, ls`Flame Chart`);
107 UI.ARIAUtils.markAsTree(this._canvas);
Blink Reformat4c46d092018-04-07 15:32:37108 this.setDefaultFocusedElement(this._canvas);
Anubha Mathur72dd5822019-06-13 23:05:19109 this._canvas.classList.add('flame-chart-canvas');
Blink Reformat4c46d092018-04-07 15:32:37110 this._canvas.addEventListener('mousemove', this._onMouseMove.bind(this), false);
111 this._canvas.addEventListener('mouseout', this._onMouseOut.bind(this), false);
112 this._canvas.addEventListener('click', this._onClick.bind(this), false);
113 this._canvas.addEventListener('keydown', this._onKeyDown.bind(this), false);
114
115 this._entryInfo = this._viewportElement.createChild('div', 'flame-chart-entry-info');
116 this._markerHighlighElement = this._viewportElement.createChild('div', 'flame-chart-marker-highlight-element');
117 this._highlightElement = this._viewportElement.createChild('div', 'flame-chart-highlight-element');
118 this._selectedElement = this._viewportElement.createChild('div', 'flame-chart-selected-element');
Michael Liao712bbc22019-10-15 19:21:51119 this._canvas.addEventListener('focus', () => {
120 this._selectedElement.classList.remove('flame-chart-unfocused-selected-element');
Tim van der Lippefd2b2ce2020-01-03 15:05:18121 this.dispatchEventToListeners(Events.CanvasFocused);
Michael Liao712bbc22019-10-15 19:21:51122 }, false);
123 this._canvas.addEventListener('blur', () => {
124 this._selectedElement.classList.add('flame-chart-unfocused-selected-element');
125 }, false);
Blink Reformat4c46d092018-04-07 15:32:37126
Tim van der Lippebb769172020-02-12 15:32:44127 UI.UIUtils.installDragHandle(
Blink Reformat4c46d092018-04-07 15:32:37128 this._viewportElement, this._startDragging.bind(this), this._dragging.bind(this), this._endDragging.bind(this),
129 null);
130
131 this._rulerEnabled = true;
132 this._rangeSelectionStart = 0;
133 this._rangeSelectionEnd = 0;
134 this._barHeight = 17;
135 this._textBaseline = 5;
136 this._textPadding = 5;
137 this._markerRadius = 6;
138 this._chartViewport.setWindowTimes(
139 dataProvider.minimumBoundary(), dataProvider.minimumBoundary() + dataProvider.totalTime());
140
141 /** @const */
142 this._headerLeftPadding = 6;
143 /** @const */
144 this._arrowSide = 8;
145 /** @const */
146 this._expansionArrowIndent = this._headerLeftPadding + this._arrowSide / 2;
147 /** @const */
148 this._headerLabelXPadding = 3;
149 /** @const */
150 this._headerLabelYPadding = 2;
151
152 this._highlightedMarkerIndex = -1;
153 this._highlightedEntryIndex = -1;
154 this._selectedEntryIndex = -1;
155 this._rawTimelineDataLength = 0;
Alexei Filippov72d792d2018-11-06 07:15:04156 /** @type {!Map<string, !Map<string,number>>} */
Blink Reformat4c46d092018-04-07 15:32:37157 this._textWidth = new Map();
Alexei Filippov6c622e92018-11-10 02:13:59158 /** @type {!Map<number, !{x: number, width: number}>} */
159 this._markerPositions = new Map();
Blink Reformat4c46d092018-04-07 15:32:37160
161 this._lastMouseOffsetX = 0;
162 this._selectedGroup = -1;
Anubha Mathur72dd5822019-06-13 23:05:19163
164 // Keyboard focused group is used to navigate groups irrespective of whether they are selectable or not
165 this._keyboardFocusedGroup = -1;
166
Paul Lewisca569a52020-09-09 16:11:51167 this._selectedGroupBackroundColor = ThemeSupport.ThemeSupport.instance().patchColorText(
168 Colors.SelectedGroupBackground, ThemeSupport.ThemeSupport.ColorUsage.Background);
169 this._selectedGroupBorderColor = ThemeSupport.ThemeSupport.instance().patchColorText(
170 Colors.SelectedGroupBorder, ThemeSupport.ThemeSupport.ColorUsage.Background);
Paul Lewiscf1f8a42020-11-04 21:05:24171
172 /** @type {number} */
173 this._offsetWidth;
174
175 /** @type {number} */
176 this._offsetHeight;
177
178 /** @type {!HTMLCanvasElement} */
179 this._canvasGL;
180
181 /** @type {number} */
182 this._dragStartX;
183
184 /** @type {number} */
185 this._dragStartY;
186
187 /** @type {number} */
188 this._lastMouseOffsetX;
189
190 /** @type {number} */
191 this._lastMouseOffsetY;
192
193 /** @type {number} */
194 this._minimumBoundary;
Blink Reformat4c46d092018-04-07 15:32:37195 }
196
197 /**
198 * @override
199 */
200 willHide() {
201 this.hideHighlight();
202 }
203
204 /**
205 * @param {number} value
206 */
207 setBarHeight(value) {
208 this._barHeight = value;
209 }
210
211 /**
212 * @param {number} value
213 */
214 setTextBaseline(value) {
215 this._textBaseline = value;
216 }
217
218 /**
219 * @param {number} value
220 */
221 setTextPadding(value) {
222 this._textPadding = value;
223 }
224
225 /**
226 * @param {boolean} enable
227 */
228 enableRuler(enable) {
229 this._rulerEnabled = enable;
230 }
231
232 alwaysShowVerticalScroll() {
233 this._chartViewport.alwaysShowVerticalScroll();
234 }
235
236 disableRangeSelection() {
237 this._chartViewport.disableRangeSelection();
238 }
239
240 /**
241 * @param {number} entryIndex
242 */
243 highlightEntry(entryIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34244 if (this._highlightedEntryIndex === entryIndex) {
Blink Reformat4c46d092018-04-07 15:32:37245 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34246 }
247 if (!this._dataProvider.entryColor(entryIndex)) {
Blink Reformat4c46d092018-04-07 15:32:37248 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34249 }
Blink Reformat4c46d092018-04-07 15:32:37250 this._highlightedEntryIndex = entryIndex;
251 this._updateElementPosition(this._highlightElement, this._highlightedEntryIndex);
Tim van der Lippefd2b2ce2020-01-03 15:05:18252 this.dispatchEventToListeners(Events.EntryHighlighted, entryIndex);
Blink Reformat4c46d092018-04-07 15:32:37253 }
254
255 hideHighlight() {
256 this._entryInfo.removeChildren();
257 this._highlightedEntryIndex = -1;
258 this._updateElementPosition(this._highlightElement, this._highlightedEntryIndex);
Tim van der Lippefd2b2ce2020-01-03 15:05:18259 this.dispatchEventToListeners(Events.EntryHighlighted, -1);
Blink Reformat4c46d092018-04-07 15:32:37260 }
261
Paul Lewis49b16822020-02-21 14:22:03262 _createCandyStripePattern() {
263 // Set the candy stripe pattern to 17px so it repeats well.
264 const size = 17;
265 this._candyStripeCanvas.width = size;
266 this._candyStripeCanvas.height = size;
267
268 const ctx = this._candyStripeCanvas.getContext('2d');
Paul Lewiscf1f8a42020-11-04 21:05:24269 if (!ctx) {
270 return;
271 }
Paul Lewis49b16822020-02-21 14:22:03272
273 // Rotate the stripe by 45deg to the right.
274 ctx.translate(size * 0.5, size * 0.5);
275 ctx.rotate(Math.PI * 0.25);
276 ctx.translate(-size * 0.5, -size * 0.5);
277
278 ctx.fillStyle = 'rgba(255, 0, 0, 0.4)';
279 for (let x = -size; x < size * 2; x += 3) {
280 ctx.fillRect(x, -size, 1, size * 3);
281 }
282 }
283
Blink Reformat4c46d092018-04-07 15:32:37284 _resetCanvas() {
285 const ratio = window.devicePixelRatio;
286 const width = Math.round(this._offsetWidth * ratio);
287 const height = Math.round(this._offsetHeight * ratio);
288 this._canvas.width = width;
289 this._canvas.height = height;
290 this._canvas.style.width = `${width / ratio}px`;
291 this._canvas.style.height = `${height / ratio}px`;
Alexei Filippov57ccafb2018-08-14 20:59:05292 if (this._useWebGL) {
293 this._canvasGL.width = width;
294 this._canvasGL.height = height;
295 this._canvasGL.style.width = `${width / ratio}px`;
296 this._canvasGL.style.height = `${height / ratio}px`;
297 }
Blink Reformat4c46d092018-04-07 15:32:37298 }
299
300 /**
301 * @override
302 * @param {number} startTime
303 * @param {number} endTime
304 * @param {boolean} animate
305 */
Alexei Filippov2578eb02018-04-11 08:15:05306 windowChanged(startTime, endTime, animate) {
307 this._flameChartDelegate.windowChanged(startTime, endTime, animate);
Blink Reformat4c46d092018-04-07 15:32:37308 }
309
310 /**
311 * @override
312 * @param {number} startTime
313 * @param {number} endTime
314 */
315 updateRangeSelection(startTime, endTime) {
316 this._flameChartDelegate.updateRangeSelection(startTime, endTime);
317 }
318
319 /**
320 * @override
321 * @param {number} width
322 * @param {number} height
323 */
324 setSize(width, height) {
325 this._offsetWidth = width;
326 this._offsetHeight = height;
327 }
328
329 /**
330 * @param {!MouseEvent} event
331 */
332 _startDragging(event) {
333 this.hideHighlight();
334 this._maxDragOffset = 0;
335 this._dragStartX = event.pageX;
336 this._dragStartY = event.pageY;
337 return true;
338 }
339
340 /**
341 * @param {!MouseEvent} event
342 */
343 _dragging(event) {
344 const dx = event.pageX - this._dragStartX;
345 const dy = event.pageY - this._dragStartY;
346 this._maxDragOffset = Math.max(this._maxDragOffset, Math.sqrt(dx * dx + dy * dy));
347 }
348
349 /**
350 * @param {!MouseEvent} event
351 */
352 _endDragging(event) {
353 this._updateHighlight();
354 }
355
356 /**
Tim van der Lippefd2b2ce2020-01-03 15:05:18357 * @return {?TimelineData}
Blink Reformat4c46d092018-04-07 15:32:37358 */
359 _timelineData() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34360 if (!this._dataProvider) {
Blink Reformat4c46d092018-04-07 15:32:37361 return null;
Tim van der Lippe1d6e57a2019-09-30 11:55:34362 }
Blink Reformat4c46d092018-04-07 15:32:37363 const timelineData = this._dataProvider.timelineData();
Paul Lewiscf1f8a42020-11-04 21:05:24364 if (timelineData !== this._rawTimelineData ||
365 (timelineData && timelineData.entryStartTimes.length !== this._rawTimelineDataLength)) {
Blink Reformat4c46d092018-04-07 15:32:37366 this._processTimelineData(timelineData);
Tim van der Lippe1d6e57a2019-09-30 11:55:34367 }
Paul Lewiscf1f8a42020-11-04 21:05:24368 return this._rawTimelineData || null;
Blink Reformat4c46d092018-04-07 15:32:37369 }
370
371 /**
372 * @param {number} entryIndex
373 */
374 _revealEntry(entryIndex) {
375 const timelineData = this._timelineData();
Tim van der Lippe1d6e57a2019-09-30 11:55:34376 if (!timelineData) {
Blink Reformat4c46d092018-04-07 15:32:37377 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34378 }
Blink Reformat4c46d092018-04-07 15:32:37379 const timeLeft = this._chartViewport.windowLeftTime();
380 const timeRight = this._chartViewport.windowRightTime();
381 const entryStartTime = timelineData.entryStartTimes[entryIndex];
382 const entryTotalTime = timelineData.entryTotalTimes[entryIndex];
383 const entryEndTime = entryStartTime + entryTotalTime;
384 let minEntryTimeWindow = Math.min(entryTotalTime, timeRight - timeLeft);
385
386 const level = timelineData.entryLevels[entryIndex];
387 this._chartViewport.setScrollOffset(this._levelToOffset(level), this._levelHeight(level));
388
389 const minVisibleWidthPx = 30;
390 const futurePixelToTime = (timeRight - timeLeft) / this._offsetWidth;
391 minEntryTimeWindow = Math.max(minEntryTimeWindow, futurePixelToTime * minVisibleWidthPx);
392 if (timeLeft > entryEndTime) {
393 const delta = timeLeft - entryEndTime + minEntryTimeWindow;
Alexei Filippov2578eb02018-04-11 08:15:05394 this.windowChanged(timeLeft - delta, timeRight - delta, /* animate */ true);
Blink Reformat4c46d092018-04-07 15:32:37395 } else if (timeRight < entryStartTime) {
396 const delta = entryStartTime - timeRight + minEntryTimeWindow;
Alexei Filippov2578eb02018-04-11 08:15:05397 this.windowChanged(timeLeft + delta, timeRight + delta, /* animate */ true);
Blink Reformat4c46d092018-04-07 15:32:37398 }
399 }
400
401 /**
402 * @param {number} startTime
403 * @param {number} endTime
404 * @param {boolean=} animate
405 */
406 setWindowTimes(startTime, endTime, animate) {
407 this._chartViewport.setWindowTimes(startTime, endTime, animate);
408 this._updateHighlight();
409 }
410
411 /**
412 * @param {!Event} event
413 */
414 _onMouseMove(event) {
Paul Lewiscf1f8a42020-11-04 21:05:24415 const mouseEvent = /** @type {!MouseEvent} */ (event);
416 this._lastMouseOffsetX = mouseEvent.offsetX;
417 this._lastMouseOffsetY = mouseEvent.offsetY;
Tim van der Lippe1d6e57a2019-09-30 11:55:34418 if (!this._enabled()) {
Blink Reformat4c46d092018-04-07 15:32:37419 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34420 }
421 if (this._chartViewport.isDragging()) {
Blink Reformat4c46d092018-04-07 15:32:37422 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34423 }
Paul Lewiscf1f8a42020-11-04 21:05:24424 if (this._coordinatesToGroupIndex(mouseEvent.offsetX, mouseEvent.offsetY, true /* headerOnly */) >= 0) {
Blink Reformat4c46d092018-04-07 15:32:37425 this.hideHighlight();
426 this._viewportElement.style.cursor = 'pointer';
427 return;
428 }
429 this._updateHighlight();
430 }
431
432 _updateHighlight() {
Alexei Filippov8ee66382018-11-30 01:53:56433 const entryIndex = this._coordinatesToEntryIndex(this._lastMouseOffsetX, this._lastMouseOffsetY);
Blink Reformat4c46d092018-04-07 15:32:37434 if (entryIndex === -1) {
435 this.hideHighlight();
436 const group =
437 this._coordinatesToGroupIndex(this._lastMouseOffsetX, this._lastMouseOffsetY, false /* headerOnly */);
Paul Lewiscf1f8a42020-11-04 21:05:24438 if (group >= 0 && this._rawTimelineData && this._rawTimelineData.groups &&
439 this._rawTimelineData.groups[group].selectable) {
Blink Reformat4c46d092018-04-07 15:32:37440 this._viewportElement.style.cursor = 'pointer';
Tim van der Lippe1d6e57a2019-09-30 11:55:34441 } else {
Blink Reformat4c46d092018-04-07 15:32:37442 this._viewportElement.style.cursor = 'default';
Tim van der Lippe1d6e57a2019-09-30 11:55:34443 }
Blink Reformat4c46d092018-04-07 15:32:37444 return;
445 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34446 if (this._chartViewport.isDragging()) {
Blink Reformat4c46d092018-04-07 15:32:37447 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34448 }
Blink Reformat4c46d092018-04-07 15:32:37449 this._updatePopover(entryIndex);
450 this._viewportElement.style.cursor = this._dataProvider.canJumpToEntry(entryIndex) ? 'pointer' : 'default';
451 this.highlightEntry(entryIndex);
452 }
453
454 _onMouseOut() {
455 this._lastMouseOffsetX = -1;
456 this._lastMouseOffsetY = -1;
457 this.hideHighlight();
458 }
459
460 /**
461 * @param {number} entryIndex
462 */
463 _updatePopover(entryIndex) {
464 if (entryIndex === this._highlightedEntryIndex) {
465 this._updatePopoverOffset();
466 return;
467 }
468 this._entryInfo.removeChildren();
469 const popoverElement = this._dataProvider.prepareHighlightedEntryInfo(entryIndex);
470 if (popoverElement) {
471 this._entryInfo.appendChild(popoverElement);
472 this._updatePopoverOffset();
473 }
474 }
475
476 _updatePopoverOffset() {
477 const mouseX = this._lastMouseOffsetX;
478 const mouseY = this._lastMouseOffsetY;
Paul Lewiscf1f8a42020-11-04 21:05:24479 const parentWidth = this._entryInfo.parentElement ? this._entryInfo.parentElement.clientWidth : 0;
480 const parentHeight = this._entryInfo.parentElement ? this._entryInfo.parentElement.clientHeight : 0;
Blink Reformat4c46d092018-04-07 15:32:37481 const infoWidth = this._entryInfo.clientWidth;
482 const infoHeight = this._entryInfo.clientHeight;
483 const /** @const */ offsetX = 10;
484 const /** @const */ offsetY = 6;
485 let x;
486 let y;
487 for (let quadrant = 0; quadrant < 4; ++quadrant) {
488 const dx = quadrant & 2 ? -offsetX - infoWidth : offsetX;
489 const dy = quadrant & 1 ? -offsetY - infoHeight : offsetY;
Jack Franklin1be909c2020-03-04 08:57:41490 x = Platform.NumberUtilities.clamp(mouseX + dx, 0, parentWidth - infoWidth);
491 y = Platform.NumberUtilities.clamp(mouseY + dy, 0, parentHeight - infoHeight);
Tim van der Lippe1d6e57a2019-09-30 11:55:34492 if (x >= mouseX || mouseX >= x + infoWidth || y >= mouseY || mouseY >= y + infoHeight) {
Blink Reformat4c46d092018-04-07 15:32:37493 break;
Tim van der Lippe1d6e57a2019-09-30 11:55:34494 }
Blink Reformat4c46d092018-04-07 15:32:37495 }
496 this._entryInfo.style.left = x + 'px';
497 this._entryInfo.style.top = y + 'px';
498 }
499
500 /**
501 * @param {!Event} event
502 */
503 _onClick(event) {
Paul Lewiscf1f8a42020-11-04 21:05:24504 const mouseEvent = /** @type {!MouseEvent} */ (event);
Blink Reformat4c46d092018-04-07 15:32:37505 this.focus();
506 // onClick comes after dragStart and dragEnd events.
507 // So if there was drag (mouse move) in the middle of that events
508 // we skip the click. Otherwise we jump to the sources.
509 const /** @const */ clickThreshold = 5;
Tim van der Lippe1d6e57a2019-09-30 11:55:34510 if (this._maxDragOffset > clickThreshold) {
Blink Reformat4c46d092018-04-07 15:32:37511 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34512 }
Blink Reformat4c46d092018-04-07 15:32:37513
Paul Lewiscf1f8a42020-11-04 21:05:24514 this._selectGroup(this._coordinatesToGroupIndex(mouseEvent.offsetX, mouseEvent.offsetY, false /* headerOnly */));
515 this._toggleGroupExpand(
516 this._coordinatesToGroupIndex(mouseEvent.offsetX, mouseEvent.offsetY, true /* headerOnly */));
Blink Reformat4c46d092018-04-07 15:32:37517 const timelineData = this._timelineData();
Paul Lewiscf1f8a42020-11-04 21:05:24518 if (mouseEvent.shiftKey && this._highlightedEntryIndex !== -1 && timelineData) {
Blink Reformat4c46d092018-04-07 15:32:37519 const start = timelineData.entryStartTimes[this._highlightedEntryIndex];
520 const end = start + timelineData.entryTotalTimes[this._highlightedEntryIndex];
521 this._chartViewport.setRangeSelection(start, end);
522 } else {
Paul Lewiscf1f8a42020-11-04 21:05:24523 this._chartViewport.onClick(mouseEvent);
Tim van der Lippefd2b2ce2020-01-03 15:05:18524 this.dispatchEventToListeners(Events.EntryInvoked, this._highlightedEntryIndex);
Blink Reformat4c46d092018-04-07 15:32:37525 }
526 }
527
528 /**
529 * @param {number} groupIndex
530 */
531 _selectGroup(groupIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34532 if (groupIndex < 0 || this._selectedGroup === groupIndex) {
Blink Reformat4c46d092018-04-07 15:32:37533 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34534 }
Paul Lewiscf1f8a42020-11-04 21:05:24535 if (!this._rawTimelineData) {
536 return;
537 }
538
Anubha Mathur72dd5822019-06-13 23:05:19539 const groups = this._rawTimelineData.groups;
Paul Lewiscf1f8a42020-11-04 21:05:24540 if (!groups) {
541 return;
542 }
543
Anubha Mathur72dd5822019-06-13 23:05:19544 this._keyboardFocusedGroup = groupIndex;
Anubha Mathur430a80f2019-12-12 00:26:11545 this._scrollGroupIntoView(groupIndex);
Michael Liao0bad0c32020-01-02 18:51:04546 const groupName = groups[groupIndex].name;
Anubha Mathur72dd5822019-06-13 23:05:19547 if (!groups[groupIndex].selectable) {
548 this._deselectAllGroups();
Michael Liao0bad0c32020-01-02 18:51:04549 UI.ARIAUtils.alert(ls`${groupName} hovered`, this._canvas);
Anubha Mathur72dd5822019-06-13 23:05:19550 } else {
551 this._selectedGroup = groupIndex;
552 this._flameChartDelegate.updateSelectedGroup(this, groups[groupIndex]);
553 this._resetCanvas();
554 this._draw();
Michael Liao (WPT)b54514b2019-08-16 23:11:53555 UI.ARIAUtils.alert(ls`${groupName} selected`, this._canvas);
Anubha Mathur72dd5822019-06-13 23:05:19556 }
557 }
Blink Reformat4c46d092018-04-07 15:32:37558
Anubha Mathur72dd5822019-06-13 23:05:19559 _deselectAllGroups() {
560 this._selectedGroup = -1;
561 this._flameChartDelegate.updateSelectedGroup(this, null);
562 this._resetCanvas();
563 this._draw();
564 }
565
566 _deselectAllEntries() {
567 this._selectedEntryIndex = -1;
Blink Reformat4c46d092018-04-07 15:32:37568 this._resetCanvas();
569 this._draw();
570 }
571
572 /**
Anubha Mathur72dd5822019-06-13 23:05:19573 * @param {number} index
574 */
575 _isGroupFocused(index) {
576 return index === this._selectedGroup || index === this._keyboardFocusedGroup;
577 }
578
579 /**
Anubha Mathur430a80f2019-12-12 00:26:11580 * @param {number} index
581 */
582 _scrollGroupIntoView(index) {
583 if (index < 0) {
584 return;
585 }
586
Paul Lewiscf1f8a42020-11-04 21:05:24587 if (!this._rawTimelineData) {
588 return;
589 }
590
Anubha Mathur430a80f2019-12-12 00:26:11591 const groups = this._rawTimelineData.groups;
592 const groupOffsets = this._groupOffsets;
Paul Lewiscf1f8a42020-11-04 21:05:24593 if (!groupOffsets || !groups) {
594 return;
595 }
Anubha Mathur430a80f2019-12-12 00:26:11596 const groupTop = groupOffsets[index];
597
598 let nextOffset = groupOffsets[index + 1];
599 if (index === groups.length - 1) {
600 nextOffset += groups[index].style.padding;
601 }
602
603 // For the top group, scroll all the way to the top of the chart
604 // to accommodate the bar with time markers
605 const scrollTop = index === 0 ? 0 : groupTop;
606
607 const scrollHeight = Math.min(nextOffset - scrollTop, this._chartViewport.chartHeight());
608 this._chartViewport.setScrollOffset(scrollTop, scrollHeight);
609 }
610
611 /**
Blink Reformat4c46d092018-04-07 15:32:37612 * @param {number} groupIndex
613 */
Anubha Mathur72dd5822019-06-13 23:05:19614 _toggleGroupExpand(groupIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34615 if (groupIndex < 0 || !this._isGroupCollapsible(groupIndex)) {
Anubha Mathur72dd5822019-06-13 23:05:19616 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34617 }
Anubha Mathur72dd5822019-06-13 23:05:19618
Paul Lewiscf1f8a42020-11-04 21:05:24619 if (!this._rawTimelineData || !this._rawTimelineData.groups) {
620 return;
621 }
622
Anubha Mathur72dd5822019-06-13 23:05:19623 this._expandGroup(groupIndex, !this._rawTimelineData.groups[groupIndex].expanded /* setExpanded */);
624 }
625
626 /**
627 * @param {number} groupIndex
628 * @param {boolean=} setExpanded
Michael Liao (WPT)b54514b2019-08-16 23:11:53629 * @param {boolean=} propagatedExpand
Anubha Mathur72dd5822019-06-13 23:05:19630 */
Michael Liao (WPT)b54514b2019-08-16 23:11:53631 _expandGroup(groupIndex, setExpanded = true, propagatedExpand = false) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34632 if (groupIndex < 0 || !this._isGroupCollapsible(groupIndex)) {
Blink Reformat4c46d092018-04-07 15:32:37633 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34634 }
Blink Reformat4c46d092018-04-07 15:32:37635
Paul Lewiscf1f8a42020-11-04 21:05:24636 if (!this._rawTimelineData) {
637 return;
638 }
639
Blink Reformat4c46d092018-04-07 15:32:37640 const groups = this._rawTimelineData.groups;
Paul Lewiscf1f8a42020-11-04 21:05:24641 if (!groups) {
642 return;
643 }
644
Blink Reformat4c46d092018-04-07 15:32:37645 const group = groups[groupIndex];
Anubha Mathur72dd5822019-06-13 23:05:19646 group.expanded = setExpanded;
647
Blink Reformat4c46d092018-04-07 15:32:37648 this._groupExpansionState[group.name] = group.expanded;
Tim van der Lippe1d6e57a2019-09-30 11:55:34649 if (this._groupExpansionSetting) {
Blink Reformat4c46d092018-04-07 15:32:37650 this._groupExpansionSetting.set(this._groupExpansionState);
Tim van der Lippe1d6e57a2019-09-30 11:55:34651 }
Blink Reformat4c46d092018-04-07 15:32:37652 this._updateLevelPositions();
653
654 this._updateHighlight();
655 if (!group.expanded) {
656 const timelineData = this._timelineData();
Paul Lewiscf1f8a42020-11-04 21:05:24657 if (timelineData) {
658 const level = timelineData.entryLevels[this._selectedEntryIndex];
659 if (this._selectedEntryIndex >= 0 && level >= group.startLevel &&
660 (groupIndex >= groups.length - 1 || groups[groupIndex + 1].startLevel > level)) {
661 this._selectedEntryIndex = -1;
662 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34663 }
Blink Reformat4c46d092018-04-07 15:32:37664 }
665
666 this._updateHeight();
667 this._resetCanvas();
668 this._draw();
Michael Liao (WPT)b54514b2019-08-16 23:11:53669
Anubha Mathur430a80f2019-12-12 00:26:11670 this._scrollGroupIntoView(groupIndex);
Michael Liao (WPT)b54514b2019-08-16 23:11:53671 // We only want to read expanded/collapsed state on user inputted expand/collapse
672 if (!propagatedExpand) {
673 const groupName = groups[groupIndex].name;
674 const content = group.expanded ? ls`${groupName} expanded` : ls`${groupName} collapsed`;
675 UI.ARIAUtils.alert(content, this._canvas);
676 }
Blink Reformat4c46d092018-04-07 15:32:37677 }
678
679 /**
Tim van der Lippebcd6b5c2021-01-13 12:31:51680 * @param {!KeyboardEvent} e
Blink Reformat4c46d092018-04-07 15:32:37681 */
682 _onKeyDown(e) {
Tim van der Lippebb769172020-02-12 15:32:44683 if (!UI.KeyboardShortcut.KeyboardShortcut.hasNoModifiers(e) || !this._timelineData()) {
Anubha Mathur72dd5822019-06-13 23:05:19684 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34685 }
Anubha Mathur72dd5822019-06-13 23:05:19686
687 const eventHandled = this._handleSelectionNavigation(e);
688
689 // Handle keyboard navigation in groups
Tim van der Lippe1d6e57a2019-09-30 11:55:34690 if (!eventHandled && this._rawTimelineData && this._rawTimelineData.groups) {
Anubha Mathur72dd5822019-06-13 23:05:19691 this._handleKeyboardGroupNavigation(e);
Tim van der Lippe1d6e57a2019-09-30 11:55:34692 }
Blink Reformat4c46d092018-04-07 15:32:37693 }
694
695 /**
Ted Meyerb0928d02020-06-23 05:12:45696 * @param {string} eventName
Tim van der Lippe64688912020-11-02 11:55:52697 * @param {function(!Event):void} onEvent
Ted Meyerb0928d02020-06-23 05:12:45698 */
699 bindCanvasEvent(eventName, onEvent) {
700 this._canvas.addEventListener(eventName, onEvent);
701 }
702
703 /**
Paul Lewiscf1f8a42020-11-04 21:05:24704 * @param {!Event} event
Blink Reformat4c46d092018-04-07 15:32:37705 */
Paul Lewiscf1f8a42020-11-04 21:05:24706 _handleKeyboardGroupNavigation(event) {
707 const keyboardEvent = /** @type {!KeyboardEvent} */ (event);
Anubha Mathur72dd5822019-06-13 23:05:19708 let handled = false;
709 let entrySelected = false;
710
Paul Lewiscf1f8a42020-11-04 21:05:24711 if (keyboardEvent.code === 'ArrowUp') {
Anubha Mathur72dd5822019-06-13 23:05:19712 handled = this._selectPreviousGroup();
Paul Lewiscf1f8a42020-11-04 21:05:24713 } else if (keyboardEvent.code === 'ArrowDown') {
Anubha Mathur72dd5822019-06-13 23:05:19714 handled = this._selectNextGroup();
Paul Lewiscf1f8a42020-11-04 21:05:24715 } else if (keyboardEvent.code === 'ArrowLeft') {
Anubha Mathur72dd5822019-06-13 23:05:19716 if (this._keyboardFocusedGroup >= 0) {
717 this._expandGroup(this._keyboardFocusedGroup, false /* setExpanded */);
718 handled = true;
719 }
Paul Lewiscf1f8a42020-11-04 21:05:24720 } else if (keyboardEvent.code === 'ArrowRight') {
Anubha Mathur72dd5822019-06-13 23:05:19721 if (this._keyboardFocusedGroup >= 0) {
722 this._expandGroup(this._keyboardFocusedGroup, true /* setExpanded */);
723 this._selectFirstChild();
724 handled = true;
725 }
Tim van der Lippebcd6b5c2021-01-13 12:31:51726 } else if (keyboardEvent.key === 'Enter') {
Anubha Mathur72dd5822019-06-13 23:05:19727 entrySelected = this._selectFirstEntryInCurrentGroup();
728 handled = entrySelected;
729 }
730
Tim van der Lippe1d6e57a2019-09-30 11:55:34731 if (handled && !entrySelected) {
Anubha Mathur72dd5822019-06-13 23:05:19732 this._deselectAllEntries();
Tim van der Lippe1d6e57a2019-09-30 11:55:34733 }
Anubha Mathur72dd5822019-06-13 23:05:19734
Tim van der Lippe1d6e57a2019-09-30 11:55:34735 if (handled) {
Paul Lewiscf1f8a42020-11-04 21:05:24736 keyboardEvent.consume(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34737 }
Anubha Mathur72dd5822019-06-13 23:05:19738 }
739
740 /**
741 * @return {boolean}
742 */
743 _selectFirstEntryInCurrentGroup() {
Paul Lewiscf1f8a42020-11-04 21:05:24744 if (!this._rawTimelineData) {
745 return false;
746 }
747
Anubha Mathur72dd5822019-06-13 23:05:19748 const allGroups = this._rawTimelineData.groups;
749
Paul Lewiscf1f8a42020-11-04 21:05:24750 if (this._keyboardFocusedGroup < 0 || !allGroups) {
Anubha Mathur72dd5822019-06-13 23:05:19751 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34752 }
Anubha Mathur72dd5822019-06-13 23:05:19753
754 const group = allGroups[this._keyboardFocusedGroup];
755 const startLevelInGroup = group.startLevel;
756
757 // Return if no levels in this group
Tim van der Lippe1d6e57a2019-09-30 11:55:34758 if (startLevelInGroup < 0) {
Anubha Mathur72dd5822019-06-13 23:05:19759 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34760 }
Anubha Mathur72dd5822019-06-13 23:05:19761
762 // Make sure this is the innermost nested group with this startLevel
763 // This is because a parent group also contains levels of all its child groups
764 // So check if the next group has the same level, if it does, user should
765 // go to that child group to select this entry
766 if (this._keyboardFocusedGroup < allGroups.length - 1 &&
Tim van der Lippe1d6e57a2019-09-30 11:55:34767 allGroups[this._keyboardFocusedGroup + 1].startLevel === startLevelInGroup) {
Anubha Mathur72dd5822019-06-13 23:05:19768 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34769 }
Anubha Mathur72dd5822019-06-13 23:05:19770
Paul Lewiscf1f8a42020-11-04 21:05:24771 if (!this._timelineLevels) {
772 return false;
773 }
Anubha Mathur72dd5822019-06-13 23:05:19774
775 // Get first (default) entry in startLevel of selected group
776 const firstEntryIndex = this._timelineLevels[startLevelInGroup][0];
777
778 this._expandGroup(this._keyboardFocusedGroup, true /* setExpanded */);
779 this.setSelectedEntry(firstEntryIndex);
780 return true;
781 }
782
783 /**
784 * @return {boolean}
785 */
786 _selectPreviousGroup() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34787 if (this._keyboardFocusedGroup <= 0) {
Anubha Mathur72dd5822019-06-13 23:05:19788 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34789 }
Anubha Mathur72dd5822019-06-13 23:05:19790
791 const groupIndexToSelect = this._getGroupIndexToSelect(-1 /* offset */);
792 this._selectGroup(groupIndexToSelect);
793 return true;
794 }
795
796 /**
797 * @return {boolean}
798 */
799 _selectNextGroup() {
Paul Lewiscf1f8a42020-11-04 21:05:24800 if (!this._rawTimelineData || !this._rawTimelineData.groups) {
801 return false;
802 }
803
Tim van der Lippe1d6e57a2019-09-30 11:55:34804 if (this._keyboardFocusedGroup >= this._rawTimelineData.groups.length - 1) {
Anubha Mathur72dd5822019-06-13 23:05:19805 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34806 }
Anubha Mathur72dd5822019-06-13 23:05:19807
808 const groupIndexToSelect = this._getGroupIndexToSelect(1 /* offset */);
809 this._selectGroup(groupIndexToSelect);
810 return true;
811 }
812
813 /**
814 * @param {number} offset
815 * @return {number}
816 */
817 _getGroupIndexToSelect(offset) {
Paul Lewiscf1f8a42020-11-04 21:05:24818 if (!this._rawTimelineData || !this._rawTimelineData.groups) {
819 throw new Error('No raw timeline data');
820 }
Anubha Mathur72dd5822019-06-13 23:05:19821 const allGroups = this._rawTimelineData.groups;
822 let groupIndexToSelect = this._keyboardFocusedGroup;
823 let groupName, groupWithSubNestingLevel;
824
825 do {
826 groupIndexToSelect += offset;
827 groupName = this._rawTimelineData.groups[groupIndexToSelect].name;
828 groupWithSubNestingLevel = this._keyboardFocusedGroup !== -1 &&
829 allGroups[groupIndexToSelect].style.nestingLevel > allGroups[this._keyboardFocusedGroup].style.nestingLevel;
830 } while (groupIndexToSelect > 0 && groupIndexToSelect < allGroups.length - 1 &&
831 (!groupName || groupWithSubNestingLevel));
832
833 return groupIndexToSelect;
834 }
835
836 _selectFirstChild() {
Paul Lewiscf1f8a42020-11-04 21:05:24837 if (!this._rawTimelineData || !this._rawTimelineData.groups) {
838 return;
839 }
840
Anubha Mathur72dd5822019-06-13 23:05:19841 const allGroups = this._rawTimelineData.groups;
Tim van der Lippe1d6e57a2019-09-30 11:55:34842 if (this._keyboardFocusedGroup < 0 || this._keyboardFocusedGroup >= allGroups.length - 1) {
Anubha Mathur72dd5822019-06-13 23:05:19843 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34844 }
Anubha Mathur72dd5822019-06-13 23:05:19845
846 const groupIndexToSelect = this._keyboardFocusedGroup + 1;
847 if (allGroups[groupIndexToSelect].style.nestingLevel > allGroups[this._keyboardFocusedGroup].style.nestingLevel) {
848 this._selectGroup(groupIndexToSelect);
Anubha Mathur72dd5822019-06-13 23:05:19849 }
850 }
851
852 /**
Tim van der Lippebcd6b5c2021-01-13 12:31:51853 * @param {!KeyboardEvent} event
Anubha Mathur72dd5822019-06-13 23:05:19854 * @return {boolean}
855 */
Paul Lewiscf1f8a42020-11-04 21:05:24856 _handleSelectionNavigation(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34857 if (this._selectedEntryIndex === -1) {
Anubha Mathur72dd5822019-06-13 23:05:19858 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34859 }
Blink Reformat4c46d092018-04-07 15:32:37860 const timelineData = this._timelineData();
Tim van der Lippe1d6e57a2019-09-30 11:55:34861 if (!timelineData) {
Anubha Mathur72dd5822019-06-13 23:05:19862 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34863 }
Blink Reformat4c46d092018-04-07 15:32:37864
865 /**
866 * @param {number} time
867 * @param {number} entryIndex
868 * @return {number}
869 */
870 function timeComparator(time, entryIndex) {
Paul Lewiscf1f8a42020-11-04 21:05:24871 if (!timelineData) {
872 throw new Error('No timeline data');
873 }
Blink Reformat4c46d092018-04-07 15:32:37874 return time - timelineData.entryStartTimes[entryIndex];
875 }
876
877 /**
878 * @param {number} entry1
879 * @param {number} entry2
880 * @return {boolean}
881 */
882 function entriesIntersect(entry1, entry2) {
Paul Lewiscf1f8a42020-11-04 21:05:24883 if (!timelineData) {
884 throw new Error('No timeline data');
885 }
886
Blink Reformat4c46d092018-04-07 15:32:37887 const start1 = timelineData.entryStartTimes[entry1];
888 const start2 = timelineData.entryStartTimes[entry2];
889 const end1 = start1 + timelineData.entryTotalTimes[entry1];
890 const end2 = start2 + timelineData.entryTotalTimes[entry2];
891 return start1 < end2 && start2 < end1;
892 }
893
Paul Lewiscf1f8a42020-11-04 21:05:24894 const keyboardEvent = /** @type {!KeyboardEvent} */ (event);
Blink Reformat4c46d092018-04-07 15:32:37895 const keys = UI.KeyboardShortcut.Keys;
Paul Lewiscf1f8a42020-11-04 21:05:24896 if (keyboardEvent.keyCode === keys.Left.code || keyboardEvent.keyCode === keys.Right.code) {
Blink Reformat4c46d092018-04-07 15:32:37897 const level = timelineData.entryLevels[this._selectedEntryIndex];
Paul Lewiscf1f8a42020-11-04 21:05:24898 const levelIndexes = this._timelineLevels ? this._timelineLevels[level] : [];
Blink Reformat4c46d092018-04-07 15:32:37899 let indexOnLevel = levelIndexes.lowerBound(this._selectedEntryIndex);
Paul Lewiscf1f8a42020-11-04 21:05:24900 indexOnLevel += keyboardEvent.keyCode === keys.Left.code ? -1 : 1;
901 event.consume(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34902 if (indexOnLevel >= 0 && indexOnLevel < levelIndexes.length) {
Tim van der Lippefd2b2ce2020-01-03 15:05:18903 this.dispatchEventToListeners(Events.EntrySelected, levelIndexes[indexOnLevel]);
Tim van der Lippe1d6e57a2019-09-30 11:55:34904 }
Anubha Mathur72dd5822019-06-13 23:05:19905 return true;
Blink Reformat4c46d092018-04-07 15:32:37906 }
Paul Lewiscf1f8a42020-11-04 21:05:24907
908 if (keyboardEvent.keyCode === keys.Up.code || keyboardEvent.keyCode === keys.Down.code) {
Blink Reformat4c46d092018-04-07 15:32:37909 let level = timelineData.entryLevels[this._selectedEntryIndex];
Paul Lewiscf1f8a42020-11-04 21:05:24910 level += keyboardEvent.keyCode === keys.Up.code ? -1 : 1;
911 if (level < 0 || (this._timelineLevels && level >= this._timelineLevels.length)) {
Anubha Mathur72dd5822019-06-13 23:05:19912 this._deselectAllEntries();
Paul Lewiscf1f8a42020-11-04 21:05:24913 keyboardEvent.consume(true);
Anubha Mathur72dd5822019-06-13 23:05:19914 return true;
915 }
Blink Reformat4c46d092018-04-07 15:32:37916 const entryTime = timelineData.entryStartTimes[this._selectedEntryIndex] +
917 timelineData.entryTotalTimes[this._selectedEntryIndex] / 2;
Paul Lewiscf1f8a42020-11-04 21:05:24918 const levelIndexes = this._timelineLevels ? this._timelineLevels[level] : [];
Blink Reformat4c46d092018-04-07 15:32:37919 let indexOnLevel = levelIndexes.upperBound(entryTime, timeComparator) - 1;
920 if (!entriesIntersect(this._selectedEntryIndex, levelIndexes[indexOnLevel])) {
921 ++indexOnLevel;
922 if (indexOnLevel >= levelIndexes.length ||
Anubha Mathur72dd5822019-06-13 23:05:19923 !entriesIntersect(this._selectedEntryIndex, levelIndexes[indexOnLevel])) {
Paul Lewiscf1f8a42020-11-04 21:05:24924 if (keyboardEvent.code === 'ArrowDown') {
Anubha Mathur72dd5822019-06-13 23:05:19925 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34926 }
Anubha Mathur72dd5822019-06-13 23:05:19927
928 // Stay in the current group and give focus to the parent group instead of entries
929 this._deselectAllEntries();
Paul Lewiscf1f8a42020-11-04 21:05:24930 keyboardEvent.consume(true);
Anubha Mathur72dd5822019-06-13 23:05:19931 return true;
932 }
Blink Reformat4c46d092018-04-07 15:32:37933 }
Paul Lewiscf1f8a42020-11-04 21:05:24934 keyboardEvent.consume(true);
Tim van der Lippefd2b2ce2020-01-03 15:05:18935 this.dispatchEventToListeners(Events.EntrySelected, levelIndexes[indexOnLevel]);
Anubha Mathur72dd5822019-06-13 23:05:19936 return true;
Blink Reformat4c46d092018-04-07 15:32:37937 }
Tim van der Lippebcd6b5c2021-01-13 12:31:51938 if (event.key === 'Enter') {
Paul Lewiscf1f8a42020-11-04 21:05:24939 event.consume(true);
Tim van der Lippefd2b2ce2020-01-03 15:05:18940 this.dispatchEventToListeners(Events.EntryInvoked, this._selectedEntryIndex);
Michael Liao712bbc22019-10-15 19:21:51941 return true;
942 }
Anubha Mathur72dd5822019-06-13 23:05:19943 return false;
Blink Reformat4c46d092018-04-07 15:32:37944 }
945
946 /**
947 * @param {number} x
948 * @param {number} y
949 * @return {number}
950 */
951 _coordinatesToEntryIndex(x, y) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34952 if (x < 0 || y < 0) {
Blink Reformat4c46d092018-04-07 15:32:37953 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34954 }
Blink Reformat4c46d092018-04-07 15:32:37955 const timelineData = this._timelineData();
Tim van der Lippe1d6e57a2019-09-30 11:55:34956 if (!timelineData) {
Blink Reformat4c46d092018-04-07 15:32:37957 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34958 }
Blink Reformat4c46d092018-04-07 15:32:37959 y += this._chartViewport.scrollOffset();
Paul Lewiscf1f8a42020-11-04 21:05:24960 if (!this._visibleLevelOffsets) {
961 throw new Error('No visible level offsets');
962 }
Blink Reformat4c46d092018-04-07 15:32:37963 const cursorLevel = this._visibleLevelOffsets.upperBound(y) - 1;
Paul Lewiscf1f8a42020-11-04 21:05:24964 if (cursorLevel < 0 || (this._visibleLevels && !this._visibleLevels[cursorLevel])) {
Blink Reformat4c46d092018-04-07 15:32:37965 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34966 }
Blink Reformat4c46d092018-04-07 15:32:37967 const offsetFromLevel = y - this._visibleLevelOffsets[cursorLevel];
Tim van der Lippe1d6e57a2019-09-30 11:55:34968 if (offsetFromLevel > this._levelHeight(cursorLevel)) {
Blink Reformat4c46d092018-04-07 15:32:37969 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34970 }
Alexei Filippov6c622e92018-11-10 02:13:59971
972 // Check markers first.
973 for (const [index, pos] of this._markerPositions) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34974 if (timelineData.entryLevels[index] !== cursorLevel) {
Alexei Filippov6c622e92018-11-10 02:13:59975 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34976 }
977 if (pos.x <= x && x < pos.x + pos.width) {
Alexei Filippov6c622e92018-11-10 02:13:59978 return /** @type {number} */ (index);
Tim van der Lippe1d6e57a2019-09-30 11:55:34979 }
Alexei Filippov6c622e92018-11-10 02:13:59980 }
981
982 // Check regular entries.
Blink Reformat4c46d092018-04-07 15:32:37983 const entryStartTimes = timelineData.entryStartTimes;
Paul Lewiscf1f8a42020-11-04 21:05:24984 /** @type {!Array.<number>} */
985 const entriesOnLevel = this._timelineLevels ? this._timelineLevels[cursorLevel] : [];
Tim van der Lippe1d6e57a2019-09-30 11:55:34986 if (!entriesOnLevel || !entriesOnLevel.length) {
Blink Reformat4c46d092018-04-07 15:32:37987 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34988 }
Blink Reformat4c46d092018-04-07 15:32:37989
Blink Reformat4c46d092018-04-07 15:32:37990 const cursorTime = this._chartViewport.pixelToTime(x);
Alexei Filippov6c622e92018-11-10 02:13:59991 const indexOnLevel = Math.max(
992 entriesOnLevel.upperBound(cursorTime, (time, entryIndex) => time - entryStartTimes[entryIndex]) - 1, 0);
Blink Reformat4c46d092018-04-07 15:32:37993
994 /**
Tim van der Lippefd2b2ce2020-01-03 15:05:18995 * @this {FlameChart}
Alexei Filippov72d792d2018-11-06 07:15:04996 * @param {number|undefined} entryIndex
Blink Reformat4c46d092018-04-07 15:32:37997 * @return {boolean}
998 */
999 function checkEntryHit(entryIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341000 if (entryIndex === undefined) {
Blink Reformat4c46d092018-04-07 15:32:371001 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341002 }
Paul Lewiscf1f8a42020-11-04 21:05:241003
1004 if (!timelineData) {
1005 return false;
1006 }
1007
Blink Reformat4c46d092018-04-07 15:32:371008 const startTime = entryStartTimes[entryIndex];
Alexei Filippov6c622e92018-11-10 02:13:591009 const duration = timelineData.entryTotalTimes[entryIndex];
Blink Reformat4c46d092018-04-07 15:32:371010 const startX = this._chartViewport.timeToPosition(startTime);
Alexei Filippov6c622e92018-11-10 02:13:591011 const endX = this._chartViewport.timeToPosition(startTime + duration);
1012 const barThresholdPx = 3;
Blink Reformat4c46d092018-04-07 15:32:371013 return startX - barThresholdPx < x && x < endX + barThresholdPx;
1014 }
1015
Alexei Filippov6c622e92018-11-10 02:13:591016 let entryIndex = entriesOnLevel[indexOnLevel];
Tim van der Lippe1d6e57a2019-09-30 11:55:341017 if (checkEntryHit.call(this, entryIndex)) {
Blink Reformat4c46d092018-04-07 15:32:371018 return entryIndex;
Tim van der Lippe1d6e57a2019-09-30 11:55:341019 }
Alexei Filippov6c622e92018-11-10 02:13:591020 entryIndex = entriesOnLevel[indexOnLevel + 1];
Tim van der Lippe1d6e57a2019-09-30 11:55:341021 if (checkEntryHit.call(this, entryIndex)) {
Blink Reformat4c46d092018-04-07 15:32:371022 return entryIndex;
Tim van der Lippe1d6e57a2019-09-30 11:55:341023 }
Blink Reformat4c46d092018-04-07 15:32:371024 return -1;
1025 }
1026
1027 /**
1028 * @param {number} x
1029 * @param {number} y
1030 * @param {boolean} headerOnly
1031 * @return {number}
1032 */
1033 _coordinatesToGroupIndex(x, y, headerOnly) {
Paul Lewiscf1f8a42020-11-04 21:05:241034 if (!this._rawTimelineData || !this._rawTimelineData.groups || !this._groupOffsets) {
1035 return -1;
1036 }
1037
Tim van der Lippe1d6e57a2019-09-30 11:55:341038 if (x < 0 || y < 0) {
Blink Reformat4c46d092018-04-07 15:32:371039 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:341040 }
Blink Reformat4c46d092018-04-07 15:32:371041 y += this._chartViewport.scrollOffset();
1042 const groups = this._rawTimelineData.groups || [];
1043 const group = this._groupOffsets.upperBound(y) - 1;
Tim van der Lippe1d6e57a2019-09-30 11:55:341044 if (group < 0 || group >= groups.length) {
Blink Reformat4c46d092018-04-07 15:32:371045 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:341046 }
Blink Reformat4c46d092018-04-07 15:32:371047 const height = headerOnly ? groups[group].style.height : this._groupOffsets[group + 1] - this._groupOffsets[group];
Tim van der Lippe1d6e57a2019-09-30 11:55:341048 if (y - this._groupOffsets[group] >= height) {
Blink Reformat4c46d092018-04-07 15:32:371049 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:341050 }
1051 if (!headerOnly) {
Blink Reformat4c46d092018-04-07 15:32:371052 return group;
Tim van der Lippe1d6e57a2019-09-30 11:55:341053 }
Blink Reformat4c46d092018-04-07 15:32:371054
1055 const context = /** @type {!CanvasRenderingContext2D} */ (this._canvas.getContext('2d'));
1056 context.save();
1057 context.font = groups[group].style.font;
1058 const right = this._headerLeftPadding + this._labelWidthForGroup(context, groups[group]);
1059 context.restore();
Tim van der Lippe1d6e57a2019-09-30 11:55:341060 if (x > right) {
Blink Reformat4c46d092018-04-07 15:32:371061 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:341062 }
Blink Reformat4c46d092018-04-07 15:32:371063
1064 return group;
1065 }
1066
1067 /**
1068 * @param {number} x
1069 * @return {number}
1070 */
1071 _markerIndexAtPosition(x) {
Paul Lewiscf1f8a42020-11-04 21:05:241072 const timelineData = this._timelineData();
1073 if (!timelineData) {
1074 return -1;
1075 }
1076
1077 const markers = timelineData.markers;
Tim van der Lippe1d6e57a2019-09-30 11:55:341078 if (!markers) {
Blink Reformat4c46d092018-04-07 15:32:371079 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:341080 }
Blink Reformat4c46d092018-04-07 15:32:371081 const /** @const */ accurracyOffsetPx = 4;
1082 const time = this._chartViewport.pixelToTime(x);
1083 const leftTime = this._chartViewport.pixelToTime(x - accurracyOffsetPx);
1084 const rightTime = this._chartViewport.pixelToTime(x + accurracyOffsetPx);
1085 const left = this._markerIndexBeforeTime(leftTime);
1086 let markerIndex = -1;
1087 let distance = Infinity;
1088 for (let i = left; i < markers.length && markers[i].startTime() < rightTime; i++) {
1089 const nextDistance = Math.abs(markers[i].startTime() - time);
1090 if (nextDistance < distance) {
1091 markerIndex = i;
1092 distance = nextDistance;
1093 }
1094 }
1095 return markerIndex;
1096 }
1097
1098 /**
1099 * @param {number} time
1100 * @return {number}
1101 */
1102 _markerIndexBeforeTime(time) {
Paul Lewiscf1f8a42020-11-04 21:05:241103 const timelineData = this._timelineData();
1104 if (!timelineData) {
1105 throw new Error('No timeline data');
1106 }
1107
1108 const markers = timelineData.markers;
1109 if (!markers) {
1110 throw new Error('No timeline markers');
1111 }
1112
1113 return timelineData.markers.lowerBound(time, (markerTimestamp, marker) => markerTimestamp - marker.startTime());
Blink Reformat4c46d092018-04-07 15:32:371114 }
1115
1116 _draw() {
1117 const timelineData = this._timelineData();
Tim van der Lippe1d6e57a2019-09-30 11:55:341118 if (!timelineData) {
Blink Reformat4c46d092018-04-07 15:32:371119 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341120 }
Blink Reformat4c46d092018-04-07 15:32:371121
Paul Lewiscf1f8a42020-11-04 21:05:241122 const visibleLevelOffsets = this._visibleLevelOffsets ? this._visibleLevelOffsets : [];
1123
Blink Reformat4c46d092018-04-07 15:32:371124 const width = this._offsetWidth;
1125 const height = this._offsetHeight;
1126 const context = /** @type {!CanvasRenderingContext2D} */ (this._canvas.getContext('2d'));
1127 context.save();
1128 const ratio = window.devicePixelRatio;
1129 const top = this._chartViewport.scrollOffset();
1130 context.scale(ratio, ratio);
Alexei Filippov57ccafb2018-08-14 20:59:051131 context.fillStyle = 'rgba(0, 0, 0, 0)';
1132 context.fillRect(0, 0, width, height);
Blink Reformat4c46d092018-04-07 15:32:371133 context.translate(0, -top);
Tim van der Lippebb769172020-02-12 15:32:441134 const defaultFont = '11px ' + Host.Platform.fontFamily();
Blink Reformat4c46d092018-04-07 15:32:371135 context.font = defaultFont;
1136
Paul Lewis49b16822020-02-21 14:22:031137 const candyStripePattern = context.createPattern(this._candyStripeCanvas, 'repeat');
1138
Blink Reformat4c46d092018-04-07 15:32:371139 const entryTotalTimes = timelineData.entryTotalTimes;
1140 const entryStartTimes = timelineData.entryStartTimes;
1141 const entryLevels = timelineData.entryLevels;
1142 const timeToPixel = this._chartViewport.timeToPixel();
1143
1144 const titleIndices = [];
1145 const markerIndices = [];
1146 const textPadding = this._textPadding;
Mathias Bynens23ee1aa2020-03-02 12:06:381147 const minTextWidth = 2 * textPadding + UI.UIUtils.measureTextWidth(context, '…');
Alexei Filippov57ccafb2018-08-14 20:59:051148 const minTextWidthDuration = this._chartViewport.pixelToTimeOffset(minTextWidth);
Paul Lewiscf1f8a42020-11-04 21:05:241149 const minVisibleBarLevel = Math.max(visibleLevelOffsets.upperBound(top) - 1, 0);
Alexei Filippov6c622e92018-11-10 02:13:591150 this._markerPositions.clear();
Blink Reformat4c46d092018-04-07 15:32:371151
Paul Lewis49b16822020-02-21 14:22:031152 let mainThreadTopLevel = -1;
1153
1154 // Find the main thread so that we can mark tasks longer than 50ms.
1155 if ('groups' in timelineData && Array.isArray(timelineData.groups)) {
Tim van der Lippe5adc1e02020-11-20 12:30:121156 const mainThread = timelineData.groups.find(group => {
1157 if (!group.track) {
Paul Lewis49b16822020-02-21 14:22:031158 return false;
1159 }
1160
Tim van der Lippe5adc1e02020-11-20 12:30:121161 return group.track.name === 'CrRendererMain';
Paul Lewis49b16822020-02-21 14:22:031162 });
1163
1164 if (mainThread) {
1165 mainThreadTopLevel = mainThread.startLevel;
1166 }
1167 }
1168
Paul Lewis06985d42020-04-30 14:51:161169 /** @type {!Map<string, {indexes: !Array<number>}>} */
Blink Reformat4c46d092018-04-07 15:32:371170 const colorBuckets = new Map();
1171 for (let level = minVisibleBarLevel; level < this._dataProvider.maxStackDepth(); ++level) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341172 if (this._levelToOffset(level) > top + height) {
Blink Reformat4c46d092018-04-07 15:32:371173 break;
Tim van der Lippe1d6e57a2019-09-30 11:55:341174 }
Paul Lewiscf1f8a42020-11-04 21:05:241175 if (!this._visibleLevels || !this._visibleLevels[level]) {
1176 continue;
1177 }
1178 if (!this._timelineLevels) {
Blink Reformat4c46d092018-04-07 15:32:371179 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341180 }
Blink Reformat4c46d092018-04-07 15:32:371181
1182 // Entries are ordered by start time within a level, so find the last visible entry.
Paul Lewiscf1f8a42020-11-04 21:05:241183 /** @type {!Array.<number>} */
Blink Reformat4c46d092018-04-07 15:32:371184 const levelIndexes = this._timelineLevels[level];
1185 const rightIndexOnLevel =
1186 levelIndexes.lowerBound(
1187 this._chartViewport.windowRightTime(), (time, entryIndex) => time - entryStartTimes[entryIndex]) -
1188 1;
1189 let lastDrawOffset = Infinity;
1190 for (let entryIndexOnLevel = rightIndexOnLevel; entryIndexOnLevel >= 0; --entryIndexOnLevel) {
1191 const entryIndex = levelIndexes[entryIndexOnLevel];
Alexei Filippov72d792d2018-11-06 07:15:041192 const duration = entryTotalTimes[entryIndex];
1193 if (isNaN(duration)) {
Alexei Filippov57ccafb2018-08-14 20:59:051194 markerIndices.push(entryIndex);
Alexei Filippov72d792d2018-11-06 07:15:041195 continue;
1196 }
Paul Lewiscf1f8a42020-11-04 21:05:241197 if (duration >= minTextWidthDuration ||
1198 (this._forceDecorationCache && this._forceDecorationCache[entryIndex])) {
Alexei Filippov57ccafb2018-08-14 20:59:051199 titleIndices.push(entryIndex);
Tim van der Lippe1d6e57a2019-09-30 11:55:341200 }
Alexei Filippov57ccafb2018-08-14 20:59:051201
Blink Reformat4c46d092018-04-07 15:32:371202 const entryStartTime = entryStartTimes[entryIndex];
Alexei Filippov57ccafb2018-08-14 20:59:051203 const entryOffsetRight = entryStartTime + duration;
Tim van der Lippe1d6e57a2019-09-30 11:55:341204 if (entryOffsetRight <= this._chartViewport.windowLeftTime()) {
Blink Reformat4c46d092018-04-07 15:32:371205 break;
Tim van der Lippe1d6e57a2019-09-30 11:55:341206 }
1207 if (this._useWebGL) {
Alexei Filippov57ccafb2018-08-14 20:59:051208 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341209 }
Blink Reformat4c46d092018-04-07 15:32:371210
1211 const barX = this._timeToPositionClipped(entryStartTime);
1212 // Check if the entry entirely fits into an already drawn pixel, we can just skip drawing it.
Tim van der Lippe1d6e57a2019-09-30 11:55:341213 if (barX >= lastDrawOffset) {
Blink Reformat4c46d092018-04-07 15:32:371214 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341215 }
Blink Reformat4c46d092018-04-07 15:32:371216 lastDrawOffset = barX;
1217
Paul Lewiscf1f8a42020-11-04 21:05:241218 if (this._entryColorsCache) {
1219 const color = this._entryColorsCache[entryIndex];
1220 let bucket = colorBuckets.get(color);
1221 if (!bucket) {
1222 bucket = {indexes: []};
1223 colorBuckets.set(color, bucket);
1224 }
1225 bucket.indexes.push(entryIndex);
Blink Reformat4c46d092018-04-07 15:32:371226 }
Blink Reformat4c46d092018-04-07 15:32:371227 }
1228 }
1229
Alexei Filippov57ccafb2018-08-14 20:59:051230 if (this._useWebGL) {
1231 this._drawGL();
1232 } else {
1233 context.save();
Alexei Filippov5f6b11d2018-08-18 03:30:281234 this._forEachGroupInViewport((offset, index, group, isFirst, groupHeight) => {
Anubha Mathur72dd5822019-06-13 23:05:191235 if (this._isGroupFocused(index)) {
Alexei Filippov57ccafb2018-08-14 20:59:051236 context.fillStyle = this._selectedGroupBackroundColor;
1237 context.fillRect(0, offset, width, groupHeight - group.style.padding);
Blink Reformat4c46d092018-04-07 15:32:371238 }
Alexei Filippov57ccafb2018-08-14 20:59:051239 });
1240 context.restore();
1241
Paul Lewis06985d42020-04-30 14:51:161242 for (const [color, {indexes}] of colorBuckets) {
Alexei Filippov57ccafb2018-08-14 20:59:051243 context.beginPath();
1244 for (let i = 0; i < indexes.length; ++i) {
1245 const entryIndex = indexes[i];
Alexei Filippov72d792d2018-11-06 07:15:041246 const duration = entryTotalTimes[entryIndex];
Tim van der Lippe1d6e57a2019-09-30 11:55:341247 if (isNaN(duration)) {
Alexei Filippov72d792d2018-11-06 07:15:041248 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341249 }
Alexei Filippov57ccafb2018-08-14 20:59:051250 const entryStartTime = entryStartTimes[entryIndex];
1251 const barX = this._timeToPositionClipped(entryStartTime);
Alexei Filippov57ccafb2018-08-14 20:59:051252 const barLevel = entryLevels[entryIndex];
1253 const barHeight = this._levelHeight(barLevel);
1254 const barY = this._levelToOffset(barLevel);
Alexei Filippov57ccafb2018-08-14 20:59:051255 const barRight = this._timeToPositionClipped(entryStartTime + duration);
1256 const barWidth = Math.max(barRight - barX, 1);
Alexei Filippov72d792d2018-11-06 07:15:041257 context.rect(barX, barY, barWidth - 0.4, barHeight - 1);
Alexei Filippov57ccafb2018-08-14 20:59:051258 }
Alexei Filippov57ccafb2018-08-14 20:59:051259 context.fillStyle = color;
1260 context.fill();
Paul Lewis49b16822020-02-21 14:22:031261
1262 // Draw long task regions.
1263 context.beginPath();
1264 for (let i = 0; i < indexes.length; ++i) {
1265 const entryIndex = indexes[i];
1266 const duration = entryTotalTimes[entryIndex];
Paul Lewis06985d42020-04-30 14:51:161267 const showLongDurations = entryLevels[entryIndex] === mainThreadTopLevel;
Paul Lewis49b16822020-02-21 14:22:031268
1269 if (!showLongDurations) {
1270 continue;
1271 }
1272
Paul Lewis06985d42020-04-30 14:51:161273 if (isNaN(duration) || duration < 50) {
Paul Lewis49b16822020-02-21 14:22:031274 continue;
1275 }
1276
1277 const entryStartTime = entryStartTimes[entryIndex];
1278 const barX = this._timeToPositionClipped(entryStartTime + 50);
1279 const barLevel = entryLevels[entryIndex];
1280 const barHeight = this._levelHeight(barLevel);
1281 const barY = this._levelToOffset(barLevel);
1282 const barRight = this._timeToPositionClipped(entryStartTime + duration);
1283 const barWidth = Math.max(barRight - barX, 1);
1284 context.rect(barX, barY, barWidth - 0.4, barHeight - 1);
1285 }
1286
Paul Lewiscf1f8a42020-11-04 21:05:241287 if (candyStripePattern) {
1288 context.fillStyle = candyStripePattern;
1289 context.fill();
1290 }
Blink Reformat4c46d092018-04-07 15:32:371291 }
Blink Reformat4c46d092018-04-07 15:32:371292 }
1293
Alexei Filippov72d792d2018-11-06 07:15:041294 context.textBaseline = 'alphabetic';
Blink Reformat4c46d092018-04-07 15:32:371295 context.beginPath();
Alexei Filippov6c622e92018-11-10 02:13:591296 let lastMarkerLevel = -1;
1297 let lastMarkerX = -Infinity;
1298 // Markers are sorted top to bottom, right to left.
Alexei Filippov72d792d2018-11-06 07:15:041299 for (let m = markerIndices.length - 1; m >= 0; --m) {
Blink Reformat4c46d092018-04-07 15:32:371300 const entryIndex = markerIndices[m];
Alexei Filippov72d792d2018-11-06 07:15:041301 const title = this._dataProvider.entryTitle(entryIndex);
Tim van der Lippe1d6e57a2019-09-30 11:55:341302 if (!title) {
Alexei Filippov72d792d2018-11-06 07:15:041303 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341304 }
Alexei Filippov6c622e92018-11-10 02:13:591305 const entryStartTime = entryStartTimes[entryIndex];
1306 const level = entryLevels[entryIndex];
Tim van der Lippe1d6e57a2019-09-30 11:55:341307 if (lastMarkerLevel !== level) {
Alexei Filippov6c622e92018-11-10 02:13:591308 lastMarkerX = -Infinity;
Tim van der Lippe1d6e57a2019-09-30 11:55:341309 }
Alexei Filippov6c622e92018-11-10 02:13:591310 const x = Math.max(this._chartViewport.timeToPosition(entryStartTime), lastMarkerX);
1311 const y = this._levelToOffset(level);
1312 const h = this._levelHeight(level);
1313 const padding = 4;
Tim van der Lippebb769172020-02-12 15:32:441314 const width = Math.ceil(UI.UIUtils.measureTextWidth(context, title)) + 2 * padding;
Alexei Filippov214df612018-11-13 19:14:001315 lastMarkerX = x + width + 1;
Alexei Filippov6c622e92018-11-10 02:13:591316 lastMarkerLevel = level;
1317 this._markerPositions.set(entryIndex, {x, width});
Alexei Filippov72d792d2018-11-06 07:15:041318 context.fillStyle = this._dataProvider.entryColor(entryIndex);
1319 context.fillRect(x, y, width, h - 1);
1320 context.fillStyle = 'white';
Alexei Filippov72d792d2018-11-06 07:15:041321 context.fillText(title, x + padding, y + h - this._textBaseline);
Blink Reformat4c46d092018-04-07 15:32:371322 }
1323 context.strokeStyle = 'rgba(0, 0, 0, 0.2)';
1324 context.stroke();
1325
Blink Reformat4c46d092018-04-07 15:32:371326 for (let i = 0; i < titleIndices.length; ++i) {
1327 const entryIndex = titleIndices[i];
1328 const entryStartTime = entryStartTimes[entryIndex];
1329 const barX = this._timeToPositionClipped(entryStartTime);
1330 const barRight = Math.min(this._timeToPositionClipped(entryStartTime + entryTotalTimes[entryIndex]), width) + 1;
1331 const barWidth = barRight - barX;
1332 const barLevel = entryLevels[entryIndex];
1333 const barY = this._levelToOffset(barLevel);
1334 let text = this._dataProvider.entryTitle(entryIndex);
1335 if (text && text.length) {
1336 context.font = this._dataProvider.entryFont(entryIndex) || defaultFont;
Tim van der Lippebb769172020-02-12 15:32:441337 text = UI.UIUtils.trimTextMiddle(context, text, barWidth - 2 * textPadding);
Blink Reformat4c46d092018-04-07 15:32:371338 }
1339 const unclippedBarX = this._chartViewport.timeToPosition(entryStartTime);
1340 const barHeight = this._levelHeight(barLevel);
1341 if (this._dataProvider.decorateEntry(
Tim van der Lippe1d6e57a2019-09-30 11:55:341342 entryIndex, context, text, barX, barY, barWidth, barHeight, unclippedBarX, timeToPixel)) {
Blink Reformat4c46d092018-04-07 15:32:371343 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341344 }
1345 if (!text || !text.length) {
Blink Reformat4c46d092018-04-07 15:32:371346 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341347 }
Blink Reformat4c46d092018-04-07 15:32:371348 context.fillStyle = this._dataProvider.textColor(entryIndex);
1349 context.fillText(text, barX + textPadding, barY + barHeight - this._textBaseline);
1350 }
1351
1352 context.restore();
1353
1354 this._drawGroupHeaders(width, height);
1355 this._drawFlowEvents(context, width, height);
1356 this._drawMarkers();
Paul Lewis2cfa94e2020-01-13 10:30:151357 const dividersData = TimelineGrid.calculateGridOffsets(this);
Paul Lewisead45752020-06-23 09:51:361358 const navStartTimes = Array.from(this._dataProvider.navStartTimes().values());
1359
1360 let navStartTimeIndex = 0;
Paul Lewiscf1f8a42020-11-04 21:05:241361 /**
1362 * @param {number} time
1363 */
Paul Lewisead45752020-06-23 09:51:361364 const drawAdjustedTime = time => {
1365 if (navStartTimes.length === 0) {
1366 return this.formatValue(time, dividersData.precision);
1367 }
1368
1369 // Track when the time crosses the boundary to the next nav start record,
1370 // and when it does, move the nav start array index accordingly.
1371 const hasNextNavStartTime = navStartTimes.length > navStartTimeIndex + 1;
1372 if (hasNextNavStartTime && time > navStartTimes[navStartTimeIndex + 1].startTime) {
1373 navStartTimeIndex++;
1374 }
1375
1376 // Adjust the time by the nearest nav start marker's value.
1377 const nearestMarker = navStartTimes[navStartTimeIndex];
1378 if (nearestMarker) {
1379 time -= nearestMarker.startTime - this.zeroTime();
1380 }
1381
1382 return this.formatValue(time, dividersData.precision);
1383 };
1384
Paul Lewis2cfa94e2020-01-13 10:30:151385 TimelineGrid.drawCanvasGrid(context, dividersData);
Blink Reformat4c46d092018-04-07 15:32:371386 if (this._rulerEnabled) {
Paul Lewisead45752020-06-23 09:51:361387 TimelineGrid.drawCanvasHeaders(context, dividersData, drawAdjustedTime, 3, HeaderHeight);
Blink Reformat4c46d092018-04-07 15:32:371388 }
1389
1390 this._updateElementPosition(this._highlightElement, this._highlightedEntryIndex);
1391 this._updateElementPosition(this._selectedElement, this._selectedEntryIndex);
1392 this._updateMarkerHighlight();
1393 }
1394
Alexei Filippov57ccafb2018-08-14 20:59:051395 _initWebGL() {
1396 const gl = /** @type {?WebGLRenderingContext} */ (this._canvasGL.getContext('webgl'));
1397 if (!gl) {
1398 console.error('Failed to obtain WebGL context.');
1399 this._useWebGL = false; // Fallback to use canvas.
1400 return;
1401 }
1402
1403 const vertexShaderSource = `
1404 attribute vec2 aVertexPosition;
Alexei Filippovaf3ffed2018-08-18 01:56:091405 attribute float aVertexColor;
Alexei Filippov57ccafb2018-08-14 20:59:051406
1407 uniform vec2 uScalingFactor;
1408 uniform vec2 uShiftVector;
1409
Alexei Filippovaf3ffed2018-08-18 01:56:091410 varying mediump vec2 vPalettePosition;
Alexei Filippov57ccafb2018-08-14 20:59:051411
1412 void main() {
1413 vec2 shiftedPosition = aVertexPosition - uShiftVector;
1414 gl_Position = vec4(shiftedPosition * uScalingFactor + vec2(-1.0, 1.0), 0.0, 1.0);
Alexei Filippovaf3ffed2018-08-18 01:56:091415 vPalettePosition = vec2(aVertexColor, 0.5);
Alexei Filippov57ccafb2018-08-14 20:59:051416 }`;
1417
1418 const fragmentShaderSource = `
Alexei Filippovaf3ffed2018-08-18 01:56:091419 varying mediump vec2 vPalettePosition;
1420 uniform sampler2D uSampler;
Alexei Filippov57ccafb2018-08-14 20:59:051421
1422 void main() {
Alexei Filippovaf3ffed2018-08-18 01:56:091423 gl_FragColor = texture2D(uSampler, vPalettePosition);
Alexei Filippov57ccafb2018-08-14 20:59:051424 }`;
1425
1426 /**
1427 * @param {!WebGLRenderingContext} gl
1428 * @param {number} type
1429 * @param {string} source
1430 * @return {?WebGLShader}
1431 */
1432 function loadShader(gl, type, source) {
1433 const shader = gl.createShader(type);
Paul Lewiscf1f8a42020-11-04 21:05:241434 if (!shader) {
1435 return null;
1436 }
1437
Alexei Filippov57ccafb2018-08-14 20:59:051438 gl.shaderSource(shader, source);
1439 gl.compileShader(shader);
Tim van der Lippe1d6e57a2019-09-30 11:55:341440 if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
Alexei Filippov57ccafb2018-08-14 20:59:051441 return shader;
Tim van der Lippe1d6e57a2019-09-30 11:55:341442 }
Alexei Filippov57ccafb2018-08-14 20:59:051443 console.error('Shader compile error: ' + gl.getShaderInfoLog(shader));
1444 gl.deleteShader(shader);
1445 return null;
1446 }
1447
1448 const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
1449 const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
1450
1451 const shaderProgram = gl.createProgram();
Paul Lewiscf1f8a42020-11-04 21:05:241452 if (!shaderProgram || !vertexShader || !fragmentShader) {
1453 return;
1454 }
Alexei Filippov57ccafb2018-08-14 20:59:051455 gl.attachShader(shaderProgram, vertexShader);
1456 gl.attachShader(shaderProgram, fragmentShader);
1457 gl.linkProgram(shaderProgram);
1458
1459 if (gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
1460 this._shaderProgram = shaderProgram;
1461 gl.useProgram(shaderProgram);
1462 } else {
Alexei Filippov57ccafb2018-08-14 20:59:051463 this._shaderProgram = null;
Paul Lewiscf1f8a42020-11-04 21:05:241464 throw new Error('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
Alexei Filippov57ccafb2018-08-14 20:59:051465 }
Alexei Filippovaf3ffed2018-08-18 01:56:091466
1467 this._vertexBuffer = gl.createBuffer();
1468 this._colorBuffer = gl.createBuffer();
1469
1470 this._uScalingFactor = gl.getUniformLocation(shaderProgram, 'uScalingFactor');
1471 this._uShiftVector = gl.getUniformLocation(shaderProgram, 'uShiftVector');
1472 const uSampler = gl.getUniformLocation(shaderProgram, 'uSampler');
1473 gl.uniform1i(uSampler, 0);
1474 this._aVertexPosition = gl.getAttribLocation(this._shaderProgram, 'aVertexPosition');
1475 this._aVertexColor = gl.getAttribLocation(this._shaderProgram, 'aVertexColor');
1476 gl.enableVertexAttribArray(this._aVertexPosition);
1477 gl.enableVertexAttribArray(this._aVertexColor);
Alexei Filippov57ccafb2018-08-14 20:59:051478 }
1479
1480 _setupGLGeometry() {
1481 const gl = /** @type {?WebGLRenderingContext} */ (this._canvasGL.getContext('webgl'));
Tim van der Lippe1d6e57a2019-09-30 11:55:341482 if (!gl) {
Alexei Filippov57ccafb2018-08-14 20:59:051483 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341484 }
Alexei Filippov57ccafb2018-08-14 20:59:051485
1486 const timelineData = this._timelineData();
Tim van der Lippe1d6e57a2019-09-30 11:55:341487 if (!timelineData) {
Alexei Filippov57ccafb2018-08-14 20:59:051488 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341489 }
Alexei Filippov57ccafb2018-08-14 20:59:051490
1491 const entryTotalTimes = timelineData.entryTotalTimes;
1492 const entryStartTimes = timelineData.entryStartTimes;
1493 const entryLevels = timelineData.entryLevels;
1494
Alexei Filippovaf3ffed2018-08-18 01:56:091495 const verticesPerBar = 6;
1496 const vertexArray = new Float32Array(entryTotalTimes.length * verticesPerBar * 2);
1497 let colorArray = new Uint8Array(entryTotalTimes.length * verticesPerBar);
Alexei Filippov57ccafb2018-08-14 20:59:051498 let vertex = 0;
Alexei Filippovaf3ffed2018-08-18 01:56:091499 /** @type {!Map<string, number>} */
Alexei Filippovc34372c2018-08-16 20:37:391500 const parsedColorCache = new Map();
Alexei Filippovaf3ffed2018-08-18 01:56:091501 /** @type {!Array<number>} */
1502 const colors = [];
1503
Paul Lewiscf1f8a42020-11-04 21:05:241504 const visibleLevels = this._visibleLevels || [];
1505 const rawTimelineData = this._rawTimelineData || {groups: []};
1506
1507 const collapsedOverviewLevels = new Array(visibleLevels.length);
1508 const groups = rawTimelineData.groups || [];
Alexei Filippov5f6b11d2018-08-18 03:30:281509 this._forEachGroup((offset, index, group) => {
Tim van der Lippe1d6e57a2019-09-30 11:55:341510 if (group.style.useFirstLineForOverview || !this._isGroupCollapsible(index) || group.expanded) {
Alexei Filippov5f6b11d2018-08-18 03:30:281511 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341512 }
Alexei Filippov5f6b11d2018-08-18 03:30:281513 let nextGroup = index + 1;
Tim van der Lippe1d6e57a2019-09-30 11:55:341514 while (nextGroup < groups.length && groups[nextGroup].style.nestingLevel > group.style.nestingLevel) {
Alexei Filippov5f6b11d2018-08-18 03:30:281515 ++nextGroup;
Tim van der Lippe1d6e57a2019-09-30 11:55:341516 }
Alexei Filippov5f6b11d2018-08-18 03:30:281517 const endLevel = nextGroup < groups.length ? groups[nextGroup].startLevel : this._dataProvider.maxStackDepth();
Tim van der Lippe1d6e57a2019-09-30 11:55:341518 for (let i = group.startLevel; i < endLevel; ++i) {
Alexei Filippov5f6b11d2018-08-18 03:30:281519 collapsedOverviewLevels[i] = offset;
Tim van der Lippe1d6e57a2019-09-30 11:55:341520 }
Alexei Filippov5f6b11d2018-08-18 03:30:281521 });
1522
Alexei Filippov57ccafb2018-08-14 20:59:051523 for (let i = 0; i < entryTotalTimes.length; ++i) {
1524 const level = entryLevels[i];
Alexei Filippov5f6b11d2018-08-18 03:30:281525 const collapsedGroupOffset = collapsedOverviewLevels[level];
Paul Lewiscf1f8a42020-11-04 21:05:241526 if (!visibleLevels[level] && !collapsedGroupOffset) {
Alexei Filippov57ccafb2018-08-14 20:59:051527 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341528 }
Paul Lewiscf1f8a42020-11-04 21:05:241529 if (!this._entryColorsCache) {
1530 continue;
1531 }
1532
Alexei Filippove5197622018-08-18 03:04:331533 const color = this._entryColorsCache[i];
Tim van der Lippe1d6e57a2019-09-30 11:55:341534 if (!color) {
Alexei Filippov57ccafb2018-08-14 20:59:051535 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341536 }
Alexei Filippovaf3ffed2018-08-18 01:56:091537 let colorIndex = parsedColorCache.get(color);
1538 if (colorIndex === undefined) {
Paul Lewiscf1f8a42020-11-04 21:05:241539 const parsedColor = Common.Color.Color.parse(color);
1540 if (parsedColor) {
1541 const rgba = parsedColor.canonicalRGBA();
1542 rgba[3] = Math.round(rgba[3] * 255);
1543 colorIndex = colors.length / 4;
1544 colors.push(...rgba);
1545 if (colorIndex === 256) {
1546 colorArray = new Uint8Array(colorArray);
1547 }
Tim van der Lippe1d6e57a2019-09-30 11:55:341548 }
Paul Lewiscf1f8a42020-11-04 21:05:241549
1550 if (colorIndex) {
1551 parsedColorCache.set(color, colorIndex);
1552 }
Alexei Filippovc34372c2018-08-16 20:37:391553 }
Tim van der Lippe1d6e57a2019-09-30 11:55:341554 for (let j = 0; j < verticesPerBar; ++j) {
Paul Lewiscf1f8a42020-11-04 21:05:241555 if (colorIndex) {
1556 colorArray[vertex + j] = colorIndex;
1557 }
Tim van der Lippe1d6e57a2019-09-30 11:55:341558 }
Alexei Filippov57ccafb2018-08-14 20:59:051559
1560 const vpos = vertex * 2;
1561 const x0 = entryStartTimes[i] - this._minimumBoundary;
1562 const x1 = x0 + entryTotalTimes[i];
Alexei Filippov5f6b11d2018-08-18 03:30:281563 const y0 = collapsedGroupOffset || this._levelToOffset(level);
Alexei Filippov57ccafb2018-08-14 20:59:051564 const y1 = y0 + this._levelHeight(level) - 1;
1565 vertexArray[vpos + 0] = x0;
1566 vertexArray[vpos + 1] = y0;
1567 vertexArray[vpos + 2] = x1;
1568 vertexArray[vpos + 3] = y0;
1569 vertexArray[vpos + 4] = x0;
1570 vertexArray[vpos + 5] = y1;
1571 vertexArray[vpos + 6] = x0;
1572 vertexArray[vpos + 7] = y1;
1573 vertexArray[vpos + 8] = x1;
1574 vertexArray[vpos + 9] = y0;
1575 vertexArray[vpos + 10] = x1;
1576 vertexArray[vpos + 11] = y1;
1577
Alexei Filippovaf3ffed2018-08-18 01:56:091578 vertex += verticesPerBar;
Alexei Filippov57ccafb2018-08-14 20:59:051579 }
Alexei Filippov57ccafb2018-08-14 20:59:051580 this._vertexCount = vertex;
1581
Alexei Filippovaf3ffed2018-08-18 01:56:091582 const paletteTexture = gl.createTexture();
1583 gl.bindTexture(gl.TEXTURE_2D, paletteTexture);
1584 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
1585 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
1586 gl.activeTexture(gl.TEXTURE0);
1587
1588 const numColors = colors.length / 4;
1589 const useShortForColors = numColors >= 256;
1590 const width = !useShortForColors ? 256 : Math.min(1 << 16, gl.getParameter(gl.MAX_TEXTURE_SIZE));
1591 console.assert(numColors <= width, 'Too many colors');
1592 const height = 1;
1593 const colorIndexType = useShortForColors ? gl.UNSIGNED_SHORT : gl.UNSIGNED_BYTE;
1594 if (useShortForColors) {
1595 const factor = (1 << 16) / width;
Tim van der Lippe1d6e57a2019-09-30 11:55:341596 for (let i = 0; i < vertex; ++i) {
Alexei Filippovaf3ffed2018-08-18 01:56:091597 colorArray[i] *= factor;
Tim van der Lippe1d6e57a2019-09-30 11:55:341598 }
Alexei Filippovaf3ffed2018-08-18 01:56:091599 }
1600
1601 const pixels = new Uint8Array(width * 4);
1602 pixels.set(colors);
1603 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
1604
Paul Lewiscf1f8a42020-11-04 21:05:241605 if (this._vertexBuffer && this._aVertexPosition) {
1606 gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer);
1607 gl.bufferData(gl.ARRAY_BUFFER, vertexArray, gl.STATIC_DRAW);
1608 gl.vertexAttribPointer(this._aVertexPosition, /* vertexComponents */ 2, gl.FLOAT, false, 0, 0);
1609 }
Alexei Filippov57ccafb2018-08-14 20:59:051610
Paul Lewiscf1f8a42020-11-04 21:05:241611 if (this._colorBuffer && this._aVertexColor) {
1612 gl.bindBuffer(gl.ARRAY_BUFFER, this._colorBuffer);
1613 gl.bufferData(gl.ARRAY_BUFFER, colorArray, gl.STATIC_DRAW);
1614 gl.vertexAttribPointer(this._aVertexColor, /* colorComponents */ 1, colorIndexType, true, 0, 0);
1615 }
Alexei Filippov57ccafb2018-08-14 20:59:051616 }
1617
1618 _drawGL() {
1619 const gl = /** @type {?WebGLRenderingContext} */ (this._canvasGL.getContext('webgl'));
Tim van der Lippe1d6e57a2019-09-30 11:55:341620 if (!gl) {
Alexei Filippov57ccafb2018-08-14 20:59:051621 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341622 }
Alexei Filippov57ccafb2018-08-14 20:59:051623 const timelineData = this._timelineData();
Tim van der Lippe1d6e57a2019-09-30 11:55:341624 if (!timelineData) {
Alexei Filippov57ccafb2018-08-14 20:59:051625 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341626 }
Alexei Filippov57ccafb2018-08-14 20:59:051627
Alexei Filippov57ccafb2018-08-14 20:59:051628 if (!this._prevTimelineData || timelineData.entryTotalTimes !== this._prevTimelineData.entryTotalTimes) {
1629 this._prevTimelineData = timelineData;
1630 this._setupGLGeometry();
1631 }
1632
Alexei Filippovc34372c2018-08-16 20:37:391633 gl.viewport(0, 0, this._canvasGL.width, this._canvasGL.height);
Alexei Filippov57ccafb2018-08-14 20:59:051634
Tim van der Lippe1d6e57a2019-09-30 11:55:341635 if (!this._vertexCount) {
Alexei Filippov57ccafb2018-08-14 20:59:051636 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341637 }
Alexei Filippov57ccafb2018-08-14 20:59:051638
Alexei Filippovc34372c2018-08-16 20:37:391639 const viewportScale = [2.0 / this.boundarySpan(), -2.0 * window.devicePixelRatio / this._canvasGL.height];
1640 const viewportShift = [this.minimumBoundary() - this.zeroTime(), this._chartViewport.scrollOffset()];
Paul Lewiscf1f8a42020-11-04 21:05:241641 if (this._uScalingFactor) {
1642 gl.uniform2fv(this._uScalingFactor, viewportScale);
1643 }
1644
1645 if (this._uShiftVector) {
1646 gl.uniform2fv(this._uShiftVector, viewportShift);
1647 }
Alexei Filippov57ccafb2018-08-14 20:59:051648
1649 gl.drawArrays(gl.TRIANGLES, 0, this._vertexCount);
1650 }
1651
Blink Reformat4c46d092018-04-07 15:32:371652 /**
1653 * @param {number} width
1654 * @param {number} height
1655 */
1656 _drawGroupHeaders(width, height) {
1657 const context = /** @type {!CanvasRenderingContext2D} */ (this._canvas.getContext('2d'));
1658 const top = this._chartViewport.scrollOffset();
1659 const ratio = window.devicePixelRatio;
Paul Lewiscf1f8a42020-11-04 21:05:241660 if (!this._rawTimelineData) {
1661 return;
1662 }
1663
Blink Reformat4c46d092018-04-07 15:32:371664 const groups = this._rawTimelineData.groups || [];
Tim van der Lippe1d6e57a2019-09-30 11:55:341665 if (!groups.length) {
Blink Reformat4c46d092018-04-07 15:32:371666 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341667 }
Blink Reformat4c46d092018-04-07 15:32:371668
1669 const groupOffsets = this._groupOffsets;
1670 const lastGroupOffset = Array.prototype.peekLast.call(groupOffsets);
Paul Lewisca569a52020-09-09 16:11:511671 const colorUsage = ThemeSupport.ThemeSupport.ColorUsage;
Blink Reformat4c46d092018-04-07 15:32:371672
1673 context.save();
1674 context.scale(ratio, ratio);
1675 context.translate(0, -top);
Tim van der Lippebb769172020-02-12 15:32:441676 const defaultFont = '11px ' + Host.Platform.fontFamily();
Blink Reformat4c46d092018-04-07 15:32:371677 context.font = defaultFont;
1678
Paul Lewisca569a52020-09-09 16:11:511679 context.fillStyle = ThemeSupport.ThemeSupport.instance().patchColorText('#fff', colorUsage.Background);
Alexei Filippov5f6b11d2018-08-18 03:30:281680 this._forEachGroupInViewport((offset, index, group) => {
Blink Reformat4c46d092018-04-07 15:32:371681 const paddingHeight = group.style.padding;
Tim van der Lippe1d6e57a2019-09-30 11:55:341682 if (paddingHeight < 5) {
Blink Reformat4c46d092018-04-07 15:32:371683 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341684 }
Blink Reformat4c46d092018-04-07 15:32:371685 context.fillRect(0, offset - paddingHeight + 2, width, paddingHeight - 4);
1686 });
Tim van der Lippe1d6e57a2019-09-30 11:55:341687 if (groups.length && lastGroupOffset < top + height) {
Blink Reformat4c46d092018-04-07 15:32:371688 context.fillRect(0, lastGroupOffset + 2, width, top + height - lastGroupOffset);
Tim van der Lippe1d6e57a2019-09-30 11:55:341689 }
Blink Reformat4c46d092018-04-07 15:32:371690
Paul Lewisca569a52020-09-09 16:11:511691 context.strokeStyle = ThemeSupport.ThemeSupport.instance().patchColorText('#eee', colorUsage.Background);
Blink Reformat4c46d092018-04-07 15:32:371692 context.beginPath();
Alexei Filippov5f6b11d2018-08-18 03:30:281693 this._forEachGroupInViewport((offset, index, group, isFirst) => {
Tim van der Lippe1d6e57a2019-09-30 11:55:341694 if (isFirst || group.style.padding < 4) {
Blink Reformat4c46d092018-04-07 15:32:371695 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341696 }
Blink Reformat4c46d092018-04-07 15:32:371697 hLine(offset - 2.5);
1698 });
1699 hLine(lastGroupOffset + 1.5);
1700 context.stroke();
1701
Alexei Filippov5f6b11d2018-08-18 03:30:281702 this._forEachGroupInViewport((offset, index, group) => {
Tim van der Lippe1d6e57a2019-09-30 11:55:341703 if (group.style.useFirstLineForOverview) {
Blink Reformat4c46d092018-04-07 15:32:371704 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341705 }
Blink Reformat4c46d092018-04-07 15:32:371706 if (!this._isGroupCollapsible(index) || group.expanded) {
Anubha Mathur72dd5822019-06-13 23:05:191707 if (!group.style.shareHeaderLine && this._isGroupFocused(index)) {
Blink Reformat4c46d092018-04-07 15:32:371708 context.fillStyle = group.style.backgroundColor;
1709 context.fillRect(0, offset, width, group.style.height);
1710 }
1711 return;
1712 }
Tim van der Lippe1d6e57a2019-09-30 11:55:341713 if (this._useWebGL) {
Alexei Filippov5f6b11d2018-08-18 03:30:281714 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341715 }
Blink Reformat4c46d092018-04-07 15:32:371716 let nextGroup = index + 1;
Tim van der Lippe1d6e57a2019-09-30 11:55:341717 while (nextGroup < groups.length && groups[nextGroup].style.nestingLevel > group.style.nestingLevel) {
Blink Reformat4c46d092018-04-07 15:32:371718 nextGroup++;
Tim van der Lippe1d6e57a2019-09-30 11:55:341719 }
Blink Reformat4c46d092018-04-07 15:32:371720 const endLevel = nextGroup < groups.length ? groups[nextGroup].startLevel : this._dataProvider.maxStackDepth();
Alexei Filippov23428d42018-04-28 01:09:071721 this._drawCollapsedOverviewForGroup(group, offset, endLevel);
Blink Reformat4c46d092018-04-07 15:32:371722 });
1723
1724 context.save();
Alexei Filippov5f6b11d2018-08-18 03:30:281725 this._forEachGroupInViewport((offset, index, group) => {
Blink Reformat4c46d092018-04-07 15:32:371726 context.font = group.style.font;
1727 if (this._isGroupCollapsible(index) && !group.expanded || group.style.shareHeaderLine) {
1728 const width = this._labelWidthForGroup(context, group) + 2;
Tim van der Lippe1d6e57a2019-09-30 11:55:341729 if (this._isGroupFocused(index)) {
Blink Reformat4c46d092018-04-07 15:32:371730 context.fillStyle = this._selectedGroupBackroundColor;
Tim van der Lippe1d6e57a2019-09-30 11:55:341731 } else {
Paul Lewiscf1f8a42020-11-04 21:05:241732 const parsedColor = Common.Color.Color.parse(group.style.backgroundColor);
1733 if (parsedColor) {
1734 context.fillStyle = /** @type {string} */ (parsedColor.setAlpha(0.8).asString(null));
1735 }
Tim van der Lippe1d6e57a2019-09-30 11:55:341736 }
Blink Reformat4c46d092018-04-07 15:32:371737
1738 context.fillRect(
1739 this._headerLeftPadding - this._headerLabelXPadding, offset + this._headerLabelYPadding, width,
1740 group.style.height - 2 * this._headerLabelYPadding);
1741 }
1742 context.fillStyle = group.style.color;
1743 context.fillText(
1744 group.name, Math.floor(this._expansionArrowIndent * (group.style.nestingLevel + 1) + this._arrowSide),
1745 offset + group.style.height - this._textBaseline);
1746 });
1747 context.restore();
1748
Paul Lewisca569a52020-09-09 16:11:511749 context.fillStyle = ThemeSupport.ThemeSupport.instance().patchColorText('#6e6e6e', colorUsage.Foreground);
Blink Reformat4c46d092018-04-07 15:32:371750 context.beginPath();
Alexei Filippov5f6b11d2018-08-18 03:30:281751 this._forEachGroupInViewport((offset, index, group) => {
Blink Reformat4c46d092018-04-07 15:32:371752 if (this._isGroupCollapsible(index)) {
1753 drawExpansionArrow.call(
1754 this, this._expansionArrowIndent * (group.style.nestingLevel + 1),
Tim van der Lipped7cfd142021-01-07 12:17:241755 offset + group.style.height - this._textBaseline - this._arrowSide / 2, Boolean(group.expanded));
Blink Reformat4c46d092018-04-07 15:32:371756 }
1757 });
1758 context.fill();
1759
Paul Lewisca569a52020-09-09 16:11:511760 context.strokeStyle = ThemeSupport.ThemeSupport.instance().patchColorText('#ddd', colorUsage.Background);
Blink Reformat4c46d092018-04-07 15:32:371761 context.beginPath();
1762 context.stroke();
1763
Alexei Filippov5f6b11d2018-08-18 03:30:281764 this._forEachGroupInViewport((offset, index, group, isFirst, groupHeight) => {
Anubha Mathur72dd5822019-06-13 23:05:191765 if (this._isGroupFocused(index)) {
Alexei Filippov23428d42018-04-28 01:09:071766 const lineWidth = 2;
1767 const bracketLength = 10;
Blink Reformat4c46d092018-04-07 15:32:371768 context.fillStyle = this._selectedGroupBorderColor;
Alexei Filippov23428d42018-04-28 01:09:071769 context.fillRect(0, offset - lineWidth, lineWidth, groupHeight - group.style.padding + 2 * lineWidth);
1770 context.fillRect(0, offset - lineWidth, bracketLength, lineWidth);
1771 context.fillRect(0, offset + groupHeight - group.style.padding, bracketLength, lineWidth);
Blink Reformat4c46d092018-04-07 15:32:371772 }
1773 });
1774
1775 context.restore();
1776
1777 /**
1778 * @param {number} y
1779 */
1780 function hLine(y) {
1781 context.moveTo(0, y);
1782 context.lineTo(width, y);
1783 }
1784
1785 /**
1786 * @param {number} x
1787 * @param {number} y
1788 * @param {boolean} expanded
Tim van der Lippefd2b2ce2020-01-03 15:05:181789 * @this {FlameChart}
Blink Reformat4c46d092018-04-07 15:32:371790 */
1791 function drawExpansionArrow(x, y, expanded) {
1792 const arrowHeight = this._arrowSide * Math.sqrt(3) / 2;
1793 const arrowCenterOffset = Math.round(arrowHeight / 2);
1794 context.save();
1795 context.translate(x, y);
1796 context.rotate(expanded ? Math.PI / 2 : 0);
1797 context.moveTo(-arrowCenterOffset, -this._arrowSide / 2);
1798 context.lineTo(-arrowCenterOffset, this._arrowSide / 2);
1799 context.lineTo(arrowHeight - arrowCenterOffset, 0);
1800 context.restore();
1801 }
1802 }
1803
1804 /**
Paul Lewiscf1f8a42020-11-04 21:05:241805 * @param {function(number, number, !Group, boolean, number):void} callback
Blink Reformat4c46d092018-04-07 15:32:371806 */
1807 _forEachGroup(callback) {
Paul Lewiscf1f8a42020-11-04 21:05:241808 if (!this._rawTimelineData) {
1809 return;
1810 }
Blink Reformat4c46d092018-04-07 15:32:371811 const groups = this._rawTimelineData.groups || [];
Tim van der Lippe1d6e57a2019-09-30 11:55:341812 if (!groups.length) {
Blink Reformat4c46d092018-04-07 15:32:371813 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341814 }
Blink Reformat4c46d092018-04-07 15:32:371815 const groupOffsets = this._groupOffsets;
Paul Lewiscf1f8a42020-11-04 21:05:241816 if (!groupOffsets) {
1817 return;
1818 }
1819
1820 /** @type {!Array<{nestingLevel: number, visible: boolean}>} */
Blink Reformat4c46d092018-04-07 15:32:371821 const groupStack = [{nestingLevel: -1, visible: true}];
1822 for (let i = 0; i < groups.length; ++i) {
1823 const groupTop = groupOffsets[i];
1824 const group = groups[i];
Blink Reformat4c46d092018-04-07 15:32:371825 let firstGroup = true;
Paul Lewiscf1f8a42020-11-04 21:05:241826 let last = groupStack.peekLast();
1827 while (last && last.nestingLevel >= group.style.nestingLevel) {
Blink Reformat4c46d092018-04-07 15:32:371828 groupStack.pop();
1829 firstGroup = false;
Paul Lewiscf1f8a42020-11-04 21:05:241830 last = groupStack.peekLast();
Blink Reformat4c46d092018-04-07 15:32:371831 }
Paul Lewiscf1f8a42020-11-04 21:05:241832 last = groupStack.peekLast();
1833 const parentGroupVisible = last ? last.visible : false;
Blink Reformat4c46d092018-04-07 15:32:371834 const thisGroupVisible = parentGroupVisible && (!this._isGroupCollapsible(i) || group.expanded);
Tim van der Lipped7cfd142021-01-07 12:17:241835 groupStack.push({nestingLevel: group.style.nestingLevel, visible: Boolean(thisGroupVisible)});
Alexei Filippov23428d42018-04-28 01:09:071836 const nextOffset = i === groups.length - 1 ? groupOffsets[i + 1] + group.style.padding : groupOffsets[i + 1];
Tim van der Lippe1d6e57a2019-09-30 11:55:341837 if (!parentGroupVisible) {
Blink Reformat4c46d092018-04-07 15:32:371838 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341839 }
Blink Reformat4c46d092018-04-07 15:32:371840 callback(groupTop, i, group, firstGroup, nextOffset - groupTop);
1841 }
1842 }
1843
1844 /**
Paul Lewiscf1f8a42020-11-04 21:05:241845 * @param {function(number, number, !Group, boolean, number):void} callback
Alexei Filippov5f6b11d2018-08-18 03:30:281846 */
1847 _forEachGroupInViewport(callback) {
1848 const top = this._chartViewport.scrollOffset();
1849 this._forEachGroup((groupTop, index, group, firstGroup, height) => {
Tim van der Lippe1d6e57a2019-09-30 11:55:341850 if (groupTop - group.style.padding > top + this._offsetHeight) {
Alexei Filippov5f6b11d2018-08-18 03:30:281851 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341852 }
1853 if (groupTop + height < top) {
Alexei Filippov5f6b11d2018-08-18 03:30:281854 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341855 }
Alexei Filippov5f6b11d2018-08-18 03:30:281856 callback(groupTop, index, group, firstGroup, height);
1857 });
1858 }
1859
1860 /**
Blink Reformat4c46d092018-04-07 15:32:371861 * @param {!CanvasRenderingContext2D} context
Tim van der Lippe8ef250c2020-02-20 16:29:251862 * @param {!Group} group
Blink Reformat4c46d092018-04-07 15:32:371863 * @return {number}
1864 */
1865 _labelWidthForGroup(context, group) {
Tim van der Lippebb769172020-02-12 15:32:441866 return UI.UIUtils.measureTextWidth(context, group.name) +
1867 this._expansionArrowIndent * (group.style.nestingLevel + 1) + 2 * this._headerLabelXPadding;
Blink Reformat4c46d092018-04-07 15:32:371868 }
1869
1870 /**
Tim van der Lippe8ef250c2020-02-20 16:29:251871 * @param {!Group} group
Blink Reformat4c46d092018-04-07 15:32:371872 * @param {number} y
1873 * @param {number} endLevel
1874 */
1875 _drawCollapsedOverviewForGroup(group, y, endLevel) {
Tim van der Lippebb769172020-02-12 15:32:441876 const range = new Common.SegmentedRange.SegmentedRange(mergeCallback);
Blink Reformat4c46d092018-04-07 15:32:371877 const timeWindowLeft = this._chartViewport.windowLeftTime();
1878 const timeWindowRight = this._chartViewport.windowRightTime();
1879 const context = /** @type {!CanvasRenderingContext2D} */ (this._canvas.getContext('2d'));
1880 const barHeight = group.style.height;
Paul Lewiscf1f8a42020-11-04 21:05:241881 if (!this._rawTimelineData) {
1882 return;
1883 }
Blink Reformat4c46d092018-04-07 15:32:371884 const entryStartTimes = this._rawTimelineData.entryStartTimes;
1885 const entryTotalTimes = this._rawTimelineData.entryTotalTimes;
1886 const timeToPixel = this._chartViewport.timeToPixel();
1887
1888 for (let level = group.startLevel; level < endLevel; ++level) {
Paul Lewiscf1f8a42020-11-04 21:05:241889 /** @type {!Array.<number>} */
1890 const levelIndexes = this._timelineLevels ? this._timelineLevels[level] : [];
Blink Reformat4c46d092018-04-07 15:32:371891 const rightIndexOnLevel =
1892 levelIndexes.lowerBound(timeWindowRight, (time, entryIndex) => time - entryStartTimes[entryIndex]) - 1;
1893 let lastDrawOffset = Infinity;
1894
1895 for (let entryIndexOnLevel = rightIndexOnLevel; entryIndexOnLevel >= 0; --entryIndexOnLevel) {
1896 const entryIndex = levelIndexes[entryIndexOnLevel];
1897 const entryStartTime = entryStartTimes[entryIndex];
1898 const barX = this._timeToPositionClipped(entryStartTime);
1899 const entryEndTime = entryStartTime + entryTotalTimes[entryIndex];
Tim van der Lippe1d6e57a2019-09-30 11:55:341900 if (isNaN(entryEndTime) || barX >= lastDrawOffset) {
Blink Reformat4c46d092018-04-07 15:32:371901 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341902 }
1903 if (entryEndTime <= timeWindowLeft) {
Blink Reformat4c46d092018-04-07 15:32:371904 break;
Tim van der Lippe1d6e57a2019-09-30 11:55:341905 }
Blink Reformat4c46d092018-04-07 15:32:371906 lastDrawOffset = barX;
Paul Lewiscf1f8a42020-11-04 21:05:241907 const color = this._entryColorsCache ? this._entryColorsCache[entryIndex] : '';
Blink Reformat4c46d092018-04-07 15:32:371908 const endBarX = this._timeToPositionClipped(entryEndTime);
1909 if (group.style.useDecoratorsForOverview && this._dataProvider.forceDecoration(entryIndex)) {
1910 const unclippedBarX = this._chartViewport.timeToPosition(entryStartTime);
1911 const barWidth = endBarX - barX;
1912 context.beginPath();
1913 context.fillStyle = color;
1914 context.fillRect(barX, y, barWidth, barHeight - 1);
1915 this._dataProvider.decorateEntry(
1916 entryIndex, context, '', barX, y, barWidth, barHeight, unclippedBarX, timeToPixel);
1917 continue;
1918 }
Tim van der Lippebb769172020-02-12 15:32:441919 range.append(new Common.SegmentedRange.Segment(barX, endBarX, color));
Blink Reformat4c46d092018-04-07 15:32:371920 }
1921 }
1922
1923 const segments = range.segments().slice().sort((a, b) => a.data.localeCompare(b.data));
1924 let lastColor;
1925 context.beginPath();
1926 for (let i = 0; i < segments.length; ++i) {
1927 const segment = segments[i];
1928 if (lastColor !== segments[i].data) {
1929 context.fill();
1930 context.beginPath();
1931 lastColor = segments[i].data;
1932 context.fillStyle = lastColor;
1933 }
Alexei Filippov23428d42018-04-28 01:09:071934 context.rect(segment.begin, y, segment.end - segment.begin, barHeight);
Blink Reformat4c46d092018-04-07 15:32:371935 }
1936 context.fill();
1937
1938 /**
Tim van der Lippebb769172020-02-12 15:32:441939 * @param {!Common.SegmentedRange.Segment} a
1940 * @param {!Common.SegmentedRange.Segment} b
1941 * @return {?Common.SegmentedRange.Segment}
Blink Reformat4c46d092018-04-07 15:32:371942 */
1943 function mergeCallback(a, b) {
1944 return a.data === b.data && a.end + 0.4 > b.end ? a : null;
1945 }
1946 }
1947
1948 /**
1949 * @param {!CanvasRenderingContext2D} context
1950 * @param {number} height
1951 * @param {number} width
1952 */
1953 _drawFlowEvents(context, width, height) {
1954 context.save();
1955 const ratio = window.devicePixelRatio;
1956 const top = this._chartViewport.scrollOffset();
1957 const arrowWidth = 6;
1958 context.scale(ratio, ratio);
1959 context.translate(0, -top);
1960
1961 context.fillStyle = '#7f5050';
1962 context.strokeStyle = '#7f5050';
1963 const td = this._timelineData();
Paul Lewiscf1f8a42020-11-04 21:05:241964 if (!td) {
1965 return;
1966 }
1967
Blink Reformat4c46d092018-04-07 15:32:371968 const endIndex = td.flowStartTimes.lowerBound(this._chartViewport.windowRightTime());
1969
1970 context.lineWidth = 0.5;
1971 for (let i = 0; i < endIndex; ++i) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341972 if (!td.flowEndTimes[i] || td.flowEndTimes[i] < this._chartViewport.windowLeftTime()) {
Blink Reformat4c46d092018-04-07 15:32:371973 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341974 }
Blink Reformat4c46d092018-04-07 15:32:371975 const startX = this._chartViewport.timeToPosition(td.flowStartTimes[i]);
1976 const endX = this._chartViewport.timeToPosition(td.flowEndTimes[i]);
1977 const startLevel = td.flowStartLevels[i];
1978 const endLevel = td.flowEndLevels[i];
1979 const startY = this._levelToOffset(startLevel) + this._levelHeight(startLevel) / 2;
1980 const endY = this._levelToOffset(endLevel) + this._levelHeight(endLevel) / 2;
1981
1982
1983 const segment = Math.min((endX - startX) / 4, 40);
1984 const distanceTime = td.flowEndTimes[i] - td.flowStartTimes[i];
1985 const distanceY = (endY - startY) / 10;
1986 const spread = 30;
1987 const lineY = distanceTime < 1 ? startY : spread + Math.max(0, startY + distanceY * (i % spread));
1988
1989 const p = [];
1990 p.push({x: startX, y: startY});
1991 p.push({x: startX + arrowWidth, y: startY});
1992 p.push({x: startX + segment + 2 * arrowWidth, y: startY});
1993 p.push({x: startX + segment, y: lineY});
1994 p.push({x: startX + segment * 2, y: lineY});
1995 p.push({x: endX - segment * 2, y: lineY});
1996 p.push({x: endX - segment, y: lineY});
1997 p.push({x: endX - segment - 2 * arrowWidth, y: endY});
1998 p.push({x: endX - arrowWidth, y: endY});
1999
2000 context.beginPath();
2001 context.moveTo(p[0].x, p[0].y);
2002 context.lineTo(p[1].x, p[1].y);
2003 context.bezierCurveTo(p[2].x, p[2].y, p[3].x, p[3].y, p[4].x, p[4].y);
2004 context.lineTo(p[5].x, p[5].y);
2005 context.bezierCurveTo(p[6].x, p[6].y, p[7].x, p[7].y, p[8].x, p[8].y);
2006 context.stroke();
2007
2008 context.beginPath();
2009 context.arc(startX, startY, 2, -Math.PI / 2, Math.PI / 2, false);
2010 context.fill();
2011
2012 context.beginPath();
2013 context.moveTo(endX, endY);
2014 context.lineTo(endX - arrowWidth, endY - 3);
2015 context.lineTo(endX - arrowWidth, endY + 3);
2016 context.fill();
2017 }
2018 context.restore();
2019 }
2020
2021 _drawMarkers() {
Paul Lewiscf1f8a42020-11-04 21:05:242022 const timelineData = this._timelineData();
2023 if (!timelineData) {
2024 return;
2025 }
2026 const markers = timelineData.markers;
Blink Reformat4c46d092018-04-07 15:32:372027 const left = this._markerIndexBeforeTime(this.minimumBoundary());
2028 const rightBoundary = this.maximumBoundary();
2029 const timeToPixel = this._chartViewport.timeToPixel();
2030
2031 const context = /** @type {!CanvasRenderingContext2D} */ (this._canvas.getContext('2d'));
2032 context.save();
2033 const ratio = window.devicePixelRatio;
2034 context.scale(ratio, ratio);
2035 context.translate(0, 3);
Tim van der Lippefd2b2ce2020-01-03 15:05:182036 const height = HeaderHeight - 1;
Blink Reformat4c46d092018-04-07 15:32:372037 for (let i = left; i < markers.length; i++) {
2038 const timestamp = markers[i].startTime();
Tim van der Lippe1d6e57a2019-09-30 11:55:342039 if (timestamp > rightBoundary) {
Blink Reformat4c46d092018-04-07 15:32:372040 break;
Tim van der Lippe1d6e57a2019-09-30 11:55:342041 }
Blink Reformat4c46d092018-04-07 15:32:372042 markers[i].draw(context, this._chartViewport.timeToPosition(timestamp), height, timeToPixel);
2043 }
2044 context.restore();
2045 }
2046
2047 _updateMarkerHighlight() {
2048 const element = this._markerHighlighElement;
Tim van der Lippe1d6e57a2019-09-30 11:55:342049 if (element.parentElement) {
Blink Reformat4c46d092018-04-07 15:32:372050 element.remove();
Tim van der Lippe1d6e57a2019-09-30 11:55:342051 }
Blink Reformat4c46d092018-04-07 15:32:372052 const markerIndex = this._highlightedMarkerIndex;
Tim van der Lippe1d6e57a2019-09-30 11:55:342053 if (markerIndex === -1) {
Blink Reformat4c46d092018-04-07 15:32:372054 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:342055 }
Paul Lewiscf1f8a42020-11-04 21:05:242056 const timelineData = this._timelineData();
2057 if (!timelineData) {
2058 return;
2059 }
2060 const marker = timelineData.markers[markerIndex];
Blink Reformat4c46d092018-04-07 15:32:372061 const barX = this._timeToPositionClipped(marker.startTime());
Tim van der Lippe70842f32020-11-23 16:56:572062 UI.Tooltip.Tooltip.install(element, marker.title() || '');
Blink Reformat4c46d092018-04-07 15:32:372063 const style = element.style;
2064 style.left = barX + 'px';
2065 style.backgroundColor = marker.color();
2066 this._viewportElement.appendChild(element);
2067 }
2068
2069 /**
Tim van der Lippefd2b2ce2020-01-03 15:05:182070 * @param {?TimelineData} timelineData
Blink Reformat4c46d092018-04-07 15:32:372071 */
2072 _processTimelineData(timelineData) {
2073 if (!timelineData) {
2074 this._timelineLevels = null;
2075 this._visibleLevelOffsets = null;
2076 this._visibleLevels = null;
2077 this._groupOffsets = null;
2078 this._rawTimelineData = null;
Alexei Filippov57ccafb2018-08-14 20:59:052079 this._forceDecorationCache = null;
Alexei Filippove5197622018-08-18 03:04:332080 this._entryColorsCache = null;
Blink Reformat4c46d092018-04-07 15:32:372081 this._rawTimelineDataLength = 0;
2082 this._selectedGroup = -1;
Anubha Mathur72dd5822019-06-13 23:05:192083 this._keyboardFocusedGroup = -1;
Blink Reformat4c46d092018-04-07 15:32:372084 this._flameChartDelegate.updateSelectedGroup(this, null);
2085 return;
2086 }
2087
2088 this._rawTimelineData = timelineData;
2089 this._rawTimelineDataLength = timelineData.entryStartTimes.length;
Alexei Filippov57ccafb2018-08-14 20:59:052090 this._forceDecorationCache = new Int8Array(this._rawTimelineDataLength);
Alexei Filippove5197622018-08-18 03:04:332091 this._entryColorsCache = new Array(this._rawTimelineDataLength);
2092 for (let i = 0; i < this._rawTimelineDataLength; ++i) {
Alexei Filippov57ccafb2018-08-14 20:59:052093 this._forceDecorationCache[i] = this._dataProvider.forceDecoration(i) ? 1 : 0;
Alexei Filippove5197622018-08-18 03:04:332094 this._entryColorsCache[i] = this._dataProvider.entryColor(i);
2095 }
Blink Reformat4c46d092018-04-07 15:32:372096
2097 const entryCounters = new Uint32Array(this._dataProvider.maxStackDepth() + 1);
Tim van der Lippe1d6e57a2019-09-30 11:55:342098 for (let i = 0; i < timelineData.entryLevels.length; ++i) {
Blink Reformat4c46d092018-04-07 15:32:372099 ++entryCounters[timelineData.entryLevels[i]];
Tim van der Lippe1d6e57a2019-09-30 11:55:342100 }
Blink Reformat4c46d092018-04-07 15:32:372101 const levelIndexes = new Array(entryCounters.length);
2102 for (let i = 0; i < levelIndexes.length; ++i) {
2103 levelIndexes[i] = new Uint32Array(entryCounters[i]);
2104 entryCounters[i] = 0;
2105 }
Anubha Mathur72dd5822019-06-13 23:05:192106
Blink Reformat4c46d092018-04-07 15:32:372107 for (let i = 0; i < timelineData.entryLevels.length; ++i) {
2108 const level = timelineData.entryLevels[i];
2109 levelIndexes[level][entryCounters[level]++] = i;
2110 }
2111 this._timelineLevels = levelIndexes;
2112 const groups = this._rawTimelineData.groups || [];
2113 for (let i = 0; i < groups.length; ++i) {
2114 const expanded = this._groupExpansionState[groups[i].name];
Tim van der Lippe1d6e57a2019-09-30 11:55:342115 if (expanded !== undefined) {
Blink Reformat4c46d092018-04-07 15:32:372116 groups[i].expanded = expanded;
Tim van der Lippe1d6e57a2019-09-30 11:55:342117 }
Blink Reformat4c46d092018-04-07 15:32:372118 }
2119 this._updateLevelPositions();
2120 this._updateHeight();
2121
2122 this._selectedGroup = timelineData.selectedGroup ? groups.indexOf(timelineData.selectedGroup) : -1;
Anubha Mathur72dd5822019-06-13 23:05:192123 this._keyboardFocusedGroup = this._selectedGroup;
Blink Reformat4c46d092018-04-07 15:32:372124 this._flameChartDelegate.updateSelectedGroup(this, timelineData.selectedGroup);
2125 }
2126
2127 _updateLevelPositions() {
2128 const levelCount = this._dataProvider.maxStackDepth();
Paul Lewiscf1f8a42020-11-04 21:05:242129 const groups = this._rawTimelineData ? (this._rawTimelineData.groups || []) : [];
Blink Reformat4c46d092018-04-07 15:32:372130 this._visibleLevelOffsets = new Uint32Array(levelCount + 1);
2131 this._visibleLevelHeights = new Uint32Array(levelCount);
2132 this._visibleLevels = new Uint16Array(levelCount);
2133 this._groupOffsets = new Uint32Array(groups.length + 1);
2134
2135 let groupIndex = -1;
Tim van der Lippefd2b2ce2020-01-03 15:05:182136 let currentOffset = this._rulerEnabled ? HeaderHeight + 2 : 2;
Blink Reformat4c46d092018-04-07 15:32:372137 let visible = true;
Paul Lewiscf1f8a42020-11-04 21:05:242138 /** @type {!Array<{nestingLevel: number, visible: boolean}>} */
Blink Reformat4c46d092018-04-07 15:32:372139 const groupStack = [{nestingLevel: -1, visible: true}];
Paul Lewiscf1f8a42020-11-04 21:05:242140 const lastGroupLevel =
2141 Math.max(levelCount, groups.length ? /** @type {!Group} */ (groups.peekLast()).startLevel + 1 : 0);
Blink Reformat4c46d092018-04-07 15:32:372142 let level;
2143 for (level = 0; level < lastGroupLevel; ++level) {
2144 let parentGroupIsVisible = true;
2145 let style;
2146 while (groupIndex < groups.length - 1 && level === groups[groupIndex + 1].startLevel) {
2147 ++groupIndex;
2148 style = groups[groupIndex].style;
2149 let nextLevel = true;
Paul Lewiscf1f8a42020-11-04 21:05:242150 let last = groupStack.peekLast();
2151 while (last && last.nestingLevel >= style.nestingLevel) {
Blink Reformat4c46d092018-04-07 15:32:372152 groupStack.pop();
2153 nextLevel = false;
Paul Lewiscf1f8a42020-11-04 21:05:242154 last = groupStack.peekLast();
Blink Reformat4c46d092018-04-07 15:32:372155 }
2156 const thisGroupIsVisible =
2157 groupIndex >= 0 && this._isGroupCollapsible(groupIndex) ? groups[groupIndex].expanded : true;
Paul Lewiscf1f8a42020-11-04 21:05:242158
2159 last = groupStack.peekLast();
2160 parentGroupIsVisible = last ? last.visible : false;
Tim van der Lipped7cfd142021-01-07 12:17:242161 visible = Boolean(thisGroupIsVisible) && parentGroupIsVisible;
Blink Reformat4c46d092018-04-07 15:32:372162 groupStack.push({nestingLevel: style.nestingLevel, visible: visible});
Tim van der Lippe1d6e57a2019-09-30 11:55:342163 if (parentGroupIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:372164 currentOffset += nextLevel ? 0 : style.padding;
Tim van der Lippe1d6e57a2019-09-30 11:55:342165 }
Blink Reformat4c46d092018-04-07 15:32:372166 this._groupOffsets[groupIndex] = currentOffset;
Tim van der Lippe1d6e57a2019-09-30 11:55:342167 if (parentGroupIsVisible && !style.shareHeaderLine) {
Blink Reformat4c46d092018-04-07 15:32:372168 currentOffset += style.height;
Tim van der Lippe1d6e57a2019-09-30 11:55:342169 }
Blink Reformat4c46d092018-04-07 15:32:372170 }
Tim van der Lippe1d6e57a2019-09-30 11:55:342171 if (level >= levelCount) {
Yang Guo8fb3ac52019-07-31 20:17:502172 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:342173 }
Blink Reformat4c46d092018-04-07 15:32:372174 const isFirstOnLevel = groupIndex >= 0 && level === groups[groupIndex].startLevel;
2175 const thisLevelIsVisible =
2176 parentGroupIsVisible && (visible || isFirstOnLevel && groups[groupIndex].style.useFirstLineForOverview);
Yang Guo8fb3ac52019-07-31 20:17:502177 let height;
2178 if (groupIndex >= 0) {
2179 const group = groups[groupIndex];
2180 const styleB = group.style;
2181 height = isFirstOnLevel && !styleB.shareHeaderLine || (styleB.collapsible && !group.expanded) ?
2182 styleB.height :
2183 (styleB.itemsHeight || this._barHeight);
2184 } else {
2185 height = this._barHeight;
Blink Reformat4c46d092018-04-07 15:32:372186 }
Paul Lewiscf1f8a42020-11-04 21:05:242187 this._visibleLevels[level] = thisLevelIsVisible ? 1 : 0;
Yang Guo8fb3ac52019-07-31 20:17:502188 this._visibleLevelOffsets[level] = currentOffset;
2189 this._visibleLevelHeights[level] = height;
Tim van der Lippe1d6e57a2019-09-30 11:55:342190 if (thisLevelIsVisible || (parentGroupIsVisible && style && style.shareHeaderLine && isFirstOnLevel)) {
Blink Reformat4c46d092018-04-07 15:32:372191 currentOffset += this._visibleLevelHeights[level];
Tim van der Lippe1d6e57a2019-09-30 11:55:342192 }
Blink Reformat4c46d092018-04-07 15:32:372193 }
Tim van der Lippe1d6e57a2019-09-30 11:55:342194 if (groupIndex >= 0) {
Blink Reformat4c46d092018-04-07 15:32:372195 this._groupOffsets[groupIndex + 1] = currentOffset;
Tim van der Lippe1d6e57a2019-09-30 11:55:342196 }
Blink Reformat4c46d092018-04-07 15:32:372197 this._visibleLevelOffsets[level] = currentOffset;
Tim van der Lippe1d6e57a2019-09-30 11:55:342198 if (this._useWebGL) {
Alexei Filippov57ccafb2018-08-14 20:59:052199 this._setupGLGeometry();
Tim van der Lippe1d6e57a2019-09-30 11:55:342200 }
Blink Reformat4c46d092018-04-07 15:32:372201 }
2202
2203 /**
2204 * @param {number} index
2205 */
2206 _isGroupCollapsible(index) {
Paul Lewiscf1f8a42020-11-04 21:05:242207 if (!this._rawTimelineData) {
2208 return;
2209 }
2210
Blink Reformat4c46d092018-04-07 15:32:372211 const groups = this._rawTimelineData.groups || [];
2212 const style = groups[index].style;
Tim van der Lippe1d6e57a2019-09-30 11:55:342213 if (!style.shareHeaderLine || !style.collapsible) {
Tim van der Lipped7cfd142021-01-07 12:17:242214 return Boolean(style.collapsible);
Tim van der Lippe1d6e57a2019-09-30 11:55:342215 }
Blink Reformat4c46d092018-04-07 15:32:372216 const isLastGroup = index + 1 >= groups.length;
Tim van der Lippe1d6e57a2019-09-30 11:55:342217 if (!isLastGroup && groups[index + 1].style.nestingLevel > style.nestingLevel) {
Blink Reformat4c46d092018-04-07 15:32:372218 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:342219 }
Blink Reformat4c46d092018-04-07 15:32:372220 const nextGroupLevel = isLastGroup ? this._dataProvider.maxStackDepth() : groups[index + 1].startLevel;
Tim van der Lippe1d6e57a2019-09-30 11:55:342221 if (nextGroupLevel !== groups[index].startLevel + 1) {
Blink Reformat4c46d092018-04-07 15:32:372222 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:342223 }
Blink Reformat4c46d092018-04-07 15:32:372224 // For groups that only have one line and share header line, pretend these are not collapsible
2225 // unless the itemsHeight does not match the headerHeight
2226 return style.height !== style.itemsHeight;
2227 }
2228
2229 /**
2230 * @param {number} entryIndex
2231 */
2232 setSelectedEntry(entryIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:342233 if (this._selectedEntryIndex === entryIndex) {
Blink Reformat4c46d092018-04-07 15:32:372234 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:342235 }
2236 if (entryIndex !== -1) {
Blink Reformat4c46d092018-04-07 15:32:372237 this._chartViewport.hideRangeSelection();
Tim van der Lippe1d6e57a2019-09-30 11:55:342238 }
Blink Reformat4c46d092018-04-07 15:32:372239 this._selectedEntryIndex = entryIndex;
2240 this._revealEntry(entryIndex);
2241 this._updateElementPosition(this._selectedElement, this._selectedEntryIndex);
2242 }
2243
2244 /**
2245 * @param {!Element} element
2246 * @param {number} entryIndex
2247 */
2248 _updateElementPosition(element, entryIndex) {
Alexei Filippov72d792d2018-11-06 07:15:042249 const elementMinWidthPx = 2;
2250 element.classList.add('hidden');
Tim van der Lippe1d6e57a2019-09-30 11:55:342251 if (entryIndex === -1) {
Blink Reformat4c46d092018-04-07 15:32:372252 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:342253 }
Blink Reformat4c46d092018-04-07 15:32:372254 const timelineData = this._timelineData();
Paul Lewiscf1f8a42020-11-04 21:05:242255 if (!timelineData) {
2256 return;
2257 }
2258
Blink Reformat4c46d092018-04-07 15:32:372259 const startTime = timelineData.entryStartTimes[entryIndex];
Alexei Filippov72d792d2018-11-06 07:15:042260 const duration = timelineData.entryTotalTimes[entryIndex];
Alexei Filippov65106502018-11-29 05:16:192261 let barX = 0;
2262 let barWidth = 0;
2263 let visible = true;
Alexei Filippov6c622e92018-11-10 02:13:592264 if (Number.isNaN(duration)) {
2265 const position = this._markerPositions.get(entryIndex);
Alexei Filippov65106502018-11-29 05:16:192266 if (position) {
2267 barX = position.x;
2268 barWidth = position.width;
2269 } else {
2270 visible = false;
2271 }
Alexei Filippov6c622e92018-11-10 02:13:592272 } else {
2273 barX = this._chartViewport.timeToPosition(startTime);
2274 barWidth = duration * this._chartViewport.timeToPixel();
2275 }
Tim van der Lippe1d6e57a2019-09-30 11:55:342276 if (barX + barWidth <= 0 || barX >= this._offsetWidth) {
Blink Reformat4c46d092018-04-07 15:32:372277 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:342278 }
Blink Reformat4c46d092018-04-07 15:32:372279 const barCenter = barX + barWidth / 2;
2280 barWidth = Math.max(barWidth, elementMinWidthPx);
2281 barX = barCenter - barWidth / 2;
2282 const entryLevel = timelineData.entryLevels[entryIndex];
2283 const barY = this._levelToOffset(entryLevel) - this._chartViewport.scrollOffset();
2284 const barHeight = this._levelHeight(entryLevel);
Paul Lewiscf1f8a42020-11-04 21:05:242285 const style = /** @type {!HTMLElement} */ (element).style;
Blink Reformat4c46d092018-04-07 15:32:372286 style.left = barX + 'px';
2287 style.top = barY + 'px';
2288 style.width = barWidth + 'px';
2289 style.height = barHeight - 1 + 'px';
Alexei Filippov65106502018-11-29 05:16:192290 element.classList.toggle('hidden', !visible);
Blink Reformat4c46d092018-04-07 15:32:372291 this._viewportElement.appendChild(element);
2292 }
2293
2294 /**
2295 * @param {number} time
2296 * @return {number}
2297 */
2298 _timeToPositionClipped(time) {
Jack Franklin1be909c2020-03-04 08:57:412299 return Platform.NumberUtilities.clamp(this._chartViewport.timeToPosition(time), 0, this._offsetWidth);
Blink Reformat4c46d092018-04-07 15:32:372300 }
2301
2302 /**
2303 * @param {number} level
2304 * @return {number}
2305 */
2306 _levelToOffset(level) {
Paul Lewiscf1f8a42020-11-04 21:05:242307 if (!this._visibleLevelOffsets) {
2308 throw new Error('No visible level offsets');
2309 }
Blink Reformat4c46d092018-04-07 15:32:372310 return this._visibleLevelOffsets[level];
2311 }
2312
2313 /**
2314 * @param {number} level
2315 * @return {number}
2316 */
2317 _levelHeight(level) {
Paul Lewiscf1f8a42020-11-04 21:05:242318 if (!this._visibleLevelHeights) {
2319 throw new Error('No visible level heights');
2320 }
Blink Reformat4c46d092018-04-07 15:32:372321 return this._visibleLevelHeights[level];
2322 }
2323
2324 _updateBoundaries() {
2325 this._totalTime = this._dataProvider.totalTime();
2326 this._minimumBoundary = this._dataProvider.minimumBoundary();
2327 this._chartViewport.setBoundaries(this._minimumBoundary, this._totalTime);
2328 }
2329
2330 _updateHeight() {
Alexei Filippov23428d42018-04-28 01:09:072331 const height = this._levelToOffset(this._dataProvider.maxStackDepth()) + 2;
Blink Reformat4c46d092018-04-07 15:32:372332 this._chartViewport.setContentHeight(height);
2333 }
2334
2335 /**
2336 * @override
2337 */
2338 onResize() {
2339 this.scheduleUpdate();
2340 }
2341
2342 /**
2343 * @override
2344 */
2345 update() {
Tim van der Lippe1d6e57a2019-09-30 11:55:342346 if (!this._timelineData()) {
Blink Reformat4c46d092018-04-07 15:32:372347 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:342348 }
Blink Reformat4c46d092018-04-07 15:32:372349 this._resetCanvas();
2350 this._updateHeight();
2351 this._updateBoundaries();
2352 this._draw();
Tim van der Lippe1d6e57a2019-09-30 11:55:342353 if (!this._chartViewport.isDragging()) {
Blink Reformat4c46d092018-04-07 15:32:372354 this._updateHighlight();
Tim van der Lippe1d6e57a2019-09-30 11:55:342355 }
Blink Reformat4c46d092018-04-07 15:32:372356 }
2357
2358 reset() {
2359 this._chartViewport.reset();
2360 this._rawTimelineData = null;
2361 this._rawTimelineDataLength = 0;
2362 this._highlightedMarkerIndex = -1;
2363 this._highlightedEntryIndex = -1;
2364 this._selectedEntryIndex = -1;
2365 /** @type {!Map<string,!Map<string,number>>} */
2366 this._textWidth = new Map();
2367 this._chartViewport.scheduleUpdate();
2368 }
2369
2370 scheduleUpdate() {
2371 this._chartViewport.scheduleUpdate();
2372 }
2373
2374 _enabled() {
2375 return this._rawTimelineDataLength !== 0;
2376 }
2377
2378 /**
2379 * @override
2380 * @param {number} time
2381 * @return {number}
2382 */
2383 computePosition(time) {
2384 return this._chartViewport.timeToPosition(time);
2385 }
2386
2387 /**
2388 * @override
2389 * @param {number} value
2390 * @param {number=} precision
2391 * @return {string}
2392 */
2393 formatValue(value, precision) {
2394 return this._dataProvider.formatValue(value - this.zeroTime(), precision);
2395 }
2396
2397 /**
2398 * @override
2399 * @return {number}
2400 */
2401 maximumBoundary() {
2402 return this._chartViewport.windowRightTime();
2403 }
2404
2405 /**
2406 * @override
2407 * @return {number}
2408 */
2409 minimumBoundary() {
2410 return this._chartViewport.windowLeftTime();
2411 }
2412
2413 /**
2414 * @override
2415 * @return {number}
2416 */
2417 zeroTime() {
2418 return this._dataProvider.minimumBoundary();
2419 }
2420
2421 /**
2422 * @override
2423 * @return {number}
2424 */
2425 boundarySpan() {
Alexei Filippov2578eb02018-04-11 08:15:052426 return this.maximumBoundary() - this.minimumBoundary();
Blink Reformat4c46d092018-04-07 15:32:372427 }
Tim van der Lippefd2b2ce2020-01-03 15:05:182428}
Blink Reformat4c46d092018-04-07 15:32:372429
Tim van der Lippefd2b2ce2020-01-03 15:05:182430export const HeaderHeight = 15;
2431export const MinimalTimeWindowMs = 0.5;
Blink Reformat4c46d092018-04-07 15:32:372432
Tim van der Lippefd2b2ce2020-01-03 15:05:182433export class TimelineData {
Blink Reformat4c46d092018-04-07 15:32:372434 /**
2435 * @param {!Array<number>|!Uint16Array} entryLevels
2436 * @param {!Array<number>|!Float32Array} entryTotalTimes
2437 * @param {!Array<number>|!Float64Array} entryStartTimes
Tim van der Lippe8ef250c2020-02-20 16:29:252438 * @param {?Array<!Group>} groups
Blink Reformat4c46d092018-04-07 15:32:372439 */
2440 constructor(entryLevels, entryTotalTimes, entryStartTimes, groups) {
2441 this.entryLevels = entryLevels;
2442 this.entryTotalTimes = entryTotalTimes;
2443 this.entryStartTimes = entryStartTimes;
Tim van der Lippedfbb48f2020-11-19 14:49:152444 this.groups = groups || [];
Tim van der Lippefd2b2ce2020-01-03 15:05:182445 /** @type {!Array.<!FlameChartMarker>} */
Blink Reformat4c46d092018-04-07 15:32:372446 this.markers = [];
Paul Lewiscf1f8a42020-11-04 21:05:242447 /** @type {!Array.<number>} */
Blink Reformat4c46d092018-04-07 15:32:372448 this.flowStartTimes = [];
Paul Lewiscf1f8a42020-11-04 21:05:242449 /** @type {!Array.<number>} */
Blink Reformat4c46d092018-04-07 15:32:372450 this.flowStartLevels = [];
Paul Lewiscf1f8a42020-11-04 21:05:242451 /** @type {!Array.<number>} */
Blink Reformat4c46d092018-04-07 15:32:372452 this.flowEndTimes = [];
Paul Lewiscf1f8a42020-11-04 21:05:242453 /** @type {!Array.<number>} */
Blink Reformat4c46d092018-04-07 15:32:372454 this.flowEndLevels = [];
Tim van der Lippe8ef250c2020-02-20 16:29:252455 /** @type {?Group} */
Blink Reformat4c46d092018-04-07 15:32:372456 this.selectedGroup = null;
2457 }
Tim van der Lippefd2b2ce2020-01-03 15:05:182458}
Blink Reformat4c46d092018-04-07 15:32:372459
Tim van der Lippefd2b2ce2020-01-03 15:05:182460/**
2461 * @interface
2462 */
2463export class FlameChartDataProvider {
Blink Reformat4c46d092018-04-07 15:32:372464 /**
2465 * @return {number}
2466 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182467 minimumBoundary() {
Paul Lewiscf1f8a42020-11-04 21:05:242468 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182469 }
Blink Reformat4c46d092018-04-07 15:32:372470
2471 /**
2472 * @return {number}
2473 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182474 totalTime() {
Paul Lewiscf1f8a42020-11-04 21:05:242475 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182476 }
Blink Reformat4c46d092018-04-07 15:32:372477
2478 /**
2479 * @param {number} value
2480 * @param {number=} precision
2481 * @return {string}
2482 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182483 formatValue(value, precision) {
Paul Lewiscf1f8a42020-11-04 21:05:242484 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182485 }
Blink Reformat4c46d092018-04-07 15:32:372486
2487 /**
2488 * @return {number}
2489 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182490 maxStackDepth() {
Paul Lewiscf1f8a42020-11-04 21:05:242491 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182492 }
Blink Reformat4c46d092018-04-07 15:32:372493
2494 /**
Tim van der Lippefd2b2ce2020-01-03 15:05:182495 * @return {?TimelineData}
Blink Reformat4c46d092018-04-07 15:32:372496 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182497 timelineData() {
Paul Lewiscf1f8a42020-11-04 21:05:242498 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182499 }
Blink Reformat4c46d092018-04-07 15:32:372500
2501 /**
2502 * @param {number} entryIndex
2503 * @return {?Element}
2504 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182505 prepareHighlightedEntryInfo(entryIndex) {
Paul Lewiscf1f8a42020-11-04 21:05:242506 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182507 }
Blink Reformat4c46d092018-04-07 15:32:372508
2509 /**
2510 * @param {number} entryIndex
2511 * @return {boolean}
2512 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182513 canJumpToEntry(entryIndex) {
Paul Lewiscf1f8a42020-11-04 21:05:242514 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182515 }
Blink Reformat4c46d092018-04-07 15:32:372516
2517 /**
2518 * @param {number} entryIndex
2519 * @return {?string}
2520 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182521 entryTitle(entryIndex) {
Paul Lewiscf1f8a42020-11-04 21:05:242522 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182523 }
Blink Reformat4c46d092018-04-07 15:32:372524
2525 /**
2526 * @param {number} entryIndex
2527 * @return {?string}
2528 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182529 entryFont(entryIndex) {
Paul Lewiscf1f8a42020-11-04 21:05:242530 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182531 }
Blink Reformat4c46d092018-04-07 15:32:372532
2533 /**
2534 * @param {number} entryIndex
2535 * @return {string}
2536 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182537 entryColor(entryIndex) {
Paul Lewiscf1f8a42020-11-04 21:05:242538 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182539 }
Blink Reformat4c46d092018-04-07 15:32:372540
2541 /**
2542 * @param {number} entryIndex
2543 * @param {!CanvasRenderingContext2D} context
2544 * @param {?string} text
2545 * @param {number} barX
2546 * @param {number} barY
2547 * @param {number} barWidth
2548 * @param {number} barHeight
2549 * @param {number} unclippedBarX
2550 * @param {number} timeToPixelRatio
2551 * @return {boolean}
2552 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182553 decorateEntry(entryIndex, context, text, barX, barY, barWidth, barHeight, unclippedBarX, timeToPixelRatio) {
Paul Lewiscf1f8a42020-11-04 21:05:242554 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182555 }
Blink Reformat4c46d092018-04-07 15:32:372556
2557 /**
2558 * @param {number} entryIndex
2559 * @return {boolean}
2560 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182561 forceDecoration(entryIndex) {
Paul Lewiscf1f8a42020-11-04 21:05:242562 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182563 }
Blink Reformat4c46d092018-04-07 15:32:372564
2565 /**
2566 * @param {number} entryIndex
2567 * @return {string}
2568 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182569 textColor(entryIndex) {
Paul Lewiscf1f8a42020-11-04 21:05:242570 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182571 }
Paul Lewisead45752020-06-23 09:51:362572
2573 /**
2574 * @return {!Map<string, !SDK.TracingModel.Event>}
2575 */
2576 navStartTimes() {
Paul Lewiscf1f8a42020-11-04 21:05:242577 throw new Error('Not implemented');
Paul Lewisead45752020-06-23 09:51:362578 }
Tim van der Lippefd2b2ce2020-01-03 15:05:182579}
Blink Reformat4c46d092018-04-07 15:32:372580
2581/**
2582 * @interface
2583 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182584export class FlameChartMarker {
Blink Reformat4c46d092018-04-07 15:32:372585 /**
2586 * @return {number}
2587 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182588 startTime() {
Paul Lewiscf1f8a42020-11-04 21:05:242589 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182590 }
Blink Reformat4c46d092018-04-07 15:32:372591
2592 /**
2593 * @return {string}
2594 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182595 color() {
Paul Lewiscf1f8a42020-11-04 21:05:242596 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182597 }
Blink Reformat4c46d092018-04-07 15:32:372598
2599 /**
Alexei Filippov72d792d2018-11-06 07:15:042600 * @return {?string}
Blink Reformat4c46d092018-04-07 15:32:372601 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182602 title() {
Paul Lewiscf1f8a42020-11-04 21:05:242603 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182604 }
Blink Reformat4c46d092018-04-07 15:32:372605
2606 /**
2607 * @param {!CanvasRenderingContext2D} context
2608 * @param {number} x
2609 * @param {number} height
2610 * @param {number} pixelsPerMillisecond
2611 */
Tim van der Lippefd2b2ce2020-01-03 15:05:182612 draw(context, x, height, pixelsPerMillisecond) {
Paul Lewiscf1f8a42020-11-04 21:05:242613 throw new Error('Not implemented');
Tim van der Lippefd2b2ce2020-01-03 15:05:182614 }
2615}
Blink Reformat4c46d092018-04-07 15:32:372616
2617/** @enum {symbol} */
Tim van der Lippefd2b2ce2020-01-03 15:05:182618export const Events = {
Michael Liao712bbc22019-10-15 19:21:512619 CanvasFocused: Symbol('CanvasFocused'),
2620 EntryInvoked: Symbol('EntryInvoked'),
Blink Reformat4c46d092018-04-07 15:32:372621 EntrySelected: Symbol('EntrySelected'),
2622 EntryHighlighted: Symbol('EntryHighlighted')
2623};
2624
Tim van der Lippefd2b2ce2020-01-03 15:05:182625export const Colors = {
Blink Reformat4c46d092018-04-07 15:32:372626 SelectedGroupBackground: 'hsl(215, 85%, 98%)',
2627 SelectedGroupBorder: 'hsl(216, 68%, 54%)',
2628};
Tim van der Lippecec9b762020-02-13 15:31:222629
2630/**
2631 * @typedef {!{
Tim van der Lippe3b1f7452021-01-08 11:25:132632 * name: !Platform.UIString.LocalizedString,
Tim van der Lippecec9b762020-02-13 15:31:222633 * startLevel: number,
2634 * expanded: (boolean|undefined),
2635 * selectable: (boolean|undefined),
Tim van der Lippedfbb48f2020-11-19 14:49:152636 * style: !GroupStyle,
2637 * track: (?TimelineModel.TimelineModel.Track|undefined),
Tim van der Lippecec9b762020-02-13 15:31:222638 * }}
2639 */
Paul Lewiscf1f8a42020-11-04 21:05:242640// @ts-ignore Typedef
Tim van der Lippecec9b762020-02-13 15:31:222641export let Group;
2642
2643/**
2644 * @typedef {!{
2645 * height: number,
2646 * padding: number,
2647 * collapsible: boolean,
2648 * font: string,
2649 * color: string,
2650 * backgroundColor: string,
2651 * nestingLevel: number,
2652 * itemsHeight: (number|undefined),
2653 * shareHeaderLine: (boolean|undefined),
2654 * useFirstLineForOverview: (boolean|undefined),
2655 * useDecoratorsForOverview: (boolean|undefined)
2656 * }}
2657 */
Paul Lewiscf1f8a42020-11-04 21:05:242658// @ts-ignore Typedef
Tim van der Lippecec9b762020-02-13 15:31:222659export let GroupStyle;