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

Unified Diff: third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartDataProvider.js

Issue 2873153002: DevTools: Draw screenshot independently of frames bar on flamechart. (Closed)
Patch Set: addressing nits Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartDataProvider.js
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartDataProvider.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartDataProvider.js
index 585c9d0b0a957618b08fbe7ecd49486e03af8988..340ee6bc67be899f46aafe52f8e35bab837bad91 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartDataProvider.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartDataProvider.js
@@ -76,7 +76,9 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
this._headerLevel1 = buildGroupStyle({shareHeaderLine: false});
this._headerLevel2 = buildGroupStyle({padding: 2, nestingLevel: 1, collapsible: false});
this._staticHeader = buildGroupStyle({collapsible: false});
- this._framesHeader = buildGroupStyle({useFirstLineForOverview: true, shareHeaderLine: true, itemsHeight: 150});
+ this._framesHeader = buildGroupStyle({useFirstLineForOverview: true});
+ this._screenshotsHeader =
+ buildGroupStyle({useFirstLineForOverview: true, nestingLevel: 1, collapsible: false, itemsHeight: 150});
this._interactionsHeaderLevel1 = buildGroupStyle({useFirstLineForOverview: true});
this._interactionsHeaderLevel2 = buildGroupStyle({padding: 2, nestingLevel: 1});
@@ -99,8 +101,9 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
* @return {?string}
*/
entryTitle(entryIndex) {
+ var entryTypes = Timeline.TimelineFlameChartDataProvider.EntryType;
var entryType = this._entryType(entryIndex);
- if (entryType === Timeline.TimelineFlameChartEntryType.Event) {
+ if (entryType === entryTypes.Event) {
var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]);
if (event.phase === SDK.TracingModel.Phase.AsyncStepInto || event.phase === SDK.TracingModel.Phase.AsyncStepPast)
return event.name + ':' + event.args['step'];
@@ -113,10 +116,12 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
return detailsText;
return detailsText ? Common.UIString('%s (%s)', name, detailsText) : name;
}
- if (entryType === Timeline.TimelineFlameChartEntryType.ExtensionEvent) {
+ if (entryType === entryTypes.ExtensionEvent) {
var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]);
return event.name;
}
+ if (entryType === entryTypes.Screenshot)
+ return '';
var title = this._entryIndexToTitle[entryIndex];
if (!title) {
title = Common.UIString('Unexpected entryIndex %d', entryIndex);
@@ -147,11 +152,11 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
reset() {
this._currentLevel = 0;
this._timelineData = null;
- /** @type {!Array<!SDK.TracingModel.Event|!TimelineModel.TimelineFrame|!TimelineModel.TimelineIRModel.Phases>} */
+ /** @type {!Array<!SDK.FilmStripModel.Frame|!SDK.TracingModel.Event|!TimelineModel.TimelineFrame|!TimelineModel.TimelineIRModel.Phases>} */
this._entryData = [];
/** @type {!Array<!SDK.TracingModel.Event>} */
this._entryParent = [];
- /** @type {!Array<!Timeline.TimelineFlameChartEntryType>} */
+ /** @type {!Array<!Timeline.TimelineFlameChartDataProvider.EntryType>} */
this._entryTypeByLevel = [];
/** @type {!Array<string>} */
this._entryIndexToTitle = [];
@@ -163,8 +168,8 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
this._asyncColorByInteractionPhase = new Map();
/** @type {!Array<!{title: string, model: !SDK.TracingModel}>} */
this._extensionInfo = [];
- /** @type {!Map<!TimelineModel.TimelineFrame, ?Image>} */
- this._frameImageCache = new Map();
+ /** @type {!Map<!SDK.FilmStripModel.Frame, ?Image>} */
+ this._screenshotImageCache = new Map();
}
/**
@@ -193,12 +198,12 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
this._timeSpan = this._model.isEmpty() ? 1000 : this._model.maximumRecordTime() - this._minimumBoundary;
this._currentLevel = 0;
- this._appendFrameBars(this._performanceModel.frames());
+ this._appendFrameBars();
this._appendHeader(Common.UIString('Interactions'), this._interactionsHeaderLevel1);
this._appendInteractionRecords();
- var eventEntryType = Timeline.TimelineFlameChartEntryType.Event;
+ var eventEntryType = Timeline.TimelineFlameChartDataProvider.EntryType.Event;
var asyncEventGroups = TimelineModel.TimelineModel.AsyncEventGroup;
var inputLatencies = this._model.mainThreadAsyncEvents().get(asyncEventGroups.input);
@@ -243,15 +248,7 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
for (let extensionIndex = 0; extensionIndex < this._extensionInfo.length; extensionIndex++)
this._innerAppendExtensionEvents(extensionIndex);
- /**
- * @param {!Timeline.TimelineFlameChartMarker} a
- * @param {!Timeline.TimelineFlameChartMarker} b
- */
- function compareStartTime(a, b) {
- return a.startTime() - b.startTime();
- }
-
- this._markers.sort(compareStartTime);
+ this._markers.sort((a, b) => a.startTime() - b.startTime());
this._timelineData.markers = this._markers;
this._flowEventIndexById.clear();
@@ -284,7 +281,8 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
clonedHeader.nestingLevel = level;
this._appendSyncEvents(
events, Timeline.TimelineUIUtils.displayNameForFrame(frame),
- /** @type {!PerfUI.FlameChart.GroupStyle} */ (clonedHeader), Timeline.TimelineFlameChartEntryType.Event);
+ /** @type {!PerfUI.FlameChart.GroupStyle} */ (clonedHeader),
+ Timeline.TimelineFlameChartDataProvider.EntryType.Event);
frame.children.forEach(this._appendFrameEvents.bind(this, level + 1));
}
@@ -295,7 +293,7 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
* @param {boolean=} forceExpanded
*/
_appendThreadTimelineData(threadTitle, syncEvents, asyncEvents, forceExpanded) {
- var entryType = Timeline.TimelineFlameChartEntryType.Event;
+ var entryType = Timeline.TimelineFlameChartDataProvider.EntryType.Event;
this._appendAsyncEvents(asyncEvents);
this._appendSyncEvents(syncEvents, threadTitle, this._headerLevel1, entryType, forceExpanded);
}
@@ -304,11 +302,11 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
* @param {!Array<!SDK.TracingModel.Event>} events
* @param {string} title
* @param {!PerfUI.FlameChart.GroupStyle} style
- * @param {!Timeline.TimelineFlameChartEntryType} entryType
+ * @param {!Timeline.TimelineFlameChartDataProvider.EntryType} entryType
* @param {boolean=} forceExpanded
*/
_appendSyncEvents(events, title, style, entryType, forceExpanded) {
- var isExtension = entryType === Timeline.TimelineFlameChartEntryType.ExtensionEvent;
+ var isExtension = entryType === Timeline.TimelineFlameChartDataProvider.EntryType.ExtensionEvent;
var openEvents = [];
var flowEventsEnabled = Runtime.experiments.isEnabled('timelineFlowEvents');
var blackboxingEnabled = !isExtension && Runtime.experiments.isEnabled('blackboxJSFramesOnTimeline');
@@ -383,7 +381,7 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
* @param {!Map<!TimelineModel.TimelineModel.AsyncEventGroup, !Array<!SDK.TracingModel.AsyncEvent>>} asyncEvents
*/
_appendAsyncEvents(asyncEvents) {
- var entryType = Timeline.TimelineFlameChartEntryType.Event;
+ var entryType = Timeline.TimelineFlameChartDataProvider.EntryType.Event;
var groups = TimelineModel.TimelineModel.AsyncEventGroup;
var groupArray = Object.keys(groups).map(key => groups[key]);
@@ -404,7 +402,7 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
* @param {string} header
* @param {!Array<!SDK.TracingModel.AsyncEvent>} events
* @param {!PerfUI.FlameChart.GroupStyle} style
- * @param {!Timeline.TimelineFlameChartEntryType} entryType
+ * @param {!Timeline.TimelineFlameChartDataProvider.EntryType} entryType
*/
_appendAsyncEventsGroup(header, events, style, entryType) {
var lastUsedTimeByLevel = [];
@@ -430,7 +428,7 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
}
_appendGPUEvents() {
- var eventType = Timeline.TimelineFlameChartEntryType.Event;
+ var eventType = Timeline.TimelineFlameChartDataProvider.EntryType.Event;
var gpuEvents = this._model.gpuEvents();
if (this._appendSyncEvents(gpuEvents, Common.UIString('GPU'), this._headerLevel1, eventType, false))
++this._currentLevel;
@@ -438,30 +436,45 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
_appendInteractionRecords() {
this._performanceModel.interactionRecords().forEach(this._appendSegment, this);
- this._entryTypeByLevel[this._currentLevel++] = Timeline.TimelineFlameChartEntryType.InteractionRecord;
+ this._entryTypeByLevel[this._currentLevel++] = Timeline.TimelineFlameChartDataProvider.EntryType.InteractionRecord;
}
- /**
- * @param {!Array.<!TimelineModel.TimelineFrame>} frames
- */
- _appendFrameBars(frames) {
- var hasFilmStrip = !!this._performanceModel.filmStripModel().frames().length;
+ _appendFrameBars() {
+ var screenshots = this._performanceModel.filmStripModel().frames();
+ var hasFilmStrip = !!screenshots.length;
this._framesHeader.collapsible = hasFilmStrip;
this._appendHeader(Common.UIString('Frames'), this._framesHeader);
this._frameGroup = this._timelineData.groups.peekLast();
var style = Timeline.TimelineUIUtils.markerStyleForFrame();
- this._entryTypeByLevel[this._currentLevel] = Timeline.TimelineFlameChartEntryType.Frame;
- for (var frame of frames) {
+ this._entryTypeByLevel[this._currentLevel] = Timeline.TimelineFlameChartDataProvider.EntryType.Frame;
+ for (var frame of this._performanceModel.frames()) {
this._markers.push(new Timeline.TimelineFlameChartMarker(
frame.startTime, frame.startTime - this._model.minimumRecordTime(), style));
this._appendFrame(frame);
}
++this._currentLevel;
+ if (!hasFilmStrip)
+ return;
+ this._appendHeader('', this._screenshotsHeader);
+ this._entryTypeByLevel[this._currentLevel] = Timeline.TimelineFlameChartDataProvider.EntryType.Screenshot;
+ var prevTimestamp;
+ for (var screenshot of screenshots) {
+ var index = this._entryData.length;
+ this._entryData.push(screenshot);
+ this._timelineData.entryLevels[index] = this._currentLevel;
+ this._timelineData.entryStartTimes[index] = screenshot.timestamp;
+ if (prevTimestamp)
+ this._timelineData.entryTotalTimes[index - 1] = screenshot.timestamp - prevTimestamp;
+ prevTimestamp = screenshot.timestamp;
+ }
+ this._timelineData.entryTotalTimes[this._timelineData.entryTotalTimes.length - 1] =
+ this._model.maximumRecordTime() - prevTimestamp;
+ ++this._currentLevel;
}
/**
* @param {number} entryIndex
- * @return {!Timeline.TimelineFlameChartEntryType}
+ * @return {!Timeline.TimelineFlameChartDataProvider.EntryType}
*/
_entryType(entryIndex) {
return this._entryTypeByLevel[this._timelineData.entryLevels[entryIndex]];
@@ -477,7 +490,7 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
var title;
var warning;
var type = this._entryType(entryIndex);
- if (type === Timeline.TimelineFlameChartEntryType.Event) {
+ if (type === Timeline.TimelineFlameChartDataProvider.EntryType.Event) {
var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]);
var totalTime = event.duration;
var selfTime = event.selfTime;
@@ -490,7 +503,7 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
}
title = this.entryTitle(entryIndex);
warning = Timeline.TimelineUIUtils.eventWarning(event);
- } else if (type === Timeline.TimelineFlameChartEntryType.Frame) {
+ } else if (type === Timeline.TimelineFlameChartDataProvider.EntryType.Frame) {
var frame = /** @type {!TimelineModel.TimelineFrame} */ (this._entryData[entryIndex]);
time = Common.UIString(
'%s ~ %.0f\xa0fps', Number.preciseMillisToString(frame.duration, 1), (1000 / frame.duration));
@@ -531,8 +544,9 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
return color;
}
+ var entryTypes = Timeline.TimelineFlameChartDataProvider.EntryType;
var type = this._entryType(entryIndex);
- if (type === Timeline.TimelineFlameChartEntryType.Event) {
+ if (type === entryTypes.Event) {
var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]);
if (!SDK.TracingModel.isAsyncPhase(event.phase))
return this._colorForEvent(event);
@@ -548,11 +562,11 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
var category = Timeline.TimelineUIUtils.eventStyle(event).category;
return patchColorAndCache(this._asyncColorByCategory, category, () => category.color);
}
- if (type === Timeline.TimelineFlameChartEntryType.Frame)
+ if (type === entryTypes.Frame)
return 'white';
- if (type === Timeline.TimelineFlameChartEntryType.InteractionRecord)
+ if (type === entryTypes.InteractionRecord)
return 'transparent';
- if (type === Timeline.TimelineFlameChartEntryType.ExtensionEvent) {
+ if (type === entryTypes.ExtensionEvent) {
var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]);
return this._extensionColorGenerator.colorForID(event.name);
}
@@ -576,40 +590,45 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
context.fillStyle = frame.idle ? 'white' : (frame.hasWarnings() ? '#fad1d1' : '#d7f0d1');
context.fillRect(barX, barY, barWidth, barHeight);
- var headerHeight = 17;
var frameDurationText = Number.preciseMillisToString(frame.duration, 1);
var textWidth = context.measureText(frameDurationText).width;
if (textWidth <= barWidth) {
- var font = this.entryFont(entryIndex);
- if (font)
- context.font = font;
context.fillStyle = this.textColor(entryIndex);
- context.fillText(frameDurationText, barX + (barWidth - textWidth) / 2, barY + headerHeight - 4);
+ context.fillText(frameDurationText, barX + (barWidth - textWidth) / 2, barY + barHeight - 4);
}
+ }
- var imageHeight = barHeight - headerHeight;
- if (imageHeight < headerHeight)
+ /**
+ * @param {number} entryIndex
+ * @param {!CanvasRenderingContext2D} context
+ * @param {number} barX
+ * @param {number} barY
+ * @param {number} barWidth
+ * @param {number} barHeight
+ */
+ async _drawScreenshot(entryIndex, context, barX, barY, barWidth, barHeight) {
+ var screenshot = /** @type {!SDK.FilmStripModel.Frame} */ (this._entryData[entryIndex]);
+ if (!this._screenshotImageCache.has(screenshot)) {
+ this._screenshotImageCache.set(screenshot, null);
+ var data = await screenshot.imageDataPromise();
+ var image = await UI.loadImageFromData(data);
+ this._screenshotImageCache.set(screenshot, image);
+ this.dispatchEventToListeners(Timeline.TimelineFlameChartDataProvider.Events.DataChanged);
return;
- if (!this._frameImageCache.has(frame)) {
- this._frameImageCache.set(frame, null); // Mark the image promise is in flight.
- var modelFrame = this._performanceModel.filmStripModelFrame(frame);
- if (modelFrame) {
- modelFrame.imageDataPromise().then(data => UI.loadImageFromData(data)).then(image => {
- this._frameImageCache.set(frame, image);
- this.dispatchEventToListeners(Timeline.TimelineFlameChartDataProvider.Events.DataChanged);
- });
- }
}
- var image = this._frameImageCache.get(frame);
+ context.fillStyle = '#eee';
+ context.fillRect(barX, barY, barWidth, barHeight);
+ var image = this._screenshotImageCache.get(screenshot);
if (!image)
return;
- var imageX = barX;
- var imageY = barY + headerHeight;
+ var imageX = barX + 1;
+ var imageY = barY + 1;
+ var imageHeight = barHeight - 2;
var scale = imageHeight / image.naturalHeight;
var imageWidth = image.naturalWidth * scale;
context.save();
context.beginPath();
- context.rect(imageX, imageY, barWidth, imageHeight);
+ context.rect(imageX, imageY, barWidth - 2, imageHeight);
context.clip();
context.drawImage(image, imageX, imageY, imageWidth, imageHeight);
context.restore();
@@ -631,12 +650,19 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
decorateEntry(entryIndex, context, text, barX, barY, barWidth, barHeight, unclippedBarX, timeToPixels) {
var data = this._entryData[entryIndex];
var type = this._entryType(entryIndex);
- if (type === Timeline.TimelineFlameChartEntryType.Frame) {
+ var entryTypes = Timeline.TimelineFlameChartDataProvider.EntryType;
+
+ if (type === entryTypes.Frame) {
this._drawFrame(entryIndex, context, text, barX, barY, barWidth, barHeight);
return true;
}
- if (type === Timeline.TimelineFlameChartEntryType.InteractionRecord) {
+ if (type === entryTypes.Screenshot) {
+ this._drawScreenshot(entryIndex, context, barX, barY, barWidth, barHeight);
+ return true;
+ }
+
+ if (type === entryTypes.InteractionRecord) {
var color = Timeline.TimelineUIUtils.interactionPhaseColor(
/** @type {!TimelineModel.TimelineIRModel.Phases} */ (data));
context.fillStyle = color;
@@ -646,7 +672,7 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
return false;
}
- if (type === Timeline.TimelineFlameChartEntryType.Event) {
+ if (type === entryTypes.Event) {
var event = /** @type {!SDK.TracingModel.Event} */ (data);
if (event.hasCategory(TimelineModel.TimelineModel.Category.LatencyInfo)) {
var timeWaitingForMainThread = TimelineModel.TimelineData.forEvent(event).timeWaitingForMainThread;
@@ -688,11 +714,14 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
* @return {boolean}
*/
forceDecoration(entryIndex) {
+ var entryTypes = Timeline.TimelineFlameChartDataProvider.EntryType;
var type = this._entryType(entryIndex);
- if (type === Timeline.TimelineFlameChartEntryType.Frame)
+ if (type === entryTypes.Frame)
+ return true;
+ if (type === entryTypes.Screenshot)
return true;
- if (type === Timeline.TimelineFlameChartEntryType.Event) {
+ if (type === entryTypes.Event) {
var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]);
return !!TimelineModel.TimelineData.forEvent(event).warning;
}
@@ -713,7 +742,7 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
*/
_innerAppendExtensionEvents(index) {
var entry = this._extensionInfo[index];
- var entryType = Timeline.TimelineFlameChartEntryType.ExtensionEvent;
+ var entryType = Timeline.TimelineFlameChartDataProvider.EntryType.ExtensionEvent;
var allThreads = [].concat(...entry.model.sortedProcesses().map(process => process.sortedThreads()));
if (!allThreads.length)
return;
@@ -845,10 +874,10 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
createSelection(entryIndex) {
var type = this._entryType(entryIndex);
var timelineSelection = null;
- if (type === Timeline.TimelineFlameChartEntryType.Event) {
+ if (type === Timeline.TimelineFlameChartDataProvider.EntryType.Event) {
timelineSelection = Timeline.TimelineSelection.fromTraceEvent(
/** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]));
- } else if (type === Timeline.TimelineFlameChartEntryType.Frame) {
+ } else if (type === Timeline.TimelineFlameChartDataProvider.EntryType.Frame) {
timelineSelection = Timeline.TimelineSelection.fromFrame(
/** @type {!TimelineModel.TimelineFrame} */ (this._entryData[entryIndex]));
}
@@ -961,7 +990,7 @@ Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
* @return {?SDK.TracingModel.Event}
*/
eventByIndex(entryIndex) {
- return this._entryType(entryIndex) === Timeline.TimelineFlameChartEntryType.Event ?
+ return this._entryType(entryIndex) === Timeline.TimelineFlameChartDataProvider.EntryType.Event ?
/** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]) :
null;
}
@@ -981,3 +1010,12 @@ Timeline.TimelineFlameChartDataProvider._indexSymbol = Symbol('index');
Timeline.TimelineFlameChartDataProvider.Events = {
DataChanged: Symbol('DataChanged')
};
+
+/** @enum {symbol} */
+Timeline.TimelineFlameChartDataProvider.EntryType = {
+ Frame: Symbol('Frame'),
+ Event: Symbol('Event'),
+ InteractionRecord: Symbol('InteractionRecord'),
+ ExtensionEvent: Symbol('ExtensionEvent'),
+ Screenshot: Symbol('Screenshot'),
+};

Powered by Google App Engine
This is Rietveld 408576698