blob: 66c725213831bd33dade19177d465722d5090a79 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @implements {UI.FlameChartDataProvider}
* @unrestricted
*/
Timeline.TimelineFlameChartDataProviderBase = class {
constructor() {
UI.FlameChartDataProvider.call(this);
this.reset();
this._font = '11px ' + Host.fontFamily();
}
/** @return {string} */
font() {
return this._font;
}
/**
* @override
* @return {number}
*/
barHeight() {
return 17;
}
/**
* @override
* @return {number}
*/
textBaseline() {
return 5;
}
/**
* @override
* @return {number}
*/
textPadding() {
return 4;
}
/**
* @override
* @param {number} entryIndex
* @return {string}
*/
entryFont(entryIndex) {
return this._font;
}
/**
* @override
* @param {number} entryIndex
* @return {?string}
*/
entryTitle(entryIndex) {
return null;
}
reset() {
this._timelineData = null;
}
/**
* @override
* @return {number}
*/
minimumBoundary() {
return this._minimumBoundary;
}
/**
* @override
* @return {number}
*/
totalTime() {
return this._timeSpan;
}
/**
* @override
* @param {number} value
* @param {number=} precision
* @return {string}
*/
formatValue(value, precision) {
return Number.preciseMillisToString(value, precision);
}
/**
* @override
* @return {number}
*/
maxStackDepth() {
return this._currentLevel;
}
/**
* @override
* @param {number} entryIndex
* @return {?Element}
*/
prepareHighlightedEntryInfo(entryIndex) {
return null;
}
/**
* @override
* @param {number} entryIndex
* @return {boolean}
*/
canJumpToEntry(entryIndex) {
return false;
}
/**
* @override
* @param {number} entryIndex
* @return {string}
*/
entryColor(entryIndex) {
return 'red';
}
/**
* @override
* @param {number} index
* @return {boolean}
*/
forceDecoration(index) {
return false;
}
/**
* @override
* @param {number} entryIndex
* @param {!CanvasRenderingContext2D} context
* @param {?string} text
* @param {number} barX
* @param {number} barY
* @param {number} barWidth
* @param {number} barHeight
* @param {number} unclippedBarX
* @param {number} timeToPixels
* @return {boolean}
*/
decorateEntry(entryIndex, context, text, barX, barY, barWidth, barHeight, unclippedBarX, timeToPixels) {
return false;
}
/**
* @override
* @return {number}
*/
paddingLeft() {
return 0;
}
/**
* @override
* @param {number} entryIndex
* @return {string}
*/
textColor(entryIndex) {
return '#333';
}
/**
* @param {number} entryIndex
* @return {?Timeline.TimelineSelection}
*/
createSelection(entryIndex) {
return null;
}
/**
* @override
* @return {!UI.FlameChart.TimelineData}
*/
timelineData() {
throw new Error('Not implemented');
}
};
/**
* @enum {symbol}
*/
Timeline.TimelineFlameChartEntryType = {
Frame: Symbol('Frame'),
Event: Symbol('Event'),
InteractionRecord: Symbol('InteractionRecord'),
ExtensionEvent: Symbol('ExtensionEvent')
};
/**
* @implements {UI.FlameChartMarker}
* @unrestricted
*/
Timeline.TimelineFlameChartMarker = class {
/**
* @param {number} startTime
* @param {number} startOffset
* @param {!Timeline.TimelineMarkerStyle} style
*/
constructor(startTime, startOffset, style) {
this._startTime = startTime;
this._startOffset = startOffset;
this._style = style;
}
/**
* @override
* @return {number}
*/
startTime() {
return this._startTime;
}
/**
* @override
* @return {string}
*/
color() {
return this._style.color;
}
/**
* @override
* @return {string}
*/
title() {
var startTime = Number.millisToString(this._startOffset);
return Common.UIString('%s at %s', this._style.title, startTime);
}
/**
* @override
* @param {!CanvasRenderingContext2D} context
* @param {number} x
* @param {number} height
* @param {number} pixelsPerMillisecond
*/
draw(context, x, height, pixelsPerMillisecond) {
var lowPriorityVisibilityThresholdInPixelsPerMs = 4;
if (this._style.lowPriority && pixelsPerMillisecond < lowPriorityVisibilityThresholdInPixelsPerMs)
return;
context.save();
if (!this._style.lowPriority) {
context.strokeStyle = this._style.color;
context.lineWidth = 2;
context.beginPath();
context.moveTo(x, 0);
context.lineTo(x, height);
context.stroke();
}
if (this._style.tall) {
context.strokeStyle = this._style.color;
context.lineWidth = this._style.lineWidth;
context.translate(this._style.lineWidth < 1 || (this._style.lineWidth & 1) ? 0.5 : 0, 0.5);
context.beginPath();
context.moveTo(x, height);
context.setLineDash(this._style.dashStyle);
context.lineTo(x, context.canvas.height);
context.stroke();
}
context.restore();
}
};
/**
* @implements {Timeline.TimelineModeView}
* @implements {UI.FlameChartDelegate}
* @unrestricted
*/
Timeline.TimelineFlameChartView = class extends UI.VBox {
/**
* @param {!Timeline.TimelineModeViewDelegate} delegate
* @param {!TimelineModel.TimelineModel} timelineModel
* @param {!TimelineModel.TimelineFrameModel} frameModel
* @param {!TimelineModel.TimelineIRModel} irModel
* @param {!Array<!{title: string, model: !SDK.TracingModel}>} extensionModels
* @param {!Array<!TimelineModel.TimelineModel.Filter>} filters
*/
constructor(delegate, timelineModel, frameModel, irModel, extensionModels, filters) {
super();
this.element.classList.add('timeline-flamechart');
this._delegate = delegate;
this._model = timelineModel;
this._extensionModels = extensionModels;
this._splitWidget = new UI.SplitWidget(false, false, 'timelineFlamechartMainView', 150);
this._dataProvider = new Timeline.TimelineFlameChartDataProvider(this._model, frameModel, irModel, filters);
var mainViewGroupExpansionSetting = Common.settings.createSetting('timelineFlamechartMainViewGroupExpansion', {});
this._mainView = new UI.FlameChart(this._dataProvider, this, mainViewGroupExpansionSetting);
this._mainView.alwaysShowVerticalScroll();
var networkViewGroupExpansionSetting =
Common.settings.createSetting('timelineFlamechartNetworkViewGroupExpansion', {});
this._networkDataProvider = new Timeline.TimelineFlameChartNetworkDataProvider(this._model);
this._networkView = new UI.FlameChart(this._networkDataProvider, this, networkViewGroupExpansionSetting);
this._networkView.alwaysShowVerticalScroll();
networkViewGroupExpansionSetting.addChangeListener(this.resizeToPreferredHeights.bind(this));
this._splitWidget.setMainWidget(this._mainView);
this._splitWidget.setSidebarWidget(this._networkView);
this._splitWidget.show(this.element);
this._onMainEntrySelected = this._onEntrySelected.bind(this, this._dataProvider);
this._onNetworkEntrySelected = this._onEntrySelected.bind(this, this._networkDataProvider);
this._mainView.addEventListener(UI.FlameChart.Events.EntrySelected, this._onMainEntrySelected, this);
this._networkView.addEventListener(UI.FlameChart.Events.EntrySelected, this._onNetworkEntrySelected, this);
this._nextExtensionIndex = 0;
Bindings.blackboxManager.addChangeListener(this.refreshRecords, this);
}
/**
* @override
*/
dispose() {
this._mainView.removeEventListener(UI.FlameChart.Events.EntrySelected, this._onMainEntrySelected, this);
this._networkView.removeEventListener(UI.FlameChart.Events.EntrySelected, this._onNetworkEntrySelected, this);
Bindings.blackboxManager.removeChangeListener(this.refreshRecords, this);
}
/**
* @override
* @return {?Element}
*/
resizerElement() {
return null;
}
/**
* @override
* @param {number} windowStartTime
* @param {number} windowEndTime
*/
requestWindowTimes(windowStartTime, windowEndTime) {
this._delegate.requestWindowTimes(windowStartTime, windowEndTime);
}
/**
* @override
* @param {number} startTime
* @param {number} endTime
*/
updateRangeSelection(startTime, endTime) {
this._delegate.select(Timeline.TimelineSelection.fromRange(startTime, endTime));
}
/**
* @override
*/
refreshRecords() {
this._dataProvider.reset();
this._nextExtensionIndex = 0;
this.extensionDataAdded();
this._mainView.scheduleUpdate();
this._networkDataProvider.reset();
this._networkView.scheduleUpdate();
}
/**
* @override
*/
extensionDataAdded() {
while (this._nextExtensionIndex < this._extensionModels.length)
this._dataProvider.appendExtensionEvents(this._extensionModels[this._nextExtensionIndex++]);
this._mainView.scheduleUpdate();
}
/**
* @override
* @param {?SDK.TracingModel.Event} event
*/
highlightEvent(event) {
var entryIndex =
event ? this._dataProvider.entryIndexForSelection(Timeline.TimelineSelection.fromTraceEvent(event)) : -1;
if (entryIndex >= 0)
this._mainView.highlightEntry(entryIndex);
else
this._mainView.hideHighlight();
}
/**
* @override
*/
wasShown() {
this._mainView.scheduleUpdate();
this._networkView.scheduleUpdate();
}
/**
* @override
* @return {!UI.Widget}
*/
view() {
return this;
}
/**
* @override
*/
reset() {
this._dataProvider.reset();
this._mainView.reset();
this._mainView.setWindowTimes(0, Infinity);
this._networkDataProvider.reset();
this._networkView.reset();
this._networkView.setWindowTimes(0, Infinity);
}
/**
* @override
* @param {number} startTime
* @param {number} endTime
*/
setWindowTimes(startTime, endTime) {
this._mainView.setWindowTimes(startTime, endTime);
this._networkView.setWindowTimes(startTime, endTime);
this._networkDataProvider.setWindowTimes(startTime, endTime);
}
/**
* @override
* @param {?SDK.TracingModel.Event} event
* @param {string=} regex
* @param {boolean=} select
*/
highlightSearchResult(event, regex, select) {
if (!event) {
this._delegate.select(null);
return;
}
var timelineSelection = this._dataProvider.selectionForEvent(event);
if (timelineSelection)
this._delegate.select(timelineSelection);
}
/**
* @override
* @param {?Timeline.TimelineSelection} selection
*/
setSelection(selection) {
var index = this._dataProvider.entryIndexForSelection(selection);
this._mainView.setSelectedEntry(index);
index = this._networkDataProvider.entryIndexForSelection(selection);
this._networkView.setSelectedEntry(index);
}
/**
* @param {!UI.FlameChartDataProvider} dataProvider
* @param {!Common.Event} event
*/
_onEntrySelected(dataProvider, event) {
var entryIndex = /** @type{number} */ (event.data);
this._delegate.select(dataProvider.createSelection(entryIndex));
}
resizeToPreferredHeights() {
this._splitWidget.setSidebarSize(this._networkDataProvider.preferredHeight());
}
};
/**
* @unrestricted
*/
Timeline.TimelineFlameChartView.Selection = class {
/**
* @param {!Timeline.TimelineSelection} selection
* @param {number} entryIndex
*/
constructor(selection, entryIndex) {
this.timelineSelection = selection;
this.entryIndex = entryIndex;
}
};