blob: f533bfe8a2d124e54e59cfca299aebfc38aecf83 [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
Jan Scheffler87dd9142021-02-27 21:19:4831/* eslint-disable rulesdir/no_underscored_properties */
32
Tim van der Lippe76961572021-04-06 10:48:0733import * as Common from '../core/common/common.js';
Tim van der Lippee0247312021-04-01 14:25:3034import * as Host from '../core/host/host.js';
Tim van der Lippebb352e62021-04-01 17:57:2835import * as i18n from '../core/i18n/i18n.js';
Tim van der Lippeaa1ed7a2021-03-31 14:38:2736import * as Platform from '../core/platform/platform.js';
Tim van der Lipped8caac42021-03-31 14:40:4437import * as Root from '../core/root/root.js';
Tim van der Lippee00b92f2021-03-31 16:52:1738import * as SDK from '../core/sdk/sdk.js'; // eslint-disable-line no-unused-vars
Paul Lewisca569a52020-09-09 16:11:5139import * as ThemeSupport from '../theme_support/theme_support.js';
Tim van der Lippedfbb48f2020-11-19 14:49:1540import * as TimelineModel from '../timeline_model/timeline_model.js'; // eslint-disable-line no-unused-vars
Tim van der Lippeaa61faf2021-04-07 15:32:0741import * as UI from '../ui/legacy/legacy.js';
Tim van der Lippebb769172020-02-12 15:32:4442
Paul Lewis2cfa94e2020-01-13 10:30:1543import {ChartViewport, ChartViewportDelegate} from './ChartViewport.js'; // eslint-disable-line no-unused-vars
44import {Calculator, TimelineGrid} from './TimelineGrid.js'; // eslint-disable-line no-unused-vars
45
Simon Zünd34490692021-03-01 08:25:1846const UIStrings = {
Christy Chenf9033fa2021-01-21 10:07:0447 /**
48 *@description Aria accessible name in Flame Chart of the Performance panel
49 */
50 flameChart: 'Flame Chart',
51 /**
52 *@description Text for the screen reader to announce a hovered group
53 *@example {Network} PH1
54 */
55 sHovered: '{PH1} hovered',
56 /**
57 *@description Text for screen reader to announce a selected group.
58 *@example {Network} PH1
59 */
60 sSelected: '{PH1} selected',
61 /**
62 *@description Text for screen reader to announce an expanded group
63 *@example {Network} PH1
64 */
65 sExpanded: '{PH1} expanded',
66 /**
67 *@description Text for screen reader to announce a collapsed group
68 *@example {Network} PH1
69 */
70 sCollapsed: '{PH1} collapsed',
71};
Jan Scheffler87dd9142021-02-27 21:19:4872const str_ = i18n.i18n.registerUIStrings('perf_ui/FlameChart.ts', UIStrings);
Christy Chenf9033fa2021-01-21 10:07:0473const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
Jan Scheffler87dd9142021-02-27 21:19:4874
Tim van der Lippefd2b2ce2020-01-03 15:05:1875export class FlameChartDelegate {
Jan Scheffler87dd9142021-02-27 21:19:4876 windowChanged(_startTime: number, _endTime: number, _animate: boolean): void {
Tim van der Lippefd2b2ce2020-01-03 15:05:1877 }
Jan Scheffler87dd9142021-02-27 21:19:4878 updateRangeSelection(_startTime: number, _endTime: number): void {
Tim van der Lippefd2b2ce2020-01-03 15:05:1879 }
Jan Scheffler87dd9142021-02-27 21:19:4880 updateSelectedGroup(_flameChart: FlameChart, _group: Group|null): void {
Tim van der Lippefd2b2ce2020-01-03 15:05:1881 }
82}
Blink Reformat4c46d092018-04-07 15:32:3783
Jan Scheffler87dd9142021-02-27 21:19:4884interface GroupExpansionState {
85 [key: string]: boolean;
86}
87
88export class FlameChart extends UI.Widget.VBox implements Calculator, ChartViewportDelegate {
89 _groupExpansionSetting?: Common.Settings.Setting<GroupExpansionState>;
90 _groupExpansionState: GroupExpansionState;
91 _flameChartDelegate: FlameChartDelegate;
92 _useWebGL: boolean;
93 _chartViewport: ChartViewport;
94 _dataProvider: FlameChartDataProvider;
95 _candyStripeCanvas: HTMLCanvasElement;
96 _viewportElement: HTMLElement;
97 _canvasGL!: HTMLCanvasElement;
98 _canvas: HTMLCanvasElement;
99 _entryInfo: HTMLElement;
100 _markerHighlighElement: HTMLElement;
101 _highlightElement: HTMLElement;
102 _selectedElement: HTMLElement;
103 _rulerEnabled: boolean;
104 _rangeSelectionStart: number;
105 _rangeSelectionEnd: number;
106 _barHeight: number;
107 _textBaseline: number;
108 _textPadding: number;
109 _markerRadius: number;
110 _headerLeftPadding: number;
111 _arrowSide: number;
112 _expansionArrowIndent: number;
113 _headerLabelXPadding: number;
114 _headerLabelYPadding: number;
115 _highlightedMarkerIndex: number;
116 _highlightedEntryIndex: number;
117 _selectedEntryIndex: number;
118 _rawTimelineDataLength: number;
119 _textWidth: Map<string, Map<string, number>>;
120 _markerPositions: Map<number, {
121 x: number,
122 width: number,
123 }>;
124 _lastMouseOffsetX: number;
125 _selectedGroup: number;
126 _keyboardFocusedGroup: number;
127 _selectedGroupBackroundColor: string;
128 _selectedGroupBorderColor: string;
129 _offsetWidth!: number;
130 _offsetHeight!: number;
131 _dragStartX!: number;
132 _dragStartY!: number;
133 _lastMouseOffsetY!: number;
134 _minimumBoundary!: number;
135 _maxDragOffset!: number;
136 _shaderProgram?: WebGLProgram|null;
137 _vertexBuffer?: WebGLBuffer|null;
138 _colorBuffer?: WebGLBuffer|null;
139 _uScalingFactor?: WebGLUniformLocation|null;
140 _uShiftVector?: WebGLUniformLocation|null;
141 _aVertexPosition?: number;
142 _aVertexColor?: number;
143 _vertexCount?: number;
144 _prevTimelineData?: TimelineData;
145 _timelineLevels?: number[][]|null;
146 _visibleLevelOffsets?: Uint32Array|null;
147 _visibleLevels?: Uint16Array|null;
148 _groupOffsets?: Uint32Array|null;
149 _rawTimelineData?: TimelineData|null;
150 _forceDecorationCache?: Int8Array|null;
151 _entryColorsCache?: string[]|null;
152 _visibleLevelHeights?: Uint32Array;
153 _totalTime?: number;
154
155 constructor(
156 dataProvider: FlameChartDataProvider, flameChartDelegate: FlameChartDelegate,
157 groupExpansionSetting?: Common.Settings.Setting<GroupExpansionState>) {
Blink Reformat4c46d092018-04-07 15:32:37158 super(true);
Tim van der Lippe006cbec92021-02-26 14:43:11159 this.registerRequiredCSS('perf_ui/flameChart.css', {enableLegacyPatching: false});
Blink Reformat4c46d092018-04-07 15:32:37160 this.contentElement.classList.add('flame-chart-main-pane');
161 this._groupExpansionSetting = groupExpansionSetting;
162 this._groupExpansionState = groupExpansionSetting && groupExpansionSetting.get() || {};
163 this._flameChartDelegate = flameChartDelegate;
164
Tim van der Lippe99e59b82019-09-30 20:00:59165 this._useWebGL = Root.Runtime.experiments.isEnabled('timelineWebGL');
Paul Lewis2cfa94e2020-01-13 10:30:15166 this._chartViewport = new ChartViewport(this);
Blink Reformat4c46d092018-04-07 15:32:37167 this._chartViewport.show(this.contentElement);
168
169 this._dataProvider = dataProvider;
Jan Scheffler87dd9142021-02-27 21:19:48170 this._candyStripeCanvas = (document.createElement('canvas') as HTMLCanvasElement);
Paul Lewis49b16822020-02-21 14:22:03171 this._createCandyStripePattern();
172
Blink Reformat4c46d092018-04-07 15:32:37173 this._viewportElement = this._chartViewport.viewportElement;
Alexei Filippov57ccafb2018-08-14 20:59:05174 if (this._useWebGL) {
Jan Scheffler87dd9142021-02-27 21:19:48175 this._canvasGL = (this._viewportElement.createChild('canvas', 'fill') as HTMLCanvasElement);
Alexei Filippov57ccafb2018-08-14 20:59:05176 this._initWebGL();
177 }
Jan Scheffler87dd9142021-02-27 21:19:48178 this._canvas = (this._viewportElement.createChild('canvas', 'fill') as HTMLCanvasElement);
Blink Reformat4c46d092018-04-07 15:32:37179
Joel Einbinder83fc76e2018-06-11 23:19:47180 this._canvas.tabIndex = 0;
Christy Chenf9033fa2021-01-21 10:07:04181 UI.ARIAUtils.setAccessibleName(this._canvas, i18nString(UIStrings.flameChart));
Anubha Mathur72dd5822019-06-13 23:05:19182 UI.ARIAUtils.markAsTree(this._canvas);
Blink Reformat4c46d092018-04-07 15:32:37183 this.setDefaultFocusedElement(this._canvas);
Anubha Mathur72dd5822019-06-13 23:05:19184 this._canvas.classList.add('flame-chart-canvas');
Blink Reformat4c46d092018-04-07 15:32:37185 this._canvas.addEventListener('mousemove', this._onMouseMove.bind(this), false);
186 this._canvas.addEventListener('mouseout', this._onMouseOut.bind(this), false);
187 this._canvas.addEventListener('click', this._onClick.bind(this), false);
188 this._canvas.addEventListener('keydown', this._onKeyDown.bind(this), false);
189
190 this._entryInfo = this._viewportElement.createChild('div', 'flame-chart-entry-info');
191 this._markerHighlighElement = this._viewportElement.createChild('div', 'flame-chart-marker-highlight-element');
192 this._highlightElement = this._viewportElement.createChild('div', 'flame-chart-highlight-element');
193 this._selectedElement = this._viewportElement.createChild('div', 'flame-chart-selected-element');
Michael Liao712bbc22019-10-15 19:21:51194 this._canvas.addEventListener('focus', () => {
Tim van der Lippefd2b2ce2020-01-03 15:05:18195 this.dispatchEventToListeners(Events.CanvasFocused);
Michael Liao712bbc22019-10-15 19:21:51196 }, false);
Blink Reformat4c46d092018-04-07 15:32:37197
Tim van der Lippebb769172020-02-12 15:32:44198 UI.UIUtils.installDragHandle(
Blink Reformat4c46d092018-04-07 15:32:37199 this._viewportElement, this._startDragging.bind(this), this._dragging.bind(this), this._endDragging.bind(this),
200 null);
201
202 this._rulerEnabled = true;
203 this._rangeSelectionStart = 0;
204 this._rangeSelectionEnd = 0;
205 this._barHeight = 17;
206 this._textBaseline = 5;
207 this._textPadding = 5;
208 this._markerRadius = 6;
209 this._chartViewport.setWindowTimes(
210 dataProvider.minimumBoundary(), dataProvider.minimumBoundary() + dataProvider.totalTime());
211
Blink Reformat4c46d092018-04-07 15:32:37212 this._headerLeftPadding = 6;
Blink Reformat4c46d092018-04-07 15:32:37213 this._arrowSide = 8;
Blink Reformat4c46d092018-04-07 15:32:37214 this._expansionArrowIndent = this._headerLeftPadding + this._arrowSide / 2;
Blink Reformat4c46d092018-04-07 15:32:37215 this._headerLabelXPadding = 3;
Blink Reformat4c46d092018-04-07 15:32:37216 this._headerLabelYPadding = 2;
217
218 this._highlightedMarkerIndex = -1;
219 this._highlightedEntryIndex = -1;
220 this._selectedEntryIndex = -1;
221 this._rawTimelineDataLength = 0;
Blink Reformat4c46d092018-04-07 15:32:37222 this._textWidth = new Map();
Alexei Filippov6c622e92018-11-10 02:13:59223 this._markerPositions = new Map();
Blink Reformat4c46d092018-04-07 15:32:37224
225 this._lastMouseOffsetX = 0;
226 this._selectedGroup = -1;
Anubha Mathur72dd5822019-06-13 23:05:19227
228 // Keyboard focused group is used to navigate groups irrespective of whether they are selectable or not
229 this._keyboardFocusedGroup = -1;
230
Paul Lewisca569a52020-09-09 16:11:51231 this._selectedGroupBackroundColor = ThemeSupport.ThemeSupport.instance().patchColorText(
232 Colors.SelectedGroupBackground, ThemeSupport.ThemeSupport.ColorUsage.Background);
233 this._selectedGroupBorderColor = ThemeSupport.ThemeSupport.instance().patchColorText(
234 Colors.SelectedGroupBorder, ThemeSupport.ThemeSupport.ColorUsage.Background);
Blink Reformat4c46d092018-04-07 15:32:37235 }
236
Jan Scheffler87dd9142021-02-27 21:19:48237 willHide(): void {
Blink Reformat4c46d092018-04-07 15:32:37238 this.hideHighlight();
239 }
240
Jan Scheffler87dd9142021-02-27 21:19:48241 setBarHeight(value: number): void {
Blink Reformat4c46d092018-04-07 15:32:37242 this._barHeight = value;
243 }
244
Jan Scheffler87dd9142021-02-27 21:19:48245 setTextBaseline(value: number): void {
Blink Reformat4c46d092018-04-07 15:32:37246 this._textBaseline = value;
247 }
248
Jan Scheffler87dd9142021-02-27 21:19:48249 setTextPadding(value: number): void {
Blink Reformat4c46d092018-04-07 15:32:37250 this._textPadding = value;
251 }
252
Jan Scheffler87dd9142021-02-27 21:19:48253 enableRuler(enable: boolean): void {
Blink Reformat4c46d092018-04-07 15:32:37254 this._rulerEnabled = enable;
255 }
256
Jan Scheffler87dd9142021-02-27 21:19:48257 alwaysShowVerticalScroll(): void {
Blink Reformat4c46d092018-04-07 15:32:37258 this._chartViewport.alwaysShowVerticalScroll();
259 }
260
Jan Scheffler87dd9142021-02-27 21:19:48261 disableRangeSelection(): void {
Blink Reformat4c46d092018-04-07 15:32:37262 this._chartViewport.disableRangeSelection();
263 }
264
Jan Scheffler87dd9142021-02-27 21:19:48265 highlightEntry(entryIndex: number): void {
Tim van der Lippe1d6e57a2019-09-30 11:55:34266 if (this._highlightedEntryIndex === entryIndex) {
Blink Reformat4c46d092018-04-07 15:32:37267 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34268 }
269 if (!this._dataProvider.entryColor(entryIndex)) {
Blink Reformat4c46d092018-04-07 15:32:37270 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34271 }
Blink Reformat4c46d092018-04-07 15:32:37272 this._highlightedEntryIndex = entryIndex;
273 this._updateElementPosition(this._highlightElement, this._highlightedEntryIndex);
Tim van der Lippefd2b2ce2020-01-03 15:05:18274 this.dispatchEventToListeners(Events.EntryHighlighted, entryIndex);
Blink Reformat4c46d092018-04-07 15:32:37275 }
276
Jan Scheffler87dd9142021-02-27 21:19:48277 hideHighlight(): void {
Blink Reformat4c46d092018-04-07 15:32:37278 this._entryInfo.removeChildren();
279 this._highlightedEntryIndex = -1;
280 this._updateElementPosition(this._highlightElement, this._highlightedEntryIndex);
Tim van der Lippefd2b2ce2020-01-03 15:05:18281 this.dispatchEventToListeners(Events.EntryHighlighted, -1);
Blink Reformat4c46d092018-04-07 15:32:37282 }
283
Jan Scheffler87dd9142021-02-27 21:19:48284 _createCandyStripePattern(): void {
Paul Lewis49b16822020-02-21 14:22:03285 // Set the candy stripe pattern to 17px so it repeats well.
286 const size = 17;
287 this._candyStripeCanvas.width = size;
288 this._candyStripeCanvas.height = size;
289
290 const ctx = this._candyStripeCanvas.getContext('2d');
Paul Lewiscf1f8a42020-11-04 21:05:24291 if (!ctx) {
292 return;
293 }
Paul Lewis49b16822020-02-21 14:22:03294
295 // Rotate the stripe by 45deg to the right.
296 ctx.translate(size * 0.5, size * 0.5);
297 ctx.rotate(Math.PI * 0.25);
298 ctx.translate(-size * 0.5, -size * 0.5);
299
300 ctx.fillStyle = 'rgba(255, 0, 0, 0.4)';
301 for (let x = -size; x < size * 2; x += 3) {
302 ctx.fillRect(x, -size, 1, size * 3);
303 }
304 }
305
Jan Scheffler87dd9142021-02-27 21:19:48306 _resetCanvas(): void {
Blink Reformat4c46d092018-04-07 15:32:37307 const ratio = window.devicePixelRatio;
308 const width = Math.round(this._offsetWidth * ratio);
309 const height = Math.round(this._offsetHeight * ratio);
310 this._canvas.width = width;
311 this._canvas.height = height;
312 this._canvas.style.width = `${width / ratio}px`;
313 this._canvas.style.height = `${height / ratio}px`;
Alexei Filippov57ccafb2018-08-14 20:59:05314 if (this._useWebGL) {
315 this._canvasGL.width = width;
316 this._canvasGL.height = height;
317 this._canvasGL.style.width = `${width / ratio}px`;
318 this._canvasGL.style.height = `${height / ratio}px`;
319 }
Blink Reformat4c46d092018-04-07 15:32:37320 }
321
Jan Scheffler87dd9142021-02-27 21:19:48322 windowChanged(startTime: number, endTime: number, animate: boolean): void {
Alexei Filippov2578eb02018-04-11 08:15:05323 this._flameChartDelegate.windowChanged(startTime, endTime, animate);
Blink Reformat4c46d092018-04-07 15:32:37324 }
325
Jan Scheffler87dd9142021-02-27 21:19:48326 updateRangeSelection(startTime: number, endTime: number): void {
Blink Reformat4c46d092018-04-07 15:32:37327 this._flameChartDelegate.updateRangeSelection(startTime, endTime);
328 }
329
Jan Scheffler87dd9142021-02-27 21:19:48330 setSize(width: number, height: number): void {
Blink Reformat4c46d092018-04-07 15:32:37331 this._offsetWidth = width;
332 this._offsetHeight = height;
333 }
334
Jan Scheffler87dd9142021-02-27 21:19:48335 _startDragging(event: MouseEvent): boolean {
Blink Reformat4c46d092018-04-07 15:32:37336 this.hideHighlight();
337 this._maxDragOffset = 0;
338 this._dragStartX = event.pageX;
339 this._dragStartY = event.pageY;
340 return true;
341 }
342
Jan Scheffler87dd9142021-02-27 21:19:48343 _dragging(event: MouseEvent): void {
Blink Reformat4c46d092018-04-07 15:32:37344 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
Jan Scheffler87dd9142021-02-27 21:19:48349 _endDragging(_event: MouseEvent): void {
Blink Reformat4c46d092018-04-07 15:32:37350 this._updateHighlight();
351 }
352
Jan Scheffler87dd9142021-02-27 21:19:48353 _timelineData(): TimelineData|null {
Tim van der Lippe1d6e57a2019-09-30 11:55:34354 if (!this._dataProvider) {
Blink Reformat4c46d092018-04-07 15:32:37355 return null;
Tim van der Lippe1d6e57a2019-09-30 11:55:34356 }
Blink Reformat4c46d092018-04-07 15:32:37357 const timelineData = this._dataProvider.timelineData();
Paul Lewiscf1f8a42020-11-04 21:05:24358 if (timelineData !== this._rawTimelineData ||
359 (timelineData && timelineData.entryStartTimes.length !== this._rawTimelineDataLength)) {
Blink Reformat4c46d092018-04-07 15:32:37360 this._processTimelineData(timelineData);
Tim van der Lippe1d6e57a2019-09-30 11:55:34361 }
Paul Lewiscf1f8a42020-11-04 21:05:24362 return this._rawTimelineData || null;
Blink Reformat4c46d092018-04-07 15:32:37363 }
364
Jan Scheffler87dd9142021-02-27 21:19:48365 _revealEntry(entryIndex: number): void {
Blink Reformat4c46d092018-04-07 15:32:37366 const timelineData = this._timelineData();
Tim van der Lippe1d6e57a2019-09-30 11:55:34367 if (!timelineData) {
Blink Reformat4c46d092018-04-07 15:32:37368 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34369 }
Blink Reformat4c46d092018-04-07 15:32:37370 const timeLeft = this._chartViewport.windowLeftTime();
371 const timeRight = this._chartViewport.windowRightTime();
372 const entryStartTime = timelineData.entryStartTimes[entryIndex];
373 const entryTotalTime = timelineData.entryTotalTimes[entryIndex];
374 const entryEndTime = entryStartTime + entryTotalTime;
375 let minEntryTimeWindow = Math.min(entryTotalTime, timeRight - timeLeft);
376
377 const level = timelineData.entryLevels[entryIndex];
378 this._chartViewport.setScrollOffset(this._levelToOffset(level), this._levelHeight(level));
379
380 const minVisibleWidthPx = 30;
381 const futurePixelToTime = (timeRight - timeLeft) / this._offsetWidth;
382 minEntryTimeWindow = Math.max(minEntryTimeWindow, futurePixelToTime * minVisibleWidthPx);
383 if (timeLeft > entryEndTime) {
384 const delta = timeLeft - entryEndTime + minEntryTimeWindow;
Alexei Filippov2578eb02018-04-11 08:15:05385 this.windowChanged(timeLeft - delta, timeRight - delta, /* animate */ true);
Blink Reformat4c46d092018-04-07 15:32:37386 } else if (timeRight < entryStartTime) {
387 const delta = entryStartTime - timeRight + minEntryTimeWindow;
Alexei Filippov2578eb02018-04-11 08:15:05388 this.windowChanged(timeLeft + delta, timeRight + delta, /* animate */ true);
Blink Reformat4c46d092018-04-07 15:32:37389 }
390 }
391
Jan Scheffler87dd9142021-02-27 21:19:48392 setWindowTimes(startTime: number, endTime: number, animate?: boolean): void {
Blink Reformat4c46d092018-04-07 15:32:37393 this._chartViewport.setWindowTimes(startTime, endTime, animate);
394 this._updateHighlight();
395 }
396
Jan Scheffler87dd9142021-02-27 21:19:48397 _onMouseMove(event: Event): void {
398 const mouseEvent = (event as MouseEvent);
Paul Lewiscf1f8a42020-11-04 21:05:24399 this._lastMouseOffsetX = mouseEvent.offsetX;
400 this._lastMouseOffsetY = mouseEvent.offsetY;
Tim van der Lippe1d6e57a2019-09-30 11:55:34401 if (!this._enabled()) {
Blink Reformat4c46d092018-04-07 15:32:37402 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34403 }
404 if (this._chartViewport.isDragging()) {
Blink Reformat4c46d092018-04-07 15:32:37405 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34406 }
Paul Lewiscf1f8a42020-11-04 21:05:24407 if (this._coordinatesToGroupIndex(mouseEvent.offsetX, mouseEvent.offsetY, true /* headerOnly */) >= 0) {
Blink Reformat4c46d092018-04-07 15:32:37408 this.hideHighlight();
409 this._viewportElement.style.cursor = 'pointer';
410 return;
411 }
412 this._updateHighlight();
413 }
414
Jan Scheffler87dd9142021-02-27 21:19:48415 _updateHighlight(): void {
Alexei Filippov8ee66382018-11-30 01:53:56416 const entryIndex = this._coordinatesToEntryIndex(this._lastMouseOffsetX, this._lastMouseOffsetY);
Blink Reformat4c46d092018-04-07 15:32:37417 if (entryIndex === -1) {
418 this.hideHighlight();
419 const group =
420 this._coordinatesToGroupIndex(this._lastMouseOffsetX, this._lastMouseOffsetY, false /* headerOnly */);
Paul Lewiscf1f8a42020-11-04 21:05:24421 if (group >= 0 && this._rawTimelineData && this._rawTimelineData.groups &&
422 this._rawTimelineData.groups[group].selectable) {
Blink Reformat4c46d092018-04-07 15:32:37423 this._viewportElement.style.cursor = 'pointer';
Tim van der Lippe1d6e57a2019-09-30 11:55:34424 } else {
Blink Reformat4c46d092018-04-07 15:32:37425 this._viewportElement.style.cursor = 'default';
Tim van der Lippe1d6e57a2019-09-30 11:55:34426 }
Blink Reformat4c46d092018-04-07 15:32:37427 return;
428 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34429 if (this._chartViewport.isDragging()) {
Blink Reformat4c46d092018-04-07 15:32:37430 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34431 }
Blink Reformat4c46d092018-04-07 15:32:37432 this._updatePopover(entryIndex);
433 this._viewportElement.style.cursor = this._dataProvider.canJumpToEntry(entryIndex) ? 'pointer' : 'default';
434 this.highlightEntry(entryIndex);
435 }
436
Jan Scheffler87dd9142021-02-27 21:19:48437 _onMouseOut(): void {
Blink Reformat4c46d092018-04-07 15:32:37438 this._lastMouseOffsetX = -1;
439 this._lastMouseOffsetY = -1;
440 this.hideHighlight();
441 }
442
Jan Scheffler87dd9142021-02-27 21:19:48443 _updatePopover(entryIndex: number): void {
Blink Reformat4c46d092018-04-07 15:32:37444 if (entryIndex === this._highlightedEntryIndex) {
445 this._updatePopoverOffset();
446 return;
447 }
448 this._entryInfo.removeChildren();
449 const popoverElement = this._dataProvider.prepareHighlightedEntryInfo(entryIndex);
450 if (popoverElement) {
451 this._entryInfo.appendChild(popoverElement);
452 this._updatePopoverOffset();
453 }
454 }
455
Jan Scheffler87dd9142021-02-27 21:19:48456 _updatePopoverOffset(): void {
Blink Reformat4c46d092018-04-07 15:32:37457 const mouseX = this._lastMouseOffsetX;
458 const mouseY = this._lastMouseOffsetY;
Paul Lewiscf1f8a42020-11-04 21:05:24459 const parentWidth = this._entryInfo.parentElement ? this._entryInfo.parentElement.clientWidth : 0;
460 const parentHeight = this._entryInfo.parentElement ? this._entryInfo.parentElement.clientHeight : 0;
Blink Reformat4c46d092018-04-07 15:32:37461 const infoWidth = this._entryInfo.clientWidth;
462 const infoHeight = this._entryInfo.clientHeight;
463 const /** @const */ offsetX = 10;
464 const /** @const */ offsetY = 6;
465 let x;
466 let y;
467 for (let quadrant = 0; quadrant < 4; ++quadrant) {
468 const dx = quadrant & 2 ? -offsetX - infoWidth : offsetX;
469 const dy = quadrant & 1 ? -offsetY - infoHeight : offsetY;
Jack Franklin1be909c2020-03-04 08:57:41470 x = Platform.NumberUtilities.clamp(mouseX + dx, 0, parentWidth - infoWidth);
471 y = Platform.NumberUtilities.clamp(mouseY + dy, 0, parentHeight - infoHeight);
Tim van der Lippe1d6e57a2019-09-30 11:55:34472 if (x >= mouseX || mouseX >= x + infoWidth || y >= mouseY || mouseY >= y + infoHeight) {
Blink Reformat4c46d092018-04-07 15:32:37473 break;
Tim van der Lippe1d6e57a2019-09-30 11:55:34474 }
Blink Reformat4c46d092018-04-07 15:32:37475 }
476 this._entryInfo.style.left = x + 'px';
477 this._entryInfo.style.top = y + 'px';
478 }
479
Jan Scheffler87dd9142021-02-27 21:19:48480 _onClick(event: Event): void {
481 const mouseEvent = (event as MouseEvent);
Blink Reformat4c46d092018-04-07 15:32:37482 this.focus();
483 // onClick comes after dragStart and dragEnd events.
484 // So if there was drag (mouse move) in the middle of that events
485 // we skip the click. Otherwise we jump to the sources.
Jan Scheffler87dd9142021-02-27 21:19:48486 const clickThreshold = 5;
Tim van der Lippe1d6e57a2019-09-30 11:55:34487 if (this._maxDragOffset > clickThreshold) {
Blink Reformat4c46d092018-04-07 15:32:37488 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34489 }
Blink Reformat4c46d092018-04-07 15:32:37490
Paul Lewiscf1f8a42020-11-04 21:05:24491 this._selectGroup(this._coordinatesToGroupIndex(mouseEvent.offsetX, mouseEvent.offsetY, false /* headerOnly */));
492 this._toggleGroupExpand(
493 this._coordinatesToGroupIndex(mouseEvent.offsetX, mouseEvent.offsetY, true /* headerOnly */));
Blink Reformat4c46d092018-04-07 15:32:37494 const timelineData = this._timelineData();
Paul Lewiscf1f8a42020-11-04 21:05:24495 if (mouseEvent.shiftKey && this._highlightedEntryIndex !== -1 && timelineData) {
Blink Reformat4c46d092018-04-07 15:32:37496 const start = timelineData.entryStartTimes[this._highlightedEntryIndex];
497 const end = start + timelineData.entryTotalTimes[this._highlightedEntryIndex];
498 this._chartViewport.setRangeSelection(start, end);
499 } else {
Paul Lewiscf1f8a42020-11-04 21:05:24500 this._chartViewport.onClick(mouseEvent);
Tim van der Lippefd2b2ce2020-01-03 15:05:18501 this.dispatchEventToListeners(Events.EntryInvoked, this._highlightedEntryIndex);
Blink Reformat4c46d092018-04-07 15:32:37502 }
503 }
504
Jan Scheffler87dd9142021-02-27 21:19:48505 _selectGroup(groupIndex: number): void {
Tim van der Lippe1d6e57a2019-09-30 11:55:34506 if (groupIndex < 0 || this._selectedGroup === groupIndex) {
Blink Reformat4c46d092018-04-07 15:32:37507 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34508 }
Paul Lewiscf1f8a42020-11-04 21:05:24509 if (!this._rawTimelineData) {
510 return;
511 }
512
Anubha Mathur72dd5822019-06-13 23:05:19513 const groups = this._rawTimelineData.groups;
Paul Lewiscf1f8a42020-11-04 21:05:24514 if (!groups) {
515 return;
516 }
517
Anubha Mathur72dd5822019-06-13 23:05:19518 this._keyboardFocusedGroup = groupIndex;
Anubha Mathur430a80f2019-12-12 00:26:11519 this._scrollGroupIntoView(groupIndex);
Michael Liao0bad0c32020-01-02 18:51:04520 const groupName = groups[groupIndex].name;
Anubha Mathur72dd5822019-06-13 23:05:19521 if (!groups[groupIndex].selectable) {
522 this._deselectAllGroups();
Christy Chenf9033fa2021-01-21 10:07:04523 UI.ARIAUtils.alert(i18nString(UIStrings.sHovered, {PH1: groupName}), this._canvas);
Anubha Mathur72dd5822019-06-13 23:05:19524 } else {
525 this._selectedGroup = groupIndex;
526 this._flameChartDelegate.updateSelectedGroup(this, groups[groupIndex]);
527 this._resetCanvas();
528 this._draw();
Christy Chenf9033fa2021-01-21 10:07:04529 UI.ARIAUtils.alert(i18nString(UIStrings.sSelected, {PH1: groupName}), this._canvas);
Anubha Mathur72dd5822019-06-13 23:05:19530 }
531 }
Blink Reformat4c46d092018-04-07 15:32:37532
Jan Scheffler87dd9142021-02-27 21:19:48533 _deselectAllGroups(): void {
Anubha Mathur72dd5822019-06-13 23:05:19534 this._selectedGroup = -1;
535 this._flameChartDelegate.updateSelectedGroup(this, null);
536 this._resetCanvas();
537 this._draw();
538 }
539
Jan Scheffler87dd9142021-02-27 21:19:48540 _deselectAllEntries(): void {
Anubha Mathur72dd5822019-06-13 23:05:19541 this._selectedEntryIndex = -1;
Blink Reformat4c46d092018-04-07 15:32:37542 this._resetCanvas();
543 this._draw();
544 }
545
Jan Scheffler87dd9142021-02-27 21:19:48546 _isGroupFocused(index: number): boolean {
Anubha Mathur72dd5822019-06-13 23:05:19547 return index === this._selectedGroup || index === this._keyboardFocusedGroup;
548 }
549
Jan Scheffler87dd9142021-02-27 21:19:48550 _scrollGroupIntoView(index: number): void {
Anubha Mathur430a80f2019-12-12 00:26:11551 if (index < 0) {
552 return;
553 }
554
Paul Lewiscf1f8a42020-11-04 21:05:24555 if (!this._rawTimelineData) {
556 return;
557 }
558
Anubha Mathur430a80f2019-12-12 00:26:11559 const groups = this._rawTimelineData.groups;
560 const groupOffsets = this._groupOffsets;
Paul Lewiscf1f8a42020-11-04 21:05:24561 if (!groupOffsets || !groups) {
562 return;
563 }
Anubha Mathur430a80f2019-12-12 00:26:11564 const groupTop = groupOffsets[index];
565
566 let nextOffset = groupOffsets[index + 1];
567 if (index === groups.length - 1) {
568 nextOffset += groups[index].style.padding;
569 }
570
571 // For the top group, scroll all the way to the top of the chart
572 // to accommodate the bar with time markers
573 const scrollTop = index === 0 ? 0 : groupTop;
574
575 const scrollHeight = Math.min(nextOffset - scrollTop, this._chartViewport.chartHeight());
576 this._chartViewport.setScrollOffset(scrollTop, scrollHeight);
577 }
578
Jan Scheffler87dd9142021-02-27 21:19:48579 _toggleGroupExpand(groupIndex: number): void {
Tim van der Lippe1d6e57a2019-09-30 11:55:34580 if (groupIndex < 0 || !this._isGroupCollapsible(groupIndex)) {
Anubha Mathur72dd5822019-06-13 23:05:19581 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34582 }
Anubha Mathur72dd5822019-06-13 23:05:19583
Paul Lewiscf1f8a42020-11-04 21:05:24584 if (!this._rawTimelineData || !this._rawTimelineData.groups) {
585 return;
586 }
587
Anubha Mathur72dd5822019-06-13 23:05:19588 this._expandGroup(groupIndex, !this._rawTimelineData.groups[groupIndex].expanded /* setExpanded */);
589 }
590
Jan Scheffler87dd9142021-02-27 21:19:48591 _expandGroup(groupIndex: number, setExpanded: boolean|undefined = true, propagatedExpand: boolean|undefined = false):
592 void {
Tim van der Lippe1d6e57a2019-09-30 11:55:34593 if (groupIndex < 0 || !this._isGroupCollapsible(groupIndex)) {
Blink Reformat4c46d092018-04-07 15:32:37594 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34595 }
Blink Reformat4c46d092018-04-07 15:32:37596
Paul Lewiscf1f8a42020-11-04 21:05:24597 if (!this._rawTimelineData) {
598 return;
599 }
600
Blink Reformat4c46d092018-04-07 15:32:37601 const groups = this._rawTimelineData.groups;
Paul Lewiscf1f8a42020-11-04 21:05:24602 if (!groups) {
603 return;
604 }
605
Blink Reformat4c46d092018-04-07 15:32:37606 const group = groups[groupIndex];
Anubha Mathur72dd5822019-06-13 23:05:19607 group.expanded = setExpanded;
608
Blink Reformat4c46d092018-04-07 15:32:37609 this._groupExpansionState[group.name] = group.expanded;
Tim van der Lippe1d6e57a2019-09-30 11:55:34610 if (this._groupExpansionSetting) {
Blink Reformat4c46d092018-04-07 15:32:37611 this._groupExpansionSetting.set(this._groupExpansionState);
Tim van der Lippe1d6e57a2019-09-30 11:55:34612 }
Blink Reformat4c46d092018-04-07 15:32:37613 this._updateLevelPositions();
614
615 this._updateHighlight();
616 if (!group.expanded) {
617 const timelineData = this._timelineData();
Paul Lewiscf1f8a42020-11-04 21:05:24618 if (timelineData) {
619 const level = timelineData.entryLevels[this._selectedEntryIndex];
620 if (this._selectedEntryIndex >= 0 && level >= group.startLevel &&
621 (groupIndex >= groups.length - 1 || groups[groupIndex + 1].startLevel > level)) {
622 this._selectedEntryIndex = -1;
623 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34624 }
Blink Reformat4c46d092018-04-07 15:32:37625 }
626
627 this._updateHeight();
628 this._resetCanvas();
629 this._draw();
Michael Liao (WPT)b54514b2019-08-16 23:11:53630
Anubha Mathur430a80f2019-12-12 00:26:11631 this._scrollGroupIntoView(groupIndex);
Michael Liao (WPT)b54514b2019-08-16 23:11:53632 // We only want to read expanded/collapsed state on user inputted expand/collapse
633 if (!propagatedExpand) {
634 const groupName = groups[groupIndex].name;
Christy Chenf9033fa2021-01-21 10:07:04635 const content = group.expanded ? i18nString(UIStrings.sExpanded, {PH1: groupName}) :
636 i18nString(UIStrings.sCollapsed, {PH1: groupName});
Michael Liao (WPT)b54514b2019-08-16 23:11:53637 UI.ARIAUtils.alert(content, this._canvas);
638 }
Blink Reformat4c46d092018-04-07 15:32:37639 }
640
Jan Scheffler87dd9142021-02-27 21:19:48641 _onKeyDown(e: KeyboardEvent): void {
Tim van der Lippebb769172020-02-12 15:32:44642 if (!UI.KeyboardShortcut.KeyboardShortcut.hasNoModifiers(e) || !this._timelineData()) {
Anubha Mathur72dd5822019-06-13 23:05:19643 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34644 }
Anubha Mathur72dd5822019-06-13 23:05:19645
646 const eventHandled = this._handleSelectionNavigation(e);
647
648 // Handle keyboard navigation in groups
Tim van der Lippe1d6e57a2019-09-30 11:55:34649 if (!eventHandled && this._rawTimelineData && this._rawTimelineData.groups) {
Anubha Mathur72dd5822019-06-13 23:05:19650 this._handleKeyboardGroupNavigation(e);
Tim van der Lippe1d6e57a2019-09-30 11:55:34651 }
Blink Reformat4c46d092018-04-07 15:32:37652 }
653
Jan Scheffler87dd9142021-02-27 21:19:48654 bindCanvasEvent(eventName: string, onEvent: (arg0: Event) => void): void {
Ted Meyerb0928d02020-06-23 05:12:45655 this._canvas.addEventListener(eventName, onEvent);
656 }
657
Jan Scheffler87dd9142021-02-27 21:19:48658 _handleKeyboardGroupNavigation(event: Event): void {
659 const keyboardEvent = (event as KeyboardEvent);
Anubha Mathur72dd5822019-06-13 23:05:19660 let handled = false;
661 let entrySelected = false;
662
Paul Lewiscf1f8a42020-11-04 21:05:24663 if (keyboardEvent.code === 'ArrowUp') {
Anubha Mathur72dd5822019-06-13 23:05:19664 handled = this._selectPreviousGroup();
Paul Lewiscf1f8a42020-11-04 21:05:24665 } else if (keyboardEvent.code === 'ArrowDown') {
Anubha Mathur72dd5822019-06-13 23:05:19666 handled = this._selectNextGroup();
Paul Lewiscf1f8a42020-11-04 21:05:24667 } else if (keyboardEvent.code === 'ArrowLeft') {
Anubha Mathur72dd5822019-06-13 23:05:19668 if (this._keyboardFocusedGroup >= 0) {
669 this._expandGroup(this._keyboardFocusedGroup, false /* setExpanded */);
670 handled = true;
671 }
Paul Lewiscf1f8a42020-11-04 21:05:24672 } else if (keyboardEvent.code === 'ArrowRight') {
Anubha Mathur72dd5822019-06-13 23:05:19673 if (this._keyboardFocusedGroup >= 0) {
674 this._expandGroup(this._keyboardFocusedGroup, true /* setExpanded */);
675 this._selectFirstChild();
676 handled = true;
677 }
Tim van der Lippebcd6b5c2021-01-13 12:31:51678 } else if (keyboardEvent.key === 'Enter') {
Anubha Mathur72dd5822019-06-13 23:05:19679 entrySelected = this._selectFirstEntryInCurrentGroup();
680 handled = entrySelected;
681 }
682
Tim van der Lippe1d6e57a2019-09-30 11:55:34683 if (handled && !entrySelected) {
Anubha Mathur72dd5822019-06-13 23:05:19684 this._deselectAllEntries();
Tim van der Lippe1d6e57a2019-09-30 11:55:34685 }
Anubha Mathur72dd5822019-06-13 23:05:19686
Tim van der Lippe1d6e57a2019-09-30 11:55:34687 if (handled) {
Paul Lewiscf1f8a42020-11-04 21:05:24688 keyboardEvent.consume(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34689 }
Anubha Mathur72dd5822019-06-13 23:05:19690 }
691
Jan Scheffler87dd9142021-02-27 21:19:48692 _selectFirstEntryInCurrentGroup(): boolean {
Paul Lewiscf1f8a42020-11-04 21:05:24693 if (!this._rawTimelineData) {
694 return false;
695 }
696
Anubha Mathur72dd5822019-06-13 23:05:19697 const allGroups = this._rawTimelineData.groups;
698
Paul Lewiscf1f8a42020-11-04 21:05:24699 if (this._keyboardFocusedGroup < 0 || !allGroups) {
Anubha Mathur72dd5822019-06-13 23:05:19700 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34701 }
Anubha Mathur72dd5822019-06-13 23:05:19702
703 const group = allGroups[this._keyboardFocusedGroup];
704 const startLevelInGroup = group.startLevel;
705
706 // Return if no levels in this group
Tim van der Lippe1d6e57a2019-09-30 11:55:34707 if (startLevelInGroup < 0) {
Anubha Mathur72dd5822019-06-13 23:05:19708 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34709 }
Anubha Mathur72dd5822019-06-13 23:05:19710
711 // Make sure this is the innermost nested group with this startLevel
712 // This is because a parent group also contains levels of all its child groups
713 // So check if the next group has the same level, if it does, user should
714 // go to that child group to select this entry
715 if (this._keyboardFocusedGroup < allGroups.length - 1 &&
Tim van der Lippe1d6e57a2019-09-30 11:55:34716 allGroups[this._keyboardFocusedGroup + 1].startLevel === startLevelInGroup) {
Anubha Mathur72dd5822019-06-13 23:05:19717 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34718 }
Anubha Mathur72dd5822019-06-13 23:05:19719
Paul Lewiscf1f8a42020-11-04 21:05:24720 if (!this._timelineLevels) {
721 return false;
722 }
Anubha Mathur72dd5822019-06-13 23:05:19723
724 // Get first (default) entry in startLevel of selected group
725 const firstEntryIndex = this._timelineLevels[startLevelInGroup][0];
726
727 this._expandGroup(this._keyboardFocusedGroup, true /* setExpanded */);
728 this.setSelectedEntry(firstEntryIndex);
729 return true;
730 }
731
Jan Scheffler87dd9142021-02-27 21:19:48732 _selectPreviousGroup(): boolean {
Tim van der Lippe1d6e57a2019-09-30 11:55:34733 if (this._keyboardFocusedGroup <= 0) {
Anubha Mathur72dd5822019-06-13 23:05:19734 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34735 }
Anubha Mathur72dd5822019-06-13 23:05:19736
737 const groupIndexToSelect = this._getGroupIndexToSelect(-1 /* offset */);
738 this._selectGroup(groupIndexToSelect);
739 return true;
740 }
741
Jan Scheffler87dd9142021-02-27 21:19:48742 _selectNextGroup(): boolean {
Paul Lewiscf1f8a42020-11-04 21:05:24743 if (!this._rawTimelineData || !this._rawTimelineData.groups) {
744 return false;
745 }
746
Tim van der Lippe1d6e57a2019-09-30 11:55:34747 if (this._keyboardFocusedGroup >= this._rawTimelineData.groups.length - 1) {
Anubha Mathur72dd5822019-06-13 23:05:19748 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34749 }
Anubha Mathur72dd5822019-06-13 23:05:19750
751 const groupIndexToSelect = this._getGroupIndexToSelect(1 /* offset */);
752 this._selectGroup(groupIndexToSelect);
753 return true;
754 }
755
Jan Scheffler87dd9142021-02-27 21:19:48756 _getGroupIndexToSelect(offset: number): number {
Paul Lewiscf1f8a42020-11-04 21:05:24757 if (!this._rawTimelineData || !this._rawTimelineData.groups) {
758 throw new Error('No raw timeline data');
759 }
Anubha Mathur72dd5822019-06-13 23:05:19760 const allGroups = this._rawTimelineData.groups;
761 let groupIndexToSelect = this._keyboardFocusedGroup;
762 let groupName, groupWithSubNestingLevel;
763
764 do {
765 groupIndexToSelect += offset;
766 groupName = this._rawTimelineData.groups[groupIndexToSelect].name;
767 groupWithSubNestingLevel = this._keyboardFocusedGroup !== -1 &&
768 allGroups[groupIndexToSelect].style.nestingLevel > allGroups[this._keyboardFocusedGroup].style.nestingLevel;
769 } while (groupIndexToSelect > 0 && groupIndexToSelect < allGroups.length - 1 &&
770 (!groupName || groupWithSubNestingLevel));
771
772 return groupIndexToSelect;
773 }
774
Jan Scheffler87dd9142021-02-27 21:19:48775 _selectFirstChild(): void {
Paul Lewiscf1f8a42020-11-04 21:05:24776 if (!this._rawTimelineData || !this._rawTimelineData.groups) {
777 return;
778 }
779
Anubha Mathur72dd5822019-06-13 23:05:19780 const allGroups = this._rawTimelineData.groups;
Tim van der Lippe1d6e57a2019-09-30 11:55:34781 if (this._keyboardFocusedGroup < 0 || this._keyboardFocusedGroup >= allGroups.length - 1) {
Anubha Mathur72dd5822019-06-13 23:05:19782 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34783 }
Anubha Mathur72dd5822019-06-13 23:05:19784
785 const groupIndexToSelect = this._keyboardFocusedGroup + 1;
786 if (allGroups[groupIndexToSelect].style.nestingLevel > allGroups[this._keyboardFocusedGroup].style.nestingLevel) {
787 this._selectGroup(groupIndexToSelect);
Anubha Mathur72dd5822019-06-13 23:05:19788 }
789 }
790
Jan Scheffler87dd9142021-02-27 21:19:48791 _handleSelectionNavigation(event: KeyboardEvent): boolean {
Tim van der Lippe1d6e57a2019-09-30 11:55:34792 if (this._selectedEntryIndex === -1) {
Anubha Mathur72dd5822019-06-13 23:05:19793 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34794 }
Blink Reformat4c46d092018-04-07 15:32:37795 const timelineData = this._timelineData();
Tim van der Lippe1d6e57a2019-09-30 11:55:34796 if (!timelineData) {
Anubha Mathur72dd5822019-06-13 23:05:19797 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34798 }
Blink Reformat4c46d092018-04-07 15:32:37799
Jan Scheffler87dd9142021-02-27 21:19:48800 function timeComparator(time: number, entryIndex: number): number {
Paul Lewiscf1f8a42020-11-04 21:05:24801 if (!timelineData) {
802 throw new Error('No timeline data');
803 }
Blink Reformat4c46d092018-04-07 15:32:37804 return time - timelineData.entryStartTimes[entryIndex];
805 }
806
Jan Scheffler87dd9142021-02-27 21:19:48807 function entriesIntersect(entry1: number, entry2: number): boolean {
Paul Lewiscf1f8a42020-11-04 21:05:24808 if (!timelineData) {
809 throw new Error('No timeline data');
810 }
811
Blink Reformat4c46d092018-04-07 15:32:37812 const start1 = timelineData.entryStartTimes[entry1];
813 const start2 = timelineData.entryStartTimes[entry2];
814 const end1 = start1 + timelineData.entryTotalTimes[entry1];
815 const end2 = start2 + timelineData.entryTotalTimes[entry2];
816 return start1 < end2 && start2 < end1;
817 }
818
Jan Scheffler87dd9142021-02-27 21:19:48819 const keyboardEvent = (event as KeyboardEvent);
Blink Reformat4c46d092018-04-07 15:32:37820 const keys = UI.KeyboardShortcut.Keys;
Paul Lewiscf1f8a42020-11-04 21:05:24821 if (keyboardEvent.keyCode === keys.Left.code || keyboardEvent.keyCode === keys.Right.code) {
Blink Reformat4c46d092018-04-07 15:32:37822 const level = timelineData.entryLevels[this._selectedEntryIndex];
Paul Lewiscf1f8a42020-11-04 21:05:24823 const levelIndexes = this._timelineLevels ? this._timelineLevels[level] : [];
Jan Scheffler87dd9142021-02-27 21:19:48824 let indexOnLevel = Platform.ArrayUtilities.lowerBound(levelIndexes, this._selectedEntryIndex, (a, b) => a - b);
Paul Lewiscf1f8a42020-11-04 21:05:24825 indexOnLevel += keyboardEvent.keyCode === keys.Left.code ? -1 : 1;
826 event.consume(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34827 if (indexOnLevel >= 0 && indexOnLevel < levelIndexes.length) {
Tim van der Lippefd2b2ce2020-01-03 15:05:18828 this.dispatchEventToListeners(Events.EntrySelected, levelIndexes[indexOnLevel]);
Tim van der Lippe1d6e57a2019-09-30 11:55:34829 }
Anubha Mathur72dd5822019-06-13 23:05:19830 return true;
Blink Reformat4c46d092018-04-07 15:32:37831 }
Paul Lewiscf1f8a42020-11-04 21:05:24832
833 if (keyboardEvent.keyCode === keys.Up.code || keyboardEvent.keyCode === keys.Down.code) {
Blink Reformat4c46d092018-04-07 15:32:37834 let level = timelineData.entryLevels[this._selectedEntryIndex];
Paul Lewiscf1f8a42020-11-04 21:05:24835 level += keyboardEvent.keyCode === keys.Up.code ? -1 : 1;
836 if (level < 0 || (this._timelineLevels && level >= this._timelineLevels.length)) {
Anubha Mathur72dd5822019-06-13 23:05:19837 this._deselectAllEntries();
Paul Lewiscf1f8a42020-11-04 21:05:24838 keyboardEvent.consume(true);
Anubha Mathur72dd5822019-06-13 23:05:19839 return true;
840 }
Blink Reformat4c46d092018-04-07 15:32:37841 const entryTime = timelineData.entryStartTimes[this._selectedEntryIndex] +
842 timelineData.entryTotalTimes[this._selectedEntryIndex] / 2;
Paul Lewiscf1f8a42020-11-04 21:05:24843 const levelIndexes = this._timelineLevels ? this._timelineLevels[level] : [];
Tim van der Lippecbdf5f22021-01-25 11:53:52844 let indexOnLevel = Platform.ArrayUtilities.upperBound(levelIndexes, entryTime, timeComparator) - 1;
Blink Reformat4c46d092018-04-07 15:32:37845 if (!entriesIntersect(this._selectedEntryIndex, levelIndexes[indexOnLevel])) {
846 ++indexOnLevel;
847 if (indexOnLevel >= levelIndexes.length ||
Anubha Mathur72dd5822019-06-13 23:05:19848 !entriesIntersect(this._selectedEntryIndex, levelIndexes[indexOnLevel])) {
Paul Lewiscf1f8a42020-11-04 21:05:24849 if (keyboardEvent.code === 'ArrowDown') {
Anubha Mathur72dd5822019-06-13 23:05:19850 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34851 }
Anubha Mathur72dd5822019-06-13 23:05:19852
853 // Stay in the current group and give focus to the parent group instead of entries
854 this._deselectAllEntries();
Paul Lewiscf1f8a42020-11-04 21:05:24855 keyboardEvent.consume(true);
Anubha Mathur72dd5822019-06-13 23:05:19856 return true;
857 }
Blink Reformat4c46d092018-04-07 15:32:37858 }
Paul Lewiscf1f8a42020-11-04 21:05:24859 keyboardEvent.consume(true);
Tim van der Lippefd2b2ce2020-01-03 15:05:18860 this.dispatchEventToListeners(Events.EntrySelected, levelIndexes[indexOnLevel]);
Anubha Mathur72dd5822019-06-13 23:05:19861 return true;
Blink Reformat4c46d092018-04-07 15:32:37862 }
Tim van der Lippebcd6b5c2021-01-13 12:31:51863 if (event.key === 'Enter') {
Paul Lewiscf1f8a42020-11-04 21:05:24864 event.consume(true);
Tim van der Lippefd2b2ce2020-01-03 15:05:18865 this.dispatchEventToListeners(Events.EntryInvoked, this._selectedEntryIndex);
Michael Liao712bbc22019-10-15 19:21:51866 return true;
867 }
Anubha Mathur72dd5822019-06-13 23:05:19868 return false;
Blink Reformat4c46d092018-04-07 15:32:37869 }
870
Jan Scheffler87dd9142021-02-27 21:19:48871 _coordinatesToEntryIndex(x: number, y: number): number {
Tim van der Lippe1d6e57a2019-09-30 11:55:34872 if (x < 0 || y < 0) {
Blink Reformat4c46d092018-04-07 15:32:37873 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34874 }
Blink Reformat4c46d092018-04-07 15:32:37875 const timelineData = this._timelineData();
Tim van der Lippe1d6e57a2019-09-30 11:55:34876 if (!timelineData) {
Blink Reformat4c46d092018-04-07 15:32:37877 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34878 }
Blink Reformat4c46d092018-04-07 15:32:37879 y += this._chartViewport.scrollOffset();
Paul Lewiscf1f8a42020-11-04 21:05:24880 if (!this._visibleLevelOffsets) {
881 throw new Error('No visible level offsets');
882 }
Tim van der Lippecbdf5f22021-01-25 11:53:52883 const cursorLevel =
884 Platform.ArrayUtilities.upperBound(this._visibleLevelOffsets, y, Platform.ArrayUtilities.DEFAULT_COMPARATOR) -
885 1;
Paul Lewiscf1f8a42020-11-04 21:05:24886 if (cursorLevel < 0 || (this._visibleLevels && !this._visibleLevels[cursorLevel])) {
Blink Reformat4c46d092018-04-07 15:32:37887 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34888 }
Blink Reformat4c46d092018-04-07 15:32:37889 const offsetFromLevel = y - this._visibleLevelOffsets[cursorLevel];
Tim van der Lippe1d6e57a2019-09-30 11:55:34890 if (offsetFromLevel > this._levelHeight(cursorLevel)) {
Blink Reformat4c46d092018-04-07 15:32:37891 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34892 }
Alexei Filippov6c622e92018-11-10 02:13:59893
894 // Check markers first.
895 for (const [index, pos] of this._markerPositions) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34896 if (timelineData.entryLevels[index] !== cursorLevel) {
Alexei Filippov6c622e92018-11-10 02:13:59897 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34898 }
899 if (pos.x <= x && x < pos.x + pos.width) {
Jan Scheffler87dd9142021-02-27 21:19:48900 return /** @type {number} */ index as number;
Tim van der Lippe1d6e57a2019-09-30 11:55:34901 }
Alexei Filippov6c622e92018-11-10 02:13:59902 }
903
904 // Check regular entries.
Blink Reformat4c46d092018-04-07 15:32:37905 const entryStartTimes = timelineData.entryStartTimes;
Jan Scheffler87dd9142021-02-27 21:19:48906 const entriesOnLevel: number[] = this._timelineLevels ? this._timelineLevels[cursorLevel] : [];
Tim van der Lippe1d6e57a2019-09-30 11:55:34907 if (!entriesOnLevel || !entriesOnLevel.length) {
Blink Reformat4c46d092018-04-07 15:32:37908 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34909 }
Blink Reformat4c46d092018-04-07 15:32:37910
Blink Reformat4c46d092018-04-07 15:32:37911 const cursorTime = this._chartViewport.pixelToTime(x);
Alexei Filippov6c622e92018-11-10 02:13:59912 const indexOnLevel = Math.max(
Tim van der Lippecbdf5f22021-01-25 11:53:52913 Platform.ArrayUtilities.upperBound(
914 entriesOnLevel, cursorTime, (time, entryIndex) => time - entryStartTimes[entryIndex]) -
915 1,
916 0);
Blink Reformat4c46d092018-04-07 15:32:37917
Jan Scheffler87dd9142021-02-27 21:19:48918 function checkEntryHit(this: FlameChart, entryIndex: number|undefined): boolean {
Tim van der Lippe1d6e57a2019-09-30 11:55:34919 if (entryIndex === undefined) {
Blink Reformat4c46d092018-04-07 15:32:37920 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34921 }
Paul Lewiscf1f8a42020-11-04 21:05:24922
923 if (!timelineData) {
924 return false;
925 }
926
Blink Reformat4c46d092018-04-07 15:32:37927 const startTime = entryStartTimes[entryIndex];
Alexei Filippov6c622e92018-11-10 02:13:59928 const duration = timelineData.entryTotalTimes[entryIndex];
Blink Reformat4c46d092018-04-07 15:32:37929 const startX = this._chartViewport.timeToPosition(startTime);
Alexei Filippov6c622e92018-11-10 02:13:59930 const endX = this._chartViewport.timeToPosition(startTime + duration);
931 const barThresholdPx = 3;
Blink Reformat4c46d092018-04-07 15:32:37932 return startX - barThresholdPx < x && x < endX + barThresholdPx;
933 }
934
Jan Scheffler87dd9142021-02-27 21:19:48935 let entryIndex: number = entriesOnLevel[indexOnLevel];
Tim van der Lippe1d6e57a2019-09-30 11:55:34936 if (checkEntryHit.call(this, entryIndex)) {
Blink Reformat4c46d092018-04-07 15:32:37937 return entryIndex;
Tim van der Lippe1d6e57a2019-09-30 11:55:34938 }
Alexei Filippov6c622e92018-11-10 02:13:59939 entryIndex = entriesOnLevel[indexOnLevel + 1];
Tim van der Lippe1d6e57a2019-09-30 11:55:34940 if (checkEntryHit.call(this, entryIndex)) {
Blink Reformat4c46d092018-04-07 15:32:37941 return entryIndex;
Tim van der Lippe1d6e57a2019-09-30 11:55:34942 }
Blink Reformat4c46d092018-04-07 15:32:37943 return -1;
944 }
945
Jan Scheffler87dd9142021-02-27 21:19:48946 _coordinatesToGroupIndex(x: number, y: number, headerOnly: boolean): number {
Paul Lewiscf1f8a42020-11-04 21:05:24947 if (!this._rawTimelineData || !this._rawTimelineData.groups || !this._groupOffsets) {
948 return -1;
949 }
950
Tim van der Lippe1d6e57a2019-09-30 11:55:34951 if (x < 0 || y < 0) {
Blink Reformat4c46d092018-04-07 15:32:37952 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34953 }
Blink Reformat4c46d092018-04-07 15:32:37954 y += this._chartViewport.scrollOffset();
955 const groups = this._rawTimelineData.groups || [];
Tim van der Lippecbdf5f22021-01-25 11:53:52956 const group =
957 Platform.ArrayUtilities.upperBound(this._groupOffsets, y, Platform.ArrayUtilities.DEFAULT_COMPARATOR) - 1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34958 if (group < 0 || group >= groups.length) {
Blink Reformat4c46d092018-04-07 15:32:37959 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34960 }
Blink Reformat4c46d092018-04-07 15:32:37961 const height = headerOnly ? groups[group].style.height : this._groupOffsets[group + 1] - this._groupOffsets[group];
Tim van der Lippe1d6e57a2019-09-30 11:55:34962 if (y - this._groupOffsets[group] >= height) {
Blink Reformat4c46d092018-04-07 15:32:37963 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34964 }
965 if (!headerOnly) {
Blink Reformat4c46d092018-04-07 15:32:37966 return group;
Tim van der Lippe1d6e57a2019-09-30 11:55:34967 }
Blink Reformat4c46d092018-04-07 15:32:37968
Jan Scheffler87dd9142021-02-27 21:19:48969 const context = (this._canvas.getContext('2d') as CanvasRenderingContext2D);
Blink Reformat4c46d092018-04-07 15:32:37970 context.save();
971 context.font = groups[group].style.font;
972 const right = this._headerLeftPadding + this._labelWidthForGroup(context, groups[group]);
973 context.restore();
Tim van der Lippe1d6e57a2019-09-30 11:55:34974 if (x > right) {
Blink Reformat4c46d092018-04-07 15:32:37975 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34976 }
Blink Reformat4c46d092018-04-07 15:32:37977
978 return group;
979 }
980
Jan Scheffler87dd9142021-02-27 21:19:48981 _markerIndexAtPosition(x: number): number {
Paul Lewiscf1f8a42020-11-04 21:05:24982 const timelineData = this._timelineData();
983 if (!timelineData) {
984 return -1;
985 }
986
987 const markers = timelineData.markers;
Tim van der Lippe1d6e57a2019-09-30 11:55:34988 if (!markers) {
Blink Reformat4c46d092018-04-07 15:32:37989 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34990 }
Blink Reformat4c46d092018-04-07 15:32:37991 const /** @const */ accurracyOffsetPx = 4;
992 const time = this._chartViewport.pixelToTime(x);
993 const leftTime = this._chartViewport.pixelToTime(x - accurracyOffsetPx);
994 const rightTime = this._chartViewport.pixelToTime(x + accurracyOffsetPx);
995 const left = this._markerIndexBeforeTime(leftTime);
996 let markerIndex = -1;
Jan Scheffler87dd9142021-02-27 21:19:48997 let distance: number = Infinity;
Blink Reformat4c46d092018-04-07 15:32:37998 for (let i = left; i < markers.length && markers[i].startTime() < rightTime; i++) {
999 const nextDistance = Math.abs(markers[i].startTime() - time);
1000 if (nextDistance < distance) {
1001 markerIndex = i;
1002 distance = nextDistance;
1003 }
1004 }
1005 return markerIndex;
1006 }
1007
Jan Scheffler87dd9142021-02-27 21:19:481008 _markerIndexBeforeTime(time: number): number {
Paul Lewiscf1f8a42020-11-04 21:05:241009 const timelineData = this._timelineData();
1010 if (!timelineData) {
1011 throw new Error('No timeline data');
1012 }
1013
1014 const markers = timelineData.markers;
1015 if (!markers) {
1016 throw new Error('No timeline markers');
1017 }
1018
Tim van der Lippe8958caa2021-01-25 15:41:211019 return Platform.ArrayUtilities.lowerBound(
1020 timelineData.markers, time, (markerTimestamp, marker) => markerTimestamp - marker.startTime());
Blink Reformat4c46d092018-04-07 15:32:371021 }
1022
Jan Scheffler87dd9142021-02-27 21:19:481023 _draw(): void {
Blink Reformat4c46d092018-04-07 15:32:371024 const timelineData = this._timelineData();
Tim van der Lippe1d6e57a2019-09-30 11:55:341025 if (!timelineData) {
Blink Reformat4c46d092018-04-07 15:32:371026 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341027 }
Blink Reformat4c46d092018-04-07 15:32:371028
Tim van der Lippecbdf5f22021-01-25 11:53:521029 const visibleLevelOffsets = this._visibleLevelOffsets ? this._visibleLevelOffsets : new Uint32Array();
Paul Lewiscf1f8a42020-11-04 21:05:241030
Blink Reformat4c46d092018-04-07 15:32:371031 const width = this._offsetWidth;
1032 const height = this._offsetHeight;
Jan Scheffler87dd9142021-02-27 21:19:481033 const context = (this._canvas.getContext('2d') as CanvasRenderingContext2D);
Blink Reformat4c46d092018-04-07 15:32:371034 context.save();
1035 const ratio = window.devicePixelRatio;
1036 const top = this._chartViewport.scrollOffset();
1037 context.scale(ratio, ratio);
Alexei Filippov57ccafb2018-08-14 20:59:051038 context.fillStyle = 'rgba(0, 0, 0, 0)';
1039 context.fillRect(0, 0, width, height);
Blink Reformat4c46d092018-04-07 15:32:371040 context.translate(0, -top);
Tim van der Lippebb769172020-02-12 15:32:441041 const defaultFont = '11px ' + Host.Platform.fontFamily();
Blink Reformat4c46d092018-04-07 15:32:371042 context.font = defaultFont;
1043
Paul Lewis49b16822020-02-21 14:22:031044 const candyStripePattern = context.createPattern(this._candyStripeCanvas, 'repeat');
1045
Blink Reformat4c46d092018-04-07 15:32:371046 const entryTotalTimes = timelineData.entryTotalTimes;
1047 const entryStartTimes = timelineData.entryStartTimes;
1048 const entryLevels = timelineData.entryLevels;
1049 const timeToPixel = this._chartViewport.timeToPixel();
1050
1051 const titleIndices = [];
1052 const markerIndices = [];
1053 const textPadding = this._textPadding;
Mathias Bynens23ee1aa2020-03-02 12:06:381054 const minTextWidth = 2 * textPadding + UI.UIUtils.measureTextWidth(context, '…');
Alexei Filippov57ccafb2018-08-14 20:59:051055 const minTextWidthDuration = this._chartViewport.pixelToTimeOffset(minTextWidth);
Tim van der Lippecbdf5f22021-01-25 11:53:521056 const minVisibleBarLevel = Math.max(
1057 Platform.ArrayUtilities.upperBound(visibleLevelOffsets, top, Platform.ArrayUtilities.DEFAULT_COMPARATOR) - 1,
1058 0);
Alexei Filippov6c622e92018-11-10 02:13:591059 this._markerPositions.clear();
Blink Reformat4c46d092018-04-07 15:32:371060
Paul Lewis49b16822020-02-21 14:22:031061 let mainThreadTopLevel = -1;
1062
1063 // Find the main thread so that we can mark tasks longer than 50ms.
1064 if ('groups' in timelineData && Array.isArray(timelineData.groups)) {
Tim van der Lippe5adc1e02020-11-20 12:30:121065 const mainThread = timelineData.groups.find(group => {
1066 if (!group.track) {
Paul Lewis49b16822020-02-21 14:22:031067 return false;
1068 }
1069
Tim van der Lippe5adc1e02020-11-20 12:30:121070 return group.track.name === 'CrRendererMain';
Paul Lewis49b16822020-02-21 14:22:031071 });
1072
1073 if (mainThread) {
1074 mainThreadTopLevel = mainThread.startLevel;
1075 }
1076 }
1077
Jan Scheffler87dd9142021-02-27 21:19:481078 const colorBuckets = new Map<string, {
1079 indexes: number[],
1080 }>();
Blink Reformat4c46d092018-04-07 15:32:371081 for (let level = minVisibleBarLevel; level < this._dataProvider.maxStackDepth(); ++level) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341082 if (this._levelToOffset(level) > top + height) {
Blink Reformat4c46d092018-04-07 15:32:371083 break;
Tim van der Lippe1d6e57a2019-09-30 11:55:341084 }
Paul Lewiscf1f8a42020-11-04 21:05:241085 if (!this._visibleLevels || !this._visibleLevels[level]) {
1086 continue;
1087 }
1088 if (!this._timelineLevels) {
Blink Reformat4c46d092018-04-07 15:32:371089 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341090 }
Blink Reformat4c46d092018-04-07 15:32:371091
1092 // Entries are ordered by start time within a level, so find the last visible entry.
1093 const levelIndexes = this._timelineLevels[level];
Tim van der Lippe8958caa2021-01-25 15:41:211094 const rightIndexOnLevel = Platform.ArrayUtilities.lowerBound(
1095 levelIndexes, this._chartViewport.windowRightTime(),
1096 (time, entryIndex) => time - entryStartTimes[entryIndex]) -
Blink Reformat4c46d092018-04-07 15:32:371097 1;
1098 let lastDrawOffset = Infinity;
1099 for (let entryIndexOnLevel = rightIndexOnLevel; entryIndexOnLevel >= 0; --entryIndexOnLevel) {
1100 const entryIndex = levelIndexes[entryIndexOnLevel];
Alexei Filippov72d792d2018-11-06 07:15:041101 const duration = entryTotalTimes[entryIndex];
1102 if (isNaN(duration)) {
Alexei Filippov57ccafb2018-08-14 20:59:051103 markerIndices.push(entryIndex);
Alexei Filippov72d792d2018-11-06 07:15:041104 continue;
1105 }
Paul Lewiscf1f8a42020-11-04 21:05:241106 if (duration >= minTextWidthDuration ||
1107 (this._forceDecorationCache && this._forceDecorationCache[entryIndex])) {
Alexei Filippov57ccafb2018-08-14 20:59:051108 titleIndices.push(entryIndex);
Tim van der Lippe1d6e57a2019-09-30 11:55:341109 }
Alexei Filippov57ccafb2018-08-14 20:59:051110
Blink Reformat4c46d092018-04-07 15:32:371111 const entryStartTime = entryStartTimes[entryIndex];
Alexei Filippov57ccafb2018-08-14 20:59:051112 const entryOffsetRight = entryStartTime + duration;
Tim van der Lippe1d6e57a2019-09-30 11:55:341113 if (entryOffsetRight <= this._chartViewport.windowLeftTime()) {
Blink Reformat4c46d092018-04-07 15:32:371114 break;
Tim van der Lippe1d6e57a2019-09-30 11:55:341115 }
1116 if (this._useWebGL) {
Alexei Filippov57ccafb2018-08-14 20:59:051117 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341118 }
Blink Reformat4c46d092018-04-07 15:32:371119
1120 const barX = this._timeToPositionClipped(entryStartTime);
1121 // 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:341122 if (barX >= lastDrawOffset) {
Blink Reformat4c46d092018-04-07 15:32:371123 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341124 }
Blink Reformat4c46d092018-04-07 15:32:371125 lastDrawOffset = barX;
1126
Paul Lewiscf1f8a42020-11-04 21:05:241127 if (this._entryColorsCache) {
1128 const color = this._entryColorsCache[entryIndex];
1129 let bucket = colorBuckets.get(color);
1130 if (!bucket) {
1131 bucket = {indexes: []};
1132 colorBuckets.set(color, bucket);
1133 }
1134 bucket.indexes.push(entryIndex);
Blink Reformat4c46d092018-04-07 15:32:371135 }
Blink Reformat4c46d092018-04-07 15:32:371136 }
1137 }
1138
Alexei Filippov57ccafb2018-08-14 20:59:051139 if (this._useWebGL) {
1140 this._drawGL();
1141 } else {
1142 context.save();
Alexei Filippov5f6b11d2018-08-18 03:30:281143 this._forEachGroupInViewport((offset, index, group, isFirst, groupHeight) => {
Anubha Mathur72dd5822019-06-13 23:05:191144 if (this._isGroupFocused(index)) {
Alexei Filippov57ccafb2018-08-14 20:59:051145 context.fillStyle = this._selectedGroupBackroundColor;
1146 context.fillRect(0, offset, width, groupHeight - group.style.padding);
Blink Reformat4c46d092018-04-07 15:32:371147 }
Alexei Filippov57ccafb2018-08-14 20:59:051148 });
1149 context.restore();
1150
Paul Lewis06985d42020-04-30 14:51:161151 for (const [color, {indexes}] of colorBuckets) {
Alexei Filippov57ccafb2018-08-14 20:59:051152 context.beginPath();
1153 for (let i = 0; i < indexes.length; ++i) {
1154 const entryIndex = indexes[i];
Alexei Filippov72d792d2018-11-06 07:15:041155 const duration = entryTotalTimes[entryIndex];
Tim van der Lippe1d6e57a2019-09-30 11:55:341156 if (isNaN(duration)) {
Alexei Filippov72d792d2018-11-06 07:15:041157 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341158 }
Alexei Filippov57ccafb2018-08-14 20:59:051159 const entryStartTime = entryStartTimes[entryIndex];
1160 const barX = this._timeToPositionClipped(entryStartTime);
Alexei Filippov57ccafb2018-08-14 20:59:051161 const barLevel = entryLevels[entryIndex];
1162 const barHeight = this._levelHeight(barLevel);
1163 const barY = this._levelToOffset(barLevel);
Alexei Filippov57ccafb2018-08-14 20:59:051164 const barRight = this._timeToPositionClipped(entryStartTime + duration);
1165 const barWidth = Math.max(barRight - barX, 1);
Alexei Filippov72d792d2018-11-06 07:15:041166 context.rect(barX, barY, barWidth - 0.4, barHeight - 1);
Alexei Filippov57ccafb2018-08-14 20:59:051167 }
Alexei Filippov57ccafb2018-08-14 20:59:051168 context.fillStyle = color;
1169 context.fill();
Paul Lewis49b16822020-02-21 14:22:031170
1171 // Draw long task regions.
1172 context.beginPath();
1173 for (let i = 0; i < indexes.length; ++i) {
1174 const entryIndex = indexes[i];
1175 const duration = entryTotalTimes[entryIndex];
Paul Lewis06985d42020-04-30 14:51:161176 const showLongDurations = entryLevels[entryIndex] === mainThreadTopLevel;
Paul Lewis49b16822020-02-21 14:22:031177
1178 if (!showLongDurations) {
1179 continue;
1180 }
1181
Paul Lewis06985d42020-04-30 14:51:161182 if (isNaN(duration) || duration < 50) {
Paul Lewis49b16822020-02-21 14:22:031183 continue;
1184 }
1185
1186 const entryStartTime = entryStartTimes[entryIndex];
1187 const barX = this._timeToPositionClipped(entryStartTime + 50);
1188 const barLevel = entryLevels[entryIndex];
1189 const barHeight = this._levelHeight(barLevel);
1190 const barY = this._levelToOffset(barLevel);
1191 const barRight = this._timeToPositionClipped(entryStartTime + duration);
1192 const barWidth = Math.max(barRight - barX, 1);
1193 context.rect(barX, barY, barWidth - 0.4, barHeight - 1);
1194 }
1195
Paul Lewiscf1f8a42020-11-04 21:05:241196 if (candyStripePattern) {
1197 context.fillStyle = candyStripePattern;
1198 context.fill();
1199 }
Blink Reformat4c46d092018-04-07 15:32:371200 }
Blink Reformat4c46d092018-04-07 15:32:371201 }
1202
Alexei Filippov72d792d2018-11-06 07:15:041203 context.textBaseline = 'alphabetic';
Blink Reformat4c46d092018-04-07 15:32:371204 context.beginPath();
Alexei Filippov6c622e92018-11-10 02:13:591205 let lastMarkerLevel = -1;
Jan Scheffler87dd9142021-02-27 21:19:481206 let lastMarkerX: number = -Infinity;
Alexei Filippov6c622e92018-11-10 02:13:591207 // Markers are sorted top to bottom, right to left.
Alexei Filippov72d792d2018-11-06 07:15:041208 for (let m = markerIndices.length - 1; m >= 0; --m) {
Blink Reformat4c46d092018-04-07 15:32:371209 const entryIndex = markerIndices[m];
Alexei Filippov72d792d2018-11-06 07:15:041210 const title = this._dataProvider.entryTitle(entryIndex);
Tim van der Lippe1d6e57a2019-09-30 11:55:341211 if (!title) {
Alexei Filippov72d792d2018-11-06 07:15:041212 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341213 }
Alexei Filippov6c622e92018-11-10 02:13:591214 const entryStartTime = entryStartTimes[entryIndex];
1215 const level = entryLevels[entryIndex];
Tim van der Lippe1d6e57a2019-09-30 11:55:341216 if (lastMarkerLevel !== level) {
Alexei Filippov6c622e92018-11-10 02:13:591217 lastMarkerX = -Infinity;
Tim van der Lippe1d6e57a2019-09-30 11:55:341218 }
Alexei Filippov6c622e92018-11-10 02:13:591219 const x = Math.max(this._chartViewport.timeToPosition(entryStartTime), lastMarkerX);
1220 const y = this._levelToOffset(level);
1221 const h = this._levelHeight(level);
1222 const padding = 4;
Tim van der Lippebb769172020-02-12 15:32:441223 const width = Math.ceil(UI.UIUtils.measureTextWidth(context, title)) + 2 * padding;
Alexei Filippov214df612018-11-13 19:14:001224 lastMarkerX = x + width + 1;
Alexei Filippov6c622e92018-11-10 02:13:591225 lastMarkerLevel = level;
1226 this._markerPositions.set(entryIndex, {x, width});
Alexei Filippov72d792d2018-11-06 07:15:041227 context.fillStyle = this._dataProvider.entryColor(entryIndex);
1228 context.fillRect(x, y, width, h - 1);
1229 context.fillStyle = 'white';
Alexei Filippov72d792d2018-11-06 07:15:041230 context.fillText(title, x + padding, y + h - this._textBaseline);
Blink Reformat4c46d092018-04-07 15:32:371231 }
1232 context.strokeStyle = 'rgba(0, 0, 0, 0.2)';
1233 context.stroke();
1234
Blink Reformat4c46d092018-04-07 15:32:371235 for (let i = 0; i < titleIndices.length; ++i) {
1236 const entryIndex = titleIndices[i];
1237 const entryStartTime = entryStartTimes[entryIndex];
1238 const barX = this._timeToPositionClipped(entryStartTime);
1239 const barRight = Math.min(this._timeToPositionClipped(entryStartTime + entryTotalTimes[entryIndex]), width) + 1;
1240 const barWidth = barRight - barX;
1241 const barLevel = entryLevels[entryIndex];
1242 const barY = this._levelToOffset(barLevel);
1243 let text = this._dataProvider.entryTitle(entryIndex);
1244 if (text && text.length) {
1245 context.font = this._dataProvider.entryFont(entryIndex) || defaultFont;
Tim van der Lippebb769172020-02-12 15:32:441246 text = UI.UIUtils.trimTextMiddle(context, text, barWidth - 2 * textPadding);
Blink Reformat4c46d092018-04-07 15:32:371247 }
1248 const unclippedBarX = this._chartViewport.timeToPosition(entryStartTime);
1249 const barHeight = this._levelHeight(barLevel);
1250 if (this._dataProvider.decorateEntry(
Tim van der Lippe1d6e57a2019-09-30 11:55:341251 entryIndex, context, text, barX, barY, barWidth, barHeight, unclippedBarX, timeToPixel)) {
Blink Reformat4c46d092018-04-07 15:32:371252 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341253 }
1254 if (!text || !text.length) {
Blink Reformat4c46d092018-04-07 15:32:371255 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341256 }
Blink Reformat4c46d092018-04-07 15:32:371257 context.fillStyle = this._dataProvider.textColor(entryIndex);
1258 context.fillText(text, barX + textPadding, barY + barHeight - this._textBaseline);
1259 }
1260
1261 context.restore();
1262
1263 this._drawGroupHeaders(width, height);
1264 this._drawFlowEvents(context, width, height);
1265 this._drawMarkers();
Paul Lewis2cfa94e2020-01-13 10:30:151266 const dividersData = TimelineGrid.calculateGridOffsets(this);
Paul Lewisead45752020-06-23 09:51:361267 const navStartTimes = Array.from(this._dataProvider.navStartTimes().values());
1268
1269 let navStartTimeIndex = 0;
Jan Scheffler87dd9142021-02-27 21:19:481270 const drawAdjustedTime = (time: number): string => {
Paul Lewisead45752020-06-23 09:51:361271 if (navStartTimes.length === 0) {
1272 return this.formatValue(time, dividersData.precision);
1273 }
1274
1275 // Track when the time crosses the boundary to the next nav start record,
1276 // and when it does, move the nav start array index accordingly.
1277 const hasNextNavStartTime = navStartTimes.length > navStartTimeIndex + 1;
1278 if (hasNextNavStartTime && time > navStartTimes[navStartTimeIndex + 1].startTime) {
1279 navStartTimeIndex++;
1280 }
1281
1282 // Adjust the time by the nearest nav start marker's value.
1283 const nearestMarker = navStartTimes[navStartTimeIndex];
1284 if (nearestMarker) {
1285 time -= nearestMarker.startTime - this.zeroTime();
1286 }
1287
1288 return this.formatValue(time, dividersData.precision);
1289 };
1290
Paul Lewis2cfa94e2020-01-13 10:30:151291 TimelineGrid.drawCanvasGrid(context, dividersData);
Blink Reformat4c46d092018-04-07 15:32:371292 if (this._rulerEnabled) {
Paul Lewisead45752020-06-23 09:51:361293 TimelineGrid.drawCanvasHeaders(context, dividersData, drawAdjustedTime, 3, HeaderHeight);
Blink Reformat4c46d092018-04-07 15:32:371294 }
1295
1296 this._updateElementPosition(this._highlightElement, this._highlightedEntryIndex);
1297 this._updateElementPosition(this._selectedElement, this._selectedEntryIndex);
1298 this._updateMarkerHighlight();
1299 }
1300
Jan Scheffler87dd9142021-02-27 21:19:481301 _initWebGL(): void {
1302 const gl = (this._canvasGL.getContext('webgl') as WebGLRenderingContext | null);
Alexei Filippov57ccafb2018-08-14 20:59:051303 if (!gl) {
1304 console.error('Failed to obtain WebGL context.');
1305 this._useWebGL = false; // Fallback to use canvas.
1306 return;
1307 }
1308
1309 const vertexShaderSource = `
Jan Scheffler87dd9142021-02-27 21:19:481310 attribute vec2 aVertexPosition;
1311 attribute float aVertexColor;
Alexei Filippov57ccafb2018-08-14 20:59:051312
Jan Scheffler87dd9142021-02-27 21:19:481313 uniform vec2 uScalingFactor;
1314 uniform vec2 uShiftVector;
Alexei Filippov57ccafb2018-08-14 20:59:051315
Jan Scheffler87dd9142021-02-27 21:19:481316 varying mediump vec2 vPalettePosition;
Alexei Filippov57ccafb2018-08-14 20:59:051317
Jan Scheffler87dd9142021-02-27 21:19:481318 void main() {
1319 vec2 shiftedPosition = aVertexPosition - uShiftVector;
1320 gl_Position = vec4(shiftedPosition * uScalingFactor + vec2(-1.0, 1.0), 0.0, 1.0);
1321 vPalettePosition = vec2(aVertexColor, 0.5);
1322 }`;
Alexei Filippov57ccafb2018-08-14 20:59:051323
1324 const fragmentShaderSource = `
Jan Scheffler87dd9142021-02-27 21:19:481325 varying mediump vec2 vPalettePosition;
1326 uniform sampler2D uSampler;
Alexei Filippov57ccafb2018-08-14 20:59:051327
Jan Scheffler87dd9142021-02-27 21:19:481328 void main() {
1329 gl_FragColor = texture2D(uSampler, vPalettePosition);
1330 }`;
Alexei Filippov57ccafb2018-08-14 20:59:051331
Jan Scheffler87dd9142021-02-27 21:19:481332 function loadShader(gl: WebGLRenderingContext, type: number, source: string): WebGLShader|null {
Alexei Filippov57ccafb2018-08-14 20:59:051333 const shader = gl.createShader(type);
Paul Lewiscf1f8a42020-11-04 21:05:241334 if (!shader) {
1335 return null;
1336 }
1337
Alexei Filippov57ccafb2018-08-14 20:59:051338 gl.shaderSource(shader, source);
1339 gl.compileShader(shader);
Tim van der Lippe1d6e57a2019-09-30 11:55:341340 if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
Alexei Filippov57ccafb2018-08-14 20:59:051341 return shader;
Tim van der Lippe1d6e57a2019-09-30 11:55:341342 }
Alexei Filippov57ccafb2018-08-14 20:59:051343 console.error('Shader compile error: ' + gl.getShaderInfoLog(shader));
1344 gl.deleteShader(shader);
1345 return null;
1346 }
1347
1348 const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
1349 const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
1350
1351 const shaderProgram = gl.createProgram();
Paul Lewiscf1f8a42020-11-04 21:05:241352 if (!shaderProgram || !vertexShader || !fragmentShader) {
1353 return;
1354 }
Alexei Filippov57ccafb2018-08-14 20:59:051355 gl.attachShader(shaderProgram, vertexShader);
1356 gl.attachShader(shaderProgram, fragmentShader);
1357 gl.linkProgram(shaderProgram);
1358
1359 if (gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
1360 this._shaderProgram = shaderProgram;
1361 gl.useProgram(shaderProgram);
1362 } else {
Alexei Filippov57ccafb2018-08-14 20:59:051363 this._shaderProgram = null;
Paul Lewiscf1f8a42020-11-04 21:05:241364 throw new Error('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
Alexei Filippov57ccafb2018-08-14 20:59:051365 }
Alexei Filippovaf3ffed2018-08-18 01:56:091366
1367 this._vertexBuffer = gl.createBuffer();
1368 this._colorBuffer = gl.createBuffer();
1369
1370 this._uScalingFactor = gl.getUniformLocation(shaderProgram, 'uScalingFactor');
1371 this._uShiftVector = gl.getUniformLocation(shaderProgram, 'uShiftVector');
1372 const uSampler = gl.getUniformLocation(shaderProgram, 'uSampler');
1373 gl.uniform1i(uSampler, 0);
1374 this._aVertexPosition = gl.getAttribLocation(this._shaderProgram, 'aVertexPosition');
1375 this._aVertexColor = gl.getAttribLocation(this._shaderProgram, 'aVertexColor');
1376 gl.enableVertexAttribArray(this._aVertexPosition);
1377 gl.enableVertexAttribArray(this._aVertexColor);
Alexei Filippov57ccafb2018-08-14 20:59:051378 }
1379
Jan Scheffler87dd9142021-02-27 21:19:481380 _setupGLGeometry(): void {
1381 const gl = (this._canvasGL.getContext('webgl') as WebGLRenderingContext | null);
Tim van der Lippe1d6e57a2019-09-30 11:55:341382 if (!gl) {
Alexei Filippov57ccafb2018-08-14 20:59:051383 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341384 }
Alexei Filippov57ccafb2018-08-14 20:59:051385
1386 const timelineData = this._timelineData();
Tim van der Lippe1d6e57a2019-09-30 11:55:341387 if (!timelineData) {
Alexei Filippov57ccafb2018-08-14 20:59:051388 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341389 }
Alexei Filippov57ccafb2018-08-14 20:59:051390
1391 const entryTotalTimes = timelineData.entryTotalTimes;
1392 const entryStartTimes = timelineData.entryStartTimes;
1393 const entryLevels = timelineData.entryLevels;
1394
Alexei Filippovaf3ffed2018-08-18 01:56:091395 const verticesPerBar = 6;
1396 const vertexArray = new Float32Array(entryTotalTimes.length * verticesPerBar * 2);
1397 let colorArray = new Uint8Array(entryTotalTimes.length * verticesPerBar);
Alexei Filippov57ccafb2018-08-14 20:59:051398 let vertex = 0;
Jan Scheffler87dd9142021-02-27 21:19:481399 const parsedColorCache = new Map<string, number>();
1400 const colors: number[] = [];
Alexei Filippovaf3ffed2018-08-18 01:56:091401
Paul Lewiscf1f8a42020-11-04 21:05:241402 const visibleLevels = this._visibleLevels || [];
1403 const rawTimelineData = this._rawTimelineData || {groups: []};
1404
1405 const collapsedOverviewLevels = new Array(visibleLevels.length);
1406 const groups = rawTimelineData.groups || [];
Alexei Filippov5f6b11d2018-08-18 03:30:281407 this._forEachGroup((offset, index, group) => {
Tim van der Lippe1d6e57a2019-09-30 11:55:341408 if (group.style.useFirstLineForOverview || !this._isGroupCollapsible(index) || group.expanded) {
Alexei Filippov5f6b11d2018-08-18 03:30:281409 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341410 }
Alexei Filippov5f6b11d2018-08-18 03:30:281411 let nextGroup = index + 1;
Tim van der Lippe1d6e57a2019-09-30 11:55:341412 while (nextGroup < groups.length && groups[nextGroup].style.nestingLevel > group.style.nestingLevel) {
Alexei Filippov5f6b11d2018-08-18 03:30:281413 ++nextGroup;
Tim van der Lippe1d6e57a2019-09-30 11:55:341414 }
Alexei Filippov5f6b11d2018-08-18 03:30:281415 const endLevel = nextGroup < groups.length ? groups[nextGroup].startLevel : this._dataProvider.maxStackDepth();
Tim van der Lippe1d6e57a2019-09-30 11:55:341416 for (let i = group.startLevel; i < endLevel; ++i) {
Alexei Filippov5f6b11d2018-08-18 03:30:281417 collapsedOverviewLevels[i] = offset;
Tim van der Lippe1d6e57a2019-09-30 11:55:341418 }
Alexei Filippov5f6b11d2018-08-18 03:30:281419 });
1420
Alexei Filippov57ccafb2018-08-14 20:59:051421 for (let i = 0; i < entryTotalTimes.length; ++i) {
1422 const level = entryLevels[i];
Alexei Filippov5f6b11d2018-08-18 03:30:281423 const collapsedGroupOffset = collapsedOverviewLevels[level];
Paul Lewiscf1f8a42020-11-04 21:05:241424 if (!visibleLevels[level] && !collapsedGroupOffset) {
Alexei Filippov57ccafb2018-08-14 20:59:051425 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341426 }
Paul Lewiscf1f8a42020-11-04 21:05:241427 if (!this._entryColorsCache) {
1428 continue;
1429 }
1430
Alexei Filippove5197622018-08-18 03:04:331431 const color = this._entryColorsCache[i];
Tim van der Lippe1d6e57a2019-09-30 11:55:341432 if (!color) {
Alexei Filippov57ccafb2018-08-14 20:59:051433 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341434 }
Alexei Filippovaf3ffed2018-08-18 01:56:091435 let colorIndex = parsedColorCache.get(color);
1436 if (colorIndex === undefined) {
Paul Lewiscf1f8a42020-11-04 21:05:241437 const parsedColor = Common.Color.Color.parse(color);
1438 if (parsedColor) {
1439 const rgba = parsedColor.canonicalRGBA();
1440 rgba[3] = Math.round(rgba[3] * 255);
1441 colorIndex = colors.length / 4;
1442 colors.push(...rgba);
1443 if (colorIndex === 256) {
1444 colorArray = new Uint8Array(colorArray);
1445 }
Tim van der Lippe1d6e57a2019-09-30 11:55:341446 }
Paul Lewiscf1f8a42020-11-04 21:05:241447
1448 if (colorIndex) {
1449 parsedColorCache.set(color, colorIndex);
1450 }
Alexei Filippovc34372c2018-08-16 20:37:391451 }
Tim van der Lippe1d6e57a2019-09-30 11:55:341452 for (let j = 0; j < verticesPerBar; ++j) {
Paul Lewiscf1f8a42020-11-04 21:05:241453 if (colorIndex) {
1454 colorArray[vertex + j] = colorIndex;
1455 }
Tim van der Lippe1d6e57a2019-09-30 11:55:341456 }
Alexei Filippov57ccafb2018-08-14 20:59:051457
1458 const vpos = vertex * 2;
1459 const x0 = entryStartTimes[i] - this._minimumBoundary;
1460 const x1 = x0 + entryTotalTimes[i];
Alexei Filippov5f6b11d2018-08-18 03:30:281461 const y0 = collapsedGroupOffset || this._levelToOffset(level);
Alexei Filippov57ccafb2018-08-14 20:59:051462 const y1 = y0 + this._levelHeight(level) - 1;
1463 vertexArray[vpos + 0] = x0;
1464 vertexArray[vpos + 1] = y0;
1465 vertexArray[vpos + 2] = x1;
1466 vertexArray[vpos + 3] = y0;
1467 vertexArray[vpos + 4] = x0;
1468 vertexArray[vpos + 5] = y1;
1469 vertexArray[vpos + 6] = x0;
1470 vertexArray[vpos + 7] = y1;
1471 vertexArray[vpos + 8] = x1;
1472 vertexArray[vpos + 9] = y0;
1473 vertexArray[vpos + 10] = x1;
1474 vertexArray[vpos + 11] = y1;
1475
Alexei Filippovaf3ffed2018-08-18 01:56:091476 vertex += verticesPerBar;
Alexei Filippov57ccafb2018-08-14 20:59:051477 }
Alexei Filippov57ccafb2018-08-14 20:59:051478 this._vertexCount = vertex;
1479
Alexei Filippovaf3ffed2018-08-18 01:56:091480 const paletteTexture = gl.createTexture();
1481 gl.bindTexture(gl.TEXTURE_2D, paletteTexture);
1482 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
1483 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
1484 gl.activeTexture(gl.TEXTURE0);
1485
1486 const numColors = colors.length / 4;
1487 const useShortForColors = numColors >= 256;
1488 const width = !useShortForColors ? 256 : Math.min(1 << 16, gl.getParameter(gl.MAX_TEXTURE_SIZE));
1489 console.assert(numColors <= width, 'Too many colors');
1490 const height = 1;
1491 const colorIndexType = useShortForColors ? gl.UNSIGNED_SHORT : gl.UNSIGNED_BYTE;
1492 if (useShortForColors) {
1493 const factor = (1 << 16) / width;
Tim van der Lippe1d6e57a2019-09-30 11:55:341494 for (let i = 0; i < vertex; ++i) {
Alexei Filippovaf3ffed2018-08-18 01:56:091495 colorArray[i] *= factor;
Tim van der Lippe1d6e57a2019-09-30 11:55:341496 }
Alexei Filippovaf3ffed2018-08-18 01:56:091497 }
1498
1499 const pixels = new Uint8Array(width * 4);
1500 pixels.set(colors);
1501 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
1502
Paul Lewiscf1f8a42020-11-04 21:05:241503 if (this._vertexBuffer && this._aVertexPosition) {
1504 gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer);
1505 gl.bufferData(gl.ARRAY_BUFFER, vertexArray, gl.STATIC_DRAW);
1506 gl.vertexAttribPointer(this._aVertexPosition, /* vertexComponents */ 2, gl.FLOAT, false, 0, 0);
1507 }
Alexei Filippov57ccafb2018-08-14 20:59:051508
Paul Lewiscf1f8a42020-11-04 21:05:241509 if (this._colorBuffer && this._aVertexColor) {
1510 gl.bindBuffer(gl.ARRAY_BUFFER, this._colorBuffer);
1511 gl.bufferData(gl.ARRAY_BUFFER, colorArray, gl.STATIC_DRAW);
1512 gl.vertexAttribPointer(this._aVertexColor, /* colorComponents */ 1, colorIndexType, true, 0, 0);
1513 }
Alexei Filippov57ccafb2018-08-14 20:59:051514 }
1515
Jan Scheffler87dd9142021-02-27 21:19:481516 _drawGL(): void {
1517 const gl = (this._canvasGL.getContext('webgl') as WebGLRenderingContext | null);
Tim van der Lippe1d6e57a2019-09-30 11:55:341518 if (!gl) {
Alexei Filippov57ccafb2018-08-14 20:59:051519 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341520 }
Alexei Filippov57ccafb2018-08-14 20:59:051521 const timelineData = this._timelineData();
Tim van der Lippe1d6e57a2019-09-30 11:55:341522 if (!timelineData) {
Alexei Filippov57ccafb2018-08-14 20:59:051523 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341524 }
Alexei Filippov57ccafb2018-08-14 20:59:051525
Alexei Filippov57ccafb2018-08-14 20:59:051526 if (!this._prevTimelineData || timelineData.entryTotalTimes !== this._prevTimelineData.entryTotalTimes) {
1527 this._prevTimelineData = timelineData;
1528 this._setupGLGeometry();
1529 }
1530
Alexei Filippovc34372c2018-08-16 20:37:391531 gl.viewport(0, 0, this._canvasGL.width, this._canvasGL.height);
Alexei Filippov57ccafb2018-08-14 20:59:051532
Tim van der Lippe1d6e57a2019-09-30 11:55:341533 if (!this._vertexCount) {
Alexei Filippov57ccafb2018-08-14 20:59:051534 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341535 }
Alexei Filippov57ccafb2018-08-14 20:59:051536
Alexei Filippovc34372c2018-08-16 20:37:391537 const viewportScale = [2.0 / this.boundarySpan(), -2.0 * window.devicePixelRatio / this._canvasGL.height];
1538 const viewportShift = [this.minimumBoundary() - this.zeroTime(), this._chartViewport.scrollOffset()];
Paul Lewiscf1f8a42020-11-04 21:05:241539 if (this._uScalingFactor) {
1540 gl.uniform2fv(this._uScalingFactor, viewportScale);
1541 }
1542
1543 if (this._uShiftVector) {
1544 gl.uniform2fv(this._uShiftVector, viewportShift);
1545 }
Alexei Filippov57ccafb2018-08-14 20:59:051546
1547 gl.drawArrays(gl.TRIANGLES, 0, this._vertexCount);
1548 }
1549
Jan Scheffler87dd9142021-02-27 21:19:481550 _drawGroupHeaders(width: number, height: number): void {
1551 const context = (this._canvas.getContext('2d') as CanvasRenderingContext2D);
Blink Reformat4c46d092018-04-07 15:32:371552 const top = this._chartViewport.scrollOffset();
1553 const ratio = window.devicePixelRatio;
Paul Lewiscf1f8a42020-11-04 21:05:241554 if (!this._rawTimelineData) {
1555 return;
1556 }
1557
Blink Reformat4c46d092018-04-07 15:32:371558 const groups = this._rawTimelineData.groups || [];
Tim van der Lippe1d6e57a2019-09-30 11:55:341559 if (!groups.length) {
Blink Reformat4c46d092018-04-07 15:32:371560 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341561 }
Blink Reformat4c46d092018-04-07 15:32:371562
1563 const groupOffsets = this._groupOffsets;
Tim van der Lippe779b46b2021-01-13 13:40:221564 if (groupOffsets === null || groupOffsets === undefined) {
1565 return;
1566 }
1567 const lastGroupOffset = groupOffsets[groupOffsets.length - 1];
Paul Lewisca569a52020-09-09 16:11:511568 const colorUsage = ThemeSupport.ThemeSupport.ColorUsage;
Blink Reformat4c46d092018-04-07 15:32:371569
1570 context.save();
1571 context.scale(ratio, ratio);
1572 context.translate(0, -top);
Tim van der Lippebb769172020-02-12 15:32:441573 const defaultFont = '11px ' + Host.Platform.fontFamily();
Blink Reformat4c46d092018-04-07 15:32:371574 context.font = defaultFont;
1575
Paul Lewisca569a52020-09-09 16:11:511576 context.fillStyle = ThemeSupport.ThemeSupport.instance().patchColorText('#fff', colorUsage.Background);
Alexei Filippov5f6b11d2018-08-18 03:30:281577 this._forEachGroupInViewport((offset, index, group) => {
Blink Reformat4c46d092018-04-07 15:32:371578 const paddingHeight = group.style.padding;
Tim van der Lippe1d6e57a2019-09-30 11:55:341579 if (paddingHeight < 5) {
Blink Reformat4c46d092018-04-07 15:32:371580 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341581 }
Blink Reformat4c46d092018-04-07 15:32:371582 context.fillRect(0, offset - paddingHeight + 2, width, paddingHeight - 4);
1583 });
Tim van der Lippe1d6e57a2019-09-30 11:55:341584 if (groups.length && lastGroupOffset < top + height) {
Blink Reformat4c46d092018-04-07 15:32:371585 context.fillRect(0, lastGroupOffset + 2, width, top + height - lastGroupOffset);
Tim van der Lippe1d6e57a2019-09-30 11:55:341586 }
Blink Reformat4c46d092018-04-07 15:32:371587
Paul Lewisca569a52020-09-09 16:11:511588 context.strokeStyle = ThemeSupport.ThemeSupport.instance().patchColorText('#eee', colorUsage.Background);
Blink Reformat4c46d092018-04-07 15:32:371589 context.beginPath();
Alexei Filippov5f6b11d2018-08-18 03:30:281590 this._forEachGroupInViewport((offset, index, group, isFirst) => {
Tim van der Lippe1d6e57a2019-09-30 11:55:341591 if (isFirst || group.style.padding < 4) {
Blink Reformat4c46d092018-04-07 15:32:371592 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341593 }
Blink Reformat4c46d092018-04-07 15:32:371594 hLine(offset - 2.5);
1595 });
1596 hLine(lastGroupOffset + 1.5);
1597 context.stroke();
1598
Alexei Filippov5f6b11d2018-08-18 03:30:281599 this._forEachGroupInViewport((offset, index, group) => {
Tim van der Lippe1d6e57a2019-09-30 11:55:341600 if (group.style.useFirstLineForOverview) {
Blink Reformat4c46d092018-04-07 15:32:371601 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341602 }
Blink Reformat4c46d092018-04-07 15:32:371603 if (!this._isGroupCollapsible(index) || group.expanded) {
Anubha Mathur72dd5822019-06-13 23:05:191604 if (!group.style.shareHeaderLine && this._isGroupFocused(index)) {
Blink Reformat4c46d092018-04-07 15:32:371605 context.fillStyle = group.style.backgroundColor;
1606 context.fillRect(0, offset, width, group.style.height);
1607 }
1608 return;
1609 }
Tim van der Lippe1d6e57a2019-09-30 11:55:341610 if (this._useWebGL) {
Alexei Filippov5f6b11d2018-08-18 03:30:281611 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341612 }
Blink Reformat4c46d092018-04-07 15:32:371613 let nextGroup = index + 1;
Tim van der Lippe1d6e57a2019-09-30 11:55:341614 while (nextGroup < groups.length && groups[nextGroup].style.nestingLevel > group.style.nestingLevel) {
Blink Reformat4c46d092018-04-07 15:32:371615 nextGroup++;
Tim van der Lippe1d6e57a2019-09-30 11:55:341616 }
Blink Reformat4c46d092018-04-07 15:32:371617 const endLevel = nextGroup < groups.length ? groups[nextGroup].startLevel : this._dataProvider.maxStackDepth();
Alexei Filippov23428d42018-04-28 01:09:071618 this._drawCollapsedOverviewForGroup(group, offset, endLevel);
Blink Reformat4c46d092018-04-07 15:32:371619 });
1620
1621 context.save();
Alexei Filippov5f6b11d2018-08-18 03:30:281622 this._forEachGroupInViewport((offset, index, group) => {
Blink Reformat4c46d092018-04-07 15:32:371623 context.font = group.style.font;
1624 if (this._isGroupCollapsible(index) && !group.expanded || group.style.shareHeaderLine) {
1625 const width = this._labelWidthForGroup(context, group) + 2;
Tim van der Lippe1d6e57a2019-09-30 11:55:341626 if (this._isGroupFocused(index)) {
Blink Reformat4c46d092018-04-07 15:32:371627 context.fillStyle = this._selectedGroupBackroundColor;
Tim van der Lippe1d6e57a2019-09-30 11:55:341628 } else {
Paul Lewiscf1f8a42020-11-04 21:05:241629 const parsedColor = Common.Color.Color.parse(group.style.backgroundColor);
1630 if (parsedColor) {
Jan Scheffler87dd9142021-02-27 21:19:481631 context.fillStyle = (parsedColor.setAlpha(0.8).asString(null) as string);
Paul Lewiscf1f8a42020-11-04 21:05:241632 }
Tim van der Lippe1d6e57a2019-09-30 11:55:341633 }
Blink Reformat4c46d092018-04-07 15:32:371634
1635 context.fillRect(
1636 this._headerLeftPadding - this._headerLabelXPadding, offset + this._headerLabelYPadding, width,
1637 group.style.height - 2 * this._headerLabelYPadding);
1638 }
1639 context.fillStyle = group.style.color;
1640 context.fillText(
1641 group.name, Math.floor(this._expansionArrowIndent * (group.style.nestingLevel + 1) + this._arrowSide),
1642 offset + group.style.height - this._textBaseline);
1643 });
1644 context.restore();
1645
Paul Lewisca569a52020-09-09 16:11:511646 context.fillStyle = ThemeSupport.ThemeSupport.instance().patchColorText('#6e6e6e', colorUsage.Foreground);
Blink Reformat4c46d092018-04-07 15:32:371647 context.beginPath();
Alexei Filippov5f6b11d2018-08-18 03:30:281648 this._forEachGroupInViewport((offset, index, group) => {
Blink Reformat4c46d092018-04-07 15:32:371649 if (this._isGroupCollapsible(index)) {
1650 drawExpansionArrow.call(
1651 this, this._expansionArrowIndent * (group.style.nestingLevel + 1),
Tim van der Lipped7cfd142021-01-07 12:17:241652 offset + group.style.height - this._textBaseline - this._arrowSide / 2, Boolean(group.expanded));
Blink Reformat4c46d092018-04-07 15:32:371653 }
1654 });
1655 context.fill();
1656
Paul Lewisca569a52020-09-09 16:11:511657 context.strokeStyle = ThemeSupport.ThemeSupport.instance().patchColorText('#ddd', colorUsage.Background);
Blink Reformat4c46d092018-04-07 15:32:371658 context.beginPath();
1659 context.stroke();
1660
Alexei Filippov5f6b11d2018-08-18 03:30:281661 this._forEachGroupInViewport((offset, index, group, isFirst, groupHeight) => {
Anubha Mathur72dd5822019-06-13 23:05:191662 if (this._isGroupFocused(index)) {
Alexei Filippov23428d42018-04-28 01:09:071663 const lineWidth = 2;
1664 const bracketLength = 10;
Blink Reformat4c46d092018-04-07 15:32:371665 context.fillStyle = this._selectedGroupBorderColor;
Alexei Filippov23428d42018-04-28 01:09:071666 context.fillRect(0, offset - lineWidth, lineWidth, groupHeight - group.style.padding + 2 * lineWidth);
1667 context.fillRect(0, offset - lineWidth, bracketLength, lineWidth);
1668 context.fillRect(0, offset + groupHeight - group.style.padding, bracketLength, lineWidth);
Blink Reformat4c46d092018-04-07 15:32:371669 }
1670 });
1671
1672 context.restore();
1673
Jan Scheffler87dd9142021-02-27 21:19:481674 function hLine(y: number): void {
Blink Reformat4c46d092018-04-07 15:32:371675 context.moveTo(0, y);
1676 context.lineTo(width, y);
1677 }
1678
Jan Scheffler87dd9142021-02-27 21:19:481679 function drawExpansionArrow(this: FlameChart, x: number, y: number, expanded: boolean): void {
Blink Reformat4c46d092018-04-07 15:32:371680 const arrowHeight = this._arrowSide * Math.sqrt(3) / 2;
1681 const arrowCenterOffset = Math.round(arrowHeight / 2);
1682 context.save();
1683 context.translate(x, y);
1684 context.rotate(expanded ? Math.PI / 2 : 0);
1685 context.moveTo(-arrowCenterOffset, -this._arrowSide / 2);
1686 context.lineTo(-arrowCenterOffset, this._arrowSide / 2);
1687 context.lineTo(arrowHeight - arrowCenterOffset, 0);
1688 context.restore();
1689 }
1690 }
1691
Jan Scheffler87dd9142021-02-27 21:19:481692 _forEachGroup(callback: (arg0: number, arg1: number, arg2: Group, arg3: boolean, arg4: number) => void): void {
Paul Lewiscf1f8a42020-11-04 21:05:241693 if (!this._rawTimelineData) {
1694 return;
1695 }
Blink Reformat4c46d092018-04-07 15:32:371696 const groups = this._rawTimelineData.groups || [];
Tim van der Lippe1d6e57a2019-09-30 11:55:341697 if (!groups.length) {
Blink Reformat4c46d092018-04-07 15:32:371698 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341699 }
Blink Reformat4c46d092018-04-07 15:32:371700 const groupOffsets = this._groupOffsets;
Paul Lewiscf1f8a42020-11-04 21:05:241701 if (!groupOffsets) {
1702 return;
1703 }
1704
Jan Scheffler87dd9142021-02-27 21:19:481705 const groupStack: {
1706 nestingLevel: number,
1707 visible: boolean,
1708 }[] = [{nestingLevel: -1, visible: true}];
Blink Reformat4c46d092018-04-07 15:32:371709 for (let i = 0; i < groups.length; ++i) {
1710 const groupTop = groupOffsets[i];
1711 const group = groups[i];
Blink Reformat4c46d092018-04-07 15:32:371712 let firstGroup = true;
Jan Scheffler87dd9142021-02-27 21:19:481713 let last: {
1714 nestingLevel: number,
1715 visible: boolean,
1716 } = groupStack[groupStack.length - 1];
Paul Lewiscf1f8a42020-11-04 21:05:241717 while (last && last.nestingLevel >= group.style.nestingLevel) {
Blink Reformat4c46d092018-04-07 15:32:371718 groupStack.pop();
1719 firstGroup = false;
Tim van der Lippe779b46b2021-01-13 13:40:221720 last = groupStack[groupStack.length - 1];
Blink Reformat4c46d092018-04-07 15:32:371721 }
Tim van der Lippe779b46b2021-01-13 13:40:221722 last = groupStack[groupStack.length - 1];
Paul Lewiscf1f8a42020-11-04 21:05:241723 const parentGroupVisible = last ? last.visible : false;
Blink Reformat4c46d092018-04-07 15:32:371724 const thisGroupVisible = parentGroupVisible && (!this._isGroupCollapsible(i) || group.expanded);
Tim van der Lipped7cfd142021-01-07 12:17:241725 groupStack.push({nestingLevel: group.style.nestingLevel, visible: Boolean(thisGroupVisible)});
Alexei Filippov23428d42018-04-28 01:09:071726 const nextOffset = i === groups.length - 1 ? groupOffsets[i + 1] + group.style.padding : groupOffsets[i + 1];
Tim van der Lippe1d6e57a2019-09-30 11:55:341727 if (!parentGroupVisible) {
Blink Reformat4c46d092018-04-07 15:32:371728 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341729 }
Blink Reformat4c46d092018-04-07 15:32:371730 callback(groupTop, i, group, firstGroup, nextOffset - groupTop);
1731 }
1732 }
1733
Jan Scheffler87dd9142021-02-27 21:19:481734 _forEachGroupInViewport(callback: (arg0: number, arg1: number, arg2: Group, arg3: boolean, arg4: number) => void):
1735 void {
Alexei Filippov5f6b11d2018-08-18 03:30:281736 const top = this._chartViewport.scrollOffset();
1737 this._forEachGroup((groupTop, index, group, firstGroup, height) => {
Tim van der Lippe1d6e57a2019-09-30 11:55:341738 if (groupTop - group.style.padding > top + this._offsetHeight) {
Alexei Filippov5f6b11d2018-08-18 03:30:281739 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341740 }
1741 if (groupTop + height < top) {
Alexei Filippov5f6b11d2018-08-18 03:30:281742 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341743 }
Alexei Filippov5f6b11d2018-08-18 03:30:281744 callback(groupTop, index, group, firstGroup, height);
1745 });
1746 }
1747
Jan Scheffler87dd9142021-02-27 21:19:481748 _labelWidthForGroup(context: CanvasRenderingContext2D, group: Group): number {
Tim van der Lippebb769172020-02-12 15:32:441749 return UI.UIUtils.measureTextWidth(context, group.name) +
1750 this._expansionArrowIndent * (group.style.nestingLevel + 1) + 2 * this._headerLabelXPadding;
Blink Reformat4c46d092018-04-07 15:32:371751 }
1752
Jan Scheffler87dd9142021-02-27 21:19:481753 _drawCollapsedOverviewForGroup(group: Group, y: number, endLevel: number): void {
Tim van der Lippebb769172020-02-12 15:32:441754 const range = new Common.SegmentedRange.SegmentedRange(mergeCallback);
Blink Reformat4c46d092018-04-07 15:32:371755 const timeWindowLeft = this._chartViewport.windowLeftTime();
1756 const timeWindowRight = this._chartViewport.windowRightTime();
Jan Scheffler87dd9142021-02-27 21:19:481757 const context = (this._canvas.getContext('2d') as CanvasRenderingContext2D);
Blink Reformat4c46d092018-04-07 15:32:371758 const barHeight = group.style.height;
Paul Lewiscf1f8a42020-11-04 21:05:241759 if (!this._rawTimelineData) {
1760 return;
1761 }
Blink Reformat4c46d092018-04-07 15:32:371762 const entryStartTimes = this._rawTimelineData.entryStartTimes;
1763 const entryTotalTimes = this._rawTimelineData.entryTotalTimes;
1764 const timeToPixel = this._chartViewport.timeToPixel();
1765
1766 for (let level = group.startLevel; level < endLevel; ++level) {
Jan Scheffler87dd9142021-02-27 21:19:481767 const levelIndexes: number[] = this._timelineLevels ? this._timelineLevels[level] : [];
Blink Reformat4c46d092018-04-07 15:32:371768 const rightIndexOnLevel =
Tim van der Lippe8958caa2021-01-25 15:41:211769 Platform.ArrayUtilities.lowerBound(
1770 levelIndexes, timeWindowRight, (time, entryIndex) => time - entryStartTimes[entryIndex]) -
1771 1;
Jan Scheffler87dd9142021-02-27 21:19:481772 let lastDrawOffset: number = Infinity;
Blink Reformat4c46d092018-04-07 15:32:371773
1774 for (let entryIndexOnLevel = rightIndexOnLevel; entryIndexOnLevel >= 0; --entryIndexOnLevel) {
1775 const entryIndex = levelIndexes[entryIndexOnLevel];
1776 const entryStartTime = entryStartTimes[entryIndex];
1777 const barX = this._timeToPositionClipped(entryStartTime);
1778 const entryEndTime = entryStartTime + entryTotalTimes[entryIndex];
Tim van der Lippe1d6e57a2019-09-30 11:55:341779 if (isNaN(entryEndTime) || barX >= lastDrawOffset) {
Blink Reformat4c46d092018-04-07 15:32:371780 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341781 }
1782 if (entryEndTime <= timeWindowLeft) {
Blink Reformat4c46d092018-04-07 15:32:371783 break;
Tim van der Lippe1d6e57a2019-09-30 11:55:341784 }
Blink Reformat4c46d092018-04-07 15:32:371785 lastDrawOffset = barX;
Paul Lewiscf1f8a42020-11-04 21:05:241786 const color = this._entryColorsCache ? this._entryColorsCache[entryIndex] : '';
Blink Reformat4c46d092018-04-07 15:32:371787 const endBarX = this._timeToPositionClipped(entryEndTime);
1788 if (group.style.useDecoratorsForOverview && this._dataProvider.forceDecoration(entryIndex)) {
1789 const unclippedBarX = this._chartViewport.timeToPosition(entryStartTime);
1790 const barWidth = endBarX - barX;
1791 context.beginPath();
1792 context.fillStyle = color;
1793 context.fillRect(barX, y, barWidth, barHeight - 1);
1794 this._dataProvider.decorateEntry(
1795 entryIndex, context, '', barX, y, barWidth, barHeight, unclippedBarX, timeToPixel);
1796 continue;
1797 }
Tim van der Lippebb769172020-02-12 15:32:441798 range.append(new Common.SegmentedRange.Segment(barX, endBarX, color));
Blink Reformat4c46d092018-04-07 15:32:371799 }
1800 }
1801
1802 const segments = range.segments().slice().sort((a, b) => a.data.localeCompare(b.data));
1803 let lastColor;
1804 context.beginPath();
1805 for (let i = 0; i < segments.length; ++i) {
1806 const segment = segments[i];
1807 if (lastColor !== segments[i].data) {
1808 context.fill();
1809 context.beginPath();
1810 lastColor = segments[i].data;
1811 context.fillStyle = lastColor;
1812 }
Alexei Filippov23428d42018-04-28 01:09:071813 context.rect(segment.begin, y, segment.end - segment.begin, barHeight);
Blink Reformat4c46d092018-04-07 15:32:371814 }
1815 context.fill();
1816
Jan Scheffler87dd9142021-02-27 21:19:481817 function mergeCallback(
1818 a: Common.SegmentedRange.Segment, b: Common.SegmentedRange.Segment): Common.SegmentedRange.Segment|null {
Blink Reformat4c46d092018-04-07 15:32:371819 return a.data === b.data && a.end + 0.4 > b.end ? a : null;
1820 }
1821 }
1822
Jan Scheffler87dd9142021-02-27 21:19:481823 _drawFlowEvents(context: CanvasRenderingContext2D, _width: number, _height: number): void {
Blink Reformat4c46d092018-04-07 15:32:371824 context.save();
1825 const ratio = window.devicePixelRatio;
1826 const top = this._chartViewport.scrollOffset();
1827 const arrowWidth = 6;
1828 context.scale(ratio, ratio);
1829 context.translate(0, -top);
1830
1831 context.fillStyle = '#7f5050';
1832 context.strokeStyle = '#7f5050';
1833 const td = this._timelineData();
Paul Lewiscf1f8a42020-11-04 21:05:241834 if (!td) {
1835 return;
1836 }
1837
Tim van der Lippe8958caa2021-01-25 15:41:211838 const endIndex = Platform.ArrayUtilities.lowerBound(
1839 td.flowStartTimes, this._chartViewport.windowRightTime(), Platform.ArrayUtilities.DEFAULT_COMPARATOR);
Blink Reformat4c46d092018-04-07 15:32:371840
1841 context.lineWidth = 0.5;
1842 for (let i = 0; i < endIndex; ++i) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341843 if (!td.flowEndTimes[i] || td.flowEndTimes[i] < this._chartViewport.windowLeftTime()) {
Blink Reformat4c46d092018-04-07 15:32:371844 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341845 }
Blink Reformat4c46d092018-04-07 15:32:371846 const startX = this._chartViewport.timeToPosition(td.flowStartTimes[i]);
1847 const endX = this._chartViewport.timeToPosition(td.flowEndTimes[i]);
1848 const startLevel = td.flowStartLevels[i];
1849 const endLevel = td.flowEndLevels[i];
1850 const startY = this._levelToOffset(startLevel) + this._levelHeight(startLevel) / 2;
1851 const endY = this._levelToOffset(endLevel) + this._levelHeight(endLevel) / 2;
1852
Blink Reformat4c46d092018-04-07 15:32:371853 const segment = Math.min((endX - startX) / 4, 40);
1854 const distanceTime = td.flowEndTimes[i] - td.flowStartTimes[i];
1855 const distanceY = (endY - startY) / 10;
1856 const spread = 30;
1857 const lineY = distanceTime < 1 ? startY : spread + Math.max(0, startY + distanceY * (i % spread));
1858
1859 const p = [];
1860 p.push({x: startX, y: startY});
1861 p.push({x: startX + arrowWidth, y: startY});
1862 p.push({x: startX + segment + 2 * arrowWidth, y: startY});
1863 p.push({x: startX + segment, y: lineY});
1864 p.push({x: startX + segment * 2, y: lineY});
1865 p.push({x: endX - segment * 2, y: lineY});
1866 p.push({x: endX - segment, y: lineY});
1867 p.push({x: endX - segment - 2 * arrowWidth, y: endY});
1868 p.push({x: endX - arrowWidth, y: endY});
1869
1870 context.beginPath();
1871 context.moveTo(p[0].x, p[0].y);
1872 context.lineTo(p[1].x, p[1].y);
1873 context.bezierCurveTo(p[2].x, p[2].y, p[3].x, p[3].y, p[4].x, p[4].y);
1874 context.lineTo(p[5].x, p[5].y);
1875 context.bezierCurveTo(p[6].x, p[6].y, p[7].x, p[7].y, p[8].x, p[8].y);
1876 context.stroke();
1877
1878 context.beginPath();
1879 context.arc(startX, startY, 2, -Math.PI / 2, Math.PI / 2, false);
1880 context.fill();
1881
1882 context.beginPath();
1883 context.moveTo(endX, endY);
1884 context.lineTo(endX - arrowWidth, endY - 3);
1885 context.lineTo(endX - arrowWidth, endY + 3);
1886 context.fill();
1887 }
1888 context.restore();
1889 }
1890
Jan Scheffler87dd9142021-02-27 21:19:481891 _drawMarkers(): void {
Paul Lewiscf1f8a42020-11-04 21:05:241892 const timelineData = this._timelineData();
1893 if (!timelineData) {
1894 return;
1895 }
1896 const markers = timelineData.markers;
Blink Reformat4c46d092018-04-07 15:32:371897 const left = this._markerIndexBeforeTime(this.minimumBoundary());
1898 const rightBoundary = this.maximumBoundary();
1899 const timeToPixel = this._chartViewport.timeToPixel();
1900
Jan Scheffler87dd9142021-02-27 21:19:481901 const context = (this._canvas.getContext('2d') as CanvasRenderingContext2D);
Blink Reformat4c46d092018-04-07 15:32:371902 context.save();
1903 const ratio = window.devicePixelRatio;
1904 context.scale(ratio, ratio);
1905 context.translate(0, 3);
Tim van der Lippefd2b2ce2020-01-03 15:05:181906 const height = HeaderHeight - 1;
Blink Reformat4c46d092018-04-07 15:32:371907 for (let i = left; i < markers.length; i++) {
1908 const timestamp = markers[i].startTime();
Tim van der Lippe1d6e57a2019-09-30 11:55:341909 if (timestamp > rightBoundary) {
Blink Reformat4c46d092018-04-07 15:32:371910 break;
Tim van der Lippe1d6e57a2019-09-30 11:55:341911 }
Blink Reformat4c46d092018-04-07 15:32:371912 markers[i].draw(context, this._chartViewport.timeToPosition(timestamp), height, timeToPixel);
1913 }
1914 context.restore();
1915 }
1916
Jan Scheffler87dd9142021-02-27 21:19:481917 _updateMarkerHighlight(): void {
Blink Reformat4c46d092018-04-07 15:32:371918 const element = this._markerHighlighElement;
Tim van der Lippe1d6e57a2019-09-30 11:55:341919 if (element.parentElement) {
Blink Reformat4c46d092018-04-07 15:32:371920 element.remove();
Tim van der Lippe1d6e57a2019-09-30 11:55:341921 }
Blink Reformat4c46d092018-04-07 15:32:371922 const markerIndex = this._highlightedMarkerIndex;
Tim van der Lippe1d6e57a2019-09-30 11:55:341923 if (markerIndex === -1) {
Blink Reformat4c46d092018-04-07 15:32:371924 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341925 }
Paul Lewiscf1f8a42020-11-04 21:05:241926 const timelineData = this._timelineData();
1927 if (!timelineData) {
1928 return;
1929 }
1930 const marker = timelineData.markers[markerIndex];
Blink Reformat4c46d092018-04-07 15:32:371931 const barX = this._timeToPositionClipped(marker.startTime());
Tim van der Lippe70842f32020-11-23 16:56:571932 UI.Tooltip.Tooltip.install(element, marker.title() || '');
Blink Reformat4c46d092018-04-07 15:32:371933 const style = element.style;
1934 style.left = barX + 'px';
1935 style.backgroundColor = marker.color();
1936 this._viewportElement.appendChild(element);
1937 }
1938
Jan Scheffler87dd9142021-02-27 21:19:481939 _processTimelineData(timelineData: TimelineData|null): void {
Blink Reformat4c46d092018-04-07 15:32:371940 if (!timelineData) {
1941 this._timelineLevels = null;
1942 this._visibleLevelOffsets = null;
1943 this._visibleLevels = null;
1944 this._groupOffsets = null;
1945 this._rawTimelineData = null;
Alexei Filippov57ccafb2018-08-14 20:59:051946 this._forceDecorationCache = null;
Alexei Filippove5197622018-08-18 03:04:331947 this._entryColorsCache = null;
Blink Reformat4c46d092018-04-07 15:32:371948 this._rawTimelineDataLength = 0;
1949 this._selectedGroup = -1;
Anubha Mathur72dd5822019-06-13 23:05:191950 this._keyboardFocusedGroup = -1;
Blink Reformat4c46d092018-04-07 15:32:371951 this._flameChartDelegate.updateSelectedGroup(this, null);
1952 return;
1953 }
1954
1955 this._rawTimelineData = timelineData;
1956 this._rawTimelineDataLength = timelineData.entryStartTimes.length;
Alexei Filippov57ccafb2018-08-14 20:59:051957 this._forceDecorationCache = new Int8Array(this._rawTimelineDataLength);
Alexei Filippove5197622018-08-18 03:04:331958 this._entryColorsCache = new Array(this._rawTimelineDataLength);
1959 for (let i = 0; i < this._rawTimelineDataLength; ++i) {
Alexei Filippov57ccafb2018-08-14 20:59:051960 this._forceDecorationCache[i] = this._dataProvider.forceDecoration(i) ? 1 : 0;
Alexei Filippove5197622018-08-18 03:04:331961 this._entryColorsCache[i] = this._dataProvider.entryColor(i);
1962 }
Blink Reformat4c46d092018-04-07 15:32:371963
1964 const entryCounters = new Uint32Array(this._dataProvider.maxStackDepth() + 1);
Tim van der Lippe1d6e57a2019-09-30 11:55:341965 for (let i = 0; i < timelineData.entryLevels.length; ++i) {
Blink Reformat4c46d092018-04-07 15:32:371966 ++entryCounters[timelineData.entryLevels[i]];
Tim van der Lippe1d6e57a2019-09-30 11:55:341967 }
Blink Reformat4c46d092018-04-07 15:32:371968 const levelIndexes = new Array(entryCounters.length);
1969 for (let i = 0; i < levelIndexes.length; ++i) {
1970 levelIndexes[i] = new Uint32Array(entryCounters[i]);
1971 entryCounters[i] = 0;
1972 }
Anubha Mathur72dd5822019-06-13 23:05:191973
Blink Reformat4c46d092018-04-07 15:32:371974 for (let i = 0; i < timelineData.entryLevels.length; ++i) {
1975 const level = timelineData.entryLevels[i];
1976 levelIndexes[level][entryCounters[level]++] = i;
1977 }
1978 this._timelineLevels = levelIndexes;
1979 const groups = this._rawTimelineData.groups || [];
1980 for (let i = 0; i < groups.length; ++i) {
1981 const expanded = this._groupExpansionState[groups[i].name];
Tim van der Lippe1d6e57a2019-09-30 11:55:341982 if (expanded !== undefined) {
Blink Reformat4c46d092018-04-07 15:32:371983 groups[i].expanded = expanded;
Tim van der Lippe1d6e57a2019-09-30 11:55:341984 }
Blink Reformat4c46d092018-04-07 15:32:371985 }
1986 this._updateLevelPositions();
1987 this._updateHeight();
1988
1989 this._selectedGroup = timelineData.selectedGroup ? groups.indexOf(timelineData.selectedGroup) : -1;
Anubha Mathur72dd5822019-06-13 23:05:191990 this._keyboardFocusedGroup = this._selectedGroup;
Blink Reformat4c46d092018-04-07 15:32:371991 this._flameChartDelegate.updateSelectedGroup(this, timelineData.selectedGroup);
1992 }
1993
Jan Scheffler87dd9142021-02-27 21:19:481994 _updateLevelPositions(): void {
Blink Reformat4c46d092018-04-07 15:32:371995 const levelCount = this._dataProvider.maxStackDepth();
Paul Lewiscf1f8a42020-11-04 21:05:241996 const groups = this._rawTimelineData ? (this._rawTimelineData.groups || []) : [];
Blink Reformat4c46d092018-04-07 15:32:371997 this._visibleLevelOffsets = new Uint32Array(levelCount + 1);
1998 this._visibleLevelHeights = new Uint32Array(levelCount);
1999 this._visibleLevels = new Uint16Array(levelCount);
2000 this._groupOffsets = new Uint32Array(groups.length + 1);
2001
2002 let groupIndex = -1;
Tim van der Lippefd2b2ce2020-01-03 15:05:182003 let currentOffset = this._rulerEnabled ? HeaderHeight + 2 : 2;
Blink Reformat4c46d092018-04-07 15:32:372004 let visible = true;
Jan Scheffler87dd9142021-02-27 21:19:482005 const groupStack: {
2006 nestingLevel: number,
2007 visible: boolean,
2008 }[] = [{nestingLevel: -1, visible: true}];
Paul Lewiscf1f8a42020-11-04 21:05:242009 const lastGroupLevel =
Jan Scheffler87dd9142021-02-27 21:19:482010 Math.max(levelCount, groups.length ? (groups[groups.length - 1] as Group).startLevel + 1 : 0);
Blink Reformat4c46d092018-04-07 15:32:372011 let level;
2012 for (level = 0; level < lastGroupLevel; ++level) {
2013 let parentGroupIsVisible = true;
2014 let style;
2015 while (groupIndex < groups.length - 1 && level === groups[groupIndex + 1].startLevel) {
2016 ++groupIndex;
2017 style = groups[groupIndex].style;
2018 let nextLevel = true;
Jan Scheffler87dd9142021-02-27 21:19:482019 let last: {
2020 nestingLevel: number,
2021 visible: boolean,
2022 } = groupStack[groupStack.length - 1];
Paul Lewiscf1f8a42020-11-04 21:05:242023 while (last && last.nestingLevel >= style.nestingLevel) {
Blink Reformat4c46d092018-04-07 15:32:372024 groupStack.pop();
2025 nextLevel = false;
Tim van der Lippe779b46b2021-01-13 13:40:222026 last = groupStack[groupStack.length - 1];
Blink Reformat4c46d092018-04-07 15:32:372027 }
2028 const thisGroupIsVisible =
2029 groupIndex >= 0 && this._isGroupCollapsible(groupIndex) ? groups[groupIndex].expanded : true;
Paul Lewiscf1f8a42020-11-04 21:05:242030
Tim van der Lippe779b46b2021-01-13 13:40:222031 last = groupStack[groupStack.length - 1];
Paul Lewiscf1f8a42020-11-04 21:05:242032 parentGroupIsVisible = last ? last.visible : false;
Tim van der Lipped7cfd142021-01-07 12:17:242033 visible = Boolean(thisGroupIsVisible) && parentGroupIsVisible;
Blink Reformat4c46d092018-04-07 15:32:372034 groupStack.push({nestingLevel: style.nestingLevel, visible: visible});
Tim van der Lippe1d6e57a2019-09-30 11:55:342035 if (parentGroupIsVisible) {
Blink Reformat4c46d092018-04-07 15:32:372036 currentOffset += nextLevel ? 0 : style.padding;
Tim van der Lippe1d6e57a2019-09-30 11:55:342037 }
Blink Reformat4c46d092018-04-07 15:32:372038 this._groupOffsets[groupIndex] = currentOffset;
Tim van der Lippe1d6e57a2019-09-30 11:55:342039 if (parentGroupIsVisible && !style.shareHeaderLine) {
Blink Reformat4c46d092018-04-07 15:32:372040 currentOffset += style.height;
Tim van der Lippe1d6e57a2019-09-30 11:55:342041 }
Blink Reformat4c46d092018-04-07 15:32:372042 }
Tim van der Lippe1d6e57a2019-09-30 11:55:342043 if (level >= levelCount) {
Yang Guo8fb3ac52019-07-31 20:17:502044 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:342045 }
Blink Reformat4c46d092018-04-07 15:32:372046 const isFirstOnLevel = groupIndex >= 0 && level === groups[groupIndex].startLevel;
2047 const thisLevelIsVisible =
2048 parentGroupIsVisible && (visible || isFirstOnLevel && groups[groupIndex].style.useFirstLineForOverview);
Yang Guo8fb3ac52019-07-31 20:17:502049 let height;
2050 if (groupIndex >= 0) {
2051 const group = groups[groupIndex];
2052 const styleB = group.style;
2053 height = isFirstOnLevel && !styleB.shareHeaderLine || (styleB.collapsible && !group.expanded) ?
2054 styleB.height :
2055 (styleB.itemsHeight || this._barHeight);
2056 } else {
2057 height = this._barHeight;
Blink Reformat4c46d092018-04-07 15:32:372058 }
Paul Lewiscf1f8a42020-11-04 21:05:242059 this._visibleLevels[level] = thisLevelIsVisible ? 1 : 0;
Yang Guo8fb3ac52019-07-31 20:17:502060 this._visibleLevelOffsets[level] = currentOffset;
2061 this._visibleLevelHeights[level] = height;
Tim van der Lippe1d6e57a2019-09-30 11:55:342062 if (thisLevelIsVisible || (parentGroupIsVisible && style && style.shareHeaderLine && isFirstOnLevel)) {
Blink Reformat4c46d092018-04-07 15:32:372063 currentOffset += this._visibleLevelHeights[level];
Tim van der Lippe1d6e57a2019-09-30 11:55:342064 }
Blink Reformat4c46d092018-04-07 15:32:372065 }
Tim van der Lippe1d6e57a2019-09-30 11:55:342066 if (groupIndex >= 0) {
Blink Reformat4c46d092018-04-07 15:32:372067 this._groupOffsets[groupIndex + 1] = currentOffset;
Tim van der Lippe1d6e57a2019-09-30 11:55:342068 }
Blink Reformat4c46d092018-04-07 15:32:372069 this._visibleLevelOffsets[level] = currentOffset;
Tim van der Lippe1d6e57a2019-09-30 11:55:342070 if (this._useWebGL) {
Alexei Filippov57ccafb2018-08-14 20:59:052071 this._setupGLGeometry();
Tim van der Lippe1d6e57a2019-09-30 11:55:342072 }
Blink Reformat4c46d092018-04-07 15:32:372073 }
2074
Jan Scheffler87dd9142021-02-27 21:19:482075 _isGroupCollapsible(index: number): boolean|undefined {
Paul Lewiscf1f8a42020-11-04 21:05:242076 if (!this._rawTimelineData) {
2077 return;
2078 }
2079
Blink Reformat4c46d092018-04-07 15:32:372080 const groups = this._rawTimelineData.groups || [];
2081 const style = groups[index].style;
Tim van der Lippe1d6e57a2019-09-30 11:55:342082 if (!style.shareHeaderLine || !style.collapsible) {
Tim van der Lipped7cfd142021-01-07 12:17:242083 return Boolean(style.collapsible);
Tim van der Lippe1d6e57a2019-09-30 11:55:342084 }
Blink Reformat4c46d092018-04-07 15:32:372085 const isLastGroup = index + 1 >= groups.length;
Tim van der Lippe1d6e57a2019-09-30 11:55:342086 if (!isLastGroup && groups[index + 1].style.nestingLevel > style.nestingLevel) {
Blink Reformat4c46d092018-04-07 15:32:372087 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:342088 }
Blink Reformat4c46d092018-04-07 15:32:372089 const nextGroupLevel = isLastGroup ? this._dataProvider.maxStackDepth() : groups[index + 1].startLevel;
Tim van der Lippe1d6e57a2019-09-30 11:55:342090 if (nextGroupLevel !== groups[index].startLevel + 1) {
Blink Reformat4c46d092018-04-07 15:32:372091 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:342092 }
Blink Reformat4c46d092018-04-07 15:32:372093 // For groups that only have one line and share header line, pretend these are not collapsible
2094 // unless the itemsHeight does not match the headerHeight
2095 return style.height !== style.itemsHeight;
2096 }
2097
Jan Scheffler87dd9142021-02-27 21:19:482098 setSelectedEntry(entryIndex: number): void {
Tim van der Lippe1d6e57a2019-09-30 11:55:342099 if (this._selectedEntryIndex === entryIndex) {
Blink Reformat4c46d092018-04-07 15:32:372100 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:342101 }
2102 if (entryIndex !== -1) {
Blink Reformat4c46d092018-04-07 15:32:372103 this._chartViewport.hideRangeSelection();
Tim van der Lippe1d6e57a2019-09-30 11:55:342104 }
Blink Reformat4c46d092018-04-07 15:32:372105 this._selectedEntryIndex = entryIndex;
2106 this._revealEntry(entryIndex);
2107 this._updateElementPosition(this._selectedElement, this._selectedEntryIndex);
2108 }
2109
Jan Scheffler87dd9142021-02-27 21:19:482110 _updateElementPosition(element: Element, entryIndex: number): void {
Alexei Filippov72d792d2018-11-06 07:15:042111 const elementMinWidthPx = 2;
2112 element.classList.add('hidden');
Tim van der Lippe1d6e57a2019-09-30 11:55:342113 if (entryIndex === -1) {
Blink Reformat4c46d092018-04-07 15:32:372114 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:342115 }
Blink Reformat4c46d092018-04-07 15:32:372116 const timelineData = this._timelineData();
Paul Lewiscf1f8a42020-11-04 21:05:242117 if (!timelineData) {
2118 return;
2119 }
2120
Blink Reformat4c46d092018-04-07 15:32:372121 const startTime = timelineData.entryStartTimes[entryIndex];
Alexei Filippov72d792d2018-11-06 07:15:042122 const duration = timelineData.entryTotalTimes[entryIndex];
Alexei Filippov65106502018-11-29 05:16:192123 let barX = 0;
2124 let barWidth = 0;
2125 let visible = true;
Alexei Filippov6c622e92018-11-10 02:13:592126 if (Number.isNaN(duration)) {
2127 const position = this._markerPositions.get(entryIndex);
Alexei Filippov65106502018-11-29 05:16:192128 if (position) {
2129 barX = position.x;
2130 barWidth = position.width;
2131 } else {
2132 visible = false;
2133 }
Alexei Filippov6c622e92018-11-10 02:13:592134 } else {
2135 barX = this._chartViewport.timeToPosition(startTime);
2136 barWidth = duration * this._chartViewport.timeToPixel();
2137 }
Tim van der Lippe1d6e57a2019-09-30 11:55:342138 if (barX + barWidth <= 0 || barX >= this._offsetWidth) {
Blink Reformat4c46d092018-04-07 15:32:372139 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:342140 }
Blink Reformat4c46d092018-04-07 15:32:372141 const barCenter = barX + barWidth / 2;
2142 barWidth = Math.max(barWidth, elementMinWidthPx);
2143 barX = barCenter - barWidth / 2;
2144 const entryLevel = timelineData.entryLevels[entryIndex];
2145 const barY = this._levelToOffset(entryLevel) - this._chartViewport.scrollOffset();
2146 const barHeight = this._levelHeight(entryLevel);
Jan Scheffler87dd9142021-02-27 21:19:482147 const style = (element as HTMLElement).style;
Blink Reformat4c46d092018-04-07 15:32:372148 style.left = barX + 'px';
2149 style.top = barY + 'px';
2150 style.width = barWidth + 'px';
2151 style.height = barHeight - 1 + 'px';
Alexei Filippov65106502018-11-29 05:16:192152 element.classList.toggle('hidden', !visible);
Blink Reformat4c46d092018-04-07 15:32:372153 this._viewportElement.appendChild(element);
2154 }
2155
Jan Scheffler87dd9142021-02-27 21:19:482156 _timeToPositionClipped(time: number): number {
Jack Franklin1be909c2020-03-04 08:57:412157 return Platform.NumberUtilities.clamp(this._chartViewport.timeToPosition(time), 0, this._offsetWidth);
Blink Reformat4c46d092018-04-07 15:32:372158 }
2159
Jan Scheffler87dd9142021-02-27 21:19:482160 _levelToOffset(level: number): number {
Paul Lewiscf1f8a42020-11-04 21:05:242161 if (!this._visibleLevelOffsets) {
2162 throw new Error('No visible level offsets');
2163 }
Blink Reformat4c46d092018-04-07 15:32:372164 return this._visibleLevelOffsets[level];
2165 }
2166
Jan Scheffler87dd9142021-02-27 21:19:482167 _levelHeight(level: number): number {
Paul Lewiscf1f8a42020-11-04 21:05:242168 if (!this._visibleLevelHeights) {
2169 throw new Error('No visible level heights');
2170 }
Blink Reformat4c46d092018-04-07 15:32:372171 return this._visibleLevelHeights[level];
2172 }
2173
Jan Scheffler87dd9142021-02-27 21:19:482174 _updateBoundaries(): void {
Blink Reformat4c46d092018-04-07 15:32:372175 this._totalTime = this._dataProvider.totalTime();
2176 this._minimumBoundary = this._dataProvider.minimumBoundary();
2177 this._chartViewport.setBoundaries(this._minimumBoundary, this._totalTime);
2178 }
2179
Jan Scheffler87dd9142021-02-27 21:19:482180 _updateHeight(): void {
Alexei Filippov23428d42018-04-28 01:09:072181 const height = this._levelToOffset(this._dataProvider.maxStackDepth()) + 2;
Blink Reformat4c46d092018-04-07 15:32:372182 this._chartViewport.setContentHeight(height);
2183 }
2184
Jan Scheffler87dd9142021-02-27 21:19:482185 onResize(): void {
Blink Reformat4c46d092018-04-07 15:32:372186 this.scheduleUpdate();
2187 }
2188
Jan Scheffler87dd9142021-02-27 21:19:482189 update(): void {
Tim van der Lippe1d6e57a2019-09-30 11:55:342190 if (!this._timelineData()) {
Blink Reformat4c46d092018-04-07 15:32:372191 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:342192 }
Blink Reformat4c46d092018-04-07 15:32:372193 this._resetCanvas();
2194 this._updateHeight();
2195 this._updateBoundaries();
2196 this._draw();
Tim van der Lippe1d6e57a2019-09-30 11:55:342197 if (!this._chartViewport.isDragging()) {
Blink Reformat4c46d092018-04-07 15:32:372198 this._updateHighlight();
Tim van der Lippe1d6e57a2019-09-30 11:55:342199 }
Blink Reformat4c46d092018-04-07 15:32:372200 }
2201
Jan Scheffler87dd9142021-02-27 21:19:482202 reset(): void {
Blink Reformat4c46d092018-04-07 15:32:372203 this._chartViewport.reset();
2204 this._rawTimelineData = null;
2205 this._rawTimelineDataLength = 0;
2206 this._highlightedMarkerIndex = -1;
2207 this._highlightedEntryIndex = -1;
2208 this._selectedEntryIndex = -1;
2209 /** @type {!Map<string,!Map<string,number>>} */
2210 this._textWidth = new Map();
2211 this._chartViewport.scheduleUpdate();
2212 }
2213
Jan Scheffler87dd9142021-02-27 21:19:482214 scheduleUpdate(): void {
Blink Reformat4c46d092018-04-07 15:32:372215 this._chartViewport.scheduleUpdate();
2216 }
2217
Jan Scheffler87dd9142021-02-27 21:19:482218 _enabled(): boolean {
Blink Reformat4c46d092018-04-07 15:32:372219 return this._rawTimelineDataLength !== 0;
2220 }
2221
Jan Scheffler87dd9142021-02-27 21:19:482222 computePosition(time: number): number {
Blink Reformat4c46d092018-04-07 15:32:372223 return this._chartViewport.timeToPosition(time);
2224 }
2225
Jan Scheffler87dd9142021-02-27 21:19:482226 formatValue(value: number, precision?: number): string {
Blink Reformat4c46d092018-04-07 15:32:372227 return this._dataProvider.formatValue(value - this.zeroTime(), precision);
2228 }
2229
Jan Scheffler87dd9142021-02-27 21:19:482230 maximumBoundary(): number {
Blink Reformat4c46d092018-04-07 15:32:372231 return this._chartViewport.windowRightTime();
2232 }
2233
Jan Scheffler87dd9142021-02-27 21:19:482234 minimumBoundary(): number {
Blink Reformat4c46d092018-04-07 15:32:372235 return this._chartViewport.windowLeftTime();
2236 }
2237
Jan Scheffler87dd9142021-02-27 21:19:482238 zeroTime(): number {
Blink Reformat4c46d092018-04-07 15:32:372239 return this._dataProvider.minimumBoundary();
2240 }
2241
Jan Scheffler87dd9142021-02-27 21:19:482242 boundarySpan(): number {
Alexei Filippov2578eb02018-04-11 08:15:052243 return this.maximumBoundary() - this.minimumBoundary();
Blink Reformat4c46d092018-04-07 15:32:372244 }
Tim van der Lippefd2b2ce2020-01-03 15:05:182245}
Blink Reformat4c46d092018-04-07 15:32:372246
Tim van der Lippefd2b2ce2020-01-03 15:05:182247export const HeaderHeight = 15;
2248export const MinimalTimeWindowMs = 0.5;
Blink Reformat4c46d092018-04-07 15:32:372249
Tim van der Lippefd2b2ce2020-01-03 15:05:182250export class TimelineData {
Jan Scheffler87dd9142021-02-27 21:19:482251 entryLevels: number[]|Uint16Array;
2252 entryTotalTimes: number[]|Float32Array;
2253 entryStartTimes: number[]|Float64Array;
2254 groups: Group[];
2255 markers: FlameChartMarker[];
2256 flowStartTimes: number[];
2257 flowStartLevels: number[];
2258 flowEndTimes: number[];
2259 flowEndLevels: number[];
2260 selectedGroup: Group|null;
2261 constructor(
2262 entryLevels: number[]|Uint16Array, entryTotalTimes: number[]|Float32Array, entryStartTimes: number[]|Float64Array,
2263 groups: Group[]|null) {
Blink Reformat4c46d092018-04-07 15:32:372264 this.entryLevels = entryLevels;
2265 this.entryTotalTimes = entryTotalTimes;
2266 this.entryStartTimes = entryStartTimes;
Tim van der Lippedfbb48f2020-11-19 14:49:152267 this.groups = groups || [];
Blink Reformat4c46d092018-04-07 15:32:372268 this.markers = [];
2269 this.flowStartTimes = [];
2270 this.flowStartLevels = [];
2271 this.flowEndTimes = [];
2272 this.flowEndLevels = [];
Blink Reformat4c46d092018-04-07 15:32:372273 this.selectedGroup = null;
2274 }
Tim van der Lippefd2b2ce2020-01-03 15:05:182275}
Blink Reformat4c46d092018-04-07 15:32:372276
Tim van der Lippefd2b2ce2020-01-03 15:05:182277/**
2278 * @interface
2279 */
Jan Scheffler87dd9142021-02-27 21:19:482280export interface FlameChartDataProvider {
2281 minimumBoundary(): number;
Blink Reformat4c46d092018-04-07 15:32:372282
Jan Scheffler87dd9142021-02-27 21:19:482283 totalTime(): number;
Blink Reformat4c46d092018-04-07 15:32:372284
Jan Scheffler87dd9142021-02-27 21:19:482285 formatValue(value: number, precision?: number): string;
Blink Reformat4c46d092018-04-07 15:32:372286
Jan Scheffler87dd9142021-02-27 21:19:482287 maxStackDepth(): number;
Blink Reformat4c46d092018-04-07 15:32:372288
Jan Scheffler87dd9142021-02-27 21:19:482289 timelineData(): TimelineData|null;
Blink Reformat4c46d092018-04-07 15:32:372290
Jan Scheffler87dd9142021-02-27 21:19:482291 prepareHighlightedEntryInfo(entryIndex: number): Element|null;
Blink Reformat4c46d092018-04-07 15:32:372292
Jan Scheffler87dd9142021-02-27 21:19:482293 canJumpToEntry(entryIndex: number): boolean;
Blink Reformat4c46d092018-04-07 15:32:372294
Jan Scheffler87dd9142021-02-27 21:19:482295 entryTitle(entryIndex: number): string|null;
Blink Reformat4c46d092018-04-07 15:32:372296
Jan Scheffler87dd9142021-02-27 21:19:482297 entryFont(entryIndex: number): string|null;
Blink Reformat4c46d092018-04-07 15:32:372298
Jan Scheffler87dd9142021-02-27 21:19:482299 entryColor(entryIndex: number): string;
Blink Reformat4c46d092018-04-07 15:32:372300
Jan Scheffler87dd9142021-02-27 21:19:482301 decorateEntry(
2302 entryIndex: number, context: CanvasRenderingContext2D, text: string|null, barX: number, barY: number,
2303 barWidth: number, barHeight: number, unclippedBarX: number, timeToPixelRatio: number): boolean;
Blink Reformat4c46d092018-04-07 15:32:372304
Jan Scheffler87dd9142021-02-27 21:19:482305 forceDecoration(entryIndex: number): boolean;
Blink Reformat4c46d092018-04-07 15:32:372306
Jan Scheffler87dd9142021-02-27 21:19:482307 textColor(entryIndex: number): string;
Paul Lewisead45752020-06-23 09:51:362308
Jan Scheffler87dd9142021-02-27 21:19:482309 navStartTimes(): Map<string, SDK.TracingModel.Event>;
Tim van der Lippefd2b2ce2020-01-03 15:05:182310}
Blink Reformat4c46d092018-04-07 15:32:372311
Jan Scheffler87dd9142021-02-27 21:19:482312export interface FlameChartMarker {
2313 startTime(): number;
2314 color(): string;
2315 title(): string|null;
2316 draw(context: CanvasRenderingContext2D, x: number, height: number, pixelsPerMillisecond: number): void;
Tim van der Lippefd2b2ce2020-01-03 15:05:182317}
Blink Reformat4c46d092018-04-07 15:32:372318
Jan Scheffler87dd9142021-02-27 21:19:482319// TODO(crbug.com/1167717): Make this a const enum again
2320// eslint-disable-next-line rulesdir/const_enum
2321export enum Events {
2322 CanvasFocused = 'CanvasFocused',
2323 EntryInvoked = 'EntryInvoked',
2324 EntrySelected = 'EntrySelected',
2325 EntryHighlighted = 'EntryHighlighted',
2326}
Blink Reformat4c46d092018-04-07 15:32:372327
Tim van der Lippefd2b2ce2020-01-03 15:05:182328export const Colors = {
Blink Reformat4c46d092018-04-07 15:32:372329 SelectedGroupBackground: 'hsl(215, 85%, 98%)',
2330 SelectedGroupBorder: 'hsl(216, 68%, 54%)',
2331};
Jan Scheffler87dd9142021-02-27 21:19:482332export interface Group {
2333 name: Common.UIString.LocalizedString;
2334 startLevel: number;
2335 expanded?: boolean;
2336 selectable?: boolean;
2337 style: {
2338 height: number,
2339 padding: number,
2340 collapsible: boolean,
2341 font: string,
2342 color: string,
2343 backgroundColor: string,
2344 nestingLevel: number,
2345 itemsHeight?: number,
2346 shareHeaderLine?: boolean,
2347 useFirstLineForOverview?: boolean,
2348 useDecoratorsForOverview?: boolean,
2349 };
2350 track?: TimelineModel.TimelineModel.Track|null;
2351}
2352export interface GroupStyle {
2353 height: number;
2354 padding: number;
2355 collapsible: boolean;
2356 font: string;
2357 color: string;
2358 backgroundColor: string;
2359 nestingLevel: number;
2360 itemsHeight?: number;
2361 shareHeaderLine?: boolean;
2362 useFirstLineForOverview?: boolean;
2363 useDecoratorsForOverview?: boolean;
2364}