| 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'),
 | 
| +};
 | 
| 
 |