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

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

Issue 2852173002: DevTools: Show screenshots on the main flamechart (Closed)
Patch Set: Created 3 years, 8 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 f0f190a35fe5eb3e918075124557e8f400af341e..37c292730ca304a5c80cae70296619fffa10eec2 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartDataProvider.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartDataProvider.js
@@ -32,11 +32,12 @@
* @implements {PerfUI.FlameChartDataProvider}
* @unrestricted
*/
-Timeline.TimelineFlameChartDataProvider = class {
+Timeline.TimelineFlameChartDataProvider = class extends Common.Object {
/**
* @param {!Array<!TimelineModel.TimelineModelFilter>} filters
*/
constructor(filters) {
+ super();
this.reset();
var font = '11px ' + Host.fontFamily();
this._font = font;
@@ -75,6 +76,7 @@ Timeline.TimelineFlameChartDataProvider = class {
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: 120});
this._interactionsHeaderLevel1 = buildGroupStyle({useFirstLineForOverview: true});
this._interactionsHeaderLevel2 = buildGroupStyle({padding: 2, nestingLevel: 1});
@@ -161,6 +163,8 @@ Timeline.TimelineFlameChartDataProvider = class {
this._asyncColorByInteractionPhase = new Map();
/** @type {!Array<!{title: string, model: !SDK.TracingModel}>} */
this._extensionInfo = [];
+ /** @type {!Map<!TimelineModel.TimelineFrame, ?Image>} */
+ this._frameImageCache = new Map();
}
/**
@@ -189,7 +193,6 @@ Timeline.TimelineFlameChartDataProvider = class {
this._timeSpan = this._model.isEmpty() ? 1000 : this._model.maximumRecordTime() - this._minimumBoundary;
this._currentLevel = 0;
- this._appendHeader(Common.UIString('Frames'), this._staticHeader);
this._appendFrameBars(this._performanceModel.frames());
this._appendHeader(Common.UIString('Interactions'), this._interactionsHeaderLevel1);
@@ -442,14 +445,20 @@ Timeline.TimelineFlameChartDataProvider = class {
* @param {!Array.<!TimelineModel.TimelineFrame>} frames
*/
_appendFrameBars(frames) {
+ var hasFilmStrip = !!this._performanceModel.filmStripModel().frames().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 i = 0; i < frames.length; ++i) {
- this._markers.push(new Timeline.TimelineFlameChartMarker(
- frames[i].startTime, frames[i].startTime - this._model.minimumRecordTime(), style));
- this._appendFrame(frames[i]);
+ for (var i = 0; i < (hasFilmStrip ? 2 : 1); ++i) {
+ this._entryTypeByLevel[this._currentLevel] = Timeline.TimelineFlameChartEntryType.Frame;
caseq 2017/05/01 22:13:35 Let's add another type for FrameThumbnail.
alph 2017/05/02 18:31:13 Acknowledged.
+ for (var frame of frames) {
+ this._markers.push(new Timeline.TimelineFlameChartMarker(
caseq 2017/05/01 22:13:35 Why do we do it twice?
alph 2017/05/02 18:31:13 Done.
+ frame.startTime, frame.startTime - this._model.minimumRecordTime(), style));
+ this._appendFrame(frame);
+ }
+ ++this._currentLevel;
}
- ++this._currentLevel;
}
/**
@@ -553,6 +562,64 @@ Timeline.TimelineFlameChartDataProvider = class {
}
/**
+ * @param {number} entryIndex
+ * @param {!CanvasRenderingContext2D} context
+ * @param {?string} text
+ * @param {number} barX
+ * @param {number} barY
+ * @param {number} barWidth
+ * @param {number} barHeight
+ */
+ _drawFrame(entryIndex, context, text, barX, barY, barWidth, barHeight) {
caseq 2017/05/01 22:13:35 Let's split it into two, one for drawing thumbnail
alph 2017/05/02 18:31:13 Done it differently
+ var /** @const */ hPadding = 1;
+ var frame = /** @type {!TimelineModel.TimelineFrame} */ (this._entryData[entryIndex]);
+ barX += hPadding;
+ barWidth -= 2 * hPadding;
+ context.fillStyle = frame.idle ? 'white' : (frame.hasWarnings() ? '#fad1d1' : '#d7f0d1');
+ context.fillRect(barX, barY, barWidth, barHeight);
+
+ var image;
+ if (this._frameImageCache.has(frame)) {
+ image = this._frameImageCache.get(frame);
+ } else {
+ this._frameImageCache.set(frame, null); // Mark the image promise is in flight.
+ var modelFrame = Timeline.TimelineUIUtils.filmStripModelFrame(this._performanceModel.filmStripModel(), frame);
+ if (modelFrame) {
+ modelFrame.imageDataPromise()
+ .then(data => UI.loadImage(data ? 'data:image/jpg;base64,' + data : ''))
+ .then(image => this._frameImageCache.set(frame, image))
+ .then(() => this.dispatchEventToListeners(Timeline.TimelineFlameChartDataProvider.Events.DataChanged));
caseq 2017/05/01 22:13:35 no need for another then, let's do this synchronou
alph 2017/05/02 18:31:13 Done.
+ }
+ }
+ if (barHeight === this._framesHeader.itemsHeight) {
+ if (!image)
+ return;
+ var padding = 2;
+ var imageHeight = barHeight - 2 * padding;
+ var imageX = barX + padding;
+ var imageY = barY + padding;
+ var scale = imageHeight / image.naturalHeight;
+ var imageWidth = image.naturalWidth * scale;
+ context.save();
+ context.beginPath();
+ context.rect(imageX, imageY, barWidth - 2 * padding, imageHeight);
+ context.clip();
+ context.drawImage(image, imageX, imageY, imageWidth, imageHeight);
+ context.restore();
+ } else {
+ 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 + barHeight - 4);
+ }
+ }
+ }
+
+ /**
* @override
* @param {number} entryIndex
* @param {!CanvasRenderingContext2D} context
@@ -569,21 +636,7 @@ Timeline.TimelineFlameChartDataProvider = class {
var data = this._entryData[entryIndex];
var type = this._entryType(entryIndex);
if (type === Timeline.TimelineFlameChartEntryType.Frame) {
- var /** @const */ vPadding = 1;
- var /** @const */ hPadding = 1;
- var frame = /** {!TimelineModel.TimelineFrame} */ (data);
- barX += hPadding;
- barWidth -= 2 * hPadding;
- barY += vPadding;
- barHeight -= 2 * vPadding + 1;
- context.fillStyle = frame.idle ? 'white' : (frame.hasWarnings() ? '#fad1d1' : '#d7f0d1');
- context.fillRect(barX, barY, barWidth, barHeight);
- var frameDurationText = Number.preciseMillisToString(frame.duration, 1);
- var textWidth = context.measureText(frameDurationText).width;
- if (barWidth >= textWidth) {
- context.fillStyle = this.textColor(entryIndex);
- context.fillText(frameDurationText, barX + (barWidth - textWidth) / 2, barY + barHeight - 3);
- }
+ this._drawFrame(entryIndex, context, text, barX, barY, barWidth, barHeight);
return true;
}
@@ -920,3 +973,8 @@ Timeline.TimelineFlameChartDataProvider = class {
Timeline.TimelineFlameChartDataProvider.InstantEventVisibleDurationMs = 0.001;
Timeline.TimelineFlameChartDataProvider._indexSymbol = Symbol('index');
+
+/** @enum {symbol} */
+Timeline.TimelineFlameChartDataProvider.Events = {
+ DataChanged: Symbol('DataChanged')
+};

Powered by Google App Engine
This is Rietveld 408576698