UI: push timeline frame rendering into new SummaryView The implementation of this UI needs to be migrated, but this is a step in that direction by at least simplifying the higher level `DetailsView`. Once I also update the aggregated range view, the new SummaryView can stop taking the random `node` argument which will be a good step. R=dsv@chromium.org Bug: 407751379 Change-Id: I4ab68ba89f69720aca6234cdd099cb7ee419e655 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6827923 Auto-Submit: Jack Franklin <jacktfranklin@chromium.org> Reviewed-by: Danil Somsikov <dsv@chromium.org> Commit-Queue: Jack Franklin <jacktfranklin@chromium.org>
diff --git a/front_end/panels/timeline/TimelineDetailsView.ts b/front_end/panels/timeline/TimelineDetailsView.ts index 87c7970..5c340ed 100644 --- a/front_end/panels/timeline/TimelineDetailsView.ts +++ b/front_end/panels/timeline/TimelineDetailsView.ts
@@ -90,7 +90,6 @@ #parsedTrace: Trace.Handlers.Types.ParsedTrace|null = null; #traceInsightsSets: Trace.Insights.Types.TraceInsightSets|null = null; #eventToRelatedInsightsMap: TimelineComponents.RelatedInsightChips.EventToRelatedInsightsMap|null = null; - #filmStrip: Trace.Extras.FilmStrip.Data|null = null; #onTraceBoundsChangeBound = this.#onTraceBoundsChange.bind(this); #thirdPartyTree = new ThirdPartyTreeViewWidget(); #entityMapper: Utils.EntityMapper.EntityMapper|null = null; @@ -286,7 +285,7 @@ this.#parsedTrace = data.parsedTrace; } if (data.parsedTrace) { - this.#filmStrip = Trace.Extras.FilmStrip.fromParsedTrace(data.parsedTrace); + this.#summaryContent.filmStrip = Trace.Extras.FilmStrip.fromParsedTrace(data.parsedTrace); this.#entityMapper = new Utils.EntityMapper.EntityMapper(data.parsedTrace); } this.#selectedEvents = data.selectedEvents; @@ -398,26 +397,7 @@ this.updateContents(); } - #getFilmStripFrame(frame: Trace.Types.Events.LegacyTimelineFrame): Trace.Extras.FilmStrip.Frame|null { - if (!this.#filmStrip) { - return null; - } - - const screenshotTime = (frame.idle ? frame.startTime : frame.endTime); - const filmStripFrame = Trace.Extras.FilmStrip.frameClosestToTimestamp(this.#filmStrip, screenshotTime); - if (!filmStripFrame) { - return null; - } - - const frameTimeMilliSeconds = Trace.Helpers.Timing.microToMilli(filmStripFrame.screenshotEvent.ts); - const frameEndTimeMilliSeconds = Trace.Helpers.Timing.microToMilli(frame.endTime); - return frameTimeMilliSeconds - frameEndTimeMilliSeconds < 10 ? filmStripFrame : null; - } - - #setSelectionForTimelineFrame(frame: Trace.Types.Events.LegacyTimelineFrame): void { - const matchedFilmStripFrame = this.#getFilmStripFrame(frame); - void this.updateSummaryAndSelectTab( - TimelineUIUtils.generateDetailsContentForFrame(frame, this.#filmStrip, matchedFilmStripFrame)); + #addLayerTreeForSelectedFrame(frame: Trace.Types.Events.LegacyTimelineFrame): void { const target = SDK.TargetManager.TargetManager.instance().rootTarget(); if (frame.layerTree && target) { const layerTreeForFrame = new TracingFrameLayerTree(target, frame.layerTree); @@ -462,10 +442,10 @@ this.updateContentsScheduled = false; if (Trace.Types.Events.isLegacyTimelineFrame(selection.event)) { - this.#setSelectionForTimelineFrame(selection.event); - } else { - await this.#setSelectionForTraceEvent(selection.event); + this.#addLayerTreeForSelectedFrame(selection.event); } + + await this.#setSelectionForTraceEvent(selection.event); } else if (selectionIsRange(selection)) { const timings = Trace.Helpers.Timing.traceWindowMicroSecondsToMilliSeconds(selection.bounds); this.updateSelectedRangeStats(timings.min, timings.max); @@ -629,6 +609,7 @@ entityMapper: Utils.EntityMapper.EntityMapper|null; target: SDK.Target.Target|null; linkifier: Components.Linkifier.Linkifier|null; + filmStrip: Trace.Extras.FilmStrip.Data|null; } type View = (input: SummaryViewInput, output: object, target: HTMLElement) => void; @@ -659,6 +640,7 @@ entityMapper: Utils.EntityMapper.EntityMapper|null = null; target: SDK.Target.Target|null = null; linkifier: Components.Linkifier.Linkifier|null = null; + filmStrip: Trace.Extras.FilmStrip.Data|null = null; constructor(element?: HTMLElement, view = SUMMARY_DEFAULT_VIEW) { super(element); @@ -676,6 +658,7 @@ entityMapper: this.entityMapper, target: this.target, linkifier: this.linkifier, + filmStrip: this.filmStrip }, {}, this.contentElement); } @@ -721,9 +704,43 @@ // clang-format on } + if (Trace.Types.Events.isLegacyTimelineFrame(selectedEvent) && input.filmStrip) { + const matchedFilmStripFrame = getFilmStripFrame(input.filmStrip, selectedEvent); + const content = + TimelineUIUtils.generateDetailsContentForFrame(selectedEvent, input.filmStrip, matchedFilmStripFrame); + return html`${content}`; + } + // Fall back to the default trace event details. Long term this needs to use // the UI Eng Vision. const traceEventDetails = await TimelineUIUtils.buildTraceEventDetails(parsedTrace, selectedEvent, linkifier, true, input.entityMapper); return html`${traceEventDetails}`; } + +const filmStripFrameCache = new WeakMap<Trace.Types.Events.LegacyTimelineFrame, Trace.Extras.FilmStrip.Frame|null>(); + +function getFilmStripFrame(filmStrip: Trace.Extras.FilmStrip.Data, frame: Trace.Types.Events.LegacyTimelineFrame): + Trace.Extras.FilmStrip.Frame|null { + const fromCache = filmStripFrameCache.get(frame); + if (typeof fromCache !== 'undefined') { + return fromCache; + } + + const screenshotTime = (frame.idle ? frame.startTime : frame.endTime); + const filmStripFrame = Trace.Extras.FilmStrip.frameClosestToTimestamp(filmStrip, screenshotTime); + if (!filmStripFrame) { + filmStripFrameCache.set(frame, null); + return null; + } + + const frameTimeMilliSeconds = Trace.Helpers.Timing.microToMilli(filmStripFrame.screenshotEvent.ts); + const frameEndTimeMilliSeconds = Trace.Helpers.Timing.microToMilli(frame.endTime); + if (frameTimeMilliSeconds - frameEndTimeMilliSeconds < 10) { + filmStripFrameCache.set(frame, filmStripFrame); + return filmStripFrame; + } + + filmStripFrameCache.set(frame, null); + return null; +}