timeline_module.js 267 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141
  1. Timeline.CountersGraph=class extends UI.VBox{constructor(delegate){super();this.element.id='memory-graphs-container';this._delegate=delegate;this._calculator=new Timeline.CountersGraph.Calculator();this._header=new UI.HBox();this._header.element.classList.add('timeline-memory-header');this._header.show(this.element);this._toolbar=new UI.Toolbar('timeline-memory-toolbar');this._header.element.appendChild(this._toolbar.element);this._graphsContainer=new UI.VBox();this._graphsContainer.show(this.element);const canvasWidget=new UI.VBoxWithResizeCallback(this._resize.bind(this));canvasWidget.show(this._graphsContainer.element);this._createCurrentValuesBar();this._canvasContainer=canvasWidget.element;this._canvasContainer.id='memory-graphs-canvas-container';this._canvas=this._canvasContainer.createChild('canvas');this._canvas.id='memory-counters-graph';this._canvasContainer.addEventListener('mouseover',this._onMouseMove.bind(this),true);this._canvasContainer.addEventListener('mousemove',this._onMouseMove.bind(this),true);this._canvasContainer.addEventListener('mouseleave',this._onMouseLeave.bind(this),true);this._canvasContainer.addEventListener('click',this._onClick.bind(this),true);this._timelineGrid=new PerfUI.TimelineGrid();this._canvasContainer.appendChild(this._timelineGrid.dividersElement);this._counters=[];this._counterUI=[];this._countersByName={};this._countersByName['jsHeapSizeUsed']=this._createCounter(Common.UIString('JS Heap'),Common.UIString('JS Heap: %s'),'hsl(220, 90%, 43%)',Number.bytesToString);this._countersByName['documents']=this._createCounter(Common.UIString('Documents'),Common.UIString('Documents: %s'),'hsl(0, 90%, 43%)');this._countersByName['nodes']=this._createCounter(Common.UIString('Nodes'),Common.UIString('Nodes: %s'),'hsl(120, 90%, 43%)');this._countersByName['jsEventListeners']=this._createCounter(Common.UIString('Listeners'),Common.UIString('Listeners: %s'),'hsl(38, 90%, 43%)');this._gpuMemoryCounter=this._createCounter(Common.UIString('GPU Memory'),Common.UIString('GPU Memory [KB]: %s'),'hsl(300, 90%, 43%)',Number.bytesToString);this._countersByName['gpuMemoryUsedKB']=this._gpuMemoryCounter;}
  2. setModel(model,track){if(this._model!==model){if(this._model){this._model.removeEventListener(Timeline.PerformanceModel.Events.WindowChanged,this._onWindowChanged,this);}
  3. this._model=model;if(this._model){this._model.addEventListener(Timeline.PerformanceModel.Events.WindowChanged,this._onWindowChanged,this);}}
  4. this._calculator.setZeroTime(model?model.timelineModel().minimumRecordTime():0);for(let i=0;i<this._counters.length;++i){this._counters[i].reset();this._counterUI[i].reset();}
  5. this.scheduleRefresh();this._track=track;if(!track){return;}
  6. const events=track.syncEvents();for(let i=0;i<events.length;++i){const event=events[i];if(event.name!==TimelineModel.TimelineModel.RecordType.UpdateCounters){continue;}
  7. const counters=event.args.data;if(!counters){return;}
  8. for(const name in counters){const counter=this._countersByName[name];if(counter){counter.appendSample(event.startTime,counters[name]);}}
  9. const gpuMemoryLimitCounterName='gpuMemoryLimitKB';if(gpuMemoryLimitCounterName in counters){this._gpuMemoryCounter.setLimit(counters[gpuMemoryLimitCounterName]);}}}
  10. _createCurrentValuesBar(){this._currentValuesBar=this._graphsContainer.element.createChild('div');this._currentValuesBar.id='counter-values-bar';}
  11. _createCounter(uiName,uiValueTemplate,color,formatter){const counter=new Timeline.CountersGraph.Counter();this._counters.push(counter);this._counterUI.push(new Timeline.CountersGraph.CounterUI(this,uiName,uiValueTemplate,color,counter,formatter));return counter;}
  12. resizerElement(){return this._header.element;}
  13. _resize(){const parentElement=this._canvas.parentElement;this._canvas.width=parentElement.clientWidth*window.devicePixelRatio;this._canvas.height=parentElement.clientHeight*window.devicePixelRatio;this._calculator.setDisplayWidth(this._canvas.width);this.refresh();}
  14. _onWindowChanged(event){const window=(event.data.window);this._calculator.setWindow(window.left,window.right);this.scheduleRefresh();}
  15. scheduleRefresh(){UI.invokeOnceAfterBatchUpdate(this,this.refresh);}
  16. draw(){this._clear();for(const counter of this._counters){counter._calculateVisibleIndexes(this._calculator);counter._calculateXValues(this._canvas.width);}
  17. for(const counterUI of this._counterUI){counterUI._drawGraph(this._canvas);}}
  18. _onClick(event){const x=event.x-this._canvasContainer.totalOffsetLeft();let minDistance=Infinity;let bestTime;for(const counterUI of this._counterUI){if(!counterUI.counter.times.length){continue;}
  19. const index=counterUI._recordIndexAt(x);const distance=Math.abs(x*window.devicePixelRatio-counterUI.counter.x[index]);if(distance<minDistance){minDistance=distance;bestTime=counterUI.counter.times[index];}}
  20. if(bestTime!==undefined){this._delegate.selectEntryAtTime(this._track.events.length?this._track.events:this._track.asyncEvents,bestTime);}}
  21. _onMouseLeave(event){delete this._markerXPosition;this._clearCurrentValueAndMarker();}
  22. _clearCurrentValueAndMarker(){for(let i=0;i<this._counterUI.length;i++){this._counterUI[i]._clearCurrentValueAndMarker();}}
  23. _onMouseMove(event){const x=event.x-this._canvasContainer.totalOffsetLeft();this._markerXPosition=x;this._refreshCurrentValues();}
  24. _refreshCurrentValues(){if(this._markerXPosition===undefined){return;}
  25. for(let i=0;i<this._counterUI.length;++i){this._counterUI[i].updateCurrentValue(this._markerXPosition);}}
  26. refresh(){this._timelineGrid.updateDividers(this._calculator);this.draw();this._refreshCurrentValues();}
  27. _clear(){const ctx=this._canvas.getContext('2d');ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);}};Timeline.CountersGraph.Counter=class{constructor(){this.times=[];this.values=[];}
  28. appendSample(time,value){if(this.values.length&&this.values.peekLast()===value){return;}
  29. this.times.push(time);this.values.push(value);}
  30. reset(){this.times=[];this.values=[];}
  31. setLimit(value){this._limitValue=value;}
  32. _calculateBounds(){let maxValue;let minValue;for(let i=this._minimumIndex;i<=this._maximumIndex;i++){const value=this.values[i];if(minValue===undefined||value<minValue){minValue=value;}
  33. if(maxValue===undefined||value>maxValue){maxValue=value;}}
  34. minValue=minValue||0;maxValue=maxValue||1;if(this._limitValue){if(maxValue>this._limitValue*0.5){maxValue=Math.max(maxValue,this._limitValue);}
  35. minValue=Math.min(minValue,this._limitValue);}
  36. return{min:minValue,max:maxValue};}
  37. _calculateVisibleIndexes(calculator){const start=calculator.minimumBoundary();const end=calculator.maximumBoundary();this._minimumIndex=Number.constrain(this.times.upperBound(start)-1,0,this.times.length-1);this._maximumIndex=Number.constrain(this.times.lowerBound(end),0,this.times.length-1);this._minTime=start;this._maxTime=end;}
  38. _calculateXValues(width){if(!this.values.length){return;}
  39. const xFactor=width/(this._maxTime-this._minTime);this.x=new Array(this.values.length);for(let i=this._minimumIndex+1;i<=this._maximumIndex;i++){this.x[i]=xFactor*(this.times[i]-this._minTime);}}};Timeline.CountersGraph.CounterUI=class{constructor(countersPane,title,currentValueLabel,graphColor,counter,formatter){this._countersPane=countersPane;this.counter=counter;this._formatter=formatter||Number.withThousandsSeparator;this._setting=Common.settings.createSetting('timelineCountersGraph-'+title,true);this._setting.setTitle(title);this._filter=new UI.ToolbarSettingCheckbox(this._setting,title);this._filter.inputElement.classList.add('-theme-preserve');const color=Common.Color.parse(graphColor).setAlpha(0.5).asString(Common.Color.Format.RGBA);if(color){this._filter.element.backgroundColor=color;this._filter.element.borderColor='transparent';}
  40. this._filter.inputElement.addEventListener('click',this._toggleCounterGraph.bind(this));countersPane._toolbar.appendToolbarItem(this._filter);this._range=this._filter.element.createChild('span','range');this._value=countersPane._currentValuesBar.createChild('span','memory-counter-value');this._value.style.color=graphColor;this.graphColor=graphColor;this.limitColor=Common.Color.parse(graphColor).setAlpha(0.3).asString(Common.Color.Format.RGBA);this.graphYValues=[];this._verticalPadding=10;this._currentValueLabel=currentValueLabel;this._marker=countersPane._canvasContainer.createChild('div','memory-counter-marker');this._marker.style.backgroundColor=graphColor;this._clearCurrentValueAndMarker();}
  41. reset(){this._range.textContent='';}
  42. setRange(minValue,maxValue){const min=this._formatter(minValue);const max=this._formatter(maxValue);this._range.textContent=Common.UIString('[%s\xa0\u2013\xa0%s]',min,max);}
  43. _toggleCounterGraph(event){this._value.classList.toggle('hidden',!this._filter.checked());this._countersPane.refresh();}
  44. _recordIndexAt(x){return this.counter.x.upperBound(x*window.devicePixelRatio,null,this.counter._minimumIndex+1,this.counter._maximumIndex+1)-
  45. 1;}
  46. updateCurrentValue(x){if(!this.visible()||!this.counter.values.length||!this.counter.x){return;}
  47. const index=this._recordIndexAt(x);const value=Number.withThousandsSeparator(this.counter.values[index]);this._value.textContent=Common.UIString(this._currentValueLabel,value);const y=this.graphYValues[index]/window.devicePixelRatio;this._marker.style.left=x+'px';this._marker.style.top=y+'px';this._marker.classList.remove('hidden');}
  48. _clearCurrentValueAndMarker(){this._value.textContent='';this._marker.classList.add('hidden');}
  49. _drawGraph(canvas){const ctx=canvas.getContext('2d');const width=canvas.width;const height=canvas.height-2*this._verticalPadding;if(height<=0){this.graphYValues=[];return;}
  50. const originY=this._verticalPadding;const counter=this.counter;const values=counter.values;if(!values.length){return;}
  51. const bounds=counter._calculateBounds();const minValue=bounds.min;const maxValue=bounds.max;this.setRange(minValue,maxValue);if(!this.visible()){return;}
  52. const yValues=this.graphYValues;const maxYRange=maxValue-minValue;const yFactor=maxYRange?height/(maxYRange):1;ctx.save();ctx.lineWidth=window.devicePixelRatio;if(ctx.lineWidth%2){ctx.translate(0.5,0.5);}
  53. ctx.beginPath();let value=values[counter._minimumIndex];let currentY=Math.round(originY+height-(value-minValue)*yFactor);ctx.moveTo(0,currentY);let i=counter._minimumIndex;for(;i<=counter._maximumIndex;i++){const x=Math.round(counter.x[i]);ctx.lineTo(x,currentY);const currentValue=values[i];if(typeof currentValue!=='undefined'){value=currentValue;}
  54. currentY=Math.round(originY+height-(value-minValue)*yFactor);ctx.lineTo(x,currentY);yValues[i]=currentY;}
  55. yValues.length=i;ctx.lineTo(width,currentY);ctx.strokeStyle=this.graphColor;ctx.stroke();if(counter._limitValue){const limitLineY=Math.round(originY+height-(counter._limitValue-minValue)*yFactor);ctx.moveTo(0,limitLineY);ctx.lineTo(width,limitLineY);ctx.strokeStyle=this.limitColor;ctx.stroke();}
  56. ctx.closePath();ctx.restore();}
  57. visible(){return this._filter.checked();}};Timeline.CountersGraph.Calculator=class{setZeroTime(time){this._zeroTime=time;}
  58. computePosition(time){return(time-this._minimumBoundary)/this.boundarySpan()*this._workingArea;}
  59. setWindow(minimumBoundary,maximumBoundary){this._minimumBoundary=minimumBoundary;this._maximumBoundary=maximumBoundary;}
  60. setDisplayWidth(clientWidth){this._workingArea=clientWidth;}
  61. formatValue(value,precision){return Number.preciseMillisToString(value-this.zeroTime(),precision);}
  62. maximumBoundary(){return this._maximumBoundary;}
  63. minimumBoundary(){return this._minimumBoundary;}
  64. zeroTime(){return this._zeroTime;}
  65. boundarySpan(){return this._maximumBoundary-this._minimumBoundary;}};;Timeline.ExtensionTracingSession=class{constructor(provider,performanceModel){this._provider=provider;this._performanceModel=performanceModel;this._completionCallback;this._completionPromise=new Promise(fulfill=>{this._completionCallback=fulfill;});this._timeOffset=0;}
  66. loadingStarted(){}
  67. processingStarted(){}
  68. loadingProgress(progress){}
  69. loadingComplete(tracingModel){if(!tracingModel){return;}
  70. this._performanceModel.addExtensionEvents(this._provider.longDisplayName(),tracingModel,this._timeOffset);this._completionCallback();}
  71. complete(url,timeOffsetMicroseconds){if(!url){this._completionCallback();return;}
  72. this._timeOffset=timeOffsetMicroseconds;Timeline.TimelineLoader.loadFromURL(url,this);}
  73. start(){this._provider.start(this);}
  74. stop(){this._provider.stop();return this._completionPromise;}};;Timeline.PerformanceModel=class extends Common.Object{constructor(){super();this._mainTarget=null;this._tracingModel=null;this._filters=[];this._timelineModel=new TimelineModel.TimelineModel();this._frameModel=new TimelineModel.TimelineFrameModel(event=>Timeline.TimelineUIUtils.eventStyle(event).category.name);this._filmStripModel=null;this._irModel=new TimelineModel.TimelineIRModel();this._window={left:0,right:Infinity};this._extensionTracingModels=[];this._recordStartTime=undefined;}
  75. setMainTarget(target){this._mainTarget=target;}
  76. mainTarget(){return this._mainTarget;}
  77. setRecordStartTime(time){this._recordStartTime=time;}
  78. recordStartTime(){return this._recordStartTime;}
  79. setFilters(filters){this._filters=filters;}
  80. filters(){return this._filters;}
  81. isVisible(event){return this._filters.every(f=>f.accept(event));}
  82. setTracingModel(model){this._tracingModel=model;this._timelineModel.setEvents(model);let inputEvents=null;let animationEvents=null;for(const track of this._timelineModel.tracks()){if(track.type===TimelineModel.TimelineModel.TrackType.Input){inputEvents=track.asyncEvents;}
  83. if(track.type===TimelineModel.TimelineModel.TrackType.Animation){animationEvents=track.asyncEvents;}}
  84. if(inputEvents||animationEvents){this._irModel.populate(inputEvents||[],animationEvents||[]);}
  85. const mainTracks=this._timelineModel.tracks().filter(track=>track.type===TimelineModel.TimelineModel.TrackType.MainThread&&track.forMainFrame&&track.events.length);const threadData=mainTracks.map(track=>{const event=track.events[0];return{thread:event.thread,time:event.startTime};});this._frameModel.addTraceEvents(this._mainTarget,this._timelineModel.inspectedTargetEvents(),threadData);for(const entry of this._extensionTracingModels){entry.model.adjustTime(this._tracingModel.minimumRecordTime()+(entry.timeOffset/1000)-this._recordStartTime);}
  86. this._autoWindowTimes();}
  87. addExtensionEvents(title,model,timeOffset){this._extensionTracingModels.push({model:model,title:title,timeOffset:timeOffset});if(!this._tracingModel){return;}
  88. model.adjustTime(this._tracingModel.minimumRecordTime()+(timeOffset/1000)-this._recordStartTime);this.dispatchEventToListeners(Timeline.PerformanceModel.Events.ExtensionDataAdded);}
  89. tracingModel(){if(!this._tracingModel){throw'call setTracingModel before accessing PerformanceModel';}
  90. return this._tracingModel;}
  91. timelineModel(){return this._timelineModel;}
  92. filmStripModel(){if(this._filmStripModel){return this._filmStripModel;}
  93. if(!this._tracingModel){throw'call setTracingModel before accessing PerformanceModel';}
  94. this._filmStripModel=new SDK.FilmStripModel(this._tracingModel);return this._filmStripModel;}
  95. frames(){return this._frameModel.frames();}
  96. frameModel(){return this._frameModel;}
  97. interactionRecords(){return this._irModel.interactionRecords();}
  98. extensionInfo(){return this._extensionTracingModels;}
  99. dispose(){if(this._tracingModel){this._tracingModel.dispose();}
  100. for(const extensionEntry of this._extensionTracingModels){extensionEntry.model.dispose();}}
  101. filmStripModelFrame(frame){const screenshotTime=frame.idle?frame.startTime:frame.endTime;const filmStripFrame=this._filmStripModel.frameByTimestamp(screenshotTime);return filmStripFrame&&filmStripFrame.timestamp-frame.endTime<10?filmStripFrame:null;}
  102. save(stream){const backingStorage=(this._tracingModel.backingStorage());return backingStorage.writeToStream(stream);}
  103. setWindow(window,animate){this._window=window;this.dispatchEventToListeners(Timeline.PerformanceModel.Events.WindowChanged,{window,animate});}
  104. window(){return this._window;}
  105. _autoWindowTimes(){const timelineModel=this._timelineModel;let tasks=[];for(const track of timelineModel.tracks()){if(track.type===TimelineModel.TimelineModel.TrackType.MainThread&&track.forMainFrame){tasks=track.tasks;}}
  106. if(!tasks.length){this.setWindow({left:timelineModel.minimumRecordTime(),right:timelineModel.maximumRecordTime()});return;}
  107. function findLowUtilizationRegion(startIndex,stopIndex){const threshold=0.1;let cutIndex=startIndex;let cutTime=(tasks[cutIndex].startTime+tasks[cutIndex].endTime)/2;let usedTime=0;const step=Math.sign(stopIndex-startIndex);for(let i=startIndex;i!==stopIndex;i+=step){const task=tasks[i];const taskTime=(task.startTime+task.endTime)/2;const interval=Math.abs(cutTime-taskTime);if(usedTime<threshold*interval){cutIndex=i;cutTime=taskTime;usedTime=0;}
  108. usedTime+=task.duration;}
  109. return cutIndex;}
  110. const rightIndex=findLowUtilizationRegion(tasks.length-1,0);const leftIndex=findLowUtilizationRegion(0,rightIndex);let leftTime=tasks[leftIndex].startTime;let rightTime=tasks[rightIndex].endTime;const span=rightTime-leftTime;const totalSpan=timelineModel.maximumRecordTime()-timelineModel.minimumRecordTime();if(span<totalSpan*0.1){leftTime=timelineModel.minimumRecordTime();rightTime=timelineModel.maximumRecordTime();}else{leftTime=Math.max(leftTime-0.05*span,timelineModel.minimumRecordTime());rightTime=Math.min(rightTime+0.05*span,timelineModel.maximumRecordTime());}
  111. this.setWindow({left:leftTime,right:rightTime});}};Timeline.PerformanceModel.Events={ExtensionDataAdded:Symbol('ExtensionDataAdded'),WindowChanged:Symbol('WindowChanged')};Timeline.PerformanceModel.Window;;Timeline.TimelineController=class{constructor(target,client){this._target=target;this._tracingManager=target.model(SDK.TracingManager);this._performanceModel=new Timeline.PerformanceModel();this._performanceModel.setMainTarget(target);this._client=client;const backingStorage=new Bindings.TempFileBackingStorage();this._tracingModel=new SDK.TracingModel(backingStorage);this._extensionSessions=[];SDK.targetManager.observeModels(SDK.CPUProfilerModel,this);}
  112. dispose(){SDK.targetManager.unobserveModels(SDK.CPUProfilerModel,this);}
  113. mainTarget(){return this._target;}
  114. async startRecording(options,providers){this._extensionTraceProviders=Extensions.extensionServer.traceProviders().slice();function disabledByDefault(category){return'disabled-by-default-'+category;}
  115. const categoriesArray=['-*','devtools.timeline',disabledByDefault('devtools.timeline'),disabledByDefault('devtools.timeline.frame'),'v8.execute',TimelineModel.TimelineModel.Category.Console,TimelineModel.TimelineModel.Category.UserTiming];categoriesArray.push(TimelineModel.TimelineModel.Category.LatencyInfo);if(Root.Runtime.experiments.isEnabled('timelineFlowEvents')){categoriesArray.push('devtools.timeline.async');}
  116. if(Root.Runtime.experiments.isEnabled('timelineV8RuntimeCallStats')&&options.enableJSSampling){categoriesArray.push(disabledByDefault('v8.runtime_stats_sampling'));}
  117. if(!Root.Runtime.queryParam('timelineTracingJSProfileDisabled')&&options.enableJSSampling){categoriesArray.push(disabledByDefault('v8.cpu_profiler'));if(Common.moduleSetting('highResolutionCpuProfiling').get()){categoriesArray.push(disabledByDefault('v8.cpu_profiler.hires'));}}
  118. categoriesArray.push(disabledByDefault('devtools.timeline.stack'));if(Root.Runtime.experiments.isEnabled('timelineInvalidationTracking')){categoriesArray.push(disabledByDefault('devtools.timeline.invalidationTracking'));}
  119. if(options.capturePictures){categoriesArray.push(disabledByDefault('devtools.timeline.layers'),disabledByDefault('devtools.timeline.picture'),disabledByDefault('blink.graphics_context_annotations'));}
  120. if(options.captureFilmStrip){categoriesArray.push(disabledByDefault('devtools.screenshot'));}
  121. this._extensionSessions=providers.map(provider=>new Timeline.ExtensionTracingSession(provider,this._performanceModel));this._extensionSessions.forEach(session=>session.start());this._performanceModel.setRecordStartTime(Date.now());const response=await this._startRecordingWithCategories(categoriesArray.join(','),options.enableJSSampling);if(response[Protocol.Error]){await this._waitForTracingToStop(false);}
  122. return response;}
  123. async stopRecording(){if(this._tracingManager){this._tracingManager.stop();}
  124. this._client.loadingStarted();await this._waitForTracingToStop(true);this._allSourcesFinished();return this._performanceModel;}
  125. _waitForTracingToStop(awaitTracingCompleteCallback){const tracingStoppedPromises=[];if(this._tracingManager&&awaitTracingCompleteCallback){tracingStoppedPromises.push(new Promise(resolve=>this._tracingCompleteCallback=resolve));}
  126. tracingStoppedPromises.push(this._stopProfilingOnAllModels());const extensionCompletionPromises=this._extensionSessions.map(session=>session.stop());if(extensionCompletionPromises.length){tracingStoppedPromises.push(Promise.race([Promise.all(extensionCompletionPromises),new Promise(r=>setTimeout(r,5000))]));}
  127. return Promise.all(tracingStoppedPromises);}
  128. modelAdded(cpuProfilerModel){if(this._profiling){cpuProfilerModel.startRecording();}}
  129. modelRemoved(cpuProfilerModel){}
  130. _startProfilingOnAllModels(){this._profiling=true;const models=SDK.targetManager.models(SDK.CPUProfilerModel);return Promise.all(models.map(model=>model.startRecording()));}
  131. _addCpuProfile(targetId,cpuProfile){if(!cpuProfile){Common.console.warn(Common.UIString('CPU profile for a target is not available.'));return;}
  132. if(!this._cpuProfiles){this._cpuProfiles=new Map();}
  133. this._cpuProfiles.set(targetId,cpuProfile);}
  134. _stopProfilingOnAllModels(){const models=this._profiling?SDK.targetManager.models(SDK.CPUProfilerModel):[];this._profiling=false;const promises=[];for(const model of models){const targetId=model.target().id();const modelPromise=model.stopRecording().then(this._addCpuProfile.bind(this,targetId));promises.push(modelPromise);}
  135. return Promise.all(promises);}
  136. async _startRecordingWithCategories(categories,enableJSSampling){await SDK.targetManager.suspendAllTargets('performance-timeline');if(enableJSSampling&&Root.Runtime.queryParam('timelineTracingJSProfileDisabled')){await this._startProfilingOnAllModels();}
  137. if(!this._tracingManager){return;}
  138. const samplingFrequencyHz=Common.moduleSetting('highResolutionCpuProfiling').get()?10000:1000;const options='sampling-frequency='+samplingFrequencyHz;return this._tracingManager.start(this,categories,options);}
  139. traceEventsCollected(events){this._tracingModel.addEvents(events);}
  140. tracingComplete(){this._tracingCompleteCallback();this._tracingCompleteCallback=null;}
  141. _allSourcesFinished(){this._client.processingStarted();setTimeout(()=>this._finalizeTrace(),0);}
  142. async _finalizeTrace(){this._injectCpuProfileEvents();await SDK.targetManager.resumeAllTargets();this._tracingModel.tracingComplete();this._client.loadingComplete(this._tracingModel);}
  143. _injectCpuProfileEvent(pid,tid,cpuProfile){if(!cpuProfile){return;}
  144. const cpuProfileEvent=({cat:SDK.TracingModel.DevToolsMetadataEventCategory,ph:SDK.TracingModel.Phase.Instant,ts:this._tracingModel.maximumRecordTime()*1000,pid:pid,tid:tid,name:TimelineModel.TimelineModel.RecordType.CpuProfile,args:{data:{cpuProfile:cpuProfile}}});this._tracingModel.addEvents([cpuProfileEvent]);}
  145. _buildTargetToProcessIdMap(){const metadataEventTypes=TimelineModel.TimelineModel.DevToolsMetadataEvent;const metadataEvents=this._tracingModel.devToolsMetadataEvents();const browserMetaEvent=metadataEvents.find(e=>e.name===metadataEventTypes.TracingStartedInBrowser);if(!browserMetaEvent){return null;}
  146. const pseudoPidToFrames=new Platform.Multimap();const targetIdToPid=new Map();const frames=browserMetaEvent.args.data['frames'];for(const frameInfo of frames){targetIdToPid.set(frameInfo.frame,frameInfo.processId);}
  147. for(const event of metadataEvents){const data=event.args.data;switch(event.name){case metadataEventTypes.FrameCommittedInBrowser:if(data.processId){targetIdToPid.set(data.frame,data.processId);}else{pseudoPidToFrames.set(data.processPseudoId,data.frame);}
  148. break;case metadataEventTypes.ProcessReadyInBrowser:for(const frame of pseudoPidToFrames.get(data.processPseudoId)||[]){targetIdToPid.set(frame,data.processId);}
  149. break;}}
  150. const mainFrame=frames.find(frame=>!frame.parent);const mainRendererProcessId=mainFrame.processId;const mainProcess=this._tracingModel.processById(mainRendererProcessId);if(mainProcess){targetIdToPid.set(SDK.targetManager.mainTarget().id(),mainProcess.id());}
  151. return targetIdToPid;}
  152. _injectCpuProfileEvents(){if(!this._cpuProfiles){return;}
  153. const metadataEventTypes=TimelineModel.TimelineModel.DevToolsMetadataEvent;const metadataEvents=this._tracingModel.devToolsMetadataEvents();const targetIdToPid=this._buildTargetToProcessIdMap();if(targetIdToPid){for(const[id,profile]of this._cpuProfiles){const pid=targetIdToPid.get(id);if(!pid){continue;}
  154. const process=this._tracingModel.processById(pid);const thread=process&&process.threadByName(TimelineModel.TimelineModel.RendererMainThreadName);if(thread){this._injectCpuProfileEvent(pid,thread.id(),profile);}}}else{const mainMetaEvent=metadataEvents.filter(event=>event.name===metadataEventTypes.TracingStartedInPage).peekLast();if(mainMetaEvent){const pid=mainMetaEvent.thread.process().id();const mainCpuProfile=this._cpuProfiles.get(this._tracingManager.target().id());this._injectCpuProfileEvent(pid,mainMetaEvent.thread.id(),mainCpuProfile);}else{let tid=0;for(const pair of this._cpuProfiles){const target=SDK.targetManager.targetById(pair[0]);const name=target&&target.name();this._tracingModel.addEvents(TimelineModel.TimelineJSProfileProcessor.buildTraceProfileFromCpuProfile(pair[1],++tid,tid===1,name));}}}
  155. const workerMetaEvents=metadataEvents.filter(event=>event.name===metadataEventTypes.TracingSessionIdForWorker);for(const metaEvent of workerMetaEvents){const workerId=metaEvent.args['data']['workerId'];const cpuProfile=this._cpuProfiles.get(workerId);this._injectCpuProfileEvent(metaEvent.thread.process().id(),metaEvent.args['data']['workerThreadId'],cpuProfile);}
  156. this._cpuProfiles=null;}
  157. tracingBufferUsage(usage){this._client.recordingProgress(usage);}
  158. eventsRetrievalProgress(progress){this._client.loadingProgress(progress);}};Timeline.TimelineController.Client=function(){};Timeline.TimelineController.Client.prototype={recordingProgress(usage){},};Timeline.TimelineController.RecordingOptions;;Timeline.TimelineDetailsView=class extends UI.VBox{constructor(delegate){super();this.element.classList.add('timeline-details');this._detailsLinkifier=new Components.Linkifier();this._tabbedPane=new UI.TabbedPane();this._tabbedPane.show(this.element);const tabIds=Timeline.TimelineDetailsView.Tab;this._defaultDetailsWidget=new UI.VBox();this._defaultDetailsWidget.element.classList.add('timeline-details-view');this._defaultDetailsContentElement=this._defaultDetailsWidget.element.createChild('div','timeline-details-view-body vbox');this._defaultDetailsContentElement.tabIndex=0;this._appendTab(tabIds.Details,Common.UIString('Summary'),this._defaultDetailsWidget);this.setPreferredTab(tabIds.Details);this._rangeDetailViews=new Map();const bottomUpView=new Timeline.BottomUpTimelineTreeView();this._appendTab(tabIds.BottomUp,Common.UIString('Bottom-Up'),bottomUpView);this._rangeDetailViews.set(tabIds.BottomUp,bottomUpView);const callTreeView=new Timeline.CallTreeTimelineTreeView();this._appendTab(tabIds.CallTree,Common.UIString('Call Tree'),callTreeView);this._rangeDetailViews.set(tabIds.CallTree,callTreeView);const eventsView=new Timeline.EventsTimelineTreeView(delegate);this._appendTab(tabIds.EventLog,Common.UIString('Event Log'),eventsView);this._rangeDetailViews.set(tabIds.EventLog,eventsView);this._tabbedPane.addEventListener(UI.TabbedPane.Events.TabSelected,this._tabSelected,this);}
  159. setModel(model,track){if(this._model!==model){if(this._model){this._model.removeEventListener(Timeline.PerformanceModel.Events.WindowChanged,this._onWindowChanged,this);}
  160. this._model=model;if(this._model){this._model.addEventListener(Timeline.PerformanceModel.Events.WindowChanged,this._onWindowChanged,this);}}
  161. this._track=track;this._tabbedPane.closeTabs([Timeline.TimelineDetailsView.Tab.PaintProfiler,Timeline.TimelineDetailsView.Tab.LayerViewer],false);for(const view of this._rangeDetailViews.values()){view.setModel(model,track);}
  162. this._lazyPaintProfilerView=null;this._lazyLayersView=null;this.setSelection(null);}
  163. _setContent(node){const allTabs=this._tabbedPane.otherTabs(Timeline.TimelineDetailsView.Tab.Details);for(let i=0;i<allTabs.length;++i){if(!this._rangeDetailViews.has(allTabs[i])){this._tabbedPane.closeTab(allTabs[i]);}}
  164. this._defaultDetailsContentElement.removeChildren();this._defaultDetailsContentElement.appendChild(node);}
  165. _updateContents(){const view=this._rangeDetailViews.get(this._tabbedPane.selectedTabId||'');if(view){const window=this._model.window();view.updateContents(this._selection||Timeline.TimelineSelection.fromRange(window.left,window.right));}}
  166. _appendTab(id,tabTitle,view,isCloseable){this._tabbedPane.appendTab(id,tabTitle,view,undefined,undefined,isCloseable);if(this._preferredTabId!==this._tabbedPane.selectedTabId){this._tabbedPane.selectTab(id);}}
  167. headerElement(){return this._tabbedPane.headerElement();}
  168. setPreferredTab(tabId){this._preferredTabId=tabId;}
  169. _onWindowChanged(event){if(!this._selection){this._updateContentsFromWindow();}}
  170. _updateContentsFromWindow(){if(!this._model){this._setContent(UI.html`<div/>`);return;}
  171. const window=this._model.window();this._updateSelectedRangeStats(window.left,window.right);this._updateContents();}
  172. setSelection(selection){this._detailsLinkifier.reset();this._selection=selection;if(!this._selection){this._updateContentsFromWindow();return;}
  173. switch(this._selection.type()){case Timeline.TimelineSelection.Type.TraceEvent:const event=(this._selection.object());Timeline.TimelineUIUtils.buildTraceEventDetails(event,this._model.timelineModel(),this._detailsLinkifier,true).then(fragment=>this._appendDetailsTabsForTraceEventAndShowDetails(event,fragment));break;case Timeline.TimelineSelection.Type.Frame:const frame=(this._selection.object());const filmStripFrame=this._model.filmStripModelFrame(frame);this._setContent(Timeline.TimelineUIUtils.generateDetailsContentForFrame(frame,filmStripFrame));if(frame.layerTree){const layersView=this._layersView();layersView.showLayerTree(frame.layerTree);if(!this._tabbedPane.hasTab(Timeline.TimelineDetailsView.Tab.LayerViewer)){this._appendTab(Timeline.TimelineDetailsView.Tab.LayerViewer,Common.UIString('Layers'),layersView);}}
  174. break;case Timeline.TimelineSelection.Type.NetworkRequest:const request=(this._selection.object());Timeline.TimelineUIUtils.buildNetworkRequestDetails(request,this._model.timelineModel(),this._detailsLinkifier).then(this._setContent.bind(this));break;case Timeline.TimelineSelection.Type.Range:this._updateSelectedRangeStats(this._selection.startTime(),this._selection.endTime());break;}
  175. this._updateContents();}
  176. _tabSelected(event){if(!event.data.isUserGesture){return;}
  177. this.setPreferredTab(event.data.tabId);this._updateContents();}
  178. _layersView(){if(this._lazyLayersView){return this._lazyLayersView;}
  179. this._lazyLayersView=new Timeline.TimelineLayersView(this._model.timelineModel(),this._showSnapshotInPaintProfiler.bind(this));return this._lazyLayersView;}
  180. _paintProfilerView(){if(this._lazyPaintProfilerView){return this._lazyPaintProfilerView;}
  181. this._lazyPaintProfilerView=new Timeline.TimelinePaintProfilerView(this._model.frameModel());return this._lazyPaintProfilerView;}
  182. _showSnapshotInPaintProfiler(snapshot){const paintProfilerView=this._paintProfilerView();paintProfilerView.setSnapshot(snapshot);if(!this._tabbedPane.hasTab(Timeline.TimelineDetailsView.Tab.PaintProfiler)){this._appendTab(Timeline.TimelineDetailsView.Tab.PaintProfiler,Common.UIString('Paint Profiler'),paintProfilerView,true);}
  183. this._tabbedPane.selectTab(Timeline.TimelineDetailsView.Tab.PaintProfiler,true);}
  184. _appendDetailsTabsForTraceEventAndShowDetails(event,content){this._setContent(content);if(event.name===TimelineModel.TimelineModel.RecordType.Paint||event.name===TimelineModel.TimelineModel.RecordType.RasterTask){this._showEventInPaintProfiler(event);}}
  185. _showEventInPaintProfiler(event){const paintProfilerModel=SDK.targetManager.models(SDK.PaintProfilerModel)[0];if(!paintProfilerModel){return;}
  186. const paintProfilerView=this._paintProfilerView();const hasProfileData=paintProfilerView.setEvent(paintProfilerModel,event);if(!hasProfileData){return;}
  187. if(this._tabbedPane.hasTab(Timeline.TimelineDetailsView.Tab.PaintProfiler)){return;}
  188. this._appendTab(Timeline.TimelineDetailsView.Tab.PaintProfiler,Common.UIString('Paint Profiler'),paintProfilerView);}
  189. _updateSelectedRangeStats(startTime,endTime){if(!this._model||!this._track){return;}
  190. const aggregatedStats=Timeline.TimelineUIUtils.statsForTimeRange(this._track.syncEvents(),startTime,endTime);const startOffset=startTime-this._model.timelineModel().minimumRecordTime();const endOffset=endTime-this._model.timelineModel().minimumRecordTime();const contentHelper=new Timeline.TimelineDetailsContentHelper(null,null);contentHelper.addSection(ls`Range: ${Number.millisToString(startOffset)} \u2013 ${Number.millisToString(endOffset)}`);const pieChart=Timeline.TimelineUIUtils.generatePieChart(aggregatedStats);contentHelper.appendElementRow('',pieChart);this._setContent(contentHelper.fragment);}};Timeline.TimelineDetailsView.Tab={Details:'Details',EventLog:'EventLog',CallTree:'CallTree',BottomUp:'BottomUp',PaintProfiler:'PaintProfiler',LayerViewer:'LayerViewer'};;Timeline.TimelineLoader=class{constructor(client){this._client=client;this._backingStorage=new Bindings.TempFileBackingStorage();this._tracingModel=new SDK.TracingModel(this._backingStorage);this._canceledCallback=null;this._state=Timeline.TimelineLoader.State.Initial;this._buffer='';this._firstRawChunk=true;this._firstChunk=true;this._loadedBytes=0;this._totalSize;this._jsonTokenizer=new TextUtils.BalancedJSONTokenizer(this._writeBalancedJSON.bind(this),true);}
  191. static loadFromFile(file,client){const loader=new Timeline.TimelineLoader(client);const fileReader=new Bindings.ChunkedFileReader(file,Timeline.TimelineLoader.TransferChunkLengthBytes);loader._canceledCallback=fileReader.cancel.bind(fileReader);loader._totalSize=file.size;fileReader.read(loader).then(success=>{if(!success){loader._reportErrorAndCancelLoading(fileReader.error().message);}});return loader;}
  192. static loadFromEvents(events,client){const loader=new Timeline.TimelineLoader(client);setTimeout(async()=>{const eventsPerChunk=5000;client.loadingStarted();for(let i=0;i<events.length;i+=eventsPerChunk){const chunk=events.slice(i,i+eventsPerChunk);loader._tracingModel.addEvents(chunk);client.loadingProgress((i+chunk.length)/events.length);await new Promise(r=>setTimeout(r));}
  193. loader.close();});return loader;}
  194. static loadFromURL(url,client){const loader=new Timeline.TimelineLoader(client);Host.ResourceLoader.loadAsStream(url,null,loader);return loader;}
  195. cancel(){this._tracingModel=null;this._backingStorage.reset();this._client.loadingComplete(null);this._client=null;if(this._canceledCallback){this._canceledCallback();}}
  196. write(chunk){if(!this._client){return Promise.resolve();}
  197. this._loadedBytes+=chunk.length;if(this._firstRawChunk){this._client.loadingStarted();}else{this._client.loadingProgress(this._totalSize?this._loadedBytes/this._totalSize:undefined);}
  198. this._firstRawChunk=false;if(this._state===Timeline.TimelineLoader.State.Initial){if(chunk.startsWith('{"nodes":[')){this._state=Timeline.TimelineLoader.State.LoadingCPUProfileFormat;}else if(chunk[0]==='{'){this._state=Timeline.TimelineLoader.State.LookingForEvents;}else if(chunk[0]==='['){this._state=Timeline.TimelineLoader.State.ReadingEvents;}else{this._reportErrorAndCancelLoading(Common.UIString('Malformed timeline data: Unknown JSON format'));return Promise.resolve();}}
  199. if(this._state===Timeline.TimelineLoader.State.LoadingCPUProfileFormat){this._buffer+=chunk;return Promise.resolve();}
  200. if(this._state===Timeline.TimelineLoader.State.LookingForEvents){const objectName='"traceEvents":';const startPos=this._buffer.length-objectName.length;this._buffer+=chunk;const pos=this._buffer.indexOf(objectName,startPos);if(pos===-1){return Promise.resolve();}
  201. chunk=this._buffer.slice(pos+objectName.length);this._state=Timeline.TimelineLoader.State.ReadingEvents;}
  202. if(this._state!==Timeline.TimelineLoader.State.ReadingEvents){return Promise.resolve();}
  203. if(this._jsonTokenizer.write(chunk)){return Promise.resolve();}
  204. this._state=Timeline.TimelineLoader.State.SkippingTail;if(this._firstChunk){this._reportErrorAndCancelLoading(Common.UIString('Malformed timeline input, wrong JSON brackets balance'));}
  205. return Promise.resolve();}
  206. _writeBalancedJSON(data){let json=data+']';if(!this._firstChunk){const commaIndex=json.indexOf(',');if(commaIndex!==-1){json=json.slice(commaIndex+1);}
  207. json='['+json;}
  208. let items;try{items=(JSON.parse(json));}catch(e){this._reportErrorAndCancelLoading(Common.UIString('Malformed timeline data: %s',e.toString()));return;}
  209. if(this._firstChunk){this._firstChunk=false;if(this._looksLikeAppVersion(items[0])){this._reportErrorAndCancelLoading(Common.UIString('Legacy Timeline format is not supported.'));return;}}
  210. try{this._tracingModel.addEvents(items);}catch(e){this._reportErrorAndCancelLoading(Common.UIString('Malformed timeline data: %s',e.toString()));}}
  211. _reportErrorAndCancelLoading(message){if(message){Common.console.error(message);}
  212. this.cancel();}
  213. _looksLikeAppVersion(item){return typeof item==='string'&&item.indexOf('Chrome')!==-1;}
  214. async close(){if(!this._client){return;}
  215. this._client.processingStarted();setTimeout(()=>this._finalizeTrace(),0);}
  216. _finalizeTrace(){if(this._state===Timeline.TimelineLoader.State.LoadingCPUProfileFormat){this._parseCPUProfileFormat(this._buffer);this._buffer='';}
  217. this._tracingModel.tracingComplete();this._client.loadingComplete(this._tracingModel);}
  218. _parseCPUProfileFormat(text){let traceEvents;try{const profile=JSON.parse(text);traceEvents=TimelineModel.TimelineJSProfileProcessor.buildTraceProfileFromCpuProfile(profile,1,true);}catch(e){this._reportErrorAndCancelLoading(Common.UIString('Malformed CPU profile format'));return;}
  219. this._tracingModel.addEvents(traceEvents);}};Timeline.TimelineLoader.TransferChunkLengthBytes=5000000;Timeline.TimelineLoader.Client=function(){};Timeline.TimelineLoader.Client.prototype={loadingStarted(){},loadingProgress(progress){},processingStarted(){},loadingComplete(tracingModel){},};Timeline.TimelineLoader.State={Initial:Symbol('Initial'),LookingForEvents:Symbol('LookingForEvents'),ReadingEvents:Symbol('ReadingEvents'),SkippingTail:Symbol('SkippingTail'),LoadingCPUProfileFormat:Symbol('LoadingCPUProfileFormat')};;Timeline.TimelineEventOverview=class extends PerfUI.TimelineOverviewBase{constructor(id,title){super();this.element.id='timeline-overview-'+id;this.element.classList.add('overview-strip');this._model=null;if(title){this.element.createChild('div','timeline-overview-strip-title').textContent=title;}}
  220. setModel(model){this._model=model;}
  221. _renderBar(begin,end,position,height,color){const x=begin;const width=end-begin;const ctx=this.context();ctx.fillStyle=color;ctx.fillRect(x,position,width,height);}};Timeline.TimelineEventOverviewInput=class extends Timeline.TimelineEventOverview{constructor(){super('input',null);}
  222. update(){super.update();if(!this._model){return;}
  223. const height=this.height();const descriptors=Timeline.TimelineUIUtils.eventDispatchDesciptors();const descriptorsByType=new Map();let maxPriority=-1;for(const descriptor of descriptors){for(const type of descriptor.eventTypes){descriptorsByType.set(type,descriptor);}
  224. maxPriority=Math.max(maxPriority,descriptor.priority);}
  225. const minWidth=2*window.devicePixelRatio;const timeOffset=this._model.timelineModel().minimumRecordTime();const timeSpan=this._model.timelineModel().maximumRecordTime()-timeOffset;const canvasWidth=this.width();const scale=canvasWidth/timeSpan;for(let priority=0;priority<=maxPriority;++priority){for(const track of this._model.timelineModel().tracks()){for(let i=0;i<track.events.length;++i){const event=track.events[i];if(event.name!==TimelineModel.TimelineModel.RecordType.EventDispatch){continue;}
  226. const descriptor=descriptorsByType.get(event.args['data']['type']);if(!descriptor||descriptor.priority!==priority){continue;}
  227. const start=Number.constrain(Math.floor((event.startTime-timeOffset)*scale),0,canvasWidth);const end=Number.constrain(Math.ceil((event.endTime-timeOffset)*scale),0,canvasWidth);const width=Math.max(end-start,minWidth);this._renderBar(start,start+width,0,height,descriptor.color);}}}}};Timeline.TimelineEventOverviewNetwork=class extends Timeline.TimelineEventOverview{constructor(){super('network',Common.UIString('NET'));}
  228. update(){super.update();if(!this._model){return;}
  229. const timelineModel=this._model.timelineModel();const bandHeight=this.height()/2;const timeOffset=timelineModel.minimumRecordTime();const timeSpan=timelineModel.maximumRecordTime()-timeOffset;const canvasWidth=this.width();const scale=canvasWidth/timeSpan;const highPath=new Path2D();const lowPath=new Path2D();const priorities=Protocol.Network.ResourcePriority;const highPrioritySet=new Set([priorities.VeryHigh,priorities.High,priorities.Medium]);for(const request of timelineModel.networkRequests()){const path=highPrioritySet.has(request.priority)?highPath:lowPath;const s=Math.max(Math.floor((request.startTime-timeOffset)*scale),0);const e=Math.min(Math.ceil((request.endTime-timeOffset)*scale+1),canvasWidth);path.rect(s,0,e-s,bandHeight-1);}
  230. const ctx=this.context();ctx.save();ctx.fillStyle='hsl(214, 60%, 60%)';ctx.fill((highPath));ctx.translate(0,bandHeight);ctx.fillStyle='hsl(214, 80%, 80%)';ctx.fill((lowPath));ctx.restore();}};Timeline.TimelineEventOverviewCPUActivity=class extends Timeline.TimelineEventOverview{constructor(){super('cpu-activity',Common.UIString('CPU'));this._backgroundCanvas=this.element.createChild('canvas','fill background');}
  231. resetCanvas(){super.resetCanvas();this._backgroundCanvas.width=this.element.clientWidth*window.devicePixelRatio;this._backgroundCanvas.height=this.element.clientHeight*window.devicePixelRatio;}
  232. update(){super.update();if(!this._model){return;}
  233. const timelineModel=this._model.timelineModel();const quantSizePx=4*window.devicePixelRatio;const width=this.width();const height=this.height();const baseLine=height;const timeOffset=timelineModel.minimumRecordTime();const timeSpan=timelineModel.maximumRecordTime()-timeOffset;const scale=width/timeSpan;const quantTime=quantSizePx/scale;const categories=Timeline.TimelineUIUtils.categories();const categoryOrder=Timeline.TimelineUIUtils.getTimelineMainEventCategories();const otherIndex=categoryOrder.indexOf('other');const idleIndex=0;console.assert(idleIndex===categoryOrder.indexOf('idle'));for(let i=idleIndex+1;i<categoryOrder.length;++i){categories[categoryOrder[i]]._overviewIndex=i;}
  234. const backgroundContext=this._backgroundCanvas.getContext('2d');for(const track of timelineModel.tracks()){if(track.type===TimelineModel.TimelineModel.TrackType.MainThread&&track.forMainFrame){drawThreadEvents(this.context(),track.events);}else{drawThreadEvents(backgroundContext,track.events);}}
  235. applyPattern(backgroundContext);function drawThreadEvents(ctx,events){const quantizer=new Timeline.Quantizer(timeOffset,quantTime,drawSample);let x=0;const categoryIndexStack=[];const paths=[];const lastY=[];for(let i=0;i<categoryOrder.length;++i){paths[i]=new Path2D();paths[i].moveTo(0,height);lastY[i]=height;}
  236. function drawSample(counters){let y=baseLine;for(let i=idleIndex+1;i<categoryOrder.length;++i){const h=(counters[i]||0)/quantTime*height;y-=h;paths[i].bezierCurveTo(x,lastY[i],x,y,x+quantSizePx/2,y);lastY[i]=y;}
  237. x+=quantSizePx;}
  238. function onEventStart(e){const index=categoryIndexStack.length?categoryIndexStack.peekLast():idleIndex;quantizer.appendInterval(e.startTime,index);categoryIndexStack.push(Timeline.TimelineUIUtils.eventStyle(e).category._overviewIndex||otherIndex);}
  239. function onEventEnd(e){quantizer.appendInterval(e.endTime,categoryIndexStack.pop());}
  240. TimelineModel.TimelineModel.forEachEvent(events,onEventStart,onEventEnd);quantizer.appendInterval(timeOffset+timeSpan+quantTime,idleIndex);for(let i=categoryOrder.length-1;i>0;--i){paths[i].lineTo(width,height);ctx.fillStyle=categories[categoryOrder[i]].color;ctx.fill(paths[i]);}}
  241. function applyPattern(ctx){const step=4*window.devicePixelRatio;ctx.save();ctx.lineWidth=step/Math.sqrt(8);for(let x=0.5;x<width+height;x+=step){ctx.moveTo(x,0);ctx.lineTo(x-height,height);}
  242. ctx.globalCompositeOperation='destination-out';ctx.stroke();ctx.restore();}}};Timeline.TimelineEventOverviewResponsiveness=class extends Timeline.TimelineEventOverview{constructor(){super('responsiveness',null);}
  243. update(){super.update();if(!this._model){return;}
  244. const height=this.height();const timeOffset=this._model.timelineModel().minimumRecordTime();const timeSpan=this._model.timelineModel().maximumRecordTime()-timeOffset;const scale=this.width()/timeSpan;const frames=this._model.frames();const ctx=(this.context());const fillPath=new Path2D();const markersPath=new Path2D();for(let i=0;i<frames.length;++i){const frame=frames[i];if(!frame.hasWarnings()){continue;}
  245. paintWarningDecoration(frame.startTime,frame.duration);}
  246. for(const track of this._model.timelineModel().tracks()){const events=track.events;for(let i=0;i<events.length;++i){if(!TimelineModel.TimelineData.forEvent(events[i]).warning){continue;}
  247. paintWarningDecoration(events[i].startTime,events[i].duration);}}
  248. ctx.fillStyle='hsl(0, 80%, 90%)';ctx.strokeStyle='red';ctx.lineWidth=2*window.devicePixelRatio;ctx.fill(fillPath);ctx.stroke(markersPath);function paintWarningDecoration(time,duration){const x=Math.round(scale*(time-timeOffset));const w=Math.round(scale*duration);fillPath.rect(x,0,w,height);markersPath.moveTo(x+w,0);markersPath.lineTo(x+w,height);}}};Timeline.TimelineFilmStripOverview=class extends Timeline.TimelineEventOverview{constructor(){super('filmstrip',null);this.reset();}
  249. update(){super.update();const frames=this._model?this._model.filmStripModel().frames():[];if(!frames.length){return;}
  250. const drawGeneration=Symbol('drawGeneration');this._drawGeneration=drawGeneration;this._imageByFrame(frames[0]).then(image=>{if(this._drawGeneration!==drawGeneration){return;}
  251. if(!image||!image.naturalWidth||!image.naturalHeight){return;}
  252. const imageHeight=this.height()-2*Timeline.TimelineFilmStripOverview.Padding;const imageWidth=Math.ceil(imageHeight*image.naturalWidth/image.naturalHeight);const popoverScale=Math.min(200/image.naturalWidth,1);this._emptyImage=new Image(image.naturalWidth*popoverScale,image.naturalHeight*popoverScale);this._drawFrames(imageWidth,imageHeight);});}
  253. _imageByFrame(frame){let imagePromise=this._frameToImagePromise.get(frame);if(!imagePromise){imagePromise=frame.imageDataPromise().then(data=>UI.loadImageFromData(data));this._frameToImagePromise.set(frame,imagePromise);}
  254. return imagePromise;}
  255. _drawFrames(imageWidth,imageHeight){if(!imageWidth||!this._model){return;}
  256. const filmStripModel=this._model.filmStripModel();if(!filmStripModel.frames().length){return;}
  257. const padding=Timeline.TimelineFilmStripOverview.Padding;const width=this.width();const zeroTime=filmStripModel.zeroTime();const spanTime=filmStripModel.spanTime();const scale=spanTime/width;const context=this.context();const drawGeneration=this._drawGeneration;context.beginPath();for(let x=padding;x<width;x+=imageWidth+2*padding){const time=zeroTime+(x+imageWidth/2)*scale;const frame=filmStripModel.frameByTimestamp(time);if(!frame){continue;}
  258. context.rect(x-0.5,0.5,imageWidth+1,imageHeight+1);this._imageByFrame(frame).then(drawFrameImage.bind(this,x));}
  259. context.strokeStyle='#ddd';context.stroke();function drawFrameImage(x,image){if(this._drawGeneration!==drawGeneration||!image){return;}
  260. context.drawImage(image,x,1,imageWidth,imageHeight);}}
  261. overviewInfoPromise(x){if(!this._model||!this._model.filmStripModel().frames().length){return Promise.resolve((null));}
  262. const time=this.calculator().positionToTime(x);const frame=this._model.filmStripModel().frameByTimestamp(time);if(frame===this._lastFrame){return Promise.resolve(this._lastElement);}
  263. const imagePromise=frame?this._imageByFrame(frame):Promise.resolve(this._emptyImage);return imagePromise.then(createFrameElement.bind(this));function createFrameElement(image){const element=createElementWithClass('div','frame');if(image){element.createChild('div','thumbnail').appendChild(image);}
  264. this._lastFrame=frame;this._lastElement=element;return element;}}
  265. reset(){this._lastFrame=undefined;this._lastElement=null;this._frameToImagePromise=new Map();this._imageWidth=0;}};Timeline.TimelineFilmStripOverview.Padding=2;Timeline.TimelineEventOverviewFrames=class extends Timeline.TimelineEventOverview{constructor(){super('framerate',Common.UIString('FPS'));}
  266. update(){super.update();if(!this._model){return;}
  267. const frames=this._model.frames();if(!frames.length){return;}
  268. const height=this.height();const padding=1*window.devicePixelRatio;const baseFrameDurationMs=1e3/60;const visualHeight=height-2*padding;const timeOffset=this._model.timelineModel().minimumRecordTime();const timeSpan=this._model.timelineModel().maximumRecordTime()-timeOffset;const scale=this.width()/timeSpan;const baseY=height-padding;const ctx=this.context();const bottomY=baseY+10*window.devicePixelRatio;let x=0;let y=bottomY;const lineWidth=window.devicePixelRatio;const offset=lineWidth&1?0.5:0;const tickDepth=1.5*window.devicePixelRatio;ctx.beginPath();ctx.moveTo(0,y);for(let i=0;i<frames.length;++i){const frame=frames[i];x=Math.round((frame.startTime-timeOffset)*scale)+offset;ctx.lineTo(x,y);ctx.lineTo(x,y+tickDepth);y=frame.idle?bottomY:Math.round(baseY-visualHeight*Math.min(baseFrameDurationMs/frame.duration,1))-offset;ctx.lineTo(x,y+tickDepth);ctx.lineTo(x,y);}
  269. const lastFrame=frames.peekLast();x=Math.round((lastFrame.startTime+lastFrame.duration-timeOffset)*scale)+offset;ctx.lineTo(x,y);ctx.lineTo(x,bottomY);ctx.fillStyle='hsl(110, 50%, 88%)';ctx.strokeStyle='hsl(110, 50%, 60%)';ctx.lineWidth=lineWidth;ctx.fill();ctx.stroke();}};Timeline.TimelineEventOverviewMemory=class extends Timeline.TimelineEventOverview{constructor(){super('memory',Common.UIString('HEAP'));this._heapSizeLabel=this.element.createChild('div','memory-graph-label');}
  270. resetHeapSizeLabels(){this._heapSizeLabel.textContent='';}
  271. update(){super.update();const ratio=window.devicePixelRatio;if(!this._model){this.resetHeapSizeLabels();return;}
  272. const tracks=this._model.timelineModel().tracks().filter(track=>track.type===TimelineModel.TimelineModel.TrackType.MainThread&&track.forMainFrame);const trackEvents=tracks.map(track=>track.events);const lowerOffset=3*ratio;let maxUsedHeapSize=0;let minUsedHeapSize=100000000000;const minTime=this._model.timelineModel().minimumRecordTime();const maxTime=this._model.timelineModel().maximumRecordTime();function isUpdateCountersEvent(event){return event.name===TimelineModel.TimelineModel.RecordType.UpdateCounters;}
  273. for(let i=0;i<trackEvents.length;i++){trackEvents[i]=trackEvents[i].filter(isUpdateCountersEvent);}
  274. function calculateMinMaxSizes(event){const counters=event.args.data;if(!counters||!counters.jsHeapSizeUsed){return;}
  275. maxUsedHeapSize=Math.max(maxUsedHeapSize,counters.jsHeapSizeUsed);minUsedHeapSize=Math.min(minUsedHeapSize,counters.jsHeapSizeUsed);}
  276. for(let i=0;i<trackEvents.length;i++){trackEvents[i].forEach(calculateMinMaxSizes);}
  277. minUsedHeapSize=Math.min(minUsedHeapSize,maxUsedHeapSize);const lineWidth=1;const width=this.width();const height=this.height()-lowerOffset;const xFactor=width/(maxTime-minTime);const yFactor=(height-lineWidth)/Math.max(maxUsedHeapSize-minUsedHeapSize,1);const histogram=new Array(width);function buildHistogram(event){const counters=event.args.data;if(!counters||!counters.jsHeapSizeUsed){return;}
  278. const x=Math.round((event.startTime-minTime)*xFactor);const y=Math.round((counters.jsHeapSizeUsed-minUsedHeapSize)*yFactor);histogram[x]=Math.max(histogram[x]||0,y);}
  279. for(let i=0;i<trackEvents.length;i++){trackEvents[i].forEach(buildHistogram);}
  280. const ctx=this.context();const heightBeyondView=height+lowerOffset+lineWidth;ctx.translate(0.5,0.5);ctx.beginPath();ctx.moveTo(-lineWidth,heightBeyondView);let y=0;let isFirstPoint=true;let lastX=0;for(let x=0;x<histogram.length;x++){if(typeof histogram[x]==='undefined'){continue;}
  281. if(isFirstPoint){isFirstPoint=false;y=histogram[x];ctx.lineTo(-lineWidth,height-y);}
  282. const nextY=histogram[x];if(Math.abs(nextY-y)>2&&Math.abs(x-lastX)>1){ctx.lineTo(x,height-y);}
  283. y=nextY;ctx.lineTo(x,height-y);lastX=x;}
  284. ctx.lineTo(width+lineWidth,height-y);ctx.lineTo(width+lineWidth,heightBeyondView);ctx.closePath();ctx.fillStyle='hsla(220, 90%, 70%, 0.2)';ctx.fill();ctx.lineWidth=lineWidth;ctx.strokeStyle='hsl(220, 90%, 70%)';ctx.stroke();this._heapSizeLabel.textContent=Common.UIString('%s \u2013 %s',Number.bytesToString(minUsedHeapSize),Number.bytesToString(maxUsedHeapSize));}};Timeline.Quantizer=class{constructor(startTime,quantDuration,callback){this._lastTime=startTime;this._quantDuration=quantDuration;this._callback=callback;this._counters=[];this._remainder=quantDuration;}
  285. appendInterval(time,group){let interval=time-this._lastTime;if(interval<=this._remainder){this._counters[group]=(this._counters[group]||0)+interval;this._remainder-=interval;this._lastTime=time;return;}
  286. this._counters[group]=(this._counters[group]||0)+this._remainder;this._callback(this._counters);interval-=this._remainder;while(interval>=this._quantDuration){const counters=[];counters[group]=this._quantDuration;this._callback(counters);interval-=this._quantDuration;}
  287. this._counters=[];this._counters[group]=interval;this._lastTime=time;this._remainder=this._quantDuration-interval;}};Timeline.TimelineEventOverviewCoverage=class extends Timeline.TimelineEventOverview{constructor(){super('coverage',Common.UIString('COVERAGE'));this._heapSizeLabel=this.element.createChild('div','timeline-overview-coverage-label');}
  288. resetHeapSizeLabels(){this._heapSizeLabel.textContent='';}
  289. setModel(model){super.setModel(model);if(this._model){this._coverageModel=model.mainTarget().model(Coverage.CoverageModel);}}
  290. update(){super.update();const ratio=window.devicePixelRatio;if(!this._coverageModel){return;}
  291. let total=0;let total_used=0;const usedByTimestamp=new Map();const totalByTimestamp=new Map();for(const urlInfo of this._coverageModel.entries()){for(const info of urlInfo.entries()){total+=info.size();for(const[stamp,used]of info.usedByTimestamp()){total_used+=used;if(!totalByTimestamp.has(stamp)){totalByTimestamp.set(stamp,new Set());}
  292. totalByTimestamp.get(stamp).add(info);if(!usedByTimestamp.has(stamp)){usedByTimestamp.set(stamp,used);}else{usedByTimestamp.set(stamp,usedByTimestamp.get(stamp)+used);}}}}
  293. const seen=new Set();const coverageByTimestamp=new Map();let sumTotal=0,sumUsed=0;const sortedByTimestamp=Array.from(totalByTimestamp.entries()).sort((a,b)=>a[0]-b[0]);for(const[stamp,infos]of sortedByTimestamp){for(const info of infos.values()){if(seen.has(info)){continue;}
  294. seen.add(info);sumTotal+=info.size();}
  295. sumUsed+=usedByTimestamp.get(stamp);coverageByTimestamp.set(stamp,sumUsed/sumTotal);}
  296. const percentUsed=total?Math.round(100*total_used/total):0;const lowerOffset=3*ratio;const minTime=this._model.recordStartTime();const maxTime=minTime+(this._model.timelineModel().maximumRecordTime()-this._model.timelineModel().minimumRecordTime());const lineWidth=1;const width=this.width();const height=this.height()-lowerOffset;const xFactor=width/(maxTime-minTime);const yFactor=height-lineWidth;let yOffset=0;const ctx=this.context();const heightBeyondView=height+lowerOffset+lineWidth;ctx.translate(0.5,0.5);ctx.beginPath();ctx.moveTo(-lineWidth,heightBeyondView);ctx.lineTo(-lineWidth,height-yOffset);for(const[stamp,coverage]of coverageByTimestamp){if(stamp>maxTime){break;}
  297. const x=(stamp-minTime)*xFactor;yOffset=coverage*yFactor;ctx.lineTo(x,height-yOffset);}
  298. ctx.lineTo(width+lineWidth,height-yOffset);ctx.lineTo(width+lineWidth,heightBeyondView);ctx.closePath();ctx.fillStyle='hsla(220, 90%, 70%, 0.2)';ctx.fill();ctx.lineWidth=lineWidth;ctx.strokeStyle='hsl(220, 90%, 70%)';ctx.stroke();for(const[stamp,coverage]of coverageByTimestamp){if(stamp>maxTime){break;}
  299. ctx.beginPath();const x=(stamp-minTime)*xFactor;const y=height-coverage*yFactor;ctx.arc(x,y,2*lineWidth,0,2*Math.PI,false);ctx.closePath();ctx.stroke();ctx.fill();}
  300. this._heapSizeLabel.textContent=`${percentUsed}% used`;}};;Timeline.TimelineFilters={};Timeline.TimelineFilters.IsLong=class extends TimelineModel.TimelineModelFilter{constructor(){super();this._minimumRecordDuration=0;}
  301. setMinimumRecordDuration(value){this._minimumRecordDuration=value;}
  302. accept(event){const duration=event.endTime?event.endTime-event.startTime:0;return duration>=this._minimumRecordDuration;}};Timeline.TimelineFilters.Category=class extends TimelineModel.TimelineModelFilter{constructor(){super();}
  303. accept(event){return!Timeline.TimelineUIUtils.eventStyle(event).category.hidden;}};Timeline.TimelineFilters.RegExp=class extends TimelineModel.TimelineModelFilter{constructor(regExp){super();this._regExp;this.setRegExp(regExp||null);}
  304. setRegExp(regExp){this._regExp=regExp;}
  305. regExp(){return this._regExp;}
  306. accept(event){return!this._regExp||Timeline.TimelineUIUtils.testContentMatching(event,this._regExp);}};;Timeline.TimelineFlameChartDataProvider=class extends Common.Object{constructor(){super();this.reset();this._font='11px '+Host.fontFamily();this._timelineData=null;this._currentLevel=0;this._performanceModel=null;this._model=null;this._minimumBoundary=0;this._maximumBoundary=0;this._timeSpan=0;this._consoleColorGenerator=new Common.Color.Generator({min:30,max:55},{min:70,max:100,count:6},50,0.7);this._extensionColorGenerator=new Common.Color.Generator({min:210,max:300},{min:70,max:100,count:6},70,0.7);this._headerLevel1=this._buildGroupStyle({shareHeaderLine:false});this._headerLevel2=this._buildGroupStyle({padding:2,nestingLevel:1,collapsible:false});this._staticHeader=this._buildGroupStyle({collapsible:false});this._framesHeader=this._buildGroupStyle({useFirstLineForOverview:true});this._timingsHeader=this._buildGroupStyle({shareHeaderLine:true,useFirstLineForOverview:true});this._screenshotsHeader=this._buildGroupStyle({useFirstLineForOverview:true,nestingLevel:1,collapsible:false,itemsHeight:150});this._interactionsHeaderLevel1=this._buildGroupStyle({useFirstLineForOverview:true});this._interactionsHeaderLevel2=this._buildGroupStyle({padding:2,nestingLevel:1});this._flowEventIndexById=new Map();}
  307. _buildGroupStyle(extra){const defaultGroupStyle={padding:4,height:17,collapsible:true,color:UI.themeSupport.patchColorText('#222',UI.ThemeSupport.ColorUsage.Foreground),backgroundColor:UI.themeSupport.patchColorText('white',UI.ThemeSupport.ColorUsage.Background),font:this._font,nestingLevel:0,shareHeaderLine:true};return(Object.assign(defaultGroupStyle,extra));}
  308. setModel(performanceModel){this.reset();this._performanceModel=performanceModel;this._model=performanceModel&&performanceModel.timelineModel();}
  309. groupTrack(group){return group._track||null;}
  310. entryTitle(entryIndex){const entryTypes=Timeline.TimelineFlameChartDataProvider.EntryType;const entryType=this._entryType(entryIndex);if(entryType===entryTypes.Event){const event=(this._entryData[entryIndex]);if(event.phase===SDK.TracingModel.Phase.AsyncStepInto||event.phase===SDK.TracingModel.Phase.AsyncStepPast){return event.name+':'+event.args['step'];}
  311. if(event._blackboxRoot){return Common.UIString('Blackboxed');}
  312. if(this._performanceModel.timelineModel().isMarkerEvent(event)){return Timeline.TimelineUIUtils.markerShortTitle(event);}
  313. return Timeline.TimelineUIUtils.eventTitle(event);}
  314. if(entryType===entryTypes.ExtensionEvent){const event=(this._entryData[entryIndex]);return event.name;}
  315. if(entryType===entryTypes.Screenshot){return'';}
  316. let title=this._entryIndexToTitle[entryIndex];if(!title){title=Common.UIString('Unexpected entryIndex %d',entryIndex);console.error(title);}
  317. return title;}
  318. textColor(index){const event=this._entryData[index];return event&&event._blackboxRoot?'#888':Timeline.FlameChartStyle.textColor;}
  319. entryFont(index){return this._font;}
  320. reset(){this._currentLevel=0;this._timelineData=null;this._entryData=[];this._entryParent=[];this._entryTypeByLevel=[];this._entryIndexToTitle=[];this._markers=[];this._asyncColorByCategory=new Map();this._asyncColorByInteractionPhase=new Map();this._extensionInfo=[];this._screenshotImageCache=new Map();}
  321. maxStackDepth(){return this._currentLevel;}
  322. timelineData(){if(this._timelineData){return this._timelineData;}
  323. this._timelineData=new PerfUI.FlameChart.TimelineData([],[],[],[]);if(!this._model){return this._timelineData;}
  324. this._flowEventIndexById.clear();this._minimumBoundary=this._model.minimumRecordTime();this._timeSpan=this._model.isEmpty()?1000:this._model.maximumRecordTime()-this._minimumBoundary;this._currentLevel=0;if(this._model.isGenericTrace()){this._processGenericTrace();}else{this._processInspectorTrace();}
  325. return this._timelineData;}
  326. _processGenericTrace(){const processGroupStyle=this._buildGroupStyle({shareHeaderLine:false});const threadGroupStyle=this._buildGroupStyle({padding:2,nestingLevel:1,shareHeaderLine:false});const eventEntryType=Timeline.TimelineFlameChartDataProvider.EntryType.Event;const tracksByProcess=new Platform.Multimap();for(const track of this._model.tracks()){if(track.thread!==null){tracksByProcess.set(track.thread.process(),track);}else{console.error('Failed to process track');}}
  327. for(const process of tracksByProcess.keysArray()){if(tracksByProcess.size>1){const name=`${process.name()} ${process.id()}`;this._appendHeader(name,processGroupStyle,false);}
  328. for(const track of tracksByProcess.get(process)){const group=this._appendSyncEvents(track,track.events,track.name,threadGroupStyle,eventEntryType,true);if(!this._timelineData.selectedGroup||track.name===TimelineModel.TimelineModel.BrowserMainThreadName){this._timelineData.selectedGroup=group;}}}}
  329. _processInspectorTrace(){this._appendFrames();this._appendInteractionRecords();const eventEntryType=Timeline.TimelineFlameChartDataProvider.EntryType.Event;const weight=track=>{switch(track.type){case TimelineModel.TimelineModel.TrackType.Input:return 0;case TimelineModel.TimelineModel.TrackType.Animation:return 1;case TimelineModel.TimelineModel.TrackType.Timings:return 2;case TimelineModel.TimelineModel.TrackType.Console:return 3;case TimelineModel.TimelineModel.TrackType.MainThread:return track.forMainFrame?4:5;case TimelineModel.TimelineModel.TrackType.Worker:return 6;case TimelineModel.TimelineModel.TrackType.Raster:return 7;case TimelineModel.TimelineModel.TrackType.GPU:return 8;case TimelineModel.TimelineModel.TrackType.Other:return 9;}};const tracks=this._model.tracks().slice();tracks.sort((a,b)=>weight(a)-weight(b));let rasterCount=0;for(const track of tracks){switch(track.type){case TimelineModel.TimelineModel.TrackType.Input:this._appendAsyncEventsGroup(track,ls`Input`,track.asyncEvents,this._interactionsHeaderLevel2,eventEntryType,false);break;case TimelineModel.TimelineModel.TrackType.Animation:this._appendAsyncEventsGroup(track,ls`Animation`,track.asyncEvents,this._interactionsHeaderLevel2,eventEntryType,false);break;case TimelineModel.TimelineModel.TrackType.Timings:const group=this._appendHeader(ls`Timings`,this._timingsHeader,true);group._track=track;this._appendPageMetrics();this._appendAsyncEventsGroup(track,null,track.asyncEvents,this._timingsHeader,eventEntryType,true);break;case TimelineModel.TimelineModel.TrackType.Console:this._appendAsyncEventsGroup(track,ls`Console`,track.asyncEvents,this._headerLevel1,eventEntryType,true);break;case TimelineModel.TimelineModel.TrackType.MainThread:if(track.forMainFrame){const group=this._appendSyncEvents(track,track.events,track.url?ls`Main \u2014 ${track.url}`:ls`Main`,this._headerLevel1,eventEntryType,true);if(group){this._timelineData.selectedGroup=group;}}else{this._appendSyncEvents(track,track.events,track.url?ls`Frame \u2014 ${track.url}`:ls`Subframe`,this._headerLevel1,eventEntryType,true);}
  330. break;case TimelineModel.TimelineModel.TrackType.Worker:this._appendSyncEvents(track,track.events,track.url?ls`Worker \u2014 ${track.url}`:ls`Dedicated Worker`,this._headerLevel1,eventEntryType,true);break;case TimelineModel.TimelineModel.TrackType.Raster:if(!rasterCount){this._appendHeader(ls`Raster`,this._headerLevel1,false);}
  331. ++rasterCount;this._appendSyncEvents(track,track.events,ls`Rasterizer Thread ${rasterCount}`,this._headerLevel2,eventEntryType,true);break;case TimelineModel.TimelineModel.TrackType.GPU:this._appendSyncEvents(track,track.events,ls`GPU`,this._headerLevel1,eventEntryType,true);break;case TimelineModel.TimelineModel.TrackType.Other:this._appendSyncEvents(track,track.events,track.name||ls`Thread`,this._headerLevel1,eventEntryType,true);this._appendAsyncEventsGroup(track,track.name,track.asyncEvents,this._headerLevel1,eventEntryType,true);break;}}
  332. if(this._timelineData.selectedGroup){this._timelineData.selectedGroup.expanded=true;}
  333. for(let extensionIndex=0;extensionIndex<this._extensionInfo.length;extensionIndex++){this._innerAppendExtensionEvents(extensionIndex);}
  334. this._markers.sort((a,b)=>a.startTime()-b.startTime());this._timelineData.markers=this._markers;this._flowEventIndexById.clear();}
  335. minimumBoundary(){return this._minimumBoundary;}
  336. totalTime(){return this._timeSpan;}
  337. search(startTime,endTime,filter){const result=[];const entryTypes=Timeline.TimelineFlameChartDataProvider.EntryType;this.timelineData();for(let i=0;i<this._entryData.length;++i){if(this._entryType(i)!==entryTypes.Event){continue;}
  338. const event=(this._entryData[i]);if(event.startTime>endTime){continue;}
  339. if((event.endTime||event.startTime)<startTime){continue;}
  340. if(filter.accept(event)){result.push(i);}}
  341. result.sort((a,b)=>SDK.TracingModel.Event.compareStartTime((this._entryData[a]),(this._entryData[b])));return result;}
  342. _appendSyncEvents(track,events,title,style,entryType,selectable){if(!events.length){return null;}
  343. const isExtension=entryType===Timeline.TimelineFlameChartDataProvider.EntryType.ExtensionEvent;const openEvents=[];const flowEventsEnabled=Root.Runtime.experiments.isEnabled('timelineFlowEvents');const blackboxingEnabled=!isExtension&&Root.Runtime.experiments.isEnabled('blackboxJSFramesOnTimeline');let maxStackDepth=0;let group=null;if(track&&track.type===TimelineModel.TimelineModel.TrackType.MainThread){group=this._appendHeader(title,style,selectable);group._track=track;}
  344. for(let i=0;i<events.length;++i){const e=events[i];if(!isExtension&&this._performanceModel.timelineModel().isMarkerEvent(e)){this._markers.push(new Timeline.TimelineFlameChartMarker(e.startTime,e.startTime-this._model.minimumRecordTime(),Timeline.TimelineUIUtils.markerStyleForEvent(e)));}
  345. if(!SDK.TracingModel.isFlowPhase(e.phase)){if(!e.endTime&&e.phase!==SDK.TracingModel.Phase.Instant){continue;}
  346. if(SDK.TracingModel.isAsyncPhase(e.phase)){continue;}
  347. if(!isExtension&&!this._performanceModel.isVisible(e)){continue;}}
  348. while(openEvents.length&&openEvents.peekLast().endTime<=e.startTime){openEvents.pop();}
  349. e._blackboxRoot=false;if(blackboxingEnabled&&this._isBlackboxedEvent(e)){const parent=openEvents.peekLast();if(parent&&parent._blackboxRoot){continue;}
  350. e._blackboxRoot=true;}
  351. if(!group){group=this._appendHeader(title,style,selectable);if(selectable){group._track=track;}}
  352. const level=this._currentLevel+openEvents.length;if(flowEventsEnabled){this._appendFlowEvent(e,level);}
  353. const index=this._appendEvent(e,level);if(openEvents.length){this._entryParent[index]=openEvents.peekLast();}
  354. if(!isExtension&&this._performanceModel.timelineModel().isMarkerEvent(e)){this._timelineData.entryTotalTimes[this._entryData.length]=undefined;}
  355. maxStackDepth=Math.max(maxStackDepth,openEvents.length+1);if(e.endTime){openEvents.push(e);}}
  356. this._entryTypeByLevel.length=this._currentLevel+maxStackDepth;this._entryTypeByLevel.fill(entryType,this._currentLevel);this._currentLevel+=maxStackDepth;return group;}
  357. _isBlackboxedEvent(event){if(event.name!==TimelineModel.TimelineModel.RecordType.JSFrame){return false;}
  358. const url=event.args['data']['url'];return url&&this._isBlackboxedURL(url);}
  359. _isBlackboxedURL(url){return Bindings.blackboxManager.isBlackboxedURL(url);}
  360. _appendAsyncEventsGroup(track,header,events,style,entryType,selectable){if(!events.length){return null;}
  361. const lastUsedTimeByLevel=[];let group=null;for(let i=0;i<events.length;++i){const asyncEvent=events[i];if(!this._performanceModel.isVisible(asyncEvent)){continue;}
  362. if(!group&&header){group=this._appendHeader(header,style,selectable);if(selectable){group._track=track;}}
  363. const startTime=asyncEvent.startTime;let level;for(level=0;level<lastUsedTimeByLevel.length&&lastUsedTimeByLevel[level]>startTime;++level){}
  364. this._appendAsyncEvent(asyncEvent,this._currentLevel+level);lastUsedTimeByLevel[level]=asyncEvent.endTime;}
  365. this._entryTypeByLevel.length=this._currentLevel+lastUsedTimeByLevel.length;this._entryTypeByLevel.fill(entryType,this._currentLevel);this._currentLevel+=lastUsedTimeByLevel.length;return group;}
  366. _appendInteractionRecords(){const interactionRecords=this._performanceModel.interactionRecords();if(!interactionRecords.length){return;}
  367. this._appendHeader(ls`Interactions`,this._interactionsHeaderLevel1,false);for(const segment of interactionRecords){const index=this._entryData.length;this._entryData.push((segment.data));this._entryIndexToTitle[index]=(segment.data);this._timelineData.entryLevels[index]=this._currentLevel;this._timelineData.entryTotalTimes[index]=segment.end-segment.begin;this._timelineData.entryStartTimes[index]=segment.begin;}
  368. this._entryTypeByLevel[this._currentLevel++]=Timeline.TimelineFlameChartDataProvider.EntryType.InteractionRecord;}
  369. _appendPageMetrics(){this._entryTypeByLevel[this._currentLevel]=Timeline.TimelineFlameChartDataProvider.EntryType.Event;const metricEvents=[];const lcpEvents=[];const timelineModel=this._performanceModel.timelineModel();for(const track of this._model.tracks()){for(const event of track.events){if(!timelineModel.isMarkerEvent(event)){continue;}
  370. if(timelineModel.isLCPCandidateEvent(event)||timelineModel.isLCPInvalidateEvent(event)){lcpEvents.push(event);}else{metricEvents.push(event);}}}
  371. if(lcpEvents.length>0){const lcpEventsByNavigationId=new Map();for(const e of lcpEvents){const key=e.args['data']['navigationId'];const previousLastEvent=lcpEventsByNavigationId.get(key);if(!previousLastEvent||previousLastEvent.args['data']['candidateIndex']<e.args['data']['candidateIndex']){lcpEventsByNavigationId.set(key,e);}}
  372. const latestCandidates=Array.from(lcpEventsByNavigationId.values());const latestEvents=latestCandidates.filter(e=>timelineModel.isLCPCandidateEvent(e));metricEvents.push(...latestEvents);}
  373. metricEvents.sort(SDK.TracingModel.Event.compareStartTime);const totalTimes=this._timelineData.entryTotalTimes;for(const event of metricEvents){this._appendEvent(event,this._currentLevel);totalTimes[totalTimes.length-1]=Number.NaN;}
  374. ++this._currentLevel;}
  375. _appendFrames(){const screenshots=this._performanceModel.filmStripModel().frames();const hasFilmStrip=!!screenshots.length;this._framesHeader.collapsible=hasFilmStrip;this._appendHeader(Common.UIString('Frames'),this._framesHeader,false);this._frameGroup=this._timelineData.groups.peekLast();const style=Timeline.TimelineUIUtils.markerStyleForFrame();this._entryTypeByLevel[this._currentLevel]=Timeline.TimelineFlameChartDataProvider.EntryType.Frame;for(const frame of this._performanceModel.frames()){this._markers.push(new Timeline.TimelineFlameChartMarker(frame.startTime,frame.startTime-this._model.minimumRecordTime(),style));this._appendFrame(frame);}
  376. ++this._currentLevel;if(!hasFilmStrip){return;}
  377. this._appendHeader('',this._screenshotsHeader,false);this._entryTypeByLevel[this._currentLevel]=Timeline.TimelineFlameChartDataProvider.EntryType.Screenshot;let prevTimestamp;for(const screenshot of screenshots){this._entryData.push(screenshot);this._timelineData.entryLevels.push(this._currentLevel);this._timelineData.entryStartTimes.push(screenshot.timestamp);if(prevTimestamp){this._timelineData.entryTotalTimes.push(screenshot.timestamp-prevTimestamp);}
  378. prevTimestamp=screenshot.timestamp;}
  379. if(screenshots.length){this._timelineData.entryTotalTimes.push(this._model.maximumRecordTime()-prevTimestamp);}
  380. ++this._currentLevel;}
  381. _entryType(entryIndex){return this._entryTypeByLevel[this._timelineData.entryLevels[entryIndex]];}
  382. prepareHighlightedEntryInfo(entryIndex){let time='';let title;let warning;const type=this._entryType(entryIndex);if(type===Timeline.TimelineFlameChartDataProvider.EntryType.Event){const event=(this._entryData[entryIndex]);const totalTime=event.duration;const selfTime=event.selfTime;const eps=1e-6;if(typeof totalTime==='number'){time=Math.abs(totalTime-selfTime)>eps&&selfTime>eps?Common.UIString('%s (self %s)',Number.millisToString(totalTime,true),Number.millisToString(selfTime,true)):Number.millisToString(totalTime,true);}
  383. if(this._performanceModel.timelineModel().isMarkerEvent(event)){title=Timeline.TimelineUIUtils.eventTitle(event);}else{title=this.entryTitle(entryIndex);}
  384. warning=Timeline.TimelineUIUtils.eventWarning(event);}else if(type===Timeline.TimelineFlameChartDataProvider.EntryType.Frame){const frame=(this._entryData[entryIndex]);time=Common.UIString('%s ~ %.0f\xa0fps',Number.preciseMillisToString(frame.duration,1),(1000/frame.duration));title=frame.idle?Common.UIString('Idle Frame'):Common.UIString('Frame');if(frame.hasWarnings()){warning=createElement('span');warning.textContent=Common.UIString('Long frame');}}else{return null;}
  385. const element=createElement('div');const root=UI.createShadowRootWithCoreStyles(element,'timeline/timelineFlamechartPopover.css');const contents=root.createChild('div','timeline-flamechart-popover');contents.createChild('span','timeline-info-time').textContent=time;contents.createChild('span','timeline-info-title').textContent=title;if(warning){warning.classList.add('timeline-info-warning');contents.appendChild(warning);}
  386. return element;}
  387. entryColor(entryIndex){function patchColorAndCache(cache,key,lookupColor){let color=cache.get(key);if(color){return color;}
  388. const parsedColor=Common.Color.parse(lookupColor(key));color=parsedColor.setAlpha(0.7).asString(Common.Color.Format.RGBA)||'';cache.set(key,color);return color;}
  389. const entryTypes=Timeline.TimelineFlameChartDataProvider.EntryType;const type=this._entryType(entryIndex);if(type===entryTypes.Event){const event=(this._entryData[entryIndex]);if(this._model.isGenericTrace()){return this._genericTraceEventColor(event);}
  390. if(this._performanceModel.timelineModel().isMarkerEvent(event)){return Timeline.TimelineUIUtils.markerStyleForEvent(event).color;}
  391. if(!SDK.TracingModel.isAsyncPhase(event.phase)){return this._colorForEvent(event);}
  392. if(event.hasCategory(TimelineModel.TimelineModel.Category.Console)||event.hasCategory(TimelineModel.TimelineModel.Category.UserTiming)){return this._consoleColorGenerator.colorForID(event.name);}
  393. if(event.hasCategory(TimelineModel.TimelineModel.Category.LatencyInfo)){const phase=TimelineModel.TimelineIRModel.phaseForEvent(event)||TimelineModel.TimelineIRModel.Phases.Uncategorized;return patchColorAndCache(this._asyncColorByInteractionPhase,phase,Timeline.TimelineUIUtils.interactionPhaseColor);}
  394. const category=Timeline.TimelineUIUtils.eventStyle(event).category;return patchColorAndCache(this._asyncColorByCategory,category,()=>category.color);}
  395. if(type===entryTypes.Frame){return'white';}
  396. if(type===entryTypes.InteractionRecord){return'transparent';}
  397. if(type===entryTypes.ExtensionEvent){const event=(this._entryData[entryIndex]);return this._extensionColorGenerator.colorForID(event.name);}
  398. return'';}
  399. _genericTraceEventColor(event){const key=event.categoriesString||event.name;return key?`hsl(${String.hashCode(key) % 300 + 30}, 40%, 70%)`:'#ccc';}
  400. _drawFrame(entryIndex,context,text,barX,barY,barWidth,barHeight){const hPadding=1;const frame=(this._entryData[entryIndex]);barX+=hPadding;barWidth-=2*hPadding;context.fillStyle=frame.idle?'white':(frame.hasWarnings()?'#fad1d1':'#d7f0d1');context.fillRect(barX,barY,barWidth,barHeight);const frameDurationText=Number.preciseMillisToString(frame.duration,1);const textWidth=context.measureText(frameDurationText).width;if(textWidth<=barWidth){context.fillStyle=this.textColor(entryIndex);context.fillText(frameDurationText,barX+(barWidth-textWidth)/2,barY+barHeight-4);}}
  401. async _drawScreenshot(entryIndex,context,barX,barY,barWidth,barHeight){const screenshot=(this._entryData[entryIndex]);if(!this._screenshotImageCache.has(screenshot)){this._screenshotImageCache.set(screenshot,null);const data=await screenshot.imageDataPromise();const image=await UI.loadImageFromData(data);this._screenshotImageCache.set(screenshot,image);this.dispatchEventToListeners(Timeline.TimelineFlameChartDataProvider.Events.DataChanged);return;}
  402. const image=this._screenshotImageCache.get(screenshot);if(!image){return;}
  403. const imageX=barX+1;const imageY=barY+1;const imageHeight=barHeight-2;const scale=imageHeight/image.naturalHeight;const imageWidth=Math.floor(image.naturalWidth*scale);context.save();context.beginPath();context.rect(barX,barY,barWidth,barHeight);context.clip();context.drawImage(image,imageX,imageY,imageWidth,imageHeight);context.strokeStyle='#ccc';context.strokeRect(imageX-0.5,imageY-0.5,Math.min(barWidth-1,imageWidth+1),imageHeight);context.restore();}
  404. decorateEntry(entryIndex,context,text,barX,barY,barWidth,barHeight,unclippedBarX,timeToPixels){const data=this._entryData[entryIndex];const type=this._entryType(entryIndex);const entryTypes=Timeline.TimelineFlameChartDataProvider.EntryType;if(type===entryTypes.Frame){this._drawFrame(entryIndex,context,text,barX,barY,barWidth,barHeight);return true;}
  405. if(type===entryTypes.Screenshot){this._drawScreenshot(entryIndex,context,barX,barY,barWidth,barHeight);return true;}
  406. if(type===entryTypes.InteractionRecord){const color=Timeline.TimelineUIUtils.interactionPhaseColor((data));context.fillStyle=color;context.fillRect(barX,barY,barWidth-1,2);context.fillRect(barX,barY-3,2,3);context.fillRect(barX+barWidth-3,barY-3,2,3);return false;}
  407. if(type===entryTypes.Event){const event=(data);if(event.hasCategory(TimelineModel.TimelineModel.Category.LatencyInfo)){const timeWaitingForMainThread=TimelineModel.TimelineData.forEvent(event).timeWaitingForMainThread;if(timeWaitingForMainThread){context.fillStyle='hsla(0, 70%, 60%, 1)';const width=Math.floor(unclippedBarX-barX+timeWaitingForMainThread*timeToPixels);context.fillRect(barX,barY+barHeight-3,width,2);}}
  408. if(TimelineModel.TimelineData.forEvent(event).warning){paintWarningDecoration(barX,barWidth-1.5);}}
  409. function paintWarningDecoration(x,width){const triangleSize=8;context.save();context.beginPath();context.rect(x,barY,width,barHeight);context.clip();context.beginPath();context.fillStyle='red';context.moveTo(x+width-triangleSize,barY);context.lineTo(x+width,barY);context.lineTo(x+width,barY+triangleSize);context.fill();context.restore();}
  410. return false;}
  411. forceDecoration(entryIndex){const entryTypes=Timeline.TimelineFlameChartDataProvider.EntryType;const type=this._entryType(entryIndex);if(type===entryTypes.Frame){return true;}
  412. if(type===entryTypes.Screenshot){return true;}
  413. if(type===entryTypes.Event){const event=(this._entryData[entryIndex]);return!!TimelineModel.TimelineData.forEvent(event).warning;}
  414. return false;}
  415. appendExtensionEvents(entry){this._extensionInfo.push(entry);if(this._timelineData){this._innerAppendExtensionEvents(this._extensionInfo.length-1);}}
  416. _innerAppendExtensionEvents(index){const entry=this._extensionInfo[index];const entryType=Timeline.TimelineFlameChartDataProvider.EntryType.ExtensionEvent;const allThreads=[].concat(...entry.model.sortedProcesses().map(process=>process.sortedThreads()));if(!allThreads.length){return;}
  417. const singleTrack=allThreads.length===1&&(!allThreads[0].events().length||!allThreads[0].asyncEvents().length);if(!singleTrack){this._appendHeader(entry.title,this._headerLevel1,false);}
  418. const style=singleTrack?this._headerLevel2:this._headerLevel1;let threadIndex=0;for(const thread of allThreads){const title=singleTrack?entry.title:thread.name()||ls`Thread ${++threadIndex}`;this._appendAsyncEventsGroup(null,title,thread.asyncEvents(),style,entryType,false);this._appendSyncEvents(null,thread.events(),title,style,entryType,false);}}
  419. _appendHeader(title,style,selectable){const group={startLevel:this._currentLevel,name:title,style:style,selectable:selectable};this._timelineData.groups.push(group);return group;}
  420. _appendEvent(event,level){const index=this._entryData.length;this._entryData.push(event);this._timelineData.entryLevels[index]=level;this._timelineData.entryTotalTimes[index]=event.duration||Timeline.TimelineFlameChartDataProvider.InstantEventVisibleDurationMs;this._timelineData.entryStartTimes[index]=event.startTime;event[Timeline.TimelineFlameChartDataProvider._indexSymbol]=index;return index;}
  421. _appendAsyncEvent(asyncEvent,level){if(SDK.TracingModel.isNestableAsyncPhase(asyncEvent.phase)){this._appendEvent(asyncEvent,level);return;}
  422. const steps=asyncEvent.steps;const eventOffset=steps.length>1&&steps[1].phase===SDK.TracingModel.Phase.AsyncStepPast?1:0;for(let i=0;i<steps.length-1;++i){const index=this._entryData.length;this._entryData.push(steps[i+eventOffset]);const startTime=steps[i].startTime;this._timelineData.entryLevels[index]=level;this._timelineData.entryTotalTimes[index]=steps[i+1].startTime-startTime;this._timelineData.entryStartTimes[index]=startTime;}}
  423. _appendFlowEvent(event,level){const timelineData=this._timelineData;function pushStartFlow(event){const flowIndex=timelineData.flowStartTimes.length;timelineData.flowStartTimes.push(event.startTime);timelineData.flowStartLevels.push(level);return flowIndex;}
  424. function pushEndFlow(event,flowIndex){timelineData.flowEndTimes[flowIndex]=event.startTime;timelineData.flowEndLevels[flowIndex]=level;}
  425. switch(event.phase){case SDK.TracingModel.Phase.FlowBegin:this._flowEventIndexById.set(event.id,pushStartFlow(event));break;case SDK.TracingModel.Phase.FlowStep:pushEndFlow(event,this._flowEventIndexById.get(event.id));this._flowEventIndexById.set(event.id,pushStartFlow(event));break;case SDK.TracingModel.Phase.FlowEnd:pushEndFlow(event,this._flowEventIndexById.get(event.id));this._flowEventIndexById.delete(event.id);break;}}
  426. _appendFrame(frame){const index=this._entryData.length;this._entryData.push(frame);this._entryIndexToTitle[index]=Number.millisToString(frame.duration,true);this._timelineData.entryLevels[index]=this._currentLevel;this._timelineData.entryTotalTimes[index]=frame.duration;this._timelineData.entryStartTimes[index]=frame.startTime;}
  427. createSelection(entryIndex){const type=this._entryType(entryIndex);let timelineSelection=null;if(type===Timeline.TimelineFlameChartDataProvider.EntryType.Event){timelineSelection=Timeline.TimelineSelection.fromTraceEvent((this._entryData[entryIndex]));}else if(type===Timeline.TimelineFlameChartDataProvider.EntryType.Frame){timelineSelection=Timeline.TimelineSelection.fromFrame((this._entryData[entryIndex]));}
  428. if(timelineSelection){this._lastSelection=new Timeline.TimelineFlameChartView.Selection(timelineSelection,entryIndex);}
  429. return timelineSelection;}
  430. formatValue(value,precision){return Number.preciseMillisToString(value,precision);}
  431. canJumpToEntry(entryIndex){return false;}
  432. entryIndexForSelection(selection){if(!selection||selection.type()===Timeline.TimelineSelection.Type.Range){return-1;}
  433. if(this._lastSelection&&this._lastSelection.timelineSelection.object()===selection.object()){return this._lastSelection.entryIndex;}
  434. const index=this._entryData.indexOf((selection.object()));if(index!==-1){this._lastSelection=new Timeline.TimelineFlameChartView.Selection(selection,index);}
  435. return index;}
  436. buildFlowForInitiator(entryIndex){if(this._lastInitiatorEntry===entryIndex){return false;}
  437. this._lastInitiatorEntry=entryIndex;let event=this.eventByIndex(entryIndex);const td=this._timelineData;td.flowStartTimes=[];td.flowStartLevels=[];td.flowEndTimes=[];td.flowEndLevels=[];while(event){let initiator;for(;event;event=this._eventParent(event)){initiator=TimelineModel.TimelineData.forEvent(event).initiator();if(initiator){break;}}
  438. if(!initiator){break;}
  439. const eventIndex=event[Timeline.TimelineFlameChartDataProvider._indexSymbol];const initiatorIndex=initiator[Timeline.TimelineFlameChartDataProvider._indexSymbol];td.flowStartTimes.push(initiator.endTime||initiator.startTime);td.flowStartLevels.push(td.entryLevels[initiatorIndex]);td.flowEndTimes.push(event.startTime);td.flowEndLevels.push(td.entryLevels[eventIndex]);event=initiator;}
  440. return true;}
  441. _eventParent(event){return this._entryParent[event[Timeline.TimelineFlameChartDataProvider._indexSymbol]]||null;}
  442. eventByIndex(entryIndex){return entryIndex>=0&&this._entryType(entryIndex)===Timeline.TimelineFlameChartDataProvider.EntryType.Event?(this._entryData[entryIndex]):null;}
  443. setEventColorMapping(colorForEvent){this._colorForEvent=colorForEvent;}};Timeline.TimelineFlameChartDataProvider.InstantEventVisibleDurationMs=0.001;Timeline.TimelineFlameChartDataProvider._indexSymbol=Symbol('index');Timeline.TimelineFlameChartDataProvider.Events={DataChanged:Symbol('DataChanged')};Timeline.TimelineFlameChartDataProvider.EntryType={Frame:Symbol('Frame'),Event:Symbol('Event'),InteractionRecord:Symbol('InteractionRecord'),ExtensionEvent:Symbol('ExtensionEvent'),Screenshot:Symbol('Screenshot'),};;Timeline.TimelineFlameChartNetworkDataProvider=class{constructor(){this._font='11px '+Host.fontFamily();this.setModel(null);this._style={padding:4,height:17,collapsible:true,color:UI.themeSupport.patchColorText('#222',UI.ThemeSupport.ColorUsage.Foreground),font:this._font,backgroundColor:UI.themeSupport.patchColorText('white',UI.ThemeSupport.ColorUsage.Background),nestingLevel:0,useFirstLineForOverview:false,useDecoratorsForOverview:true,shareHeaderLine:false};this._group={startLevel:0,name:Common.UIString('Network'),expanded:false,style:this._style};this._minimumBoundary=0;this._maximumBoundary=0;this._timeSpan=0;}
  444. setModel(performanceModel){this._model=performanceModel&&performanceModel.timelineModel();this._maxLevel=0;this._timelineData=null;this._requests=[];}
  445. isEmpty(){this.timelineData();return!this._requests.length;}
  446. maxStackDepth(){return this._maxLevel;}
  447. timelineData(){if(this._timelineData){return this._timelineData;}
  448. this._requests=[];this._timelineData=new PerfUI.FlameChart.TimelineData([],[],[],[]);if(this._model){this._appendTimelineData();}
  449. return this._timelineData;}
  450. minimumBoundary(){return this._minimumBoundary;}
  451. totalTime(){return this._timeSpan;}
  452. setWindowTimes(startTime,endTime){this._startTime=startTime;this._endTime=endTime;this._updateTimelineData();}
  453. createSelection(index){if(index===-1){return null;}
  454. const request=this._requests[index];this._lastSelection=new Timeline.TimelineFlameChartView.Selection(Timeline.TimelineSelection.fromNetworkRequest(request),index);return this._lastSelection.timelineSelection;}
  455. entryIndexForSelection(selection){if(!selection){return-1;}
  456. if(this._lastSelection&&this._lastSelection.timelineSelection.object()===selection.object()){return this._lastSelection.entryIndex;}
  457. if(selection.type()!==Timeline.TimelineSelection.Type.NetworkRequest){return-1;}
  458. const request=(selection.object());const index=this._requests.indexOf(request);if(index!==-1){this._lastSelection=new Timeline.TimelineFlameChartView.Selection(Timeline.TimelineSelection.fromNetworkRequest(request),index);}
  459. return index;}
  460. entryColor(index){const request=(this._requests[index]);const category=Timeline.TimelineUIUtils.networkRequestCategory(request);return Timeline.TimelineUIUtils.networkCategoryColor(category);}
  461. textColor(index){return Timeline.FlameChartStyle.textColor;}
  462. entryTitle(index){const request=(this._requests[index]);const parsedURL=new Common.ParsedURL(request.url||'');return parsedURL.isValid?`${parsedURL.displayName} (${parsedURL.host})`:request.url||null;}
  463. entryFont(index){return this._font;}
  464. decorateEntry(index,context,text,barX,barY,barWidth,barHeight,unclippedBarX,timeToPixelRatio){const request=(this._requests[index]);if(!request.timing){return false;}
  465. const beginTime=request.beginTime();const timeToPixel=time=>Math.floor(unclippedBarX+(time-beginTime)*timeToPixelRatio);const minBarWidthPx=2;const startTime=request.getStartTime();const endTime=request.endTime;const{sendStartTime,headersEndTime}=request.getSendReceiveTiming();const sendStart=Math.max(timeToPixel(sendStartTime),unclippedBarX);const headersEnd=Math.max(timeToPixel(headersEndTime),sendStart);const finish=Math.max(timeToPixel(request.finishTime||endTime),headersEnd+minBarWidthPx);const start=timeToPixel(startTime);const end=Math.max(timeToPixel(endTime),finish);context.fillStyle='hsla(0, 100%, 100%, 0.8)';context.fillRect(sendStart+0.5,barY+0.5,headersEnd-sendStart-0.5,barHeight-2);context.fillStyle=UI.themeSupport.patchColorText('white',UI.ThemeSupport.ColorUsage.Background);context.fillRect(barX,barY-0.5,sendStart-barX,barHeight);context.fillRect(finish,barY-0.5,barX+barWidth-finish,barHeight);if(!request.cached()&&request.timing.pushStart){const pushStart=timeToPixel(request.timing.pushStart*1000);const pushEnd=request.timing.pushEnd?timeToPixel(request.timing.pushEnd*1000):start;const dentSize=Number.constrain(pushEnd-pushStart-2,0,4);const padding=1;context.save();context.beginPath();context.moveTo(pushStart+dentSize,barY+barHeight/2);context.lineTo(pushStart,barY+padding);context.lineTo(pushEnd-dentSize,barY+padding);context.lineTo(pushEnd,barY+barHeight/2);context.lineTo(pushEnd-dentSize,barY+barHeight-padding);context.lineTo(pushStart,barY+barHeight-padding);context.closePath();if(request.timing.pushEnd){context.fillStyle=this.entryColor(index);}else{const gradient=context.createLinearGradient(pushStart,0,pushEnd,0);gradient.addColorStop(0,this.entryColor(index));gradient.addColorStop(1,'white');context.fillStyle=gradient;}
  466. context.globalAlpha=0.3;context.fill();context.restore();}
  467. function drawTick(begin,end,y){const tickHeightPx=6;context.moveTo(begin,y-tickHeightPx/2);context.lineTo(begin,y+tickHeightPx/2);context.moveTo(begin,y);context.lineTo(end,y);}
  468. context.beginPath();context.lineWidth=1;context.strokeStyle='#ccc';const lineY=Math.floor(barY+barHeight/2)+0.5;const leftTick=start+0.5;const rightTick=end-0.5;drawTick(leftTick,sendStart,lineY);drawTick(rightTick,finish,lineY);context.stroke();if(typeof request.priority==='string'){const color=this._colorForPriority(request.priority);if(color){context.fillStyle=color;context.fillRect(sendStart+0.5,barY+0.5,3.5,3.5);}}
  469. const textStart=Math.max(sendStart,0);const textWidth=finish-textStart;const minTextWidthPx=20;if(textWidth>=minTextWidthPx){text=this.entryTitle(index)||'';if(request.fromServiceWorker){text='⚙ '+text;}
  470. if(text){const textPadding=4;const textBaseline=5;const textBaseHeight=barHeight-textBaseline;const trimmedText=UI.trimTextEnd(context,text,textWidth-2*textPadding);context.fillStyle='#333';context.fillText(trimmedText,textStart+textPadding,barY+textBaseHeight);}}
  471. return true;}
  472. forceDecoration(index){return true;}
  473. prepareHighlightedEntryInfo(index){const maxURLChars=80;const request=(this._requests[index]);if(!request.url){return null;}
  474. const element=createElement('div');const root=UI.createShadowRootWithCoreStyles(element,'timeline/timelineFlamechartPopover.css');const contents=root.createChild('div','timeline-flamechart-popover');const startTime=request.getStartTime();const duration=request.endTime-startTime;if(startTime&&isFinite(duration)){contents.createChild('span','timeline-info-network-time').textContent=Number.millisToString(duration,true);}
  475. if(typeof request.priority==='string'){const div=contents.createChild('span');div.textContent=PerfUI.uiLabelForNetworkPriority((request.priority));div.style.color=this._colorForPriority(request.priority)||'black';}
  476. contents.createChild('span').textContent=request.url.trimMiddle(maxURLChars);return element;}
  477. _colorForPriority(priority){if(!this._priorityToValue){const priorities=Protocol.Network.ResourcePriority;this._priorityToValue=new Map([[priorities.VeryLow,1],[priorities.Low,2],[priorities.Medium,3],[priorities.High,4],[priorities.VeryHigh,5]]);}
  478. const value=this._priorityToValue.get(priority);return value?`hsla(214, 80%, 50%, ${value / 5})`:null;}
  479. _appendTimelineData(){this._minimumBoundary=this._model.minimumRecordTime();this._maximumBoundary=this._model.maximumRecordTime();this._timeSpan=this._model.isEmpty()?1000:this._maximumBoundary-this._minimumBoundary;this._model.networkRequests().forEach(this._appendEntry.bind(this));this._updateTimelineData();}
  480. _updateTimelineData(){if(!this._timelineData){return;}
  481. const lastTimeByLevel=[];let maxLevel=0;for(let i=0;i<this._requests.length;++i){const r=this._requests[i];const beginTime=r.beginTime();const visible=beginTime<this._endTime&&r.endTime>this._startTime;if(!visible){this._timelineData.entryLevels[i]=-1;continue;}
  482. while(lastTimeByLevel.length&&lastTimeByLevel.peekLast()<=beginTime){lastTimeByLevel.pop();}
  483. this._timelineData.entryLevels[i]=lastTimeByLevel.length;lastTimeByLevel.push(r.endTime);maxLevel=Math.max(maxLevel,lastTimeByLevel.length);}
  484. for(let i=0;i<this._requests.length;++i){if(this._timelineData.entryLevels[i]===-1){this._timelineData.entryLevels[i]=maxLevel;}}
  485. this._timelineData=new PerfUI.FlameChart.TimelineData(this._timelineData.entryLevels,this._timelineData.entryTotalTimes,this._timelineData.entryStartTimes,[this._group]);this._maxLevel=maxLevel;}
  486. _appendEntry(request){this._requests.push(request);this._timelineData.entryStartTimes.push(request.beginTime());this._timelineData.entryTotalTimes.push(request.endTime-request.beginTime());this._timelineData.entryLevels.push(this._requests.length-1);}
  487. preferredHeight(){return this._style.height*(this._group.expanded?Number.constrain(this._maxLevel+1,4,8.5):1);}
  488. isExpanded(){return this._group.expanded;}
  489. formatValue(value,precision){return Number.preciseMillisToString(value,precision);}
  490. canJumpToEntry(entryIndex){return false;}};;Timeline.TimelineFlameChartView=class extends UI.VBox{constructor(delegate){super();this.element.classList.add('timeline-flamechart');this._delegate=delegate;this._model=null;this._searchResults;this._eventListeners=[];this._showMemoryGraphSetting=Common.settings.createSetting('timelineShowMemory',false);this._networkSplitWidget=new UI.SplitWidget(false,false,'timelineFlamechartMainView',150);const mainViewGroupExpansionSetting=Common.settings.createSetting('timelineFlamechartMainViewGroupExpansion',{});this._mainDataProvider=new Timeline.TimelineFlameChartDataProvider();this._mainDataProvider.addEventListener(Timeline.TimelineFlameChartDataProvider.Events.DataChanged,()=>this._mainFlameChart.scheduleUpdate());this._mainFlameChart=new PerfUI.FlameChart(this._mainDataProvider,this,mainViewGroupExpansionSetting);this._mainFlameChart.alwaysShowVerticalScroll();this._mainFlameChart.enableRuler(false);this._networkFlameChartGroupExpansionSetting=Common.settings.createSetting('timelineFlamechartNetworkViewGroupExpansion',{});this._networkDataProvider=new Timeline.TimelineFlameChartNetworkDataProvider();this._networkFlameChart=new PerfUI.FlameChart(this._networkDataProvider,this,this._networkFlameChartGroupExpansionSetting);this._networkFlameChart.alwaysShowVerticalScroll();this._networkFlameChart.disableRangeSelection();this._networkPane=new UI.VBox();this._networkPane.setMinimumSize(23,23);this._networkFlameChart.show(this._networkPane.element);this._splitResizer=this._networkPane.element.createChild('div','timeline-flamechart-resizer');this._networkSplitWidget.hideDefaultResizer(true);this._networkSplitWidget.installResizer(this._splitResizer);this._networkSplitWidget.setMainWidget(this._mainFlameChart);this._networkSplitWidget.setSidebarWidget(this._networkPane);this._chartSplitWidget=new UI.SplitWidget(false,true,'timelineCountersSplitViewState');this._countersView=new Timeline.CountersGraph(this._delegate);this._chartSplitWidget.setMainWidget(this._networkSplitWidget);this._chartSplitWidget.setSidebarWidget(this._countersView);this._chartSplitWidget.hideDefaultResizer();this._chartSplitWidget.installResizer((this._countersView.resizerElement()));this._updateCountersGraphToggle();this._detailsSplitWidget=new UI.SplitWidget(false,true,'timelinePanelDetailsSplitViewState');this._detailsSplitWidget.element.classList.add('timeline-details-split');this._detailsView=new Timeline.TimelineDetailsView(delegate);this._detailsSplitWidget.installResizer(this._detailsView.headerElement());this._detailsSplitWidget.setMainWidget(this._chartSplitWidget);this._detailsSplitWidget.setSidebarWidget(this._detailsView);this._detailsSplitWidget.show(this.element);this._onMainEntrySelected=this._onEntrySelected.bind(this,this._mainDataProvider);this._onNetworkEntrySelected=this._onEntrySelected.bind(this,this._networkDataProvider);this._mainFlameChart.addEventListener(PerfUI.FlameChart.Events.EntrySelected,this._onMainEntrySelected,this);this._mainFlameChart.addEventListener(PerfUI.FlameChart.Events.EntryInvoked,this._onMainEntrySelected,this);this._networkFlameChart.addEventListener(PerfUI.FlameChart.Events.EntrySelected,this._onNetworkEntrySelected,this);this._networkFlameChart.addEventListener(PerfUI.FlameChart.Events.EntryInvoked,this._onNetworkEntrySelected,this);this._mainFlameChart.addEventListener(PerfUI.FlameChart.Events.EntryHighlighted,this._onEntryHighlighted,this);this._nextExtensionIndex=0;this._boundRefresh=this._refresh.bind(this);this._selectedTrack=null;this._mainDataProvider.setEventColorMapping(Timeline.TimelineUIUtils.eventColor);this._groupBySetting=Common.settings.createSetting('timelineTreeGroupBy',Timeline.AggregatedTimelineTreeView.GroupBy.None);this._groupBySetting.addChangeListener(this._updateColorMapper,this);this._updateColorMapper();}
  491. _updateColorMapper(){this._urlToColorCache=new Map();if(!this._model){return;}
  492. this._mainDataProvider.setEventColorMapping(Timeline.TimelineUIUtils.eventColor);this._mainFlameChart.update();}
  493. _onWindowChanged(event){const window=(event.data.window);const animate=!!event.data.animate;this._mainFlameChart.setWindowTimes(window.left,window.right,animate);this._networkFlameChart.setWindowTimes(window.left,window.right,animate);this._networkDataProvider.setWindowTimes(window.left,window.right);this._updateSearchResults(false,false);}
  494. windowChanged(windowStartTime,windowEndTime,animate){this._model.setWindow({left:windowStartTime,right:windowEndTime},animate);}
  495. updateRangeSelection(startTime,endTime){this._delegate.select(Timeline.TimelineSelection.fromRange(startTime,endTime));}
  496. updateSelectedGroup(flameChart,group){if(flameChart!==this._mainFlameChart){return;}
  497. const track=group?this._mainDataProvider.groupTrack(group):null;this._selectedTrack=track;this._updateTrack();}
  498. setModel(model){if(model===this._model){return;}
  499. Common.EventTarget.removeEventListeners(this._eventListeners);this._model=model;this._selectedTrack=null;this._mainDataProvider.setModel(this._model);this._networkDataProvider.setModel(this._model);if(this._model){this._eventListeners=[this._model.addEventListener(Timeline.PerformanceModel.Events.WindowChanged,this._onWindowChanged,this),this._model.addEventListener(Timeline.PerformanceModel.Events.ExtensionDataAdded,this._appendExtensionData,this)];const window=model.window();this._mainFlameChart.setWindowTimes(window.left,window.right);this._networkFlameChart.setWindowTimes(window.left,window.right);this._networkDataProvider.setWindowTimes(window.left,window.right);this._updateSearchResults(false,false);}
  500. this._updateColorMapper();this._updateTrack();this._nextExtensionIndex=0;this._appendExtensionData();this._refresh();}
  501. _updateTrack(){this._countersView.setModel(this._model,this._selectedTrack);this._detailsView.setModel(this._model,this._selectedTrack);}
  502. _refresh(){if(this._networkDataProvider.isEmpty()){this._mainFlameChart.enableRuler(true);this._networkSplitWidget.hideSidebar();}else{this._mainFlameChart.enableRuler(false);this._networkSplitWidget.showBoth();this.resizeToPreferredHeights();}
  503. this._mainFlameChart.reset();this._networkFlameChart.reset();this._updateSearchResults(false,false);}
  504. _appendExtensionData(){if(!this._model){return;}
  505. const extensions=this._model.extensionInfo();while(this._nextExtensionIndex<extensions.length){this._mainDataProvider.appendExtensionEvents(extensions[this._nextExtensionIndex++]);}
  506. this._mainFlameChart.scheduleUpdate();}
  507. _onEntryHighlighted(commonEvent){SDK.OverlayModel.hideDOMNodeHighlight();const entryIndex=(commonEvent.data);const event=this._mainDataProvider.eventByIndex(entryIndex);if(!event){return;}
  508. const target=this._model&&this._model.timelineModel().targetByEvent(event);if(!target){return;}
  509. const timelineData=TimelineModel.TimelineData.forEvent(event);const backendNodeId=timelineData.backendNodeId;if(!backendNodeId){return;}
  510. new SDK.DeferredDOMNode(target,backendNodeId).highlight();}
  511. highlightEvent(event){const entryIndex=event?this._mainDataProvider.entryIndexForSelection(Timeline.TimelineSelection.fromTraceEvent(event)):-1;if(entryIndex>=0){this._mainFlameChart.highlightEntry(entryIndex);}else{this._mainFlameChart.hideHighlight();}}
  512. willHide(){this._networkFlameChartGroupExpansionSetting.removeChangeListener(this.resizeToPreferredHeights,this);this._showMemoryGraphSetting.removeChangeListener(this._updateCountersGraphToggle,this);Bindings.blackboxManager.removeChangeListener(this._boundRefresh);}
  513. wasShown(){this._networkFlameChartGroupExpansionSetting.addChangeListener(this.resizeToPreferredHeights,this);this._showMemoryGraphSetting.addChangeListener(this._updateCountersGraphToggle,this);Bindings.blackboxManager.addChangeListener(this._boundRefresh);if(this._needsResizeToPreferredHeights){this.resizeToPreferredHeights();}
  514. this._mainFlameChart.scheduleUpdate();this._networkFlameChart.scheduleUpdate();}
  515. _updateCountersGraphToggle(){if(this._showMemoryGraphSetting.get()){this._chartSplitWidget.showBoth();}else{this._chartSplitWidget.hideSidebar();}}
  516. setSelection(selection){let index=this._mainDataProvider.entryIndexForSelection(selection);this._mainFlameChart.setSelectedEntry(index);index=this._networkDataProvider.entryIndexForSelection(selection);this._networkFlameChart.setSelectedEntry(index);if(this._detailsView){this._detailsView.setSelection(selection);}}
  517. _onEntrySelected(dataProvider,event){const entryIndex=(event.data);if(Root.Runtime.experiments.isEnabled('timelineEventInitiators')&&dataProvider===this._mainDataProvider){if(this._mainDataProvider.buildFlowForInitiator(entryIndex)){this._mainFlameChart.scheduleUpdate();}}
  518. this._delegate.select(dataProvider.createSelection(entryIndex));}
  519. resizeToPreferredHeights(){if(!this.isShowing()){this._needsResizeToPreferredHeights=true;return;}
  520. this._needsResizeToPreferredHeights=false;this._networkPane.element.classList.toggle('timeline-network-resizer-disabled',!this._networkDataProvider.isExpanded());this._networkSplitWidget.setSidebarSize(this._networkDataProvider.preferredHeight()+this._splitResizer.clientHeight+PerfUI.FlameChart.HeaderHeight+
  521. 2);}
  522. setSearchableView(searchableView){this._searchableView=searchableView;}
  523. jumpToNextSearchResult(){if(!this._searchResults||!this._searchResults.length){return;}
  524. const index=typeof this._selectedSearchResult!=='undefined'?this._searchResults.indexOf(this._selectedSearchResult):-1;this._selectSearchResult(mod(index+1,this._searchResults.length));}
  525. jumpToPreviousSearchResult(){if(!this._searchResults||!this._searchResults.length){return;}
  526. const index=typeof this._selectedSearchResult!=='undefined'?this._searchResults.indexOf(this._selectedSearchResult):0;this._selectSearchResult(mod(index-1,this._searchResults.length));}
  527. supportsCaseSensitiveSearch(){return true;}
  528. supportsRegexSearch(){return true;}
  529. _selectSearchResult(index){this._searchableView.updateCurrentMatchIndex(index);this._selectedSearchResult=this._searchResults[index];this._delegate.select(this._mainDataProvider.createSelection(this._selectedSearchResult));}
  530. _updateSearchResults(shouldJump,jumpBackwards){const oldSelectedSearchResult=this._selectedSearchResult;delete this._selectedSearchResult;this._searchResults=[];if(!this._searchRegex||!this._model){return;}
  531. const regExpFilter=new Timeline.TimelineFilters.RegExp(this._searchRegex);const window=this._model.window();this._searchResults=this._mainDataProvider.search(window.left,window.right,regExpFilter);this._searchableView.updateSearchMatchesCount(this._searchResults.length);if(!shouldJump||!this._searchResults.length){return;}
  532. let selectedIndex=this._searchResults.indexOf(oldSelectedSearchResult);if(selectedIndex===-1){selectedIndex=jumpBackwards?this._searchResults.length-1:0;}
  533. this._selectSearchResult(selectedIndex);}
  534. searchCanceled(){if(typeof this._selectedSearchResult!=='undefined'){this._delegate.select(null);}
  535. delete this._searchResults;delete this._selectedSearchResult;delete this._searchRegex;}
  536. performSearch(searchConfig,shouldJump,jumpBackwards){this._searchRegex=searchConfig.toSearchRegex();this._updateSearchResults(shouldJump,jumpBackwards);}};Timeline.TimelineFlameChartView.Selection=class{constructor(selection,entryIndex){this.timelineSelection=selection;this.entryIndex=entryIndex;}};Timeline.FlameChartStyle={textColor:'#333'};Timeline.TimelineFlameChartMarker=class{constructor(startTime,startOffset,style){this._startTime=startTime;this._startOffset=startOffset;this._style=style;}
  537. startTime(){return this._startTime;}
  538. color(){return this._style.color;}
  539. title(){if(this._style.lowPriority){return null;}
  540. const startTime=Number.millisToString(this._startOffset);return ls`${this._style.title} at ${startTime}`;}
  541. draw(context,x,height,pixelsPerMillisecond){const lowPriorityVisibilityThresholdInPixelsPerMs=4;if(this._style.lowPriority&&pixelsPerMillisecond<lowPriorityVisibilityThresholdInPixelsPerMs){return;}
  542. context.save();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,0);context.setLineDash(this._style.dashStyle);context.lineTo(x,context.canvas.height);context.stroke();}
  543. context.restore();}};Timeline.TimelineFlameChartView._ColorBy={URL:'URL',};;Timeline.TimelineHistoryManager=class{constructor(){this._recordings=[];this._action=(UI.actionRegistry.action('timeline.show-history'));this._nextNumberByDomain=new Map();this._button=new Timeline.TimelineHistoryManager.ToolbarButton(this._action);UI.ARIAUtils.markAsMenuButton(this._button.element);this.clear();this._allOverviews=[{constructor:Timeline.TimelineEventOverviewResponsiveness,height:3},{constructor:Timeline.TimelineEventOverviewFrames,height:16},{constructor:Timeline.TimelineEventOverviewCPUActivity,height:20},{constructor:Timeline.TimelineEventOverviewNetwork,height:8}];this._totalHeight=this._allOverviews.reduce((acc,entry)=>acc+entry.height,0);this._enabled=true;this._lastActiveModel=null;}
  544. addRecording(performanceModel){this._lastActiveModel=performanceModel;this._recordings.unshift(performanceModel);this._buildPreview(performanceModel);const modelTitle=this._title(performanceModel);this._button.setText(modelTitle);const buttonTitle=this._action.title();UI.ARIAUtils.setAccessibleName(this._button.element,ls`Current Session: ${modelTitle}. ${buttonTitle}`);this._updateState();if(this._recordings.length<=Timeline.TimelineHistoryManager._maxRecordings){return;}
  545. const lruModel=this._recordings.reduce((a,b)=>lastUsedTime(a)<lastUsedTime(b)?a:b);this._recordings.splice(this._recordings.indexOf(lruModel),1);lruModel.dispose();function lastUsedTime(model){return Timeline.TimelineHistoryManager._dataForModel(model).lastUsed;}}
  546. setEnabled(enabled){this._enabled=enabled;this._updateState();}
  547. button(){return this._button;}
  548. clear(){this._recordings.forEach(model=>model.dispose());this._recordings=[];this._lastActiveModel=null;this._updateState();this._button.setText(Common.UIString('(no recordings)'));this._nextNumberByDomain.clear();}
  549. async showHistoryDropDown(){if(this._recordings.length<2||!this._enabled){return null;}
  550. const model=await Timeline.TimelineHistoryManager.DropDown.show(this._recordings,(this._lastActiveModel),this._button.element);if(!model){return null;}
  551. const index=this._recordings.indexOf(model);if(index<0){console.assert(false,`selected recording not found`);return null;}
  552. this._setCurrentModel(model);return model;}
  553. cancelIfShowing(){Timeline.TimelineHistoryManager.DropDown.cancelIfShowing();}
  554. navigate(direction){if(!this._enabled||!this._lastActiveModel){return null;}
  555. const index=this._recordings.indexOf(this._lastActiveModel);if(index<0){return null;}
  556. const newIndex=Number.constrain(index+direction,0,this._recordings.length-1);const model=this._recordings[newIndex];this._setCurrentModel(model);return model;}
  557. _setCurrentModel(model){Timeline.TimelineHistoryManager._dataForModel(model).lastUsed=Date.now();this._lastActiveModel=model;const modelTitle=this._title(model);const buttonTitle=this._action.title();this._button.setText(modelTitle);UI.ARIAUtils.setAccessibleName(this._button.element,ls`Current Session: ${modelTitle}. ${buttonTitle}`);}
  558. _updateState(){this._action.setEnabled(this._recordings.length>1&&this._enabled);}
  559. static _previewElement(performanceModel){const data=Timeline.TimelineHistoryManager._dataForModel(performanceModel);const startedAt=performanceModel.recordStartTime();data.time.textContent=startedAt?Common.UIString('(%s ago)',Timeline.TimelineHistoryManager._coarseAge(startedAt)):'';return data.preview;}
  560. static _coarseAge(time){const seconds=Math.round((Date.now()-time)/1000);if(seconds<50){return Common.UIString('moments');}
  561. const minutes=Math.round(seconds/60);if(minutes<50){return Common.UIString('%s m',minutes);}
  562. const hours=Math.round(minutes/60);return Common.UIString('%s h',hours);}
  563. _title(performanceModel){return Timeline.TimelineHistoryManager._dataForModel(performanceModel).title;}
  564. _buildPreview(performanceModel){const parsedURL=performanceModel.timelineModel().pageURL().asParsedURL();const domain=parsedURL?parsedURL.host:'';const sequenceNumber=this._nextNumberByDomain.get(domain)||1;const title=Common.UIString('%s #%d',domain,sequenceNumber);this._nextNumberByDomain.set(domain,sequenceNumber+1);const timeElement=createElement('span');const preview=createElementWithClass('div','preview-item vbox');const data={preview:preview,title:title,time:timeElement,lastUsed:Date.now()};performanceModel[Timeline.TimelineHistoryManager._previewDataSymbol]=data;preview.appendChild(this._buildTextDetails(performanceModel,title,timeElement));const screenshotAndOverview=preview.createChild('div','hbox');screenshotAndOverview.appendChild(this._buildScreenshotThumbnail(performanceModel));screenshotAndOverview.appendChild(this._buildOverview(performanceModel));return data.preview;}
  565. _buildTextDetails(performanceModel,title,timeElement){const container=createElementWithClass('div','text-details hbox');const nameSpan=container.createChild('span','name');nameSpan.textContent=title;UI.ARIAUtils.setAccessibleName(nameSpan,title);const tracingModel=performanceModel.tracingModel();const duration=Number.millisToString(tracingModel.maximumRecordTime()-tracingModel.minimumRecordTime(),false);const timeContainer=container.createChild('span','time');timeContainer.appendChild(createTextNode(duration));timeContainer.appendChild(timeElement);return container;}
  566. _buildScreenshotThumbnail(performanceModel){const container=createElementWithClass('div','screenshot-thumb');const thumbnailAspectRatio=3/2;container.style.width=this._totalHeight*thumbnailAspectRatio+'px';container.style.height=this._totalHeight+'px';const filmStripModel=performanceModel.filmStripModel();const lastFrame=filmStripModel.frames().peekLast();if(!lastFrame){return container;}
  567. lastFrame.imageDataPromise().then(data=>UI.loadImageFromData(data)).then(image=>image&&container.appendChild(image));return container;}
  568. _buildOverview(performanceModel){const container=createElement('div');container.style.width=Timeline.TimelineHistoryManager._previewWidth+'px';container.style.height=this._totalHeight+'px';const canvas=container.createChild('canvas');canvas.width=window.devicePixelRatio*Timeline.TimelineHistoryManager._previewWidth;canvas.height=window.devicePixelRatio*this._totalHeight;const ctx=canvas.getContext('2d');let yOffset=0;for(const overview of this._allOverviews){const timelineOverview=new overview.constructor();timelineOverview.setCanvasSize(Timeline.TimelineHistoryManager._previewWidth,overview.height);timelineOverview.setModel(performanceModel);timelineOverview.update();const sourceContext=timelineOverview.context();const imageData=sourceContext.getImageData(0,0,sourceContext.canvas.width,sourceContext.canvas.height);ctx.putImageData(imageData,0,yOffset);yOffset+=overview.height*window.devicePixelRatio;}
  569. return container;}
  570. static _dataForModel(model){return model[Timeline.TimelineHistoryManager._previewDataSymbol]||null;}};Timeline.TimelineHistoryManager.PreviewData;Timeline.TimelineHistoryManager._maxRecordings=5;Timeline.TimelineHistoryManager._previewWidth=450;Timeline.TimelineHistoryManager._previewDataSymbol=Symbol('previewData');Timeline.TimelineHistoryManager.DropDown=class{constructor(models){this._glassPane=new UI.GlassPane();this._glassPane.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent);this._glassPane.setOutsideClickCallback(()=>this._close(null));this._glassPane.setPointerEventsBehavior(UI.GlassPane.PointerEventsBehavior.BlockedByGlassPane);this._glassPane.setAnchorBehavior(UI.GlassPane.AnchorBehavior.PreferBottom);this._glassPane.element.addEventListener('blur',()=>this._close(null));const shadowRoot=UI.createShadowRootWithCoreStyles(this._glassPane.contentElement,'timeline/timelineHistoryManager.css');const contentElement=shadowRoot.createChild('div','drop-down');const listModel=new UI.ListModel();this._listControl=new UI.ListControl(listModel,this,UI.ListMode.NonViewport);this._listControl.element.addEventListener('mousemove',this._onMouseMove.bind(this),false);listModel.replaceAll(models);UI.ARIAUtils.markAsMenu(this._listControl.element);UI.ARIAUtils.setAccessibleName(this._listControl.element,ls`Select Timeline Session`);contentElement.appendChild(this._listControl.element);contentElement.addEventListener('keydown',this._onKeyDown.bind(this),false);contentElement.addEventListener('click',this._onClick.bind(this),false);this._focusRestorer=new UI.ElementFocusRestorer(this._listControl.element);this._selectionDone=null;}
  571. static show(models,currentModel,anchor){if(Timeline.TimelineHistoryManager.DropDown._instance){return Promise.resolve((null));}
  572. const instance=new Timeline.TimelineHistoryManager.DropDown(models);return instance._show(anchor,currentModel);}
  573. static cancelIfShowing(){if(!Timeline.TimelineHistoryManager.DropDown._instance){return;}
  574. Timeline.TimelineHistoryManager.DropDown._instance._close(null);}
  575. _show(anchor,currentModel){Timeline.TimelineHistoryManager.DropDown._instance=this;this._glassPane.setContentAnchorBox(anchor.boxInWindow());this._glassPane.show((this._glassPane.contentElement.ownerDocument));this._listControl.element.focus();this._listControl.selectItem(currentModel);return new Promise(fulfill=>this._selectionDone=fulfill);}
  576. _onMouseMove(event){const node=event.target.enclosingNodeOrSelfWithClass('preview-item');const listItem=node&&this._listControl.itemForNode(node);if(!listItem){return;}
  577. this._listControl.selectItem(listItem);}
  578. _onClick(event){if(!event.target.enclosingNodeOrSelfWithClass('preview-item')){return;}
  579. this._close(this._listControl.selectedItem());}
  580. _onKeyDown(event){switch(event.key){case'Tab':case'Escape':this._close(null);break;case'Enter':this._close(this._listControl.selectedItem());break;default:return;}
  581. event.consume(true);}
  582. _close(model){this._selectionDone(model);this._focusRestorer.restore();this._glassPane.hide();Timeline.TimelineHistoryManager.DropDown._instance=null;}
  583. createElementForItem(item){const element=Timeline.TimelineHistoryManager._previewElement(item);UI.ARIAUtils.markAsMenuItem(element);element.classList.remove('selected');return element;}
  584. heightForItem(item){console.assert(false,'Should not be called');return 0;}
  585. isItemSelectable(item){return true;}
  586. selectedItemChanged(from,to,fromElement,toElement){if(fromElement){fromElement.classList.remove('selected');}
  587. if(toElement){toElement.classList.add('selected');}}};Timeline.TimelineHistoryManager.DropDown._instance=null;Timeline.TimelineHistoryManager.ToolbarButton=class extends UI.ToolbarItem{constructor(action){super(createElementWithClass('button','history-dropdown-button'));UI.appendStyle(this.element,'timeline/historyToolbarButton.css');this._contentElement=this.element.createChild('span','content');const dropdownArrowIcon=UI.Icon.create('smallicon-triangle-down');this.element.appendChild(dropdownArrowIcon);this.element.addEventListener('click',()=>void action.execute(),false);this.setEnabled(action.enabled());action.addEventListener(UI.Action.Events.Enabled,event=>this.setEnabled((event.data)));this.setTitle(action.title());}
  588. setText(text){this._contentElement.textContent=text;}};;Timeline.TimelineTreeView=class extends UI.VBox{constructor(){super();this._model=null;this._track=null;this._tree=null;this.element.classList.add('timeline-tree-view');}
  589. static eventNameForSorting(event){if(event.name===TimelineModel.TimelineModel.RecordType.JSFrame){const data=event.args['data'];return data['functionName']+'@'+(data['scriptId']||data['url']||'');}
  590. return event.name+':@'+TimelineModel.TimelineProfileTree.eventURL(event);}
  591. setSearchableView(searchableView){this._searchableView=searchableView;}
  592. setModel(model,track){this._model=model;this._track=track;this.refreshTree();}
  593. getToolbarInputAccessiblePlaceHolder(){return'';}
  594. model(){return this._model;}
  595. init(){this._linkifier=new Components.Linkifier();this._taskFilter=new TimelineModel.ExclusiveNameFilter([TimelineModel.TimelineModel.RecordType.Task]);this._textFilter=new Timeline.TimelineFilters.RegExp();this._currentThreadSetting=Common.settings.createSetting('timelineTreeCurrentThread',0);this._currentThreadSetting.addChangeListener(this.refreshTree,this);const columns=([]);this.populateColumns(columns);this._splitWidget=new UI.SplitWidget(true,true,'timelineTreeViewDetailsSplitWidget');const mainView=new UI.VBox();const toolbar=new UI.Toolbar('',mainView.element);this.populateToolbar(toolbar);this._dataGrid=new DataGrid.SortableDataGrid(columns);this._dataGrid.addEventListener(DataGrid.DataGrid.Events.SortingChanged,this._sortingChanged,this);this._dataGrid.element.addEventListener('mousemove',this._onMouseMove.bind(this),true);this._dataGrid.setResizeMethod(DataGrid.DataGrid.ResizeMethod.Last);this._dataGrid.setRowContextMenuCallback(this._onContextMenu.bind(this));this._dataGrid.asWidget().show(mainView.element);this._dataGrid.addEventListener(DataGrid.DataGrid.Events.SelectedNode,this._updateDetailsForSelection,this);this._detailsView=new UI.VBox();this._detailsView.element.classList.add('timeline-details-view','timeline-details-view-body');this._splitWidget.setMainWidget(mainView);this._splitWidget.setSidebarWidget(this._detailsView);this._splitWidget.hideSidebar();this._splitWidget.show(this.element);this._splitWidget.addEventListener(UI.SplitWidget.Events.ShowModeChanged,this._onShowModeChanged,this);this._lastSelectedNode;}
  596. lastSelectedNode(){return this._lastSelectedNode;}
  597. updateContents(selection){this.setRange(selection.startTime(),selection.endTime());}
  598. setRange(startTime,endTime){this._startTime=startTime;this._endTime=endTime;this.refreshTree();}
  599. filters(){return[this._taskFilter,this._textFilter,...this._model.filters()];}
  600. filtersWithoutTextFilter(){return[this._taskFilter,...this._model.filters()];}
  601. textFilter(){return this._textFilter;}
  602. _exposePercentages(){return false;}
  603. populateToolbar(toolbar){this._textFilterUI=new UI.ToolbarInput(Common.UIString('Filter'),this.getToolbarInputAccessiblePlaceHolder());this._textFilterUI.addEventListener(UI.ToolbarInput.Event.TextChanged,textFilterChanged,this);toolbar.appendToolbarItem(this._textFilterUI);function textFilterChanged(){const searchQuery=this._textFilterUI.value();this._textFilter.setRegExp(searchQuery?createPlainTextSearchRegex(searchQuery,'i'):null);this.refreshTree();}}
  604. _modelEvents(){return this._track?this._track.syncEvents():[];}
  605. _onHover(node){}
  606. _appendContextMenuItems(contextMenu,node){}
  607. _linkifyLocation(event){const target=this._model.timelineModel().targetByEvent(event);if(!target){return null;}
  608. const frame=TimelineModel.TimelineProfileTree.eventStackFrame(event);if(!frame){return null;}
  609. return this._linkifier.maybeLinkifyConsoleCallFrame(target,frame);}
  610. selectProfileNode(treeNode,suppressSelectedEvent){const pathToRoot=[];for(let node=treeNode;node;node=node.parent){pathToRoot.push(node);}
  611. for(let i=pathToRoot.length-1;i>0;--i){const gridNode=this.dataGridNodeForTreeNode(pathToRoot[i]);if(gridNode&&gridNode.dataGrid){gridNode.expand();}}
  612. const gridNode=this.dataGridNodeForTreeNode(treeNode);if(gridNode.dataGrid){gridNode.reveal();gridNode.select(suppressSelectedEvent);}}
  613. refreshTree(){this._linkifier.reset();this._dataGrid.rootNode().removeChildren();if(!this._model){this._updateDetailsForSelection();return;}
  614. this._root=this._buildTree();const children=this._root.children();let maxSelfTime=0;let maxTotalTime=0;const totalUsedTime=this._root.totalTime-this._root.selfTime;for(const child of children.values()){maxSelfTime=Math.max(maxSelfTime,child.selfTime);maxTotalTime=Math.max(maxTotalTime,child.totalTime);}
  615. for(const child of children.values()){const gridNode=new Timeline.TimelineTreeView.TreeGridNode(child,totalUsedTime,maxSelfTime,maxTotalTime,this);this._dataGrid.insertChild(gridNode);}
  616. this._sortingChanged();this._updateDetailsForSelection();if(this._searchableView){this._searchableView.refreshSearch();}
  617. const rootNode=this._dataGrid.rootNode();if(rootNode.children.length>0){rootNode.children[0].select();}}
  618. _buildTree(){throw new Error('Not Implemented');}
  619. buildTopDownTree(doNotAggregate,groupIdCallback){return new TimelineModel.TimelineProfileTree.TopDownRootNode(this._modelEvents(),this.filters(),this._startTime,this._endTime,doNotAggregate,groupIdCallback);}
  620. populateColumns(columns){columns.push({id:'self',title:Common.UIString('Self Time'),width:'120px',fixedWidth:true,sortable:true});columns.push({id:'total',title:Common.UIString('Total Time'),width:'120px',fixedWidth:true,sortable:true});columns.push({id:'activity',title:Common.UIString('Activity'),disclosure:true,sortable:true});}
  621. _sortingChanged(){const columnId=this._dataGrid.sortColumnId();if(!columnId){return;}
  622. let sortFunction;switch(columnId){case'startTime':sortFunction=compareStartTime;break;case'self':sortFunction=compareNumericField.bind(null,'selfTime');break;case'total':sortFunction=compareNumericField.bind(null,'totalTime');break;case'activity':sortFunction=compareName;break;default:console.assert(false,'Unknown sort field: '+columnId);return;}
  623. this._dataGrid.sortNodes(sortFunction,!this._dataGrid.isSortOrderAscending());function compareNumericField(field,a,b){const nodeA=(a);const nodeB=(b);return nodeA._profileNode[field]-nodeB._profileNode[field];}
  624. function compareStartTime(a,b){const nodeA=(a);const nodeB=(b);return nodeA._profileNode.event.startTime-nodeB._profileNode.event.startTime;}
  625. function compareName(a,b){const nodeA=(a);const nodeB=(b);const nameA=Timeline.TimelineTreeView.eventNameForSorting(nodeA._profileNode.event);const nameB=Timeline.TimelineTreeView.eventNameForSorting(nodeB._profileNode.event);return nameA.localeCompare(nameB);}}
  626. _onShowModeChanged(){if(this._splitWidget.showMode()===UI.SplitWidget.ShowMode.OnlyMain){return;}
  627. this._lastSelectedNode=undefined;this._updateDetailsForSelection();}
  628. _updateDetailsForSelection(){const selectedNode=this._dataGrid.selectedNode?(this._dataGrid.selectedNode)._profileNode:null;if(selectedNode===this._lastSelectedNode){return;}
  629. this._lastSelectedNode=selectedNode;if(this._splitWidget.showMode()===UI.SplitWidget.ShowMode.OnlyMain){return;}
  630. this._detailsView.detachChildWidgets();this._detailsView.element.removeChildren();if(selectedNode&&this._showDetailsForNode(selectedNode)){return;}
  631. const banner=this._detailsView.element.createChild('div','full-widget-dimmed-banner');banner.createTextChild(Common.UIString('Select item for details.'));}
  632. _showDetailsForNode(node){return false;}
  633. _onMouseMove(event){const gridNode=event.target&&(event.target instanceof Node)?(this._dataGrid.dataGridNodeFromNode((event.target))):null;const profileNode=gridNode&&gridNode._profileNode;if(profileNode===this._lastHoveredProfileNode){return;}
  634. this._lastHoveredProfileNode=profileNode;this._onHover(profileNode);}
  635. _onContextMenu(contextMenu,gridNode){if(gridNode._linkElement&&!contextMenu.containsTarget(gridNode._linkElement)){contextMenu.appendApplicableItems(gridNode._linkElement);}
  636. const profileNode=gridNode._profileNode;if(profileNode){this._appendContextMenuItems(contextMenu,profileNode);}}
  637. dataGridNodeForTreeNode(treeNode){return treeNode[Timeline.TimelineTreeView.TreeGridNode._gridNodeSymbol]||null;}
  638. searchCanceled(){this._searchResults=[];this._currentResult=0;}
  639. performSearch(searchConfig,shouldJump,jumpBackwards){this._searchResults=[];this._currentResult=0;if(!this._root){return;}
  640. const searchRegex=searchConfig.toSearchRegex();this._searchResults=this._root.searchTree(event=>Timeline.TimelineUIUtils.testContentMatching(event,searchRegex));this._searchableView.updateSearchMatchesCount(this._searchResults.length);}
  641. jumpToNextSearchResult(){if(!this._searchResults.length){return;}
  642. this.selectProfileNode(this._searchResults[this._currentResult],false);this._currentResult=mod(this._currentResult+1,this._searchResults.length);}
  643. jumpToPreviousSearchResult(){if(!this._searchResults.length){return;}
  644. this.selectProfileNode(this._searchResults[this._currentResult],false);this._currentResult=mod(this._currentResult-1,this._searchResults.length);}
  645. supportsCaseSensitiveSearch(){return true;}
  646. supportsRegexSearch(){return true;}};Timeline.TimelineTreeView.GridNode=class extends DataGrid.SortableDataGridNode{constructor(profileNode,grandTotalTime,maxSelfTime,maxTotalTime,treeView){super(null,false);this._populated=false;this._profileNode=profileNode;this._treeView=treeView;this._grandTotalTime=grandTotalTime;this._maxSelfTime=maxSelfTime;this._maxTotalTime=maxTotalTime;this._linkElement=null;}
  647. createCell(columnId){if(columnId==='activity'){return this._createNameCell(columnId);}
  648. return this._createValueCell(columnId)||super.createCell(columnId);}
  649. _createNameCell(columnId){const cell=this.createTD(columnId);const container=cell.createChild('div','name-container');const iconContainer=container.createChild('div','activity-icon-container');const icon=iconContainer.createChild('div','activity-icon');const name=container.createChild('div','activity-name');const event=this._profileNode.event;if(this._profileNode.isGroupNode()){const treeView=(this._treeView);const info=treeView._displayInfoForGroupNode(this._profileNode);name.textContent=info.name;icon.style.backgroundColor=info.color;if(info.icon){iconContainer.insertBefore(info.icon,icon);}}else if(event){const data=event.args['data'];const deoptReason=data&&data['deoptReason'];if(deoptReason){container.createChild('div','activity-warning').title=Common.UIString('Not optimized: %s',deoptReason);}
  650. name.textContent=Timeline.TimelineUIUtils.eventTitle(event);this._linkElement=this._treeView._linkifyLocation(event);if(this._linkElement){container.createChild('div','activity-link').appendChild(this._linkElement);}
  651. const eventStyle=Timeline.TimelineUIUtils.eventStyle(event);const eventCategory=eventStyle.category;UI.ARIAUtils.setAccessibleName(icon,eventCategory.title);icon.style.backgroundColor=eventCategory.color;}
  652. return cell;}
  653. _createValueCell(columnId){if(columnId!=='self'&&columnId!=='total'&&columnId!=='startTime'){return null;}
  654. let showPercents=false;let value;let maxTime;switch(columnId){case'startTime':value=this._profileNode.event.startTime-this._treeView._model.timelineModel().minimumRecordTime();break;case'self':value=this._profileNode.selfTime;maxTime=this._maxSelfTime;showPercents=true;break;case'total':value=this._profileNode.totalTime;maxTime=this._maxTotalTime;showPercents=true;break;default:return null;}
  655. const cell=this.createTD(columnId);cell.className='numeric-column';const textDiv=cell.createChild('div');textDiv.createChild('span').textContent=Common.UIString('%.1f\xa0ms',value);if(showPercents&&this._treeView._exposePercentages()){textDiv.createChild('span','percent-column').textContent=Common.UIString('%.1f\xa0%%',value/this._grandTotalTime*100);}
  656. if(maxTime){textDiv.classList.add('background-percent-bar');cell.createChild('div','background-bar-container').createChild('div','background-bar').style.width=(value*100/maxTime).toFixed(1)+'%';}
  657. return cell;}};Timeline.TimelineTreeView.TreeGridNode=class extends Timeline.TimelineTreeView.GridNode{constructor(profileNode,grandTotalTime,maxSelfTime,maxTotalTime,treeView){super(profileNode,grandTotalTime,maxSelfTime,maxTotalTime,treeView);this.setHasChildren(this._profileNode.hasChildren());profileNode[Timeline.TimelineTreeView.TreeGridNode._gridNodeSymbol]=this;}
  658. populate(){if(this._populated){return;}
  659. this._populated=true;if(!this._profileNode.children){return;}
  660. for(const node of this._profileNode.children().values()){const gridNode=new Timeline.TimelineTreeView.TreeGridNode(node,this._grandTotalTime,this._maxSelfTime,this._maxTotalTime,this._treeView);this.insertChildOrdered(gridNode);}}};Timeline.TimelineTreeView.TreeGridNode._gridNodeSymbol=Symbol('treeGridNode');Timeline.AggregatedTimelineTreeView=class extends Timeline.TimelineTreeView{constructor(){super();this._groupBySetting=Common.settings.createSetting('timelineTreeGroupBy',Timeline.AggregatedTimelineTreeView.GroupBy.None);this._groupBySetting.addChangeListener(this.refreshTree.bind(this));this.init();this._stackView=new Timeline.TimelineStackView(this);this._stackView.addEventListener(Timeline.TimelineStackView.Events.SelectionChanged,this._onStackViewSelectionChanged,this);this._productByURLCache=new Map();this._colorByURLCache=new Map();}
  661. setModel(model,track){super.setModel(model,track);}
  662. updateContents(selection){this._updateExtensionResolver();super.updateContents(selection);const rootNode=this._dataGrid.rootNode();if(rootNode.children.length){rootNode.children[0].select();}}
  663. _updateExtensionResolver(){this._executionContextNamesByOrigin=new Map();for(const runtimeModel of SDK.targetManager.models(SDK.RuntimeModel)){for(const context of runtimeModel.executionContexts()){this._executionContextNamesByOrigin.set(context.origin,context.name);}}}
  664. _beautifyDomainName(name){if(Timeline.AggregatedTimelineTreeView._isExtensionInternalURL(name)){name=Common.UIString('[Chrome extensions overhead]');}else if(Timeline.AggregatedTimelineTreeView._isV8NativeURL(name)){name=Common.UIString('[V8 Runtime]');}else if(name.startsWith('chrome-extension')){name=this._executionContextNamesByOrigin.get(name)||name;}
  665. return name;}
  666. _displayInfoForGroupNode(node){const categories=Timeline.TimelineUIUtils.categories();const color=node.id?Timeline.TimelineUIUtils.eventColor((node.event)):categories['other'].color;const unattributed=Common.UIString('[unattributed]');const id=typeof node.id==='symbol'?undefined:node.id;switch(this._groupBySetting.get()){case Timeline.AggregatedTimelineTreeView.GroupBy.Category:{const category=id?categories[id]||categories['other']:unattributed;return{name:category.title,color:category.color};}
  667. case Timeline.AggregatedTimelineTreeView.GroupBy.Domain:case Timeline.AggregatedTimelineTreeView.GroupBy.Subdomain:{const domainName=id?this._beautifyDomainName(id):undefined;return{name:domainName||unattributed,color:color};}
  668. case Timeline.AggregatedTimelineTreeView.GroupBy.EventName:{const name=node.event.name===TimelineModel.TimelineModel.RecordType.JSFrame?Common.UIString('JavaScript'):Timeline.TimelineUIUtils.eventTitle(node.event);return{name:name,color:node.event.name===TimelineModel.TimelineModel.RecordType.JSFrame?Timeline.TimelineUIUtils.eventStyle(node.event).category.color:color};}
  669. case Timeline.AggregatedTimelineTreeView.GroupBy.URL:break;case Timeline.AggregatedTimelineTreeView.GroupBy.Frame:{const frame=id?this._model.timelineModel().pageFrameById(id):undefined;const frameName=frame?Timeline.TimelineUIUtils.displayNameForFrame(frame,80):Common.UIString('Page');return{name:frameName,color:color};}
  670. default:console.assert(false,'Unexpected grouping type');}
  671. return{name:id||unattributed,color:color};}
  672. populateToolbar(toolbar){super.populateToolbar(toolbar);const groupBy=Timeline.AggregatedTimelineTreeView.GroupBy;const options=[{label:Common.UIString('No Grouping'),value:groupBy.None},{label:Common.UIString('Group by Activity'),value:groupBy.EventName},{label:Common.UIString('Group by Category'),value:groupBy.Category},{label:Common.UIString('Group by Domain'),value:groupBy.Domain},{label:Common.UIString('Group by Frame'),value:groupBy.Frame},{label:Common.UIString('Group by Subdomain'),value:groupBy.Subdomain},{label:Common.UIString('Group by URL'),value:groupBy.URL},];toolbar.appendToolbarItem(new UI.ToolbarSettingComboBox(options,this._groupBySetting,ls`Group by`));toolbar.appendSpacer();toolbar.appendToolbarItem(this._splitWidget.createShowHideSidebarButton(Common.UIString('heaviest stack')));}
  673. _buildHeaviestStack(treeNode){console.assert(!!treeNode.parent,'Attempt to build stack for tree root');let result=[];for(let node=treeNode;node&&node.parent;node=node.parent){result.push(node);}
  674. result=result.reverse();for(let node=treeNode;node&&node.children()&&node.children().size;){const children=Array.from(node.children().values());node=children.reduce((a,b)=>a.totalTime>b.totalTime?a:b);result.push(node);}
  675. return result;}
  676. _exposePercentages(){return true;}
  677. _onStackViewSelectionChanged(){const treeNode=this._stackView.selectedTreeNode();if(treeNode){this.selectProfileNode(treeNode,true);}}
  678. _showDetailsForNode(node){const stack=this._buildHeaviestStack(node);this._stackView.setStack(stack,node);this._stackView.show(this._detailsView.element);return true;}
  679. _groupingFunction(groupBy){const GroupBy=Timeline.AggregatedTimelineTreeView.GroupBy;switch(groupBy){case GroupBy.None:return null;case GroupBy.EventName:return event=>Timeline.TimelineUIUtils.eventStyle(event).title;case GroupBy.Category:return event=>Timeline.TimelineUIUtils.eventStyle(event).category.name;case GroupBy.Subdomain:return this._domainByEvent.bind(this,false);case GroupBy.Domain:return this._domainByEvent.bind(this,true);case GroupBy.URL:return event=>TimelineModel.TimelineProfileTree.eventURL(event)||'';case GroupBy.Frame:return event=>TimelineModel.TimelineData.forEvent(event).frameId;default:console.assert(false,`Unexpected aggregation setting: ${groupBy}`);return null;}}
  680. _domainByEvent(groupSubdomains,event){const url=TimelineModel.TimelineProfileTree.eventURL(event);if(!url){return'';}
  681. if(Timeline.AggregatedTimelineTreeView._isExtensionInternalURL(url)){return Timeline.AggregatedTimelineTreeView._extensionInternalPrefix;}
  682. if(Timeline.AggregatedTimelineTreeView._isV8NativeURL(url)){return Timeline.AggregatedTimelineTreeView._v8NativePrefix;}
  683. const parsedURL=url.asParsedURL();if(!parsedURL){return'';}
  684. if(parsedURL.scheme==='chrome-extension'){return parsedURL.scheme+'://'+parsedURL.host;}
  685. if(!groupSubdomains){return parsedURL.host;}
  686. if(/^[.0-9]+$/.test(parsedURL.host)){return parsedURL.host;}
  687. const domainMatch=/([^.]*\.)?[^.]*$/.exec(parsedURL.host);return domainMatch&&domainMatch[0]||'';}
  688. _appendContextMenuItems(contextMenu,node){if(this._groupBySetting.get()!==Timeline.AggregatedTimelineTreeView.GroupBy.Frame){return;}
  689. if(!node.isGroupNode()){return;}
  690. const frame=this._model.timelineModel().pageFrameById((node.id));if(!frame||!frame.ownerNode){return;}
  691. contextMenu.appendApplicableItems(frame.ownerNode);}
  692. static _isExtensionInternalURL(url){return url.startsWith(Timeline.AggregatedTimelineTreeView._extensionInternalPrefix);}
  693. static _isV8NativeURL(url){return url.startsWith(Timeline.AggregatedTimelineTreeView._v8NativePrefix);}};Timeline.AggregatedTimelineTreeView._extensionInternalPrefix='extensions::';Timeline.AggregatedTimelineTreeView._v8NativePrefix='native ';Timeline.AggregatedTimelineTreeView.GroupBy={None:'None',EventName:'EventName',Category:'Category',Domain:'Domain',Subdomain:'Subdomain',URL:'URL',Frame:'Frame'};Timeline.CallTreeTimelineTreeView=class extends Timeline.AggregatedTimelineTreeView{constructor(){super();this._dataGrid.markColumnAsSortedBy('total',DataGrid.DataGrid.Order.Descending);}
  694. getToolbarInputAccessiblePlaceHolder(){return ls`Filter call tree`;}
  695. _buildTree(){const grouping=this._groupBySetting.get();return this.buildTopDownTree(false,this._groupingFunction(grouping));}};Timeline.BottomUpTimelineTreeView=class extends Timeline.AggregatedTimelineTreeView{constructor(){super();this._dataGrid.markColumnAsSortedBy('self',DataGrid.DataGrid.Order.Descending);}
  696. getToolbarInputAccessiblePlaceHolder(){return ls`Filter bottom-up`;}
  697. _buildTree(){return new TimelineModel.TimelineProfileTree.BottomUpRootNode(this._modelEvents(),this.textFilter(),this.filtersWithoutTextFilter(),this._startTime,this._endTime,this._groupingFunction(this._groupBySetting.get()));}};Timeline.TimelineStackView=class extends UI.VBox{constructor(treeView){super();const header=this.element.createChild('div','timeline-stack-view-header');header.textContent=Common.UIString('Heaviest stack');this._treeView=treeView;const columns=([{id:'total',title:Common.UIString('Total Time'),fixedWidth:true,width:'110px'},{id:'activity',title:Common.UIString('Activity')}]);this._dataGrid=new DataGrid.ViewportDataGrid(columns);this._dataGrid.setResizeMethod(DataGrid.DataGrid.ResizeMethod.Last);this._dataGrid.addEventListener(DataGrid.DataGrid.Events.SelectedNode,this._onSelectionChanged,this);this._dataGrid.asWidget().show(this.element);}
  698. setStack(stack,selectedNode){const rootNode=this._dataGrid.rootNode();rootNode.removeChildren();let nodeToReveal=null;const totalTime=Math.max.apply(Math,stack.map(node=>node.totalTime));for(const node of stack){const gridNode=new Timeline.TimelineTreeView.GridNode(node,totalTime,totalTime,totalTime,this._treeView);rootNode.appendChild(gridNode);if(node===selectedNode){nodeToReveal=gridNode;}}
  699. nodeToReveal.revealAndSelect();}
  700. selectedTreeNode(){const selectedNode=this._dataGrid.selectedNode;return selectedNode&&(selectedNode)._profileNode;}
  701. _onSelectionChanged(){this.dispatchEventToListeners(Timeline.TimelineStackView.Events.SelectionChanged);}};Timeline.TimelineStackView.Events={SelectionChanged:Symbol('SelectionChanged')};;Timeline.EventsTimelineTreeView=class extends Timeline.TimelineTreeView{constructor(delegate){super();this._filtersControl=new Timeline.EventsTimelineTreeView.Filters();this._filtersControl.addEventListener(Timeline.EventsTimelineTreeView.Filters.Events.FilterChanged,this._onFilterChanged,this);this.init();this._delegate=delegate;this._dataGrid.markColumnAsSortedBy('startTime',DataGrid.DataGrid.Order.Ascending);this._splitWidget.showBoth();}
  702. filters(){return[...super.filters(),...this._filtersControl.filters()];}
  703. updateContents(selection){super.updateContents(selection);if(selection.type()===Timeline.TimelineSelection.Type.TraceEvent){const event=(selection.object());this._selectEvent(event,true);}}
  704. getToolbarInputAccessiblePlaceHolder(){return ls`Filter event log`;}
  705. _buildTree(){this._currentTree=this.buildTopDownTree(true,null);return this._currentTree;}
  706. _onFilterChanged(){const selectedEvent=this.lastSelectedNode()&&this.lastSelectedNode().event;this.refreshTree();if(selectedEvent){this._selectEvent(selectedEvent,false);}}
  707. _findNodeWithEvent(event){const iterators=[this._currentTree.children().values()];while(iterators.length){const iterator=iterators.peekLast().next();if(iterator.done){iterators.pop();continue;}
  708. const child=(iterator.value);if(child.event===event){return child;}
  709. iterators.push(child.children().values());}
  710. return null;}
  711. _selectEvent(event,expand){const node=this._findNodeWithEvent(event);if(!node){return;}
  712. this.selectProfileNode(node,false);if(expand){this.dataGridNodeForTreeNode(node).expand();}}
  713. populateColumns(columns){columns.push({id:'startTime',title:Common.UIString('Start Time'),width:'80px',fixedWidth:true,sortable:true});super.populateColumns(columns);columns.filter(c=>c.fixedWidth).forEach(c=>c.width='80px');}
  714. populateToolbar(toolbar){super.populateToolbar(toolbar);this._filtersControl.populateToolbar(toolbar);}
  715. _showDetailsForNode(node){const traceEvent=node.event;if(!traceEvent){return false;}
  716. Timeline.TimelineUIUtils.buildTraceEventDetails(traceEvent,this.model().timelineModel(),this._linkifier,false).then(fragment=>this._detailsView.element.appendChild(fragment));return true;}
  717. _onHover(node){this._delegate.highlightEvent(node&&node.event);}};Timeline.EventsTimelineTreeView.Filters=class extends Common.Object{constructor(){super();this._categoryFilter=new Timeline.TimelineFilters.Category();this._durationFilter=new Timeline.TimelineFilters.IsLong();this._filters=[this._categoryFilter,this._durationFilter];}
  718. filters(){return this._filters;}
  719. populateToolbar(toolbar){const durationFilterUI=new UI.ToolbarComboBox(durationFilterChanged.bind(this),ls`Duration filter`);for(const durationMs of Timeline.EventsTimelineTreeView.Filters._durationFilterPresetsMs){durationFilterUI.addOption(durationFilterUI.createOption(durationMs?Common.UIString('\u2265 %d\xa0ms',durationMs):Common.UIString('All'),String(durationMs)));}
  720. toolbar.appendToolbarItem(durationFilterUI);const categoryFiltersUI={};const categories=Timeline.TimelineUIUtils.categories();for(const categoryName in categories){const category=categories[categoryName];if(!category.visible){continue;}
  721. const checkbox=new UI.ToolbarCheckbox(category.title,undefined,categoriesFilterChanged.bind(this,categoryName));checkbox.setChecked(true);checkbox.inputElement.style.backgroundColor=category.color;categoryFiltersUI[category.name]=checkbox;toolbar.appendToolbarItem(checkbox);}
  722. function durationFilterChanged(){const duration=durationFilterUI.selectedOption().value;const minimumRecordDuration=parseInt(duration,10);this._durationFilter.setMinimumRecordDuration(minimumRecordDuration);this._notifyFiltersChanged();}
  723. function categoriesFilterChanged(name){const categories=Timeline.TimelineUIUtils.categories();categories[name].hidden=!categoryFiltersUI[name].checked();this._notifyFiltersChanged();}}
  724. _notifyFiltersChanged(){this.dispatchEventToListeners(Timeline.EventsTimelineTreeView.Filters.Events.FilterChanged);}};Timeline.EventsTimelineTreeView.Filters._durationFilterPresetsMs=[0,1,15];Timeline.EventsTimelineTreeView.Filters.Events={FilterChanged:Symbol('FilterChanged')};;Timeline.TimelineUIUtils=class{static _initEventStyles(){if(Timeline.TimelineUIUtils._eventStylesMap){return Timeline.TimelineUIUtils._eventStylesMap;}
  725. const type=TimelineModel.TimelineModel.RecordType;const categories=Timeline.TimelineUIUtils.categories();const rendering=categories['rendering'];const scripting=categories['scripting'];const loading=categories['loading'];const painting=categories['painting'];const other=categories['other'];const idle=categories['idle'];const eventStyles={};eventStyles[type.Task]=new Timeline.TimelineRecordStyle(ls`Task`,other);eventStyles[type.Program]=new Timeline.TimelineRecordStyle(ls`Other`,other);eventStyles[type.Animation]=new Timeline.TimelineRecordStyle(ls`Animation`,rendering);eventStyles[type.EventDispatch]=new Timeline.TimelineRecordStyle(ls`Event`,scripting);eventStyles[type.RequestMainThreadFrame]=new Timeline.TimelineRecordStyle(ls`Request Main Thread Frame`,rendering,true);eventStyles[type.BeginFrame]=new Timeline.TimelineRecordStyle(ls`Frame Start`,rendering,true);eventStyles[type.BeginMainThreadFrame]=new Timeline.TimelineRecordStyle(ls`Frame Start (main thread)`,rendering,true);eventStyles[type.DrawFrame]=new Timeline.TimelineRecordStyle(ls`Draw Frame`,rendering,true);eventStyles[type.HitTest]=new Timeline.TimelineRecordStyle(ls`Hit Test`,rendering);eventStyles[type.ScheduleStyleRecalculation]=new Timeline.TimelineRecordStyle(ls`Schedule Style Recalculation`,rendering);eventStyles[type.RecalculateStyles]=new Timeline.TimelineRecordStyle(ls`Recalculate Style`,rendering);eventStyles[type.UpdateLayoutTree]=new Timeline.TimelineRecordStyle(ls`Recalculate Style`,rendering);eventStyles[type.InvalidateLayout]=new Timeline.TimelineRecordStyle(ls`Invalidate Layout`,rendering,true);eventStyles[type.Layout]=new Timeline.TimelineRecordStyle(ls`Layout`,rendering);eventStyles[type.PaintSetup]=new Timeline.TimelineRecordStyle(ls`Paint Setup`,painting);eventStyles[type.PaintImage]=new Timeline.TimelineRecordStyle(ls`Paint Image`,painting,true);eventStyles[type.UpdateLayer]=new Timeline.TimelineRecordStyle(ls`Update Layer`,painting,true);eventStyles[type.UpdateLayerTree]=new Timeline.TimelineRecordStyle(ls`Update Layer Tree`,rendering);eventStyles[type.Paint]=new Timeline.TimelineRecordStyle(ls`Paint`,painting);eventStyles[type.RasterTask]=new Timeline.TimelineRecordStyle(ls`Rasterize Paint`,painting);eventStyles[type.ScrollLayer]=new Timeline.TimelineRecordStyle(ls`Scroll`,rendering);eventStyles[type.CompositeLayers]=new Timeline.TimelineRecordStyle(ls`Composite Layers`,painting);eventStyles[type.ParseHTML]=new Timeline.TimelineRecordStyle(ls`Parse HTML`,loading);eventStyles[type.ParseAuthorStyleSheet]=new Timeline.TimelineRecordStyle(ls`Parse Stylesheet`,loading);eventStyles[type.TimerInstall]=new Timeline.TimelineRecordStyle(ls`Install Timer`,scripting);eventStyles[type.TimerRemove]=new Timeline.TimelineRecordStyle(ls`Remove Timer`,scripting);eventStyles[type.TimerFire]=new Timeline.TimelineRecordStyle(ls`Timer Fired`,scripting);eventStyles[type.XHRReadyStateChange]=new Timeline.TimelineRecordStyle(ls`XHR Ready State Change`,scripting);eventStyles[type.XHRLoad]=new Timeline.TimelineRecordStyle(ls`XHR Load`,scripting);eventStyles[type.CompileScript]=new Timeline.TimelineRecordStyle(ls`Compile Script`,scripting);eventStyles[type.EvaluateScript]=new Timeline.TimelineRecordStyle(ls`Evaluate Script`,scripting);eventStyles[type.CompileModule]=new Timeline.TimelineRecordStyle(ls`Compile Module`,scripting);eventStyles[type.EvaluateModule]=new Timeline.TimelineRecordStyle(ls`Evaluate Module`,scripting);eventStyles[type.StreamingCompileScript]=new Timeline.TimelineRecordStyle(ls`Streaming Compile Task`,other);eventStyles[type.StreamingCompileScriptWaiting]=new Timeline.TimelineRecordStyle(ls`Waiting for Network`,idle);eventStyles[type.StreamingCompileScriptParsing]=new Timeline.TimelineRecordStyle(ls`Parse and Compile`,scripting);eventStyles[type.WasmStreamFromResponseCallback]=new Timeline.TimelineRecordStyle(ls`Streaming Wasm Response`,scripting);eventStyles[type.WasmCompiledModule]=new Timeline.TimelineRecordStyle(ls`Compiled Wasm Module`,scripting);eventStyles[type.WasmCachedModule]=new Timeline.TimelineRecordStyle(ls`Cached Wasm Module`,scripting);eventStyles[type.WasmModuleCacheHit]=new Timeline.TimelineRecordStyle(ls`Wasm Module Cache Hit`,scripting);eventStyles[type.WasmModuleCacheInvalid]=new Timeline.TimelineRecordStyle(ls`Wasm Module Cache Invalid`,scripting);eventStyles[type.FrameStartedLoading]=new Timeline.TimelineRecordStyle(ls`Frame Started Loading`,loading,true);eventStyles[type.MarkLoad]=new Timeline.TimelineRecordStyle(ls`Onload Event`,scripting,true);eventStyles[type.MarkDOMContent]=new Timeline.TimelineRecordStyle(ls`DOMContentLoaded Event`,scripting,true);eventStyles[type.MarkFirstPaint]=new Timeline.TimelineRecordStyle(ls`First Paint`,painting,true);eventStyles[type.MarkFCP]=new Timeline.TimelineRecordStyle(ls`First Contentful Paint`,rendering,true);eventStyles[type.MarkFMP]=new Timeline.TimelineRecordStyle(ls`First Meaningful Paint`,rendering,true);eventStyles[type.MarkLCPCandidate]=new Timeline.TimelineRecordStyle(ls`Largest Contentful Paint`,rendering,true);eventStyles[type.TimeStamp]=new Timeline.TimelineRecordStyle(ls`Timestamp`,scripting);eventStyles[type.ConsoleTime]=new Timeline.TimelineRecordStyle(ls`Console Time`,scripting);eventStyles[type.UserTiming]=new Timeline.TimelineRecordStyle(ls`User Timing`,scripting);eventStyles[type.ResourceWillSendRequest]=new Timeline.TimelineRecordStyle(ls`Will Send Request`,loading);eventStyles[type.ResourceSendRequest]=new Timeline.TimelineRecordStyle(ls`Send Request`,loading);eventStyles[type.ResourceReceiveResponse]=new Timeline.TimelineRecordStyle(ls`Receive Response`,loading);eventStyles[type.ResourceFinish]=new Timeline.TimelineRecordStyle(ls`Finish Loading`,loading);eventStyles[type.ResourceReceivedData]=new Timeline.TimelineRecordStyle(ls`Receive Data`,loading);eventStyles[type.RunMicrotasks]=new Timeline.TimelineRecordStyle(ls`Run Microtasks`,scripting);eventStyles[type.FunctionCall]=new Timeline.TimelineRecordStyle(ls`Function Call`,scripting);eventStyles[type.GCEvent]=new Timeline.TimelineRecordStyle(ls`GC Event`,scripting);eventStyles[type.MajorGC]=new Timeline.TimelineRecordStyle(ls`Major GC`,scripting);eventStyles[type.MinorGC]=new Timeline.TimelineRecordStyle(ls`Minor GC`,scripting);eventStyles[type.JSFrame]=new Timeline.TimelineRecordStyle(ls`JS Frame`,scripting);eventStyles[type.RequestAnimationFrame]=new Timeline.TimelineRecordStyle(ls`Request Animation Frame`,scripting);eventStyles[type.CancelAnimationFrame]=new Timeline.TimelineRecordStyle(ls`Cancel Animation Frame`,scripting);eventStyles[type.FireAnimationFrame]=new Timeline.TimelineRecordStyle(ls`Animation Frame Fired`,scripting);eventStyles[type.RequestIdleCallback]=new Timeline.TimelineRecordStyle(ls`Request Idle Callback`,scripting);eventStyles[type.CancelIdleCallback]=new Timeline.TimelineRecordStyle(ls`Cancel Idle Callback`,scripting);eventStyles[type.FireIdleCallback]=new Timeline.TimelineRecordStyle(ls`Fire Idle Callback`,scripting);eventStyles[type.WebSocketCreate]=new Timeline.TimelineRecordStyle(ls`Create WebSocket`,scripting);eventStyles[type.WebSocketSendHandshakeRequest]=new Timeline.TimelineRecordStyle(ls`Send WebSocket Handshake`,scripting);eventStyles[type.WebSocketReceiveHandshakeResponse]=new Timeline.TimelineRecordStyle(ls`Receive WebSocket Handshake`,scripting);eventStyles[type.WebSocketDestroy]=new Timeline.TimelineRecordStyle(ls`Destroy WebSocket`,scripting);eventStyles[type.EmbedderCallback]=new Timeline.TimelineRecordStyle(ls`Embedder Callback`,scripting);eventStyles[type.DecodeImage]=new Timeline.TimelineRecordStyle(ls`Image Decode`,painting);eventStyles[type.ResizeImage]=new Timeline.TimelineRecordStyle(ls`Image Resize`,painting);eventStyles[type.GPUTask]=new Timeline.TimelineRecordStyle(ls`GPU`,categories['gpu']);eventStyles[type.LatencyInfo]=new Timeline.TimelineRecordStyle(ls`Input Latency`,scripting);eventStyles[type.GCCollectGarbage]=new Timeline.TimelineRecordStyle(ls`DOM GC`,scripting);eventStyles[type.CryptoDoEncrypt]=new Timeline.TimelineRecordStyle(ls`Encrypt`,scripting);eventStyles[type.CryptoDoEncryptReply]=new Timeline.TimelineRecordStyle(ls`Encrypt Reply`,scripting);eventStyles[type.CryptoDoDecrypt]=new Timeline.TimelineRecordStyle(ls`Decrypt`,scripting);eventStyles[type.CryptoDoDecryptReply]=new Timeline.TimelineRecordStyle(ls`Decrypt Reply`,scripting);eventStyles[type.CryptoDoDigest]=new Timeline.TimelineRecordStyle(ls`Digest`,scripting);eventStyles[type.CryptoDoDigestReply]=new Timeline.TimelineRecordStyle(ls`Digest Reply`,scripting);eventStyles[type.CryptoDoSign]=new Timeline.TimelineRecordStyle(ls`Sign`,scripting);eventStyles[type.CryptoDoSignReply]=new Timeline.TimelineRecordStyle(ls`Sign Reply`,scripting);eventStyles[type.CryptoDoVerify]=new Timeline.TimelineRecordStyle(ls`Verify`,scripting);eventStyles[type.CryptoDoVerifyReply]=new Timeline.TimelineRecordStyle(ls`Verify Reply`,scripting);eventStyles[type.AsyncTask]=new Timeline.TimelineRecordStyle(ls`Async Task`,categories['async']);Timeline.TimelineUIUtils._eventStylesMap=eventStyles;return eventStyles;}
  726. static setEventStylesMap(eventStyles){Timeline.TimelineUIUtils._eventStylesMap=eventStyles;}
  727. static inputEventDisplayName(inputEventType){if(!Timeline.TimelineUIUtils._inputEventToDisplayName){const inputEvent=TimelineModel.TimelineIRModel.InputEvents;Timeline.TimelineUIUtils._inputEventToDisplayName=new Map([[inputEvent.Char,ls`Key Character`],[inputEvent.KeyDown,ls`Key Down`],[inputEvent.KeyDownRaw,ls`Key Down`],[inputEvent.KeyUp,ls`Key Up`],[inputEvent.Click,ls`Click`],[inputEvent.ContextMenu,ls`Context Menu`],[inputEvent.MouseDown,ls`Mouse Down`],[inputEvent.MouseMove,ls`Mouse Move`],[inputEvent.MouseUp,ls`Mouse Up`],[inputEvent.MouseWheel,ls`Mouse Wheel`],[inputEvent.ScrollBegin,ls`Scroll Begin`],[inputEvent.ScrollEnd,ls`Scroll End`],[inputEvent.ScrollUpdate,ls`Scroll Update`],[inputEvent.FlingStart,ls`Fling Start`],[inputEvent.FlingCancel,ls`Fling Halt`],[inputEvent.Tap,ls`Tap`],[inputEvent.TapCancel,ls`Tap Halt`],[inputEvent.ShowPress,ls`Tap Begin`],[inputEvent.TapDown,ls`Tap Down`],[inputEvent.TouchCancel,ls`Touch Cancel`],[inputEvent.TouchEnd,ls`Touch End`],[inputEvent.TouchMove,ls`Touch Move`],[inputEvent.TouchStart,ls`Touch Start`],[inputEvent.PinchBegin,ls`Pinch Begin`],[inputEvent.PinchEnd,ls`Pinch End`],[inputEvent.PinchUpdate,ls`Pinch Update`]]);}
  728. return Timeline.TimelineUIUtils._inputEventToDisplayName.get(inputEventType)||null;}
  729. static frameDisplayName(frame){if(!TimelineModel.TimelineJSProfileProcessor.isNativeRuntimeFrame(frame)){return UI.beautifyFunctionName(frame.functionName);}
  730. const nativeGroup=TimelineModel.TimelineJSProfileProcessor.nativeGroup(frame.functionName);const groups=TimelineModel.TimelineJSProfileProcessor.NativeGroups;switch(nativeGroup){case groups.Compile:return ls`Compile`;case groups.Parse:return ls`Parse`;}
  731. return frame.functionName;}
  732. static testContentMatching(traceEvent,regExp){const title=Timeline.TimelineUIUtils.eventStyle(traceEvent).title;const tokens=[title];const url=TimelineModel.TimelineData.forEvent(traceEvent).url;if(url){tokens.push(url);}
  733. appendObjectProperties(traceEvent.args,2);return regExp.test(tokens.join('|'));function appendObjectProperties(object,depth){if(!depth){return;}
  734. for(const key in object){const value=object[key];const type=typeof value;if(type==='string'){tokens.push(value);}else if(type==='number'){tokens.push(String(value));}else if(type==='object'){appendObjectProperties(value,depth-1);}}}}
  735. static eventURL(event){const data=event.args['data']||event.args['beginData'];const url=data&&data.url;if(url){return url;}
  736. const stackTrace=data&&data['stackTrace'];const frame=stackTrace&&stackTrace.length&&stackTrace[0]||TimelineModel.TimelineData.forEvent(event).topFrame();return frame&&frame.url||null;}
  737. static eventStyle(event){const eventStyles=Timeline.TimelineUIUtils._initEventStyles();if(event.hasCategory(TimelineModel.TimelineModel.Category.Console)||event.hasCategory(TimelineModel.TimelineModel.Category.UserTiming)){return new Timeline.TimelineRecordStyle(event.name,Timeline.TimelineUIUtils.categories()['scripting']);}
  738. if(event.hasCategory(TimelineModel.TimelineModel.Category.LatencyInfo)){const prefix='InputLatency::';const inputEventType=event.name.startsWith(prefix)?event.name.substr(prefix.length):event.name;const displayName=Timeline.TimelineUIUtils.inputEventDisplayName((inputEventType));return new Timeline.TimelineRecordStyle(displayName||inputEventType,Timeline.TimelineUIUtils.categories()['scripting']);}
  739. let result=eventStyles[event.name];if(!result){result=new Timeline.TimelineRecordStyle(event.name,Timeline.TimelineUIUtils.categories()['other'],true);eventStyles[event.name]=result;}
  740. return result;}
  741. static eventColor(event){if(event.name===TimelineModel.TimelineModel.RecordType.JSFrame){const frame=event.args['data'];if(Timeline.TimelineUIUtils.isUserFrame(frame)){return Timeline.TimelineUIUtils.colorForId(frame.url);}}
  742. const color=Timeline.TimelineUIUtils.eventStyle(event).category.color;if(event.name===TimelineModel.TimelineModel.RecordType.StreamingCompileScriptWaiting){return(Common.Color.parse(Timeline.TimelineUIUtils.categories().scripting.color).setAlpha(0.3).asString(null));}
  743. return color;}
  744. static eventColorByProduct(model,urlToColorCache,event){const url=Timeline.TimelineUIUtils.eventURL(event)||'';let color=urlToColorCache.get(url);if(color){return color;}
  745. const defaultColor='#f2ecdc';const parsedURL=url.asParsedURL();if(!parsedURL){return defaultColor;}
  746. const name=parsedURL.host;const rootFrames=model.rootFrames();if(rootFrames.some(pageFrame=>new Common.ParsedURL(pageFrame.url).host===name)){color=defaultColor;}
  747. if(!color){color=defaultColor;}
  748. urlToColorCache.set(url,color);return color;}
  749. static eventTitle(event){const recordType=TimelineModel.TimelineModel.RecordType;const eventData=event.args['data'];if(event.name===recordType.JSFrame){return Timeline.TimelineUIUtils.frameDisplayName(eventData);}
  750. const title=Timeline.TimelineUIUtils.eventStyle(event).title;if(event.hasCategory(TimelineModel.TimelineModel.Category.Console)){return title;}
  751. if(event.name===recordType.TimeStamp){return ls`${title}: ${eventData['message']}`;}
  752. if(event.name===recordType.Animation&&eventData&&eventData['name']){return ls`${title}: ${eventData['name']}`;}
  753. if(event.name===recordType.EventDispatch&&eventData&&eventData['type']){return ls`${title}: ${eventData['type']}`;}
  754. return title;}
  755. static _interactionPhaseStyles(){let map=Timeline.TimelineUIUtils._interactionPhaseStylesMap;if(!map){map=new Map([[TimelineModel.TimelineIRModel.Phases.Idle,{color:'white',label:'Idle'}],[TimelineModel.TimelineIRModel.Phases.Response,{color:'hsl(43, 83%, 64%)',label:ls`Response`}],[TimelineModel.TimelineIRModel.Phases.Scroll,{color:'hsl(256, 67%, 70%)',label:ls`Scroll`}],[TimelineModel.TimelineIRModel.Phases.Fling,{color:'hsl(256, 67%, 70%)',label:ls`Fling`}],[TimelineModel.TimelineIRModel.Phases.Drag,{color:'hsl(256, 67%, 70%)',label:ls`Drag`}],[TimelineModel.TimelineIRModel.Phases.Animation,{color:'hsl(256, 67%, 70%)',label:ls`Animation`}],[TimelineModel.TimelineIRModel.Phases.Uncategorized,{color:'hsl(0, 0%, 87%)',label:ls`Uncategorized`}]]);Timeline.TimelineUIUtils._interactionPhaseStylesMap=map;}
  756. return map;}
  757. static interactionPhaseColor(phase){return Timeline.TimelineUIUtils._interactionPhaseStyles().get(phase).color;}
  758. static interactionPhaseLabel(phase){return Timeline.TimelineUIUtils._interactionPhaseStyles().get(phase).label;}
  759. static isUserFrame(frame){return frame.scriptId!=='0'&&!(frame.url&&frame.url.startsWith('native '));}
  760. static networkRequestCategory(request){const categories=Timeline.TimelineUIUtils.NetworkCategory;switch(request.mimeType){case'text/html':return categories.HTML;case'application/javascript':case'application/x-javascript':case'text/javascript':return categories.Script;case'text/css':return categories.Style;case'audio/ogg':case'image/gif':case'image/jpeg':case'image/png':case'image/svg+xml':case'image/webp':case'image/x-icon':case'font/opentype':case'font/woff2':case'application/font-woff':return categories.Media;default:return categories.Other;}}
  761. static networkCategoryColor(category){const categories=Timeline.TimelineUIUtils.NetworkCategory;switch(category){case categories.HTML:return'hsl(214, 67%, 66%)';case categories.Script:return'hsl(43, 83%, 64%)';case categories.Style:return'hsl(256, 67%, 70%)';case categories.Media:return'hsl(109, 33%, 55%)';default:return'hsl(0, 0%, 70%)';}}
  762. static buildDetailsTextForTraceEvent(event,target){const recordType=TimelineModel.TimelineModel.RecordType;let detailsText;const eventData=event.args['data'];switch(event.name){case recordType.GCEvent:case recordType.MajorGC:case recordType.MinorGC:{const delta=event.args['usedHeapSizeBefore']-event.args['usedHeapSizeAfter'];detailsText=Common.UIString('%s collected',Number.bytesToString(delta));break;}
  763. case recordType.FunctionCall:if(eventData){detailsText=linkifyLocationAsText(eventData['scriptId'],eventData['lineNumber'],eventData['columnNumber']);}
  764. break;case recordType.JSFrame:detailsText=Timeline.TimelineUIUtils.frameDisplayName(eventData);break;case recordType.EventDispatch:detailsText=eventData?eventData['type']:null;break;case recordType.Paint:{const width=Timeline.TimelineUIUtils.quadWidth(eventData.clip);const height=Timeline.TimelineUIUtils.quadHeight(eventData.clip);if(width&&height){detailsText=Common.UIString('%d\xa0\u00d7\xa0%d',width,height);}
  765. break;}
  766. case recordType.ParseHTML:{const startLine=event.args['beginData']['startLine'];const endLine=event.args['endData']&&event.args['endData']['endLine'];const url=Bindings.displayNameForURL(event.args['beginData']['url']);if(endLine>=0){detailsText=Common.UIString('%s [%s\u2026%s]',url,startLine+1,endLine+1);}else{detailsText=Common.UIString('%s [%s\u2026]',url,startLine+1);}
  767. break;}
  768. case recordType.CompileModule:detailsText=Bindings.displayNameForURL(event.args['fileName']);break;case recordType.CompileScript:case recordType.EvaluateScript:{const url=eventData&&eventData['url'];if(url){detailsText=Bindings.displayNameForURL(url)+':'+(eventData['lineNumber']+1);}
  769. break;}
  770. case recordType.WasmCompiledModule:case recordType.WasmModuleCacheHit:{const url=event.args['url'];if(url){detailsText=Bindings.displayNameForURL(url);}
  771. break;}
  772. case recordType.StreamingCompileScript:case recordType.XHRReadyStateChange:case recordType.XHRLoad:{const url=eventData['url'];if(url){detailsText=Bindings.displayNameForURL(url);}
  773. break;}
  774. case recordType.TimeStamp:detailsText=eventData['message'];break;case recordType.WebSocketCreate:case recordType.WebSocketSendHandshakeRequest:case recordType.WebSocketReceiveHandshakeResponse:case recordType.WebSocketDestroy:case recordType.ResourceWillSendRequest:case recordType.ResourceSendRequest:case recordType.ResourceReceivedData:case recordType.ResourceReceiveResponse:case recordType.ResourceFinish:case recordType.PaintImage:case recordType.DecodeImage:case recordType.ResizeImage:case recordType.DecodeLazyPixelRef:{const url=TimelineModel.TimelineData.forEvent(event).url;if(url){detailsText=Bindings.displayNameForURL(url);}
  775. break;}
  776. case recordType.EmbedderCallback:detailsText=eventData['callbackName'];break;case recordType.Animation:detailsText=eventData&&eventData['name'];break;case recordType.AsyncTask:detailsText=eventData?eventData['name']:null;break;default:if(event.hasCategory(TimelineModel.TimelineModel.Category.Console)){detailsText=null;}else{detailsText=linkifyTopCallFrameAsText();}
  777. break;}
  778. return detailsText;function linkifyLocationAsText(scriptId,lineNumber,columnNumber){const debuggerModel=target?target.model(SDK.DebuggerModel):null;if(!target||target.isDisposed()||!scriptId||!debuggerModel){return null;}
  779. const rawLocation=debuggerModel.createRawLocationByScriptId(scriptId,lineNumber,columnNumber);if(!rawLocation){return null;}
  780. const uiLocation=Bindings.debuggerWorkspaceBinding.rawLocationToUILocation(rawLocation);return uiLocation?uiLocation.linkText():null;}
  781. function linkifyTopCallFrameAsText(){const frame=TimelineModel.TimelineData.forEvent(event).topFrame();if(!frame){return null;}
  782. let text=linkifyLocationAsText(frame.scriptId,frame.lineNumber,frame.columnNumber);if(!text){text=frame.url;if(typeof frame.lineNumber==='number'){text+=':'+(frame.lineNumber+1);}}
  783. return text;}}
  784. static buildDetailsNodeForTraceEvent(event,target,linkifier){const recordType=TimelineModel.TimelineModel.RecordType;let details=null;let detailsText;const eventData=event.args['data'];switch(event.name){case recordType.GCEvent:case recordType.MajorGC:case recordType.MinorGC:case recordType.EventDispatch:case recordType.Paint:case recordType.Animation:case recordType.EmbedderCallback:case recordType.ParseHTML:case recordType.WasmStreamFromResponseCallback:case recordType.WasmCompiledModule:case recordType.WasmModuleCacheHit:case recordType.WasmCachedModule:case recordType.WasmModuleCacheInvalid:case recordType.WebSocketCreate:case recordType.WebSocketSendHandshakeRequest:case recordType.WebSocketReceiveHandshakeResponse:case recordType.WebSocketDestroy:detailsText=Timeline.TimelineUIUtils.buildDetailsTextForTraceEvent(event,target);break;case recordType.PaintImage:case recordType.DecodeImage:case recordType.ResizeImage:case recordType.DecodeLazyPixelRef:case recordType.XHRReadyStateChange:case recordType.XHRLoad:case recordType.ResourceWillSendRequest:case recordType.ResourceSendRequest:case recordType.ResourceReceivedData:case recordType.ResourceReceiveResponse:case recordType.ResourceFinish:{const url=TimelineModel.TimelineData.forEvent(event).url;if(url){details=Components.Linkifier.linkifyURL(url);}
  785. break;}
  786. case recordType.FunctionCall:case recordType.JSFrame:details=createElement('span');details.createTextChild(Timeline.TimelineUIUtils.frameDisplayName(eventData));const location=linkifyLocation(eventData['scriptId'],eventData['url'],eventData['lineNumber'],eventData['columnNumber']);if(location){details.createTextChild(' @ ');details.appendChild(location);}
  787. break;case recordType.CompileModule:details=linkifyLocation('',event.args['fileName'],0,0);break;case recordType.CompileScript:case recordType.EvaluateScript:{const url=eventData['url'];if(url){details=linkifyLocation('',url,eventData['lineNumber'],0);}
  788. break;}
  789. case recordType.StreamingCompileScript:{const url=eventData['url'];if(url){details=linkifyLocation('',url,0,0);}
  790. break;}
  791. default:if(event.hasCategory(TimelineModel.TimelineModel.Category.Console)){detailsText=null;}else{details=linkifyTopCallFrame();}
  792. break;}
  793. if(!details&&detailsText){details=createTextNode(detailsText);}
  794. return details;function linkifyLocation(scriptId,url,lineNumber,columnNumber){return linkifier.linkifyScriptLocation(target,scriptId,url,lineNumber,columnNumber,'timeline-details');}
  795. function linkifyTopCallFrame(){const frame=TimelineModel.TimelineData.forEvent(event).topFrame();return frame?linkifier.maybeLinkifyConsoleCallFrame(target,frame,'timeline-details'):null;}}
  796. static buildDetailsNodeForPerformanceEvent(event){let link='https://developers.google.com/web/fundamentals/performance/user-centric-performance-metrics#user-centric_performance_metrics';let name='page performance metrics';const recordType=TimelineModel.TimelineModel.RecordType;switch(event.name){case recordType.MarkLCPCandidate:link='https://web.dev/largest-contentful-paint';name='largest contentful paint';break;case recordType.MarkFCP:link='https://web.dev/first-contentful-paint';name='first contentful paint';break;case recordType.MarkFMP:link='https://web.dev/first-meaningful-paint/';name='first meaningful paint';break;default:break;}
  797. return UI.html`<div>${UI.XLink.create(link, ls`Learn more`)} about ${name}.</div>`;}
  798. static async buildTraceEventDetails(event,model,linkifier,detailed){const maybeTarget=model.targetByEvent(event);let relatedNodesMap=null;if(maybeTarget){const target=(maybeTarget);if(typeof event[Timeline.TimelineUIUtils._previewElementSymbol]==='undefined'){let previewElement=null;const url=TimelineModel.TimelineData.forEvent(event).url;if(url){previewElement=await Components.ImagePreview.build(target,url,false,{imageAltText:Components.ImagePreview.defaultAltTextForImageURL(url)});}else if(TimelineModel.TimelineData.forEvent(event).picture){previewElement=await Timeline.TimelineUIUtils.buildPicturePreviewContent(event,target);}
  799. event[Timeline.TimelineUIUtils._previewElementSymbol]=previewElement;}
  800. const nodeIdsToResolve=new Set();const timelineData=TimelineModel.TimelineData.forEvent(event);if(timelineData.backendNodeId){nodeIdsToResolve.add(timelineData.backendNodeId);}
  801. const invalidationTrackingEvents=TimelineModel.InvalidationTracker.invalidationEventsFor(event);if(invalidationTrackingEvents){Timeline.TimelineUIUtils._collectInvalidationNodeIds(nodeIdsToResolve,invalidationTrackingEvents);}
  802. if(nodeIdsToResolve.size){const domModel=target.model(SDK.DOMModel);if(domModel){relatedNodesMap=await domModel.pushNodesByBackendIdsToFrontend(nodeIdsToResolve);}}}
  803. const recordTypes=TimelineModel.TimelineModel.RecordType;let relatedNodeLabel;const contentHelper=new Timeline.TimelineDetailsContentHelper(model.targetByEvent(event),linkifier);const color=model.isMarkerEvent(event)?Timeline.TimelineUIUtils.markerStyleForEvent(event).color:Timeline.TimelineUIUtils.eventStyle(event).category.color;contentHelper.addSection(Timeline.TimelineUIUtils.eventTitle(event),color);const eventData=event.args['data'];const timelineData=TimelineModel.TimelineData.forEvent(event);const initiator=timelineData.initiator();let url=null;if(timelineData.warning){contentHelper.appendWarningRow(event);}
  804. if(event.name===recordTypes.JSFrame&&eventData['deoptReason']){contentHelper.appendWarningRow(event,TimelineModel.TimelineModel.WarningType.V8Deopt);}
  805. if(detailed&&!Number.isNaN(event.duration+0)){contentHelper.appendTextRow(ls`Total Time`,Number.millisToString(event.duration,true));contentHelper.appendTextRow(ls`Self Time`,Number.millisToString(event.selfTime,true));}
  806. if(model.isGenericTrace()){for(const key in event.args){try{contentHelper.appendTextRow(key,JSON.stringify(event.args[key]));}catch(e){contentHelper.appendTextRow(key,`<${typeof event.args[key]}>`);}}
  807. return contentHelper.fragment;}
  808. switch(event.name){case recordTypes.GCEvent:case recordTypes.MajorGC:case recordTypes.MinorGC:const delta=event.args['usedHeapSizeBefore']-event.args['usedHeapSizeAfter'];contentHelper.appendTextRow(ls`Collected`,Number.bytesToString(delta));break;case recordTypes.JSFrame:case recordTypes.FunctionCall:const detailsNode=Timeline.TimelineUIUtils.buildDetailsNodeForTraceEvent(event,model.targetByEvent(event),linkifier);if(detailsNode){contentHelper.appendElementRow(ls`Function`,detailsNode);}
  809. break;case recordTypes.TimerFire:case recordTypes.TimerInstall:case recordTypes.TimerRemove:contentHelper.appendTextRow(ls`Timer ID`,eventData['timerId']);if(event.name===recordTypes.TimerInstall){contentHelper.appendTextRow(ls`Timeout`,Number.millisToString(eventData['timeout']));contentHelper.appendTextRow(ls`Repeats`,!eventData['singleShot']);}
  810. break;case recordTypes.FireAnimationFrame:contentHelper.appendTextRow(ls`Callback ID`,eventData['id']);break;case recordTypes.ResourceWillSendRequest:case recordTypes.ResourceSendRequest:case recordTypes.ResourceReceiveResponse:case recordTypes.ResourceReceivedData:case recordTypes.ResourceFinish:url=timelineData.url;if(url){contentHelper.appendElementRow(ls`Resource`,Components.Linkifier.linkifyURL(url));}
  811. if(eventData['requestMethod']){contentHelper.appendTextRow(ls`Request Method`,eventData['requestMethod']);}
  812. if(typeof eventData['statusCode']==='number'){contentHelper.appendTextRow(ls`Status Code`,eventData['statusCode']);}
  813. if(eventData['mimeType']){contentHelper.appendTextRow(ls`MIME Type`,eventData['mimeType']);}
  814. if('priority'in eventData){const priority=PerfUI.uiLabelForNetworkPriority(eventData['priority']);contentHelper.appendTextRow(ls`Priority`,priority);}
  815. if(eventData['encodedDataLength']){contentHelper.appendTextRow(ls`Encoded Data`,ls`${eventData['encodedDataLength']} Bytes`);}
  816. if(eventData['decodedBodyLength']){contentHelper.appendTextRow(ls`Decoded Body`,ls`${eventData['decodedBodyLength']} Bytes`);}
  817. break;case recordTypes.CompileModule:contentHelper.appendLocationRow(ls`Module`,event.args['fileName'],0);break;case recordTypes.CompileScript:url=eventData&&eventData['url'];if(url){contentHelper.appendLocationRow(ls`Script`,url,eventData['lineNumber'],eventData['columnNumber']);}
  818. contentHelper.appendTextRow(ls`Streamed`,eventData['streamed']);const producedCacheSize=eventData&&eventData['producedCacheSize'];if(producedCacheSize){contentHelper.appendTextRow(ls`Produced Cache Size`,producedCacheSize);}
  819. const cacheConsumeOptions=eventData&&eventData['cacheConsumeOptions'];if(cacheConsumeOptions){contentHelper.appendTextRow(ls`Cache Consume Options`,cacheConsumeOptions);contentHelper.appendTextRow(ls`Consumed Cache Size`,eventData['consumedCacheSize']);contentHelper.appendTextRow(ls`Cache Rejected`,eventData['cacheRejected']);}
  820. break;case recordTypes.EvaluateScript:url=eventData&&eventData['url'];if(url){contentHelper.appendLocationRow(ls`Script`,url,eventData['lineNumber'],eventData['columnNumber']);}
  821. break;case recordTypes.WasmStreamFromResponseCallback:case recordTypes.WasmCompiledModule:case recordTypes.WasmCachedModule:case recordTypes.WasmModuleCacheHit:case recordTypes.WasmModuleCacheInvalid:if(eventData){url=event.args['url'];if(url){contentHelper.appendTextRow(ls`Url`,url);}
  822. const producedCachedSize=event.args['producedCachedSize'];if(producedCachedSize){contentHelper.appendTextRow(ls`Produced Cache Size`,producedCachedSize);}
  823. const consumedCachedSize=event.args['consumedCachedSize'];if(consumedCachedSize){contentHelper.appendTextRow(ls`Consumed Cache Size`,consumedCachedSize);}}
  824. break;case recordTypes.Paint:const clip=eventData['clip'];contentHelper.appendTextRow(ls`Location`,ls`(${clip[0]}, ${clip[1]})`);const clipWidth=Timeline.TimelineUIUtils.quadWidth(clip);const clipHeight=Timeline.TimelineUIUtils.quadHeight(clip);contentHelper.appendTextRow(ls`Dimensions`,ls`${clipWidth} × ${clipHeight}`);case recordTypes.PaintSetup:case recordTypes.Rasterize:case recordTypes.ScrollLayer:relatedNodeLabel=ls`Layer Root`;break;case recordTypes.PaintImage:case recordTypes.DecodeLazyPixelRef:case recordTypes.DecodeImage:case recordTypes.ResizeImage:case recordTypes.DrawLazyPixelRef:relatedNodeLabel=ls`Owner Element`;url=timelineData.url;if(url){contentHelper.appendElementRow(ls`Image URL`,Components.Linkifier.linkifyURL(url));}
  825. break;case recordTypes.ParseAuthorStyleSheet:url=eventData['styleSheetUrl'];if(url){contentHelper.appendElementRow(ls`Stylesheet URL`,Components.Linkifier.linkifyURL(url));}
  826. break;case recordTypes.UpdateLayoutTree:case recordTypes.RecalculateStyles:contentHelper.appendTextRow(ls`Elements Affected`,event.args['elementCount']);break;case recordTypes.Layout:const beginData=event.args['beginData'];contentHelper.appendTextRow(ls`Nodes That Need Layout`,ls`${beginData['dirtyObjects']} of ${beginData['totalObjects']}`);relatedNodeLabel=ls`Layout root`;break;case recordTypes.ConsoleTime:contentHelper.appendTextRow(ls`Message`,event.name);break;case recordTypes.WebSocketCreate:case recordTypes.WebSocketSendHandshakeRequest:case recordTypes.WebSocketReceiveHandshakeResponse:case recordTypes.WebSocketDestroy:const initiatorData=initiator?initiator.args['data']:eventData;if(typeof initiatorData['webSocketURL']!=='undefined'){contentHelper.appendTextRow(ls`URL`,initiatorData['webSocketURL']);}
  827. if(typeof initiatorData['webSocketProtocol']!=='undefined'){contentHelper.appendTextRow(ls`WebSocket Protocol`,initiatorData['webSocketProtocol']);}
  828. if(typeof eventData['message']!=='undefined'){contentHelper.appendTextRow(ls`Message`,eventData['message']);}
  829. break;case recordTypes.EmbedderCallback:contentHelper.appendTextRow(ls`Callback Function`,eventData['callbackName']);break;case recordTypes.Animation:if(event.phase===SDK.TracingModel.Phase.NestableAsyncInstant){contentHelper.appendTextRow(ls`State`,eventData['state']);}
  830. break;case recordTypes.ParseHTML:{const beginData=event.args['beginData'];const startLine=beginData['startLine']-1;const endLine=event.args['endData']?event.args['endData']['endLine']-1:undefined;url=beginData['url'];if(url){contentHelper.appendLocationRange(ls`Range`,url,startLine,endLine);}
  831. break;}
  832. case recordTypes.FireIdleCallback:contentHelper.appendTextRow(ls`Allotted Time`,Number.millisToString(eventData['allottedMilliseconds']));contentHelper.appendTextRow(ls`Invoked by Timeout`,eventData['timedOut']);case recordTypes.RequestIdleCallback:case recordTypes.CancelIdleCallback:contentHelper.appendTextRow(ls`Callback ID`,eventData['id']);break;case recordTypes.EventDispatch:contentHelper.appendTextRow(ls`Type`,eventData['type']);break;case recordTypes.MarkLCPCandidate:contentHelper.appendTextRow(ls`Type`,String(eventData['type']));contentHelper.appendTextRow(ls`Size`,String(eventData['size']));case recordTypes.MarkFirstPaint:case recordTypes.MarkFCP:case recordTypes.MarkFMP:case recordTypes.MarkLoad:case recordTypes.MarkDOMContent:contentHelper.appendTextRow(ls`Timestamp`,Number.preciseMillisToString(event.startTime-model.minimumRecordTime(),1));contentHelper.appendElementRow(ls`Details`,Timeline.TimelineUIUtils.buildDetailsNodeForPerformanceEvent(event));break;default:{const detailsNode=Timeline.TimelineUIUtils.buildDetailsNodeForTraceEvent(event,model.targetByEvent(event),linkifier);if(detailsNode){contentHelper.appendElementRow(ls`Details`,detailsNode);}
  833. break;}}
  834. if(timelineData.timeWaitingForMainThread){contentHelper.appendTextRow(ls`Time Waiting for Main Thread`,Number.millisToString(timelineData.timeWaitingForMainThread,true));}
  835. const relatedNode=relatedNodesMap&&relatedNodesMap.get(timelineData.backendNodeId);if(relatedNode){const nodeSpan=await Common.Linkifier.linkify(relatedNode);contentHelper.appendElementRow(relatedNodeLabel||ls`Related Node`,nodeSpan);}
  836. if(event[Timeline.TimelineUIUtils._previewElementSymbol]){contentHelper.addSection(ls`Preview`);contentHelper.appendElementRow('',event[Timeline.TimelineUIUtils._previewElementSymbol]);}
  837. if(initiator||timelineData.stackTraceForSelfOrInitiator()||TimelineModel.InvalidationTracker.invalidationEventsFor(event)){Timeline.TimelineUIUtils._generateCauses(event,model.targetByEvent(event),relatedNodesMap,contentHelper);}
  838. const stats={};const showPieChart=detailed&&Timeline.TimelineUIUtils._aggregatedStatsForTraceEvent(stats,model,event);if(showPieChart){contentHelper.addSection(ls`Aggregated Time`);const pieChart=Timeline.TimelineUIUtils.generatePieChart(stats,Timeline.TimelineUIUtils.eventStyle(event).category,event.selfTime);contentHelper.appendElementRow('',pieChart);}
  839. return contentHelper.fragment;}
  840. static statsForTimeRange(events,startTime,endTime){if(!events.length){return{'idle':endTime-startTime};}
  841. buildRangeStatsCacheIfNeeded(events);const aggregatedStats=subtractStats(aggregatedStatsAtTime(endTime),aggregatedStatsAtTime(startTime));const aggregatedTotal=Object.values(aggregatedStats).reduce((a,b)=>a+b,0);aggregatedStats['idle']=Math.max(0,endTime-startTime-aggregatedTotal);return aggregatedStats;function aggregatedStatsAtTime(time){const stats={};const cache=events[Timeline.TimelineUIUtils._categoryBreakdownCacheSymbol];for(const category in cache){const categoryCache=cache[category];const index=categoryCache.time.upperBound(time);let value;if(index===0){value=0;}else if(index===categoryCache.time.length){value=categoryCache.value.peekLast();}else{const t0=categoryCache.time[index-1];const t1=categoryCache.time[index];const v0=categoryCache.value[index-1];const v1=categoryCache.value[index];value=v0+(v1-v0)*(time-t0)/(t1-t0);}
  842. stats[category]=value;}
  843. return stats;}
  844. function subtractStats(a,b){const result=Object.assign({},a);for(const key in b){result[key]-=b[key];}
  845. return result;}
  846. function buildRangeStatsCacheIfNeeded(events){if(events[Timeline.TimelineUIUtils._categoryBreakdownCacheSymbol]){return;}
  847. const aggregatedStats={};const categoryStack=[];let lastTime=0;TimelineModel.TimelineModel.forEachEvent(events,onStartEvent,onEndEvent,undefined,undefined,undefined,filterForStats());function filterForStats(){const visibleEventsFilter=Timeline.TimelineUIUtils.visibleEventsFilter();return event=>visibleEventsFilter.accept(event)||SDK.TracingModel.isTopLevelEvent(event);}
  848. function updateCategory(category,time){let statsArrays=aggregatedStats[category];if(!statsArrays){statsArrays={time:[],value:[]};aggregatedStats[category]=statsArrays;}
  849. if(statsArrays.time.length&&statsArrays.time.peekLast()===time){return;}
  850. const lastValue=statsArrays.value.length?statsArrays.value.peekLast():0;statsArrays.value.push(lastValue+time-lastTime);statsArrays.time.push(time);}
  851. function categoryChange(from,to,time){if(from){updateCategory(from,time);}
  852. lastTime=time;if(to){updateCategory(to,time);}}
  853. function onStartEvent(e){const category=Timeline.TimelineUIUtils.eventStyle(e).category.name;const parentCategory=categoryStack.length?categoryStack.peekLast():null;if(category!==parentCategory){categoryChange(parentCategory,category,e.startTime);}
  854. categoryStack.push(category);}
  855. function onEndEvent(e){const category=categoryStack.pop();const parentCategory=categoryStack.length?categoryStack.peekLast():null;if(category!==parentCategory){categoryChange(category,parentCategory,e.endTime);}}
  856. const obj=(events);obj[Timeline.TimelineUIUtils._categoryBreakdownCacheSymbol]=aggregatedStats;}}
  857. static async buildNetworkRequestDetails(request,model,linkifier){const target=model.targetByEvent(request.children[0]);const contentHelper=new Timeline.TimelineDetailsContentHelper(target,linkifier);const category=Timeline.TimelineUIUtils.networkRequestCategory(request);const color=Timeline.TimelineUIUtils.networkCategoryColor(category);contentHelper.addSection(ls`Network request`,color);if(request.url){contentHelper.appendElementRow(ls`URL`,Components.Linkifier.linkifyURL(request.url));}
  858. const fullDuration=request.endTime-(request.getStartTime()||-Infinity);if(isFinite(fullDuration)){let textRow=Number.millisToString(fullDuration,true);const networkDuration=request.finishTime-request.getStartTime();const processingDuration=request.endTime-request.finishTime;if(isFinite(networkDuration)&&isFinite(processingDuration)){const networkDurationStr=Number.millisToString(networkDuration,true);const processingDurationStr=Number.millisToString(processingDuration,true);const cacheOrNetworkLabel=request.cached()?ls`load from cache`:ls`network transfer`;textRow+=ls` (${networkDurationStr} ${cacheOrNetworkLabel} + ${processingDurationStr} resource loading)`;}
  859. contentHelper.appendTextRow(ls`Duration`,textRow);}
  860. if(request.requestMethod){contentHelper.appendTextRow(ls`Request Method`,request.requestMethod);}
  861. if(typeof request.priority==='string'){const priority=PerfUI.uiLabelForNetworkPriority((request.priority));contentHelper.appendTextRow(ls`Priority`,priority);}
  862. if(request.mimeType){contentHelper.appendTextRow(ls`Mime Type`,request.mimeType);}
  863. let lengthText='';if(request.memoryCached()){lengthText+=ls` (from memory cache)`;}else if(request.cached()){lengthText+=ls` (from cache)`;}else if(request.timing&&request.timing.pushStart){lengthText+=ls` (from push)`;}
  864. if(request.fromServiceWorker){lengthText+=ls` (from service worker)`;}
  865. if(request.encodedDataLength||!lengthText){lengthText=`${Number.bytesToString(request.encodedDataLength)}${lengthText}`;}
  866. contentHelper.appendTextRow(ls`Encoded Data`,lengthText);if(request.decodedBodyLength){contentHelper.appendTextRow(ls`Decoded Body`,Number.bytesToString(request.decodedBodyLength));}
  867. const title=ls`Initiator`;const sendRequest=request.children[0];const topFrame=TimelineModel.TimelineData.forEvent(sendRequest).topFrame();if(topFrame){const link=linkifier.maybeLinkifyConsoleCallFrame(target,topFrame);if(link){contentHelper.appendElementRow(title,link);}}else{const initiator=TimelineModel.TimelineData.forEvent(sendRequest).initiator();if(initiator){const initiatorURL=TimelineModel.TimelineData.forEvent(initiator).url;if(initiatorURL){const link=linkifier.maybeLinkifyScriptLocation(target,null,initiatorURL,0);if(link){contentHelper.appendElementRow(title,link);}}}}
  868. if(!request.previewElement&&request.url&&target){request.previewElement=await Components.ImagePreview.build(target,request.url,false,{imageAltText:Components.ImagePreview.defaultAltTextForImageURL(request.url)});}
  869. if(request.previewElement){contentHelper.appendElementRow(ls`Preview`,request.previewElement);}
  870. return contentHelper.fragment;}
  871. static _stackTraceFromCallFrames(callFrames){return({callFrames:callFrames});}
  872. static _generateCauses(event,target,relatedNodesMap,contentHelper){const recordTypes=TimelineModel.TimelineModel.RecordType;let callSiteStackLabel;let stackLabel;switch(event.name){case recordTypes.TimerFire:callSiteStackLabel=ls`Timer Installed`;break;case recordTypes.FireAnimationFrame:callSiteStackLabel=ls`Animation Frame Requested`;break;case recordTypes.FireIdleCallback:callSiteStackLabel=ls`Idle Callback Requested`;break;case recordTypes.UpdateLayoutTree:case recordTypes.RecalculateStyles:stackLabel=ls`Recalculation Forced`;break;case recordTypes.Layout:callSiteStackLabel=ls`First Layout Invalidation`;stackLabel=ls`Layout Forced`;break;}
  873. const timelineData=TimelineModel.TimelineData.forEvent(event);if(timelineData.stackTrace&&timelineData.stackTrace.length){contentHelper.addSection(ls`Call Stacks`);contentHelper.appendStackTrace(stackLabel||ls`Stack Trace`,Timeline.TimelineUIUtils._stackTraceFromCallFrames(timelineData.stackTrace));}
  874. const initiator=TimelineModel.TimelineData.forEvent(event).initiator();if(TimelineModel.InvalidationTracker.invalidationEventsFor(event)&&target){contentHelper.addSection(ls`Invalidations`);Timeline.TimelineUIUtils._generateInvalidations(event,target,relatedNodesMap,contentHelper);}else if(initiator){const delay=event.startTime-initiator.startTime;contentHelper.appendTextRow(ls`Pending for`,Number.preciseMillisToString(delay,1));const link=createElementWithClass('span','devtools-link');link.textContent=ls`Reveal`;link.addEventListener('click',()=>{Timeline.TimelinePanel.instance().select(Timeline.TimelineSelection.fromTraceEvent((initiator)));});contentHelper.appendElementRow(ls`Initiator`,link);const initiatorStackTrace=TimelineModel.TimelineData.forEvent(initiator).stackTrace;if(initiatorStackTrace){contentHelper.appendStackTrace(callSiteStackLabel||ls`First Invalidated`,Timeline.TimelineUIUtils._stackTraceFromCallFrames(initiatorStackTrace));}}}
  875. static _generateInvalidations(event,target,relatedNodesMap,contentHelper){const invalidationTrackingEvents=TimelineModel.InvalidationTracker.invalidationEventsFor(event);const invalidations={};invalidationTrackingEvents.forEach(function(invalidation){if(!invalidations[invalidation.type]){invalidations[invalidation.type]=[invalidation];}else{invalidations[invalidation.type].push(invalidation);}});Object.keys(invalidations).forEach(function(type){Timeline.TimelineUIUtils._generateInvalidationsForType(type,target,invalidations[type],relatedNodesMap,contentHelper);});}
  876. static _generateInvalidationsForType(type,target,invalidations,relatedNodesMap,contentHelper){let title;switch(type){case TimelineModel.TimelineModel.RecordType.StyleRecalcInvalidationTracking:title=ls`Style Invalidations`;break;case TimelineModel.TimelineModel.RecordType.LayoutInvalidationTracking:title=ls`Layout Invalidations`;break;default:title=ls`Other Invalidations`;break;}
  877. const invalidationsTreeOutline=new UI.TreeOutlineInShadow();invalidationsTreeOutline.registerRequiredCSS('timeline/invalidationsTree.css');invalidationsTreeOutline.element.classList.add('invalidations-tree');const invalidationGroups=groupInvalidationsByCause(invalidations);invalidationGroups.forEach(function(group){const groupElement=new Timeline.TimelineUIUtils.InvalidationsGroupElement(target,relatedNodesMap,contentHelper,group);invalidationsTreeOutline.appendChild(groupElement);});contentHelper.appendElementRow(title,invalidationsTreeOutline.element,false,true);function groupInvalidationsByCause(invalidations){const causeToInvalidationMap=new Map();for(let index=0;index<invalidations.length;index++){const invalidation=invalidations[index];let causeKey='';if(invalidation.cause.reason){causeKey+=invalidation.cause.reason+'.';}
  878. if(invalidation.cause.stackTrace){invalidation.cause.stackTrace.forEach(function(stackFrame){causeKey+=stackFrame['functionName']+'.';causeKey+=stackFrame['scriptId']+'.';causeKey+=stackFrame['url']+'.';causeKey+=stackFrame['lineNumber']+'.';causeKey+=stackFrame['columnNumber']+'.';});}
  879. if(causeToInvalidationMap.has(causeKey)){causeToInvalidationMap.get(causeKey).push(invalidation);}else{causeToInvalidationMap.set(causeKey,[invalidation]);}}
  880. return causeToInvalidationMap.valuesArray();}}
  881. static _collectInvalidationNodeIds(nodeIds,invalidations){nodeIds.addAll(invalidations.map(invalidation=>invalidation.nodeId).filter(id=>id));}
  882. static _aggregatedStatsForTraceEvent(total,model,event){const events=model.inspectedTargetEvents();function eventComparator(startTime,e){return startTime-e.startTime;}
  883. const index=events.binaryIndexOf(event.startTime,eventComparator);if(index<0){return false;}
  884. let hasChildren=false;const endTime=event.endTime;if(endTime){for(let i=index;i<events.length;i++){const nextEvent=events[i];if(nextEvent.startTime>=endTime){break;}
  885. if(!nextEvent.selfTime){continue;}
  886. if(nextEvent.thread!==event.thread){continue;}
  887. if(i>index){hasChildren=true;}
  888. const categoryName=Timeline.TimelineUIUtils.eventStyle(nextEvent).category.name;total[categoryName]=(total[categoryName]||0)+nextEvent.selfTime;}}
  889. if(SDK.TracingModel.isAsyncPhase(event.phase)){if(event.endTime){let aggregatedTotal=0;for(const categoryName in total){aggregatedTotal+=total[categoryName];}
  890. total['idle']=Math.max(0,event.endTime-event.startTime-aggregatedTotal);}
  891. return false;}
  892. return hasChildren;}
  893. static async buildPicturePreviewContent(event,target){const snapshotWithRect=await new TimelineModel.LayerPaintEvent(event,target).snapshotPromise();if(!snapshotWithRect){return null;}
  894. const imageURLPromise=snapshotWithRect.snapshot.replay();snapshotWithRect.snapshot.release();const imageURL=await imageURLPromise;if(!imageURL){return null;}
  895. const container=createElement('div');UI.appendStyle(container,'components/imagePreview.css');container.classList.add('image-preview-container','vbox','link');const img=container.createChild('img');img.src=imageURL;img.alt=Components.ImagePreview.defaultAltTextForImageURL(imageURL);const paintProfilerButton=container.createChild('a');paintProfilerButton.textContent=ls`Paint Profiler`;container.addEventListener('click',()=>Timeline.TimelinePanel.instance().select(Timeline.TimelineSelection.fromTraceEvent(event)),false);return container;}
  896. static createEventDivider(event,zeroTime){const eventDivider=createElementWithClass('div','resources-event-divider');const startTime=Number.millisToString(event.startTime-zeroTime);eventDivider.title=Common.UIString('%s at %s',Timeline.TimelineUIUtils.eventTitle(event),startTime);const style=Timeline.TimelineUIUtils.markerStyleForEvent(event);if(style.tall){eventDivider.style.backgroundColor=style.color;}
  897. return eventDivider;}
  898. static _visibleTypes(){const eventStyles=Timeline.TimelineUIUtils._initEventStyles();const result=[];for(const name in eventStyles){if(!eventStyles[name].hidden){result.push(name);}}
  899. return result;}
  900. static visibleEventsFilter(){return new TimelineModel.TimelineVisibleEventsFilter(Timeline.TimelineUIUtils._visibleTypes());}
  901. static categories(){if(Timeline.TimelineUIUtils._categories){return Timeline.TimelineUIUtils._categories;}
  902. Timeline.TimelineUIUtils._categories={loading:new Timeline.TimelineCategory('loading',ls`Loading`,true,'hsl(214, 67%, 74%)','hsl(214, 67%, 66%)'),scripting:new Timeline.TimelineCategory('scripting',ls`Scripting`,true,'hsl(43, 83%, 72%)','hsl(43, 83%, 64%) '),rendering:new Timeline.TimelineCategory('rendering',ls`Rendering`,true,'hsl(256, 67%, 76%)','hsl(256, 67%, 70%)'),painting:new Timeline.TimelineCategory('painting',ls`Painting`,true,'hsl(109, 33%, 64%)','hsl(109, 33%, 55%)'),gpu:new Timeline.TimelineCategory('gpu',ls`GPU`,false,'hsl(109, 33%, 64%)','hsl(109, 33%, 55%)'),async:new Timeline.TimelineCategory('async',ls`Async`,false,'hsl(0, 100%, 50%)','hsl(0, 100%, 40%)'),other:new Timeline.TimelineCategory('other',ls`System`,false,'hsl(0, 0%, 87%)','hsl(0, 0%, 79%)'),idle:new Timeline.TimelineCategory('idle',ls`Idle`,false,'hsl(0, 0%, 98%)','hsl(0, 0%, 98%)')};return Timeline.TimelineUIUtils._categories;}
  903. static setCategories(categories){Timeline.TimelineUIUtils._categories=categories;}
  904. static getTimelineMainEventCategories(){if(Timeline.TimelineUIUtils._eventCategories){return Timeline.TimelineUIUtils._eventCategories;}
  905. Timeline.TimelineUIUtils._eventCategories=['idle','loading','painting','rendering','scripting','other'];return Timeline.TimelineUIUtils._eventCategories;}
  906. static setTimelineMainEventCategories(categories){Timeline.TimelineUIUtils._eventCategories=categories;}
  907. static generatePieChart(aggregatedStats,selfCategory,selfTime){let total=0;for(const categoryName in aggregatedStats){total+=aggregatedStats[categoryName];}
  908. const element=createElementWithClass('div','timeline-details-view-pie-chart-wrapper hbox');const pieChart=new PerfUI.PieChart({chartName:ls`Time spent in rendering`,size:110,formatter:value=>Number.preciseMillisToString(value),showLegend:true,});pieChart.element.classList.add('timeline-details-view-pie-chart');pieChart.setTotal(total);const pieChartContainer=element.createChild('div','vbox');pieChartContainer.appendChild(pieChart.element);function appendLegendRow(name,title,value,color){if(!value){return;}
  909. pieChart.addSlice(value,color,title);}
  910. if(selfCategory){if(selfTime){appendLegendRow(selfCategory.name,Common.UIString('%s (self)',selfCategory.title),selfTime,selfCategory.color);}
  911. const categoryTime=aggregatedStats[selfCategory.name];const value=categoryTime-selfTime;if(value>0){appendLegendRow(selfCategory.name,Common.UIString('%s (children)',selfCategory.title),value,selfCategory.childColor);}}
  912. for(const categoryName in Timeline.TimelineUIUtils.categories()){const category=Timeline.TimelineUIUtils.categories()[categoryName];if(category===selfCategory){continue;}
  913. appendLegendRow(category.name,category.title,aggregatedStats[category.name],category.childColor);}
  914. return element;}
  915. static generateDetailsContentForFrame(frame,filmStripFrame){const contentHelper=new Timeline.TimelineDetailsContentHelper(null,null);contentHelper.addSection(ls`Frame`);const duration=Timeline.TimelineUIUtils.frameDuration(frame);contentHelper.appendElementRow(ls`Duration`,duration,frame.hasWarnings());const durationInMillis=frame.endTime-frame.startTime;contentHelper.appendTextRow(ls`FPS`,Math.floor(1000/durationInMillis));contentHelper.appendTextRow(ls`CPU time`,Number.millisToString(frame.cpuTime,true));if(filmStripFrame){const filmStripPreview=createElementWithClass('div','timeline-filmstrip-preview');filmStripFrame.imageDataPromise().then(data=>UI.loadImageFromData(data)).then(image=>image&&filmStripPreview.appendChild(image));contentHelper.appendElementRow('',filmStripPreview);filmStripPreview.addEventListener('click',frameClicked.bind(null,filmStripFrame),false);}
  916. if(frame.layerTree){contentHelper.appendElementRow(ls`Layer tree`,Components.Linkifier.linkifyRevealable(frame.layerTree,ls`Show`));}
  917. function frameClicked(filmStripFrame){new PerfUI.FilmStripView.Dialog(filmStripFrame,0);}
  918. return contentHelper.fragment;}
  919. static frameDuration(frame){const durationText=Common.UIString('%s (at %s)',Number.millisToString(frame.endTime-frame.startTime,true),Number.millisToString(frame.startTimeOffset,true));if(!frame.hasWarnings()){return UI.formatLocalized('%s',[durationText]);}
  920. const link=UI.XLink.create('https://developers.google.com/web/fundamentals/performance/rendering/',ls`jank`);return UI.formatLocalized('%s. Long frame times are an indication of %s',[durationText,link]);}
  921. static createFillStyle(context,width,height,color0,color1,color2){const gradient=context.createLinearGradient(0,0,width,height);gradient.addColorStop(0,color0);gradient.addColorStop(0.25,color1);gradient.addColorStop(0.75,color1);gradient.addColorStop(1,color2);return gradient;}
  922. static quadWidth(quad){return Math.round(Math.sqrt(Math.pow(quad[0]-quad[2],2)+Math.pow(quad[1]-quad[3],2)));}
  923. static quadHeight(quad){return Math.round(Math.sqrt(Math.pow(quad[0]-quad[6],2)+Math.pow(quad[1]-quad[7],2)));}
  924. static eventDispatchDesciptors(){if(Timeline.TimelineUIUtils._eventDispatchDesciptors){return Timeline.TimelineUIUtils._eventDispatchDesciptors;}
  925. const lightOrange='hsl(40,100%,80%)';const orange='hsl(40,100%,50%)';const green='hsl(90,100%,40%)';const purple='hsl(256,100%,75%)';Timeline.TimelineUIUtils._eventDispatchDesciptors=[new Timeline.TimelineUIUtils.EventDispatchTypeDescriptor(1,lightOrange,['mousemove','mouseenter','mouseleave','mouseout','mouseover']),new Timeline.TimelineUIUtils.EventDispatchTypeDescriptor(1,lightOrange,['pointerover','pointerout','pointerenter','pointerleave','pointermove']),new Timeline.TimelineUIUtils.EventDispatchTypeDescriptor(2,green,['wheel']),new Timeline.TimelineUIUtils.EventDispatchTypeDescriptor(3,orange,['click','mousedown','mouseup']),new Timeline.TimelineUIUtils.EventDispatchTypeDescriptor(3,orange,['touchstart','touchend','touchmove','touchcancel']),new Timeline.TimelineUIUtils.EventDispatchTypeDescriptor(3,orange,['pointerdown','pointerup','pointercancel','gotpointercapture','lostpointercapture']),new Timeline.TimelineUIUtils.EventDispatchTypeDescriptor(3,purple,['keydown','keyup','keypress'])];return Timeline.TimelineUIUtils._eventDispatchDesciptors;}
  926. static markerShortTitle(event){const recordTypes=TimelineModel.TimelineModel.RecordType;switch(event.name){case recordTypes.MarkDOMContent:return ls`DCL`;case recordTypes.MarkLoad:return ls`L`;case recordTypes.MarkFirstPaint:return ls`FP`;case recordTypes.MarkFCP:return ls`FCP`;case recordTypes.MarkFMP:return ls`FMP`;case recordTypes.MarkLCPCandidate:return ls`LCP`;}
  927. return null;}
  928. static markerStyleForEvent(event){const tallMarkerDashStyle=[6,4];const title=Timeline.TimelineUIUtils.eventTitle(event);if(event.hasCategory(TimelineModel.TimelineModel.Category.Console)||event.hasCategory(TimelineModel.TimelineModel.Category.UserTiming)){return{title:title,dashStyle:tallMarkerDashStyle,lineWidth:0.5,color:event.hasCategory(TimelineModel.TimelineModel.Category.UserTiming)?'purple':'orange',tall:false,lowPriority:false,};}
  929. const recordTypes=TimelineModel.TimelineModel.RecordType;let tall=false;let color='grey';switch(event.name){case recordTypes.FrameStartedLoading:color='green';tall=true;break;case recordTypes.MarkDOMContent:color='#0867CB';tall=true;break;case recordTypes.MarkLoad:color='#B31412';tall=true;break;case recordTypes.MarkFirstPaint:color='#228847';tall=true;break;case recordTypes.MarkFCP:color='#1A6937';tall=true;break;case recordTypes.MarkFMP:color='#134A26';tall=true;break;case recordTypes.MarkLCPCandidate:color='#1A3422';tall=true;break;case recordTypes.TimeStamp:color='orange';break;}
  930. return{title:title,dashStyle:tallMarkerDashStyle,lineWidth:0.5,color:color,tall:tall,lowPriority:false,};}
  931. static markerStyleForFrame(){return{title:ls`Frame`,color:'rgba(100, 100, 100, 0.4)',lineWidth:3,dashStyle:[3],tall:true,lowPriority:true};}
  932. static colorForId(id){if(!Timeline.TimelineUIUtils.colorForId._colorGenerator){Timeline.TimelineUIUtils.colorForId._colorGenerator=new Common.Color.Generator({min:30,max:330},{min:50,max:80,count:3},85);Timeline.TimelineUIUtils.colorForId._colorGenerator.setColorForID('','#f2ecdc');}
  933. return Timeline.TimelineUIUtils.colorForId._colorGenerator.colorForID(id);}
  934. static eventWarning(event,warningType){const timelineData=TimelineModel.TimelineData.forEvent(event);const warning=warningType||timelineData.warning;if(!warning){return null;}
  935. const warnings=TimelineModel.TimelineModel.WarningType;const span=createElement('span');const eventData=event.args['data'];switch(warning){case warnings.ForcedStyle:case warnings.ForcedLayout:const forcedReflowLink=UI.createDocumentationLink('../../fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing#avoid-forced-synchronous-layouts',ls`Forced reflow`);span.appendChild(UI.formatLocalized('%s is a likely performance bottleneck.',[forcedReflowLink]));break;case warnings.IdleDeadlineExceeded:const exceededMs=Number.millisToString(event.duration-eventData['allottedMilliseconds'],true);span.textContent=ls`Idle callback execution extended beyond deadline by ${exceededMs}`;break;case warnings.LongHandler:span.textContent=Common.UIString('Handler took %s',Number.millisToString(event.duration,true));break;case warnings.LongRecurringHandler:span.textContent=Common.UIString('Recurring handler took %s',Number.millisToString(event.duration,true));break;case warnings.LongTask:const longTaskLink=UI.createDocumentationLink('../../fundamentals/performance/rail#goals-and-guidelines',ls`Long task`);span.appendChild(UI.formatLocalized('%s took %s.',[longTaskLink,Number.millisToString(event.duration,true)]));break;case warnings.V8Deopt:span.appendChild(UI.XLink.create('https://github.com/GoogleChrome/devtools-docs/issues/53',Common.UIString('Not optimized')));span.createTextChild(Common.UIString(': %s',eventData['deoptReason']));break;default:console.assert(false,'Unhandled TimelineModel.WarningType');}
  936. return span;}
  937. static displayNameForFrame(frame,trimAt){const url=frame.url;if(!trimAt){trimAt=30;}
  938. return url.startsWith('about:')?`"${frame.name.trimMiddle(trimAt)}"`:frame.url.trimEnd(trimAt);}};Timeline.TimelineRecordStyle=class{constructor(title,category,hidden=false){this.title=title;this.category=category;this.hidden=hidden;}};Timeline.TimelineUIUtils.NetworkCategory={HTML:Symbol('HTML'),Script:Symbol('Script'),Style:Symbol('Style'),Media:Symbol('Media'),Other:Symbol('Other')};Timeline.TimelineUIUtils._aggregatedStatsKey=Symbol('aggregatedStats');Timeline.TimelineUIUtils.InvalidationsGroupElement=class extends UI.TreeElement{constructor(target,relatedNodesMap,contentHelper,invalidations){super('',true);this.listItemElement.classList.add('header');this.selectable=false;this.toggleOnClick=true;this._relatedNodesMap=relatedNodesMap;this._contentHelper=contentHelper;this._invalidations=invalidations;this.title=this._createTitle(target);}
  939. _createTitle(target){const first=this._invalidations[0];const reason=first.cause.reason||ls`Unknown cause`;const topFrame=first.cause.stackTrace&&first.cause.stackTrace[0];const truncatedNodesElement=this._getTruncatedNodesElement(this._invalidations);if(truncatedNodesElement===null){return UI.formatLocalized(reason,[]);}
  940. const title=UI.formatLocalized('%s for %s',[reason,truncatedNodesElement]);if(topFrame&&this._contentHelper.linkifier()){const stack=createElementWithClass('span','monospace');const completeTitle=UI.formatLocalized('%s. %s',[title,stack]);stack.createChild('span').textContent=Timeline.TimelineUIUtils.frameDisplayName(topFrame);const link=this._contentHelper.linkifier().maybeLinkifyConsoleCallFrame(target,topFrame);if(link){stack.createChild('span').textContent=' @ ';stack.createChild('span').appendChild(link);}
  941. return completeTitle;}
  942. return title;}
  943. async onpopulate(){const content=createElementWithClass('div','content');const first=this._invalidations[0];if(first.cause.stackTrace){const stack=content.createChild('div');stack.createTextChild(ls`Stack trace:`);this._contentHelper.createChildStackTraceElement(stack,Timeline.TimelineUIUtils._stackTraceFromCallFrames(first.cause.stackTrace));}
  944. content.createTextChild(this._invalidations.length!==1?ls`Nodes:`:ls`Node:`);const nodeList=content.createChild('div','node-list');let firstNode=true;for(let i=0;i<this._invalidations.length;i++){const invalidation=this._invalidations[i];const invalidationNode=this._createInvalidationNode(invalidation,true);if(invalidationNode){if(!firstNode){nodeList.createTextChild(ls`, `);}
  945. firstNode=false;nodeList.appendChild(invalidationNode);const extraData=invalidation.extraData?', '+invalidation.extraData:'';if(invalidation.changedId){nodeList.createTextChild(Common.UIString('(changed id to "%s"%s)',invalidation.changedId,extraData));}else if(invalidation.changedClass){nodeList.createTextChild(Common.UIString('(changed class to "%s"%s)',invalidation.changedClass,extraData));}else if(invalidation.changedAttribute){nodeList.createTextChild(Common.UIString('(changed attribute to "%s"%s)',invalidation.changedAttribute,extraData));}else if(invalidation.changedPseudo){nodeList.createTextChild(Common.UIString('(changed pesudo to "%s"%s)',invalidation.changedPseudo,extraData));}else if(invalidation.selectorPart){nodeList.createTextChild(Common.UIString('(changed "%s"%s)',invalidation.selectorPart,extraData));}}}
  946. const contentTreeElement=new UI.TreeElement(content,false);contentTreeElement.selectable=false;this.appendChild(contentTreeElement);}
  947. _getTruncatedNodesElement(invalidations){const invalidationNodes=[];const invalidationNodeIdMap={};for(let i=0;i<invalidations.length;i++){const invalidation=invalidations[i];const invalidationNode=this._createInvalidationNode(invalidation,false);invalidationNode.addEventListener('click',e=>e.consume(),false);if(invalidationNode&&!invalidationNodeIdMap[invalidation.nodeId]){invalidationNodes.push(invalidationNode);invalidationNodeIdMap[invalidation.nodeId]=true;}}
  948. if(invalidationNodes.length===1){return invalidationNodes[0];}else if(invalidationNodes.length===2){return UI.formatLocalized('%s and %s',invalidationNodes);}else if(invalidationNodes.length===3){return UI.formatLocalized('%s, %s, and 1 other',invalidationNodes.slice(0,2));}else if(invalidationNodes.length>=4){return UI.formatLocalized('%s, %s, and %s others',[...invalidationNodes.slice(0,2),(invalidationNodes.length-2).toString()]);}
  949. return null;}
  950. _createInvalidationNode(invalidation,showUnknownNodes){const node=(invalidation.nodeId&&this._relatedNodesMap)?this._relatedNodesMap.get(invalidation.nodeId):null;if(node){const nodeSpan=createElement('span');Common.Linkifier.linkify(node).then(link=>nodeSpan.appendChild(link));return nodeSpan;}
  951. if(invalidation.nodeName){const nodeSpan=createElement('span');nodeSpan.textContent=Common.UIString('[ %s ]',invalidation.nodeName);return nodeSpan;}
  952. if(showUnknownNodes){const nodeSpan=createElement('span');return nodeSpan.createTextChild(Common.UIString('[ unknown node ]'));}}};Timeline.TimelineUIUtils._previewElementSymbol=Symbol('previewElement');Timeline.TimelineUIUtils.EventDispatchTypeDescriptor=class{constructor(priority,color,eventTypes){this.priority=priority;this.color=color;this.eventTypes=eventTypes;}};Timeline.TimelineCategory=class extends Common.Object{constructor(name,title,visible,childColor,color){super();this.name=name;this.title=title;this.visible=visible;this.childColor=childColor;this.color=color;this.hidden=false;}
  953. get hidden(){return this._hidden;}
  954. set hidden(hidden){this._hidden=hidden;this.dispatchEventToListeners(Timeline.TimelineCategory.Events.VisibilityChanged,this);}};Timeline.TimelineCategory.Events={VisibilityChanged:Symbol('VisibilityChanged')};Timeline.TimelineMarkerStyle;Timeline.TimelinePopupContentHelper=class{constructor(title){this._contentTable=createElement('table');const titleCell=this._createCell(Common.UIString('%s - Details',title),'timeline-details-title');titleCell.colSpan=2;const titleRow=createElement('tr');titleRow.appendChild(titleCell);this._contentTable.appendChild(titleRow);}
  955. contentTable(){return this._contentTable;}
  956. _createCell(content,styleName){const text=createElement('label');text.createTextChild(String(content));const cell=createElement('td');cell.className='timeline-details';if(styleName){cell.className+=' '+styleName;}
  957. cell.textContent=content;return cell;}
  958. appendTextRow(title,content){const row=createElement('tr');row.appendChild(this._createCell(title,'timeline-details-row-title'));row.appendChild(this._createCell(content,'timeline-details-row-data'));this._contentTable.appendChild(row);}
  959. appendElementRow(title,content){const row=createElement('tr');const titleCell=this._createCell(title,'timeline-details-row-title');row.appendChild(titleCell);const cell=createElement('td');cell.className='details';if(content instanceof Node){cell.appendChild(content);}else{cell.createTextChild(content||'');}
  960. row.appendChild(cell);this._contentTable.appendChild(row);}};Timeline.TimelineDetailsContentHelper=class{constructor(target,linkifier){this.fragment=createDocumentFragment();this._linkifier=linkifier;this._target=target;this.element=createElementWithClass('div','timeline-details-view-block');this._tableElement=this.element.createChild('div','vbox timeline-details-chip-body');this.fragment.appendChild(this.element);}
  961. addSection(title,swatchColor){if(!this._tableElement.hasChildNodes()){this.element.removeChildren();}else{this.element=createElementWithClass('div','timeline-details-view-block');this.fragment.appendChild(this.element);}
  962. if(title){const titleElement=this.element.createChild('div','timeline-details-chip-title');if(swatchColor){titleElement.createChild('div').style.backgroundColor=swatchColor;}
  963. titleElement.createTextChild(title);}
  964. this._tableElement=this.element.createChild('div','vbox timeline-details-chip-body');this.fragment.appendChild(this.element);}
  965. linkifier(){return this._linkifier;}
  966. appendTextRow(title,value){const rowElement=this._tableElement.createChild('div','timeline-details-view-row');rowElement.createChild('div','timeline-details-view-row-title').textContent=title;rowElement.createChild('div','timeline-details-view-row-value').textContent=value;}
  967. appendElementRow(title,content,isWarning,isStacked){const rowElement=this._tableElement.createChild('div','timeline-details-view-row');if(isWarning){rowElement.classList.add('timeline-details-warning');}
  968. if(isStacked){rowElement.classList.add('timeline-details-stack-values');}
  969. const titleElement=rowElement.createChild('div','timeline-details-view-row-title');titleElement.textContent=title;const valueElement=rowElement.createChild('div','timeline-details-view-row-value');if(content instanceof Node){valueElement.appendChild(content);}else{valueElement.createTextChild(content||'');}}
  970. appendLocationRow(title,url,startLine,startColumn){if(!this._linkifier||!this._target){return;}
  971. const link=this._linkifier.maybeLinkifyScriptLocation(this._target,null,url,startLine,startColumn);if(!link){return;}
  972. this.appendElementRow(title,link);}
  973. appendLocationRange(title,url,startLine,endLine){if(!this._linkifier||!this._target){return;}
  974. const locationContent=createElement('span');const link=this._linkifier.maybeLinkifyScriptLocation(this._target,null,url,startLine);if(!link){return;}
  975. locationContent.appendChild(link);locationContent.createTextChild(String.sprintf(' [%s\u2026%s]',startLine+1,endLine+1||''));this.appendElementRow(title,locationContent);}
  976. appendStackTrace(title,stackTrace){if(!this._linkifier||!this._target){return;}
  977. const rowElement=this._tableElement.createChild('div','timeline-details-view-row');rowElement.createChild('div','timeline-details-view-row-title').textContent=title;this.createChildStackTraceElement(rowElement,stackTrace);}
  978. createChildStackTraceElement(parentElement,stackTrace){if(!this._linkifier||!this._target){return;}
  979. parentElement.classList.add('timeline-details-stack-values');const stackTraceElement=parentElement.createChild('div','timeline-details-view-row-value timeline-details-view-row-stack-trace');const callFrameContents=Components.JSPresentationUtils.buildStackTracePreviewContents(this._target,this._linkifier,stackTrace);stackTraceElement.appendChild(callFrameContents.element);}
  980. appendWarningRow(event,warningType){const warning=Timeline.TimelineUIUtils.eventWarning(event,warningType);if(warning){this.appendElementRow(ls`Warning`,warning,true);}}};Timeline.TimelineUIUtils._categoryBreakdownCacheSymbol=Symbol('categoryBreakdownCache');;Timeline.TimelineLayersView=class extends UI.SplitWidget{constructor(model,showPaintProfilerCallback){super(true,false,'timelineLayersView');this._model=model;this._showPaintProfilerCallback=showPaintProfilerCallback;this.element.classList.add('timeline-layers-view');this._rightSplitWidget=new UI.SplitWidget(true,true,'timelineLayersViewDetails');this._rightSplitWidget.element.classList.add('timeline-layers-view-properties');this.setMainWidget(this._rightSplitWidget);const vbox=new UI.VBox();this.setSidebarWidget(vbox);this._layerViewHost=new LayerViewer.LayerViewHost();const layerTreeOutline=new LayerViewer.LayerTreeOutline(this._layerViewHost);vbox.element.appendChild(layerTreeOutline.element);this._layers3DView=new LayerViewer.Layers3DView(this._layerViewHost);this._layers3DView.addEventListener(LayerViewer.Layers3DView.Events.PaintProfilerRequested,this._onPaintProfilerRequested,this);this._rightSplitWidget.setMainWidget(this._layers3DView);const layerDetailsView=new LayerViewer.LayerDetailsView(this._layerViewHost);this._rightSplitWidget.setSidebarWidget(layerDetailsView);layerDetailsView.addEventListener(LayerViewer.LayerDetailsView.Events.PaintProfilerRequested,this._onPaintProfilerRequested,this);}
  981. showLayerTree(frameLayerTree){this._frameLayerTree=frameLayerTree;if(this.isShowing()){this._update();}else{this._updateWhenVisible=true;}}
  982. wasShown(){if(this._updateWhenVisible){this._updateWhenVisible=false;this._update();}}
  983. _onPaintProfilerRequested(event){const selection=(event.data);this._layers3DView.snapshotForSelection(selection).then(snapshotWithRect=>{if(snapshotWithRect){this._showPaintProfilerCallback(snapshotWithRect.snapshot);}});}
  984. _update(){this._frameLayerTree.layerTreePromise().then(layerTree=>this._layerViewHost.setLayerTree(layerTree));}};;Timeline.TimelinePaintProfilerView=class extends UI.SplitWidget{constructor(frameModel){super(false,false);this.element.classList.add('timeline-paint-profiler-view');this.setSidebarSize(60);this.setResizable(false);this._frameModel=frameModel;this._logAndImageSplitWidget=new UI.SplitWidget(true,false);this._logAndImageSplitWidget.element.classList.add('timeline-paint-profiler-log-split');this.setMainWidget(this._logAndImageSplitWidget);this._imageView=new Timeline.TimelinePaintImageView();this._logAndImageSplitWidget.setMainWidget(this._imageView);this._paintProfilerView=new LayerViewer.PaintProfilerView(this._imageView.showImage.bind(this._imageView));this._paintProfilerView.addEventListener(LayerViewer.PaintProfilerView.Events.WindowChanged,this._onWindowChanged,this);this.setSidebarWidget(this._paintProfilerView);this._logTreeView=new LayerViewer.PaintProfilerCommandLogView();this._logAndImageSplitWidget.setSidebarWidget(this._logTreeView);this._needsUpdateWhenVisible=false;this._pendingSnapshot=null;this._event=null;this._paintProfilerModel=null;this._lastLoadedSnapshot=null;}
  985. wasShown(){if(this._needsUpdateWhenVisible){this._needsUpdateWhenVisible=false;this._update();}}
  986. setSnapshot(snapshot){this._releaseSnapshot();this._pendingSnapshot=snapshot;this._event=null;this._updateWhenVisible();}
  987. setEvent(paintProfilerModel,event){this._releaseSnapshot();this._paintProfilerModel=paintProfilerModel;this._pendingSnapshot=null;this._event=event;this._updateWhenVisible();if(this._event.name===TimelineModel.TimelineModel.RecordType.Paint){return!!TimelineModel.TimelineData.forEvent(event).picture;}
  988. if(this._event.name===TimelineModel.TimelineModel.RecordType.RasterTask){return this._frameModel.hasRasterTile(this._event);}
  989. return false;}
  990. _updateWhenVisible(){if(this.isShowing()){this._update();}else{this._needsUpdateWhenVisible=true;}}
  991. _update(){this._logTreeView.setCommandLog([]);this._paintProfilerView.setSnapshotAndLog(null,[],null);let snapshotPromise;if(this._pendingSnapshot){snapshotPromise=Promise.resolve({rect:null,snapshot:this._pendingSnapshot});}else if(this._event.name===TimelineModel.TimelineModel.RecordType.Paint){const picture=TimelineModel.TimelineData.forEvent(this._event).picture;snapshotPromise=picture.objectPromise().then(data=>this._paintProfilerModel.loadSnapshot(data['skp64'])).then(snapshot=>snapshot&&{rect:null,snapshot:snapshot});}else if(this._event.name===TimelineModel.TimelineModel.RecordType.RasterTask){snapshotPromise=this._frameModel.rasterTilePromise(this._event);}else{console.assert(false,'Unexpected event type or no snapshot');return;}
  992. snapshotPromise.then(snapshotWithRect=>{this._releaseSnapshot();if(!snapshotWithRect){this._imageView.showImage();return;}
  993. const snapshot=snapshotWithRect.snapshot;this._lastLoadedSnapshot=snapshot;this._imageView.setMask(snapshotWithRect.rect);snapshot.commandLog().then(log=>onCommandLogDone.call(this,snapshot,snapshotWithRect.rect,log));});function onCommandLogDone(snapshot,clipRect,log){this._logTreeView.setCommandLog(log||[]);this._paintProfilerView.setSnapshotAndLog(snapshot,log||[],clipRect);}}
  994. _releaseSnapshot(){if(!this._lastLoadedSnapshot){return;}
  995. this._lastLoadedSnapshot.release();this._lastLoadedSnapshot=null;}
  996. _onWindowChanged(){this._logTreeView.updateWindow(this._paintProfilerView.selectionWindow());}};Timeline.TimelinePaintImageView=class extends UI.Widget{constructor(){super(true);this.registerRequiredCSS('timeline/timelinePaintProfiler.css');this.contentElement.classList.add('fill','paint-profiler-image-view');this._imageContainer=this.contentElement.createChild('div','paint-profiler-image-container');this._imageElement=this._imageContainer.createChild('img');this._maskElement=this._imageContainer.createChild('div');this._imageElement.addEventListener('load',this._updateImagePosition.bind(this),false);this._transformController=new LayerViewer.TransformController(this.contentElement,true);this._transformController.addEventListener(LayerViewer.TransformController.Events.TransformChanged,this._updateImagePosition,this);}
  997. onResize(){if(this._imageElement.src){this._updateImagePosition();}}
  998. _updateImagePosition(){const width=this._imageElement.naturalWidth;const height=this._imageElement.naturalHeight;const clientWidth=this.contentElement.clientWidth;const clientHeight=this.contentElement.clientHeight;const paddingFraction=0.1;const paddingX=clientWidth*paddingFraction;const paddingY=clientHeight*paddingFraction;const scaleX=(clientWidth-paddingX)/width;const scaleY=(clientHeight-paddingY)/height;const scale=Math.min(scaleX,scaleY);if(this._maskRectangle){const style=this._maskElement.style;style.width=width+'px';style.height=height+'px';style.borderLeftWidth=this._maskRectangle.x+'px';style.borderTopWidth=this._maskRectangle.y+'px';style.borderRightWidth=(width-this._maskRectangle.x-this._maskRectangle.width)+'px';style.borderBottomWidth=(height-this._maskRectangle.y-this._maskRectangle.height)+'px';}
  999. this._transformController.setScaleConstraints(0.5,10/scale);let matrix=new WebKitCSSMatrix().scale(this._transformController.scale(),this._transformController.scale()).translate(clientWidth/2,clientHeight/2).scale(scale,scale).translate(-width/2,-height/2);const bounds=UI.Geometry.boundsForTransformedPoints(matrix,[0,0,0,width,height,0]);this._transformController.clampOffsets(paddingX-bounds.maxX,clientWidth-paddingX-bounds.minX,paddingY-bounds.maxY,clientHeight-paddingY-bounds.minY);matrix=new WebKitCSSMatrix().translate(this._transformController.offsetX(),this._transformController.offsetY()).multiply(matrix);this._imageContainer.style.webkitTransform=matrix.toString();}
  1000. showImage(imageURL){this._imageContainer.classList.toggle('hidden',!imageURL);if(imageURL){this._imageElement.src=imageURL;}}
  1001. setMask(maskRectangle){this._maskRectangle=maskRectangle;this._maskElement.classList.toggle('hidden',!maskRectangle);}};;Timeline.TimelinePanel=class extends UI.Panel{constructor(){super('timeline');this.registerRequiredCSS('timeline/timelinePanel.css');this.element.addEventListener('contextmenu',this._contextMenu.bind(this),false);this._dropTarget=new UI.DropTarget(this.element,[UI.DropTarget.Type.File,UI.DropTarget.Type.URI],Common.UIString('Drop timeline file or URL here'),this._handleDrop.bind(this));this._recordingOptionUIControls=[];this._state=Timeline.TimelinePanel.State.Idle;this._recordingPageReload=false;this._millisecondsToRecordAfterLoadEvent=3000;this._toggleRecordAction=(UI.actionRegistry.action('timeline.toggle-recording'));this._recordReloadAction=(UI.actionRegistry.action('timeline.record-reload'));this._historyManager=new Timeline.TimelineHistoryManager();this._performanceModel=null;this._viewModeSetting=Common.settings.createSetting('timelineViewMode',Timeline.TimelinePanel.ViewMode.FlameChart);this._disableCaptureJSProfileSetting=Common.settings.createSetting('timelineDisableJSSampling',false);this._disableCaptureJSProfileSetting.setTitle(Common.UIString('Disable JavaScript samples'));this._captureLayersAndPicturesSetting=Common.settings.createSetting('timelineCaptureLayersAndPictures',false);this._captureLayersAndPicturesSetting.setTitle(Common.UIString('Enable advanced paint instrumentation (slow)'));this._showScreenshotsSetting=Common.settings.createSetting('timelineShowScreenshots',true);this._showScreenshotsSetting.setTitle(Common.UIString('Screenshots'));this._showScreenshotsSetting.addChangeListener(this._updateOverviewControls,this);this._startCoverage=Common.settings.createSetting('timelineStartCoverage',false);this._startCoverage.setTitle(ls`Coverage`);if(!Root.Runtime.experiments.isEnabled('recordCoverageWithPerformanceTracing')){this._startCoverage.set(false);}
  1002. this._showMemorySetting=Common.settings.createSetting('timelineShowMemory',false);this._showMemorySetting.setTitle(Common.UIString('Memory'));this._showMemorySetting.addChangeListener(this._onModeChanged,this);const timelineToolbarContainer=this.element.createChild('div','timeline-toolbar-container');this._panelToolbar=new UI.Toolbar('timeline-main-toolbar',timelineToolbarContainer);this._panelRightToolbar=new UI.Toolbar('',timelineToolbarContainer);this._createSettingsPane();this._updateShowSettingsToolbarButton();this._timelinePane=new UI.VBox();this._timelinePane.show(this.element);const topPaneElement=this._timelinePane.element.createChild('div','hbox');topPaneElement.id='timeline-overview-panel';this._overviewPane=new PerfUI.TimelineOverviewPane('timeline');this._overviewPane.addEventListener(PerfUI.TimelineOverviewPane.Events.WindowChanged,this._onOverviewWindowChanged.bind(this));this._overviewPane.show(topPaneElement);this._overviewControls=[];this._statusPaneContainer=this._timelinePane.element.createChild('div','status-pane-container fill');this._createFileSelector();SDK.targetManager.addModelListener(SDK.ResourceTreeModel,SDK.ResourceTreeModel.Events.Load,this._loadEventFired,this);this._flameChart=new Timeline.TimelineFlameChartView(this);this._searchableView=new UI.SearchableView(this._flameChart);this._searchableView.setMinimumSize(0,100);this._searchableView.element.classList.add('searchable-view');this._searchableView.show(this._timelinePane.element);this._flameChart.show(this._searchableView.element);this._flameChart.setSearchableView(this._searchableView);this._onModeChanged();this._populateToolbar();this._showLandingPage();this._updateTimelineControls();Extensions.extensionServer.addEventListener(Extensions.ExtensionServer.Events.TraceProviderAdded,this._appendExtensionsToToolbar,this);SDK.targetManager.addEventListener(SDK.TargetManager.Events.SuspendStateChanged,this._onSuspendStateChanged,this);}
  1003. static instance(){return(self.runtime.sharedInstance(Timeline.TimelinePanel));}
  1004. searchableView(){return this._searchableView;}
  1005. wasShown(){UI.context.setFlavor(Timeline.TimelinePanel,this);}
  1006. willHide(){UI.context.setFlavor(Timeline.TimelinePanel,null);this._historyManager.cancelIfShowing();}
  1007. loadFromEvents(events){if(this._state!==Timeline.TimelinePanel.State.Idle){return;}
  1008. this._prepareToLoadTimeline();this._loader=Timeline.TimelineLoader.loadFromEvents(events,this);}
  1009. _onOverviewWindowChanged(event){const left=event.data.startTime;const right=event.data.endTime;this._performanceModel.setWindow({left,right},true);}
  1010. _onModelWindowChanged(event){const window=(event.data.window);this._overviewPane.setWindowTimes(window.left,window.right);}
  1011. _setState(state){this._state=state;this._updateTimelineControls();}
  1012. _createSettingCheckbox(setting,tooltip){const checkboxItem=new UI.ToolbarSettingCheckbox(setting,tooltip);this._recordingOptionUIControls.push(checkboxItem);return checkboxItem;}
  1013. _populateToolbar(){this._panelToolbar.appendToolbarItem(UI.Toolbar.createActionButton(this._toggleRecordAction));this._panelToolbar.appendToolbarItem(UI.Toolbar.createActionButton(this._recordReloadAction));this._clearButton=new UI.ToolbarButton(Common.UIString('Clear'),'largeicon-clear');this._clearButton.addEventListener(UI.ToolbarButton.Events.Click,()=>this._onClearButton());this._panelToolbar.appendToolbarItem(this._clearButton);this._loadButton=new UI.ToolbarButton(Common.UIString('Load profile...'),'largeicon-load');this._loadButton.addEventListener(UI.ToolbarButton.Events.Click,()=>this._selectFileToLoad());this._saveButton=new UI.ToolbarButton(Common.UIString('Save profile...'),'largeicon-download');this._saveButton.addEventListener(UI.ToolbarButton.Events.Click,()=>this._saveToFile());this._panelToolbar.appendSeparator();this._panelToolbar.appendToolbarItem(this._loadButton);this._panelToolbar.appendToolbarItem(this._saveButton);this._panelToolbar.appendSeparator();this._panelToolbar.appendToolbarItem(this._historyManager.button());this._panelToolbar.appendSeparator();this._panelToolbar.appendSeparator();this._showScreenshotsToolbarCheckbox=this._createSettingCheckbox(this._showScreenshotsSetting,Common.UIString('Capture screenshots'));this._panelToolbar.appendToolbarItem(this._showScreenshotsToolbarCheckbox);this._showMemoryToolbarCheckbox=this._createSettingCheckbox(this._showMemorySetting,Common.UIString('Show memory timeline'));this._panelToolbar.appendToolbarItem(this._showMemoryToolbarCheckbox);if(Root.Runtime.experiments.isEnabled('recordCoverageWithPerformanceTracing')){this._startCoverageCheckbox=this._createSettingCheckbox(this._startCoverage,ls`Record coverage with performance trace`);this._panelToolbar.appendToolbarItem(this._startCoverageCheckbox);}
  1014. this._panelToolbar.appendToolbarItem(UI.Toolbar.createActionButtonForId('components.collect-garbage'));this._panelRightToolbar.appendSeparator();this._panelRightToolbar.appendToolbarItem(this._showSettingsPaneButton);}
  1015. _createSettingsPane(){this._showSettingsPaneSetting=Common.settings.createSetting('timelineShowSettingsToolbar',false);this._showSettingsPaneButton=new UI.ToolbarSettingToggle(this._showSettingsPaneSetting,'largeicon-settings-gear',Common.UIString('Capture settings'));SDK.multitargetNetworkManager.addEventListener(SDK.MultitargetNetworkManager.Events.ConditionsChanged,this._updateShowSettingsToolbarButton,this);MobileThrottling.throttlingManager().addEventListener(MobileThrottling.ThrottlingManager.Events.RateChanged,this._updateShowSettingsToolbarButton,this);this._disableCaptureJSProfileSetting.addChangeListener(this._updateShowSettingsToolbarButton,this);this._captureLayersAndPicturesSetting.addChangeListener(this._updateShowSettingsToolbarButton,this);this._settingsPane=new UI.HBox();this._settingsPane.element.classList.add('timeline-settings-pane');this._settingsPane.show(this.element);const captureToolbar=new UI.Toolbar('',this._settingsPane.element);captureToolbar.element.classList.add('flex-auto');captureToolbar.makeVertical();captureToolbar.appendToolbarItem(this._createSettingCheckbox(this._disableCaptureJSProfileSetting,Common.UIString('Disables JavaScript sampling, reduces overhead when running against mobile devices')));captureToolbar.appendToolbarItem(this._createSettingCheckbox(this._captureLayersAndPicturesSetting,Common.UIString('Captures advanced paint instrumentation, introduces significant performance overhead')));const throttlingPane=new UI.VBox();throttlingPane.element.classList.add('flex-auto');throttlingPane.show(this._settingsPane.element);const networkThrottlingToolbar=new UI.Toolbar('',throttlingPane.element);networkThrottlingToolbar.appendText(Common.UIString('Network:'));this._networkThrottlingSelect=this._createNetworkConditionsSelect();networkThrottlingToolbar.appendToolbarItem(this._networkThrottlingSelect);const cpuThrottlingToolbar=new UI.Toolbar('',throttlingPane.element);cpuThrottlingToolbar.appendText(Common.UIString('CPU:'));this._cpuThrottlingSelect=MobileThrottling.throttlingManager().createCPUThrottlingSelector();cpuThrottlingToolbar.appendToolbarItem(this._cpuThrottlingSelect);this._showSettingsPaneSetting.addChangeListener(this._updateSettingsPaneVisibility.bind(this));this._updateSettingsPaneVisibility();}
  1016. _appendExtensionsToToolbar(event){const provider=(event.data);const setting=Timeline.TimelinePanel._settingForTraceProvider(provider);const checkbox=this._createSettingCheckbox(setting,provider.longDisplayName());this._panelToolbar.appendToolbarItem(checkbox);}
  1017. static _settingForTraceProvider(traceProvider){let setting=traceProvider[Timeline.TimelinePanel._traceProviderSettingSymbol];if(!setting){const providerId=traceProvider.persistentIdentifier();setting=Common.settings.createSetting(providerId,false);setting.setTitle(traceProvider.shortDisplayName());traceProvider[Timeline.TimelinePanel._traceProviderSettingSymbol]=setting;}
  1018. return setting;}
  1019. _createNetworkConditionsSelect(){const toolbarItem=new UI.ToolbarComboBox(null,ls`Network conditions`);toolbarItem.setMaxWidth(140);MobileThrottling.throttlingManager().decorateSelectWithNetworkThrottling(toolbarItem.selectElement());return toolbarItem;}
  1020. _prepareToLoadTimeline(){console.assert(this._state===Timeline.TimelinePanel.State.Idle);this._setState(Timeline.TimelinePanel.State.Loading);if(this._performanceModel){this._performanceModel.dispose();this._performanceModel=null;}}
  1021. _createFileSelector(){if(this._fileSelectorElement){this._fileSelectorElement.remove();}
  1022. this._fileSelectorElement=UI.createFileSelectorElement(this._loadFromFile.bind(this));this._timelinePane.element.appendChild(this._fileSelectorElement);}
  1023. _contextMenu(event){const contextMenu=new UI.ContextMenu(event);contextMenu.appendItemsAtLocation('timelineMenu');contextMenu.show();}
  1024. async _saveToFile(){if(this._state!==Timeline.TimelinePanel.State.Idle){return;}
  1025. const performanceModel=this._performanceModel;if(!performanceModel){return;}
  1026. const now=new Date();const fileName='Profile-'+now.toISO8601Compact()+'.json';const stream=new Bindings.FileOutputStream();const accepted=await stream.open(fileName);if(!accepted){return;}
  1027. const error=await performanceModel.save(stream);if(!error){return;}
  1028. Common.console.error(Common.UIString('Failed to save timeline: %s (%s, %s)',error.message,error.name,error.code));}
  1029. async _showHistory(){const model=await this._historyManager.showHistoryDropDown();if(model&&model!==this._performanceModel){this._setModel(model);}}
  1030. _navigateHistory(direction){const model=this._historyManager.navigate(direction);if(model&&model!==this._performanceModel){this._setModel(model);}
  1031. return true;}
  1032. _selectFileToLoad(){this._fileSelectorElement.click();}
  1033. _loadFromFile(file){if(this._state!==Timeline.TimelinePanel.State.Idle){return;}
  1034. this._prepareToLoadTimeline();this._loader=Timeline.TimelineLoader.loadFromFile(file,this);this._createFileSelector();}
  1035. _loadFromURL(url){if(this._state!==Timeline.TimelinePanel.State.Idle){return;}
  1036. this._prepareToLoadTimeline();this._loader=Timeline.TimelineLoader.loadFromURL(url,this);}
  1037. _updateOverviewControls(){this._overviewControls=[];this._overviewControls.push(new Timeline.TimelineEventOverviewResponsiveness());if(Root.Runtime.experiments.isEnabled('inputEventsOnTimelineOverview')){this._overviewControls.push(new Timeline.TimelineEventOverviewInput());}
  1038. this._overviewControls.push(new Timeline.TimelineEventOverviewFrames());this._overviewControls.push(new Timeline.TimelineEventOverviewCPUActivity());this._overviewControls.push(new Timeline.TimelineEventOverviewNetwork());if(this._showScreenshotsSetting.get()&&this._performanceModel&&this._performanceModel.filmStripModel().frames().length){this._overviewControls.push(new Timeline.TimelineFilmStripOverview());}
  1039. if(this._showMemorySetting.get()){this._overviewControls.push(new Timeline.TimelineEventOverviewMemory());}
  1040. if(this._startCoverage.get()){this._overviewControls.push(new Timeline.TimelineEventOverviewCoverage());}
  1041. for(const control of this._overviewControls){control.setModel(this._performanceModel);}
  1042. this._overviewPane.setOverviewControls(this._overviewControls);}
  1043. _onModeChanged(){this._updateOverviewControls();this.doResize();this.select(null);}
  1044. _updateSettingsPaneVisibility(){if(this._showSettingsPaneSetting.get()){this._settingsPane.showWidget();}else{this._settingsPane.hideWidget();}}
  1045. _updateShowSettingsToolbarButton(){const messages=[];if(MobileThrottling.throttlingManager().cpuThrottlingRate()!==1){messages.push(Common.UIString('- CPU throttling is enabled'));}
  1046. if(SDK.multitargetNetworkManager.isThrottling()){messages.push(Common.UIString('- Network throttling is enabled'));}
  1047. if(this._captureLayersAndPicturesSetting.get()){messages.push(Common.UIString('- Significant overhead due to paint instrumentation'));}
  1048. if(this._disableCaptureJSProfileSetting.get()){messages.push(Common.UIString('- JavaScript sampling is disabled'));}
  1049. this._showSettingsPaneButton.setDefaultWithRedColor(messages.length);this._showSettingsPaneButton.setToggleWithRedColor(messages.length);if(messages.length){const tooltipElement=createElement('div');messages.forEach(message=>{tooltipElement.createChild('div').textContent=message;});this._showSettingsPaneButton.setTitle(tooltipElement);}else{this._showSettingsPaneButton.setTitle(Common.UIString('Capture settings'));}}
  1050. _setUIControlsEnabled(enabled){this._recordingOptionUIControls.forEach(control=>control.setEnabled(enabled));}
  1051. async _startRecording(){console.assert(!this._statusPane,'Status pane is already opened.');this._setState(Timeline.TimelinePanel.State.StartPending);const recordingOptions={enableJSSampling:!this._disableCaptureJSProfileSetting.get(),capturePictures:this._captureLayersAndPicturesSetting.get(),captureFilmStrip:this._showScreenshotsSetting.get(),startCoverage:this._startCoverage.get()};if(recordingOptions.startCoverage){await UI.viewManager.showView('coverage').then(()=>UI.viewManager.view('coverage').widget()).then(widget=>widget.ensureRecordingStarted());}
  1052. this._showRecordingStarted();const enabledTraceProviders=Extensions.extensionServer.traceProviders().filter(provider=>Timeline.TimelinePanel._settingForTraceProvider(provider).get());const mainTarget=(SDK.targetManager.mainTarget());if(Timeline.UIDevtoolsUtils.isUiDevTools()){this._controller=new Timeline.UIDevtoolsController(mainTarget,this);}else{this._controller=new Timeline.TimelineController(mainTarget,this);}
  1053. this._setUIControlsEnabled(false);this._hideLandingPage();const response=await this._controller.startRecording(recordingOptions,enabledTraceProviders);if(response[Protocol.Error]){this._recordingFailed(response[Protocol.Error]);}else{this._recordingStarted();}}
  1054. async _stopRecording(){if(this._statusPane){this._statusPane.finish();this._statusPane.updateStatus(Common.UIString('Stopping timeline\u2026'));this._statusPane.updateProgressBar(Common.UIString('Received'),0);}
  1055. this._setState(Timeline.TimelinePanel.State.StopPending);const model=await this._controller.stopRecording();this._performanceModel=model;this._setUIControlsEnabled(true);this._controller.dispose();this._controller=null;}
  1056. _recordingFailed(error){if(this._statusPane){this._statusPane.hide();}
  1057. this._statusPane=new Timeline.TimelinePanel.StatusPane({description:error},()=>this.loadingComplete(null));this._statusPane.showPane(this._statusPaneContainer);this._statusPane.updateStatus(ls`Recording failed`);this._statusPane.updateButton(ls`Close`);this._setState(Timeline.TimelinePanel.State.RecordingFailed);this._performanceModel=null;this._setUIControlsEnabled(false);this._controller.dispose();this._controller=null;}
  1058. _onSuspendStateChanged(){this._updateTimelineControls();}
  1059. _updateTimelineControls(){const state=Timeline.TimelinePanel.State;this._toggleRecordAction.setToggled(this._state===state.Recording);this._toggleRecordAction.setEnabled(this._state===state.Recording||this._state===state.Idle);this._recordReloadAction.setEnabled(this._state===state.Idle);this._historyManager.setEnabled(this._state===state.Idle);this._clearButton.setEnabled(this._state===state.Idle);this._panelToolbar.setEnabled(this._state!==state.Loading);this._panelRightToolbar.setEnabled(this._state!==state.Loading);this._dropTarget.setEnabled(this._state===state.Idle);this._loadButton.setEnabled(this._state===state.Idle);this._saveButton.setEnabled(this._state===state.Idle&&!!this._performanceModel);}
  1060. _toggleRecording(){if(this._state===Timeline.TimelinePanel.State.Idle){this._recordingPageReload=false;this._startRecording();Host.userMetrics.actionTaken(Host.UserMetrics.Action.TimelineStarted);}else if(this._state===Timeline.TimelinePanel.State.Recording){this._stopRecording();}}
  1061. _recordReload(){if(this._state!==Timeline.TimelinePanel.State.Idle){return;}
  1062. this._recordingPageReload=true;this._startRecording();Host.userMetrics.actionTaken(Host.UserMetrics.Action.TimelinePageReloadStarted);}
  1063. _onClearButton(){this._historyManager.clear();this._clear();}
  1064. _clear(){this._showLandingPage();this._reset();}
  1065. _reset(){self.runtime.sharedInstance(PerfUI.LineLevelProfile.Performance).reset();this._setModel(null);}
  1066. _applyFilters(model){if(model.timelineModel().isGenericTrace()||Root.Runtime.experiments.isEnabled('timelineShowAllEvents')){return;}
  1067. model.setFilters([Timeline.TimelineUIUtils.visibleEventsFilter()]);}
  1068. _setModel(model){if(this._performanceModel){this._performanceModel.removeEventListener(Timeline.PerformanceModel.Events.WindowChanged,this._onModelWindowChanged,this);}
  1069. this._performanceModel=model;if(model){this._applyFilters(model);}
  1070. this._flameChart.setModel(model);this._updateOverviewControls();this._overviewPane.reset();if(model){this._performanceModel.addEventListener(Timeline.PerformanceModel.Events.WindowChanged,this._onModelWindowChanged,this);this._overviewPane.setBounds(model.timelineModel().minimumRecordTime(),model.timelineModel().maximumRecordTime());const lineLevelProfile=self.runtime.sharedInstance(PerfUI.LineLevelProfile.Performance);lineLevelProfile.reset();for(const profile of model.timelineModel().cpuProfiles()){lineLevelProfile.appendCPUProfile(profile);}
  1071. this._setMarkers(model.timelineModel());this._flameChart.setSelection(null);this._overviewPane.setWindowTimes(model.window().left,model.window().right);}
  1072. for(const control of this._overviewControls){control.setModel(model);}
  1073. if(this._flameChart){this._flameChart.resizeToPreferredHeights();}
  1074. this._updateTimelineControls();}
  1075. _recordingStarted(){if(this._recordingPageReload){const target=this._controller.mainTarget();const resourceModel=target.model(SDK.ResourceTreeModel);if(resourceModel){resourceModel.reloadPage();}}
  1076. this._reset();this._setState(Timeline.TimelinePanel.State.Recording);this._showRecordingStarted();this._statusPane.updateStatus(Common.UIString('Profiling\u2026'));this._statusPane.updateProgressBar(Common.UIString('Buffer usage'),0);this._statusPane.startTimer();this._hideLandingPage();}
  1077. recordingProgress(usage){this._statusPane.updateProgressBar(Common.UIString('Buffer usage'),usage*100);}
  1078. _showLandingPage(){if(this._landingPage){this._landingPage.show(this._statusPaneContainer);return;}
  1079. function encloseWithTag(tagName,contents){const e=createElement(tagName);e.textContent=contents;return e;}
  1080. const learnMoreNode=UI.XLink.create('https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/',Common.UIString('Learn\xa0more'));const recordKey=encloseWithTag('b',UI.shortcutRegistry.shortcutDescriptorsForAction('timeline.toggle-recording')[0].name);const reloadKey=encloseWithTag('b',UI.shortcutRegistry.shortcutDescriptorsForAction('timeline.record-reload')[0].name);const navigateNode=encloseWithTag('b',Common.UIString('WASD'));this._landingPage=new UI.VBox();this._landingPage.contentElement.classList.add('timeline-landing-page','fill');const centered=this._landingPage.contentElement.createChild('div');const recordButton=UI.createInlineButton(UI.Toolbar.createActionButton(this._toggleRecordAction));const reloadButton=UI.createInlineButton(UI.Toolbar.createActionButtonForId('timeline.record-reload'));centered.createChild('p').appendChild(UI.formatLocalized('Click the record button %s or hit %s to start a new recording.\nClick the reload button %s or hit %s to record the page load.',[recordButton,recordKey,reloadButton,reloadKey]));centered.createChild('p').appendChild(UI.formatLocalized('After recording, select an area of interest in the overview by dragging.\nThen, zoom and pan the timeline with the mousewheel or %s keys.\n%s',[navigateNode,learnMoreNode]));this._landingPage.show(this._statusPaneContainer);}
  1081. _hideLandingPage(){this._landingPage.detach();}
  1082. loadingStarted(){this._hideLandingPage();if(this._statusPane){this._statusPane.hide();}
  1083. this._statusPane=new Timeline.TimelinePanel.StatusPane({showProgress:true},this._cancelLoading.bind(this));this._statusPane.showPane(this._statusPaneContainer);this._statusPane.updateStatus(Common.UIString('Loading profile\u2026'));if(!this._loader){this._statusPane.finish();}
  1084. this.loadingProgress(0);}
  1085. loadingProgress(progress){if(typeof progress==='number'){this._statusPane.updateProgressBar(Common.UIString('Received'),progress*100);}}
  1086. processingStarted(){this._statusPane.updateStatus(Common.UIString('Processing profile\u2026'));}
  1087. loadingComplete(tracingModel){delete this._loader;this._setState(Timeline.TimelinePanel.State.Idle);if(this._statusPane){this._statusPane.hide();}
  1088. delete this._statusPane;if(!tracingModel){this._clear();return;}
  1089. if(!this._performanceModel){this._performanceModel=new Timeline.PerformanceModel();}
  1090. this._performanceModel.setTracingModel(tracingModel);this._setModel(this._performanceModel);this._historyManager.addRecording(this._performanceModel);if(this._startCoverage.get()){UI.viewManager.showView('coverage').then(()=>UI.viewManager.view('coverage').widget()).then(widget=>widget.stopRecording()).then(()=>this._updateOverviewControls());}}
  1091. _showRecordingStarted(){if(this._statusPane){return;}
  1092. this._statusPane=new Timeline.TimelinePanel.StatusPane({showTimer:true,showProgress:true},this._stopRecording.bind(this));this._statusPane.showPane(this._statusPaneContainer);this._statusPane.updateStatus(Common.UIString('Initializing profiler\u2026'));}
  1093. _cancelLoading(){if(this._loader){this._loader.cancel();}}
  1094. _setMarkers(timelineModel){const markers=new Map();const recordTypes=TimelineModel.TimelineModel.RecordType;const zeroTime=timelineModel.minimumRecordTime();for(const event of timelineModel.timeMarkerEvents()){if(event.name===recordTypes.TimeStamp||event.name===recordTypes.ConsoleTime){continue;}
  1095. markers.set(event.startTime,Timeline.TimelineUIUtils.createEventDivider(event,zeroTime));}
  1096. this._overviewPane.setMarkers(markers);}
  1097. async _loadEventFired(event){if(this._state!==Timeline.TimelinePanel.State.Recording||!this._recordingPageReload||this._controller.mainTarget()!==event.data.resourceTreeModel.target()){return;}
  1098. const controller=this._controller;await new Promise(r=>setTimeout(r,this._millisecondsToRecordAfterLoadEvent));if(controller!==this._controller||this._state!==Timeline.TimelinePanel.State.Recording){return;}
  1099. this._stopRecording();}
  1100. _frameForSelection(selection){switch(selection.type()){case Timeline.TimelineSelection.Type.Frame:return(selection.object());case Timeline.TimelineSelection.Type.Range:return null;case Timeline.TimelineSelection.Type.TraceEvent:return this._performanceModel.frameModel().frames(selection._endTime,selection._endTime)[0];default:console.assert(false,'Should never be reached');return null;}}
  1101. _jumpToFrame(offset){const currentFrame=this._selection&&this._frameForSelection(this._selection);if(!currentFrame){return;}
  1102. const frames=this._performanceModel.frames();let index=frames.indexOf(currentFrame);console.assert(index>=0,'Can\'t find current frame in the frame list');index=Number.constrain(index+offset,0,frames.length-1);const frame=frames[index];this._revealTimeRange(frame.startTime,frame.endTime);this.select(Timeline.TimelineSelection.fromFrame(frame));return true;}
  1103. select(selection){this._selection=selection;this._flameChart.setSelection(selection);}
  1104. selectEntryAtTime(events,time){if(!events){return;}
  1105. for(let index=events.upperBound(time,(time,event)=>time-event.startTime)-1;index>=0;--index){const event=events[index];const endTime=event.endTime||event.startTime;if(SDK.TracingModel.isTopLevelEvent(event)&&endTime<time){break;}
  1106. if(this._performanceModel.isVisible(event)&&endTime>=time){this.select(Timeline.TimelineSelection.fromTraceEvent(event));return;}}
  1107. this.select(null);}
  1108. highlightEvent(event){this._flameChart.highlightEvent(event);}
  1109. _revealTimeRange(startTime,endTime){const window=this._performanceModel.window();let offset=0;if(window.right<endTime){offset=endTime-window.right;}else if(window.left>startTime){offset=startTime-window.left;}
  1110. this._performanceModel.setWindow({left:window.left+offset,right:window.right+offset},true);}
  1111. _handleDrop(dataTransfer){const items=dataTransfer.items;if(!items.length){return;}
  1112. const item=items[0];if(item.kind==='string'){const url=dataTransfer.getData('text/uri-list');if(new Common.ParsedURL(url).isValid){this._loadFromURL(url);}}else if(item.kind==='file'){const entry=items[0].webkitGetAsEntry();if(!entry.isFile){return;}
  1113. entry.file(this._loadFromFile.bind(this));}}};Timeline.TimelinePanel.State={Idle:Symbol('Idle'),StartPending:Symbol('StartPending'),Recording:Symbol('Recording'),StopPending:Symbol('StopPending'),Loading:Symbol('Loading'),RecordingFailed:Symbol('RecordingFailed')};Timeline.TimelinePanel.ViewMode={FlameChart:'FlameChart',BottomUp:'BottomUp',CallTree:'CallTree',EventLog:'EventLog'};Timeline.TimelinePanel.rowHeight=18;Timeline.TimelinePanel.headerHeight=20;Timeline.TimelinePanel.ModelSelectionData;Timeline.TimelineSelection=class{constructor(type,startTime,endTime,object){this._type=type;this._startTime=startTime;this._endTime=endTime;this._object=object||null;}
  1114. static fromFrame(frame){return new Timeline.TimelineSelection(Timeline.TimelineSelection.Type.Frame,frame.startTime,frame.endTime,frame);}
  1115. static fromNetworkRequest(request){return new Timeline.TimelineSelection(Timeline.TimelineSelection.Type.NetworkRequest,request.startTime,request.endTime||request.startTime,request);}
  1116. static fromTraceEvent(event){return new Timeline.TimelineSelection(Timeline.TimelineSelection.Type.TraceEvent,event.startTime,event.endTime||(event.startTime+1),event);}
  1117. static fromRange(startTime,endTime){return new Timeline.TimelineSelection(Timeline.TimelineSelection.Type.Range,startTime,endTime);}
  1118. type(){return this._type;}
  1119. object(){return this._object;}
  1120. startTime(){return this._startTime;}
  1121. endTime(){return this._endTime;}};Timeline.TimelineSelection.Type={Frame:'Frame',NetworkRequest:'NetworkRequest',TraceEvent:'TraceEvent',Range:'Range'};Timeline.TimelineModeViewDelegate=function(){};Timeline.TimelineModeViewDelegate.prototype={select(selection){},selectEntryAtTime(events,time){},highlightEvent(event){},};Timeline.TimelinePanel.StatusPane=class extends UI.VBox{constructor(options,stopCallback){super(true);this.registerRequiredCSS('timeline/timelineStatusDialog.css');this.contentElement.classList.add('timeline-status-dialog');const statusLine=this.contentElement.createChild('div','status-dialog-line status');statusLine.createChild('div','label').textContent=Common.UIString('Status');this._status=statusLine.createChild('div','content');UI.ARIAUtils.markAsStatus(this._status);if(options.showTimer){const timeLine=this.contentElement.createChild('div','status-dialog-line time');timeLine.createChild('div','label').textContent=Common.UIString('Time');this._time=timeLine.createChild('div','content');}
  1122. if(options.showProgress){const progressLine=this.contentElement.createChild('div','status-dialog-line progress');this._progressLabel=progressLine.createChild('div','label');this._progressBar=progressLine.createChild('div','indicator-container').createChild('div','indicator');UI.ARIAUtils.markAsProgressBar(this._progressBar);}
  1123. if(typeof options.description==='string'){const descriptionLine=this.contentElement.createChild('div','status-dialog-line description');descriptionLine.createChild('div','label').textContent=ls`Description`;this._description=descriptionLine.createChild('div','content');this._description.innerText=options.description;}
  1124. this._stopButton=UI.createTextButton(Common.UIString('Stop'),stopCallback,'',true);this.contentElement.createChild('div','stop-button').appendChild(this._stopButton);}
  1125. finish(){this._stopTimer();this._stopButton.disabled=true;}
  1126. hide(){this.element.parentNode.classList.remove('tinted');this.element.remove();}
  1127. showPane(parent){this.show(parent);parent.classList.add('tinted');this._stopButton.focus();}
  1128. updateStatus(text){this._status.textContent=text;}
  1129. updateProgressBar(activity,percent){this._progressLabel.textContent=activity;this._progressBar.style.width=percent.toFixed(1)+'%';UI.ARIAUtils.setValueNow(this._progressBar,percent);this._updateTimer();}
  1130. updateButton(caption){this._stopButton.innerText=caption;}
  1131. startTimer(){this._startTime=Date.now();this._timeUpdateTimer=setInterval(this._updateTimer.bind(this,false),1000);this._updateTimer();}
  1132. _stopTimer(){if(!this._timeUpdateTimer){return;}
  1133. clearInterval(this._timeUpdateTimer);this._updateTimer(true);delete this._timeUpdateTimer;}
  1134. _updateTimer(precise){if(!this._timeUpdateTimer){return;}
  1135. const elapsed=(Date.now()-this._startTime)/1000;this._time.textContent=Common.UIString('%s\xa0sec',elapsed.toFixed(precise?1:0));}};Timeline.LoadTimelineHandler=class{handleQueryParam(value){UI.viewManager.showView('timeline').then(()=>{Timeline.TimelinePanel.instance()._loadFromURL(window.decodeURIComponent(value));});}};Timeline.TimelinePanel.ActionDelegate=class{handleAction(context,actionId){const panel=UI.context.flavor(Timeline.TimelinePanel);console.assert(panel&&panel instanceof Timeline.TimelinePanel);switch(actionId){case'timeline.toggle-recording':panel._toggleRecording();return true;case'timeline.record-reload':panel._recordReload();return true;case'timeline.save-to-file':panel._saveToFile();return true;case'timeline.load-from-file':panel._selectFileToLoad();return true;case'timeline.jump-to-previous-frame':panel._jumpToFrame(-1);return true;case'timeline.jump-to-next-frame':panel._jumpToFrame(1);return true;case'timeline.show-history':panel._showHistory();return true;case'timeline.previous-recording':panel._navigateHistory(1);return true;case'timeline.next-recording':panel._navigateHistory(-1);return true;}
  1136. return false;}};Timeline.TimelinePanel._traceProviderSettingSymbol=Symbol('traceProviderSetting');;Timeline.UIDevtoolsUtils=class{static isUiDevTools(){return Root.Runtime.queryParam('uiDevTools')==='true';}
  1137. static categorizeEvents(){if(Timeline.UIDevtoolsUtils._eventStylesMap){return Timeline.UIDevtoolsUtils._eventStylesMap;}
  1138. const type=Timeline.UIDevtoolsUtils.RecordType;const categories=Timeline.UIDevtoolsUtils.categories();const drawing=categories['drawing'];const rasterizing=categories['rasterizing'];const layout=categories['layout'];const painting=categories['painting'];const other=categories['other'];const eventStyles={};eventStyles[type.ViewPaint]=new Timeline.TimelineRecordStyle(ls`View::Paint`,painting);eventStyles[type.ViewOnPaint]=new Timeline.TimelineRecordStyle(ls`View::OnPaint`,painting);eventStyles[type.ViewPaintChildren]=new Timeline.TimelineRecordStyle(ls`View::PaintChildren`,painting);eventStyles[type.ViewOnPaintBackground]=new Timeline.TimelineRecordStyle(ls`View::OnPaintBackground`,painting);eventStyles[type.ViewOnPaintBorder]=new Timeline.TimelineRecordStyle(ls`View::OnPaintBorder`,painting);eventStyles[type.LayerPaintContentsToDisplayList]=new Timeline.TimelineRecordStyle(ls`Layer::PaintContentsToDisplayList`,painting);eventStyles[type.ViewLayout]=new Timeline.TimelineRecordStyle(ls`View::Layout`,layout);eventStyles[type.ViewLayoutBoundsChanged]=new Timeline.TimelineRecordStyle(ls`View::Layout(bounds_changed)`,layout);eventStyles[type.RasterTask]=new Timeline.TimelineRecordStyle(ls`RasterTask`,rasterizing);eventStyles[type.RasterizerTaskImplRunOnWorkerThread]=new Timeline.TimelineRecordStyle(ls`RasterizerTaskImpl::RunOnWorkerThread`,rasterizing);eventStyles[type.DirectRendererDrawFrame]=new Timeline.TimelineRecordStyle(ls`DirectRenderer::DrawFrame`,drawing);eventStyles[type.BeginFrame]=new Timeline.TimelineRecordStyle(ls`Frame Start`,drawing,true);eventStyles[type.DrawFrame]=new Timeline.TimelineRecordStyle(ls`Draw Frame`,drawing,true);eventStyles[type.NeedsBeginFrameChanged]=new Timeline.TimelineRecordStyle(ls`NeedsBeginFrameChanged`,drawing,true);eventStyles[type.ThreadControllerImplRunTask]=new Timeline.TimelineRecordStyle(ls`ThreadControllerImpl::RunTask`,other);Timeline.UIDevtoolsUtils._eventStylesMap=eventStyles;return eventStyles;}
  1139. static categories(){if(Timeline.UIDevtoolsUtils._categories){return Timeline.UIDevtoolsUtils._categories;}
  1140. Timeline.UIDevtoolsUtils._categories={layout:new Timeline.TimelineCategory('layout',ls`Layout`,true,'hsl(214, 67%, 74%)','hsl(214, 67%, 66%)'),rasterizing:new Timeline.TimelineCategory('rasterizing',ls`Rasterizing`,true,'hsl(43, 83%, 72%)','hsl(43, 83%, 64%) '),drawing:new Timeline.TimelineCategory('drawing',ls`Drawing`,true,'hsl(256, 67%, 76%)','hsl(256, 67%, 70%)'),painting:new Timeline.TimelineCategory('painting',ls`Painting`,true,'hsl(109, 33%, 64%)','hsl(109, 33%, 55%)'),other:new Timeline.TimelineCategory('other',ls`System`,false,'hsl(0, 0%, 87%)','hsl(0, 0%, 79%)'),idle:new Timeline.TimelineCategory('idle',ls`Idle`,false,'hsl(0, 0%, 98%)','hsl(0, 0%, 98%)')};return Timeline.UIDevtoolsUtils._categories;}
  1141. static getMainCategoriesList(){return['idle','drawing','painting','rasterizing','layout','other'];}};Timeline.UIDevtoolsUtils.RecordType={ViewPaint:'View::Paint',ViewOnPaint:'View::OnPaint',ViewPaintChildren:'View::PaintChildren',ViewOnPaintBackground:'View::OnPaintBackground',ViewOnPaintBorder:'View::OnPaintBorder',ViewLayout:'View::Layout',ViewLayoutBoundsChanged:'View::Layout(bounds_changed)',LayerPaintContentsToDisplayList:'Layer::PaintContentsToDisplayList',DirectRendererDrawFrame:'DirectRenderer::DrawFrame',RasterTask:'RasterTask',RasterizerTaskImplRunOnWorkerThread:'RasterizerTaskImpl::RunOnWorkerThread',BeginFrame:'BeginFrame',DrawFrame:'DrawFrame',NeedsBeginFrameChanged:'NeedsBeginFrameChanged',ThreadControllerImplRunTask:'ThreadControllerImpl::RunTask',};;Timeline.UIDevtoolsController=class extends Timeline.TimelineController{constructor(target,client){super(target,client);Timeline.TimelineUIUtils.setEventStylesMap(Timeline.UIDevtoolsUtils.categorizeEvents());Timeline.TimelineUIUtils.setCategories(Timeline.UIDevtoolsUtils.categories());Timeline.TimelineUIUtils.setTimelineMainEventCategories(Timeline.UIDevtoolsUtils.getMainCategoriesList());}};;Root.Runtime.cachedResources["timeline/historyToolbarButton.css"]="/*\n * Copyright 2017 The Chromium Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style license that can be\n * found in the LICENSE file.\n */\n\n.content {\n margin-left: 5px;\n}\n\n.history-dropdown-button {\n width: 160px;\n height: 26px;\n text-align: left;\n display: flex;\n}\n\n.history-dropdown-button[disabled] {\n opacity: .5;\n}\n\n.history-dropdown-button > .content {\n padding-right: 5px;\n overflow: hidden;\n text-overflow: ellipsis;\n flex: 1 1;\n min-width: 35px;\n}\n\n.history-dropdown-button[data-keyboard-focus=\"true\"]:focus::before {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 0px;\n right: 0px;\n bottom: 2px;\n border-radius: 2px;\n background: rgba(0, 0, 0, 0.08);\n}\n\n/*# sourceURL=timeline/historyToolbarButton.css */";Root.Runtime.cachedResources["timeline/invalidationsTree.css"]="/*\n * Copyright 2015 The Chromium Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style license that can be\n * found in the LICENSE file.\n */\n\n.header, .children, .content {\n min-height: initial;\n line-height: initial;\n}\n\n/* This TreeElement is always expanded and has no arrow. */\n/* FIXME(crbug.com/475618): Implement this in TreeElement. */\n.children li::before {\n display: none;\n}\n\n.content {\n margin-bottom: 4px;\n}\n\n.content .stack-preview-container {\n margin-left: 8px;\n}\n\n.content .node-list {\n margin-left: 10px;\n}\n\n/*# sourceURL=timeline/invalidationsTree.css */";Root.Runtime.cachedResources["timeline/timelineFlamechartPopover.css"]="/*\n * Copyright (c) 2015 The Chromium Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style license that can be\n * found in the LICENSE file.\n */\n\n.timeline-flamechart-popover {\n overflow: hidden;\n}\n\n.timeline-flamechart-popover span {\n margin-right: 5px;\n}\n\n.timeline-flamechart-popover span.timeline-info-network-time {\n color: #009;\n}\n\n.timeline-flamechart-popover span.timeline-info-time {\n color: #282;\n}\n\n.timeline-flamechart-popover span.timeline-info-warning {\n color: #e44;\n}\n\n.timeline-flamechart-popover span.timeline-info-warning * {\n color: inherit;\n}\n\n/*# sourceURL=timeline/timelineFlamechartPopover.css */";Root.Runtime.cachedResources["timeline/timelineHistoryManager.css"]="/*\n * Copyright 2017 The Chromium Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style license that can be\n * found in the LICENSE file.\n */\n\n.drop-down {\n padding: 1px;\n box-shadow: var(--drop-shadow);\n background: white;\n}\n\n.preview-item {\n border-color: transparent;\n border-style: solid;\n border-width: 1px 5px;\n padding: 2px 0px;\n margin: 2px 1px;\n}\n\n.preview-item.selected {\n border-color: var(--selection-bg-color);\n}\n\n.preview-item canvas {\n width: 100%;\n height: 100%;\n}\n\n.text-details {\n font-size: 11px;\n padding: 3px;\n}\n\n.text-details span {\n flex: 1 0;\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.text-details .name {\n font-weight: bold;\n}\n\n.text-details span.time {\n color: #555;\n text-align: right;\n}\n\n.screenshot-thumb {\n display: flex;\n border: 1px solid #ccc;\n margin: 2px 4px;\n}\n\n.screenshot-thumb img {\n margin: auto;\n max-width: 100%;\n max-height: 100%;\n}\n\n/*# sourceURL=timeline/timelineHistoryManager.css */";Root.Runtime.cachedResources["timeline/timelinePanel.css"]="/*\n * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.\n * Copyright (C) 2009 Anthony Ricaud <rik@webkit.org>\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n * notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n * 3. Neither the name of Apple Computer, Inc. (\"Apple\") nor the names of\n * its contributors may be used to endorse or promote products derived\n * from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n.timeline-toolbar-container {\n display: flex;\n flex: none;\n}\n\n.timeline-toolbar-container > .toolbar {\n background-color: var(--toolbar-bg-color);\n border-bottom: var(--divider-border);\n}\n\n.timeline-main-toolbar {\n flex: 1 1 auto;\n}\n\n.timeline-settings-pane {\n flex: none;\n background-color: var(--toolbar-bg-color);\n border-bottom: var(--divider-border);\n}\n\n#timeline-overview-panel {\n flex: none;\n position: relative;\n border-bottom: 1px solid #bbb;\n}\n\n#timeline-overview-grid {\n background-color: rgb(255, 255, 255);\n}\n\n#timeline-overview-grid .timeline-grid-header {\n height: 12px;\n}\n\n#timeline-overview-grid .resources-dividers-label-bar {\n pointer-events: auto;\n height: 12px;\n}\n\n#timeline-overview-grid .resources-divider-label {\n top: 1px;\n}\n\n.timeline-details-split {\n flex: auto;\n}\n\n.timeline.panel .status-pane-container {\n z-index: 1000;\n display: flex;\n align-items: center;\n pointer-events: none;\n}\n\n.timeline.panel .status-pane-container.tinted {\n background-color: lightgray;\n pointer-events: auto;\n}\n\n.timeline.panel .status-pane-container > div {\n pointer-events: auto;\n}\n\n#timeline-overview-panel .overview-strip {\n margin-top: 2px;\n justify-content: center;\n}\n\n#timeline-overview-panel .overview-strip .timeline-overview-strip-title {\n color: #666;\n font-size: 10px;\n font-weight: bold;\n z-index: 100;\n background-color: rgba(255, 255, 255, 0.7);\n padding: 0 4px;\n position: absolute;\n top: -2px;\n right: 0;\n}\n\n#timeline-overview-cpu-activity {\n flex-basis: 20px;\n}\n\n#timeline-overview-network {\n flex-basis: 8px;\n}\n\n#timeline-overview-framerate {\n flex-basis: 16px;\n margin-top: 0 !important;\n}\n\n#timeline-overview-filmstrip {\n flex-basis: 30px;\n}\n\n#timeline-overview-memory {\n flex-basis: 20px;\n}\n\n#timeline-overview-framerate::before,\n#timeline-overview-network::before,\n#timeline-overview-cpu-activity::before {\n content: \"\";\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n border-bottom: 1px solid hsla(0, 0%, 0%, 0.06);\n z-index: -200;\n}\n\n.overview-strip .background {\n z-index: -10;\n}\n\n#timeline-overview-responsiveness {\n flex-basis: 5px;\n margin-top: 0 !important;\n}\n\n#timeline-overview-input {\n flex-basis: 6px;\n}\n\n#timeline-overview-pane {\n flex: auto;\n position: relative;\n overflow: hidden;\n}\n\n#timeline-overview-container {\n display: flex;\n flex-direction: column;\n flex: none;\n position: relative;\n overflow: hidden;\n}\n\n#timeline-overview-container canvas {\n width: 100%;\n height: 100%;\n}\n\n.popover ul {\n margin: 0;\n padding: 0;\n list-style-type: none;\n}\n\n.memory-graph-label {\n position: absolute;\n right: 0;\n bottom: 0;\n font-size: 9px;\n color: #888;\n white-space: nowrap;\n padding: 0 4px;\n background-color: hsla(0, 0%, 100%, 0.8);\n}\n\n#memory-graphs-canvas-container {\n overflow: hidden;\n flex: auto;\n position: relative;\n}\n\n#memory-counters-graph {\n flex: auto;\n}\n\n#memory-graphs-canvas-container .memory-counter-marker {\n position: absolute;\n border-radius: 3px;\n width: 5px;\n height: 5px;\n margin-left: -3px;\n margin-top: -2px;\n}\n\n#memory-graphs-container .timeline-memory-header {\n flex: 0 0 26px;\n background-color: #eee;\n border-bottom: 1px solid #ddd;\n justify-content: space-between;\n}\n\n#memory-graphs-container .timeline-memory-header::after {\n content: \"\";\n background-image: url(Images/toolbarResizerVertical.png);\n background-repeat: no-repeat;\n background-position: right center, center;\n flex: 20px 0 0;\n margin: 0 4px;\n}\n\n.timeline-memory-toolbar {\n flex-shrink: 1;\n}\n\n.memory-counter-value {\n margin: 8px;\n}\n\n#counter-values-bar {\n flex: 0 0 20px;\n border-top: solid 1px lightgray;\n width: 100%;\n overflow: hidden;\n line-height: 18px;\n}\n\n#timeline-overview-coverage {\n flex-basis: 20px;\n}\n\n.timeline-overview-coverage-label {\n position: absolute;\n right: 0;\n bottom: 0;\n font-size: 9px;\n color: #888;\n white-space: nowrap;\n padding: 0 4px;\n background-color: hsla(0, 0%, 100%, 0.8);\n}\n\n.timeline-details {\n vertical-align: top;\n}\n\n.timeline-details-title {\n border-bottom: 1px solid #B8B8B8;\n font-weight: bold;\n padding-bottom: 5px;\n padding-top: 0;\n white-space: nowrap;\n}\n\n.timeline-details-row-title {\n font-weight: bold;\n text-align: right;\n white-space: nowrap;\n}\n\n.timeline-details-row-data {\n white-space: nowrap;\n}\n\n.timeline-details-view {\n color: #333;\n overflow: hidden;\n}\n\n.timeline-details-view-body {\n flex: auto;\n overflow: auto;\n position: relative;\n background-color: var(--toolbar-bg-color);\n -webkit-user-select: text;\n}\n\n.timeline-details-view-body > div {\n overflow: hidden;\n}\n\n.timeline-details-view-block {\n flex: none;\n display: flex;\n background-color: white;\n flex-direction: column;\n padding-bottom: 5px;\n border-bottom: var(--divider-border);\n}\n\n.timeline-details-view-row {\n padding-left: 10px;\n flex-direction: row;\n display: flex;\n line-height: 20px;\n}\n\n.timeline-details-view-block .timeline-details-stack-values {\n flex-direction: column !important;\n}\n\n.timeline-details-chip-title {\n font-size: 13px;\n padding: 8px;\n display: flex;\n align-items: center;\n}\n\n.timeline-details-chip-title > div {\n width: 12px;\n height: 12px;\n border: 1px solid rgba(0, 0, 0, 0.2);\n display: inline-block;\n margin-right: 4px;\n content: \" \";\n}\n\n.timeline-details-view-row-title:not(:empty) {\n color: rgb(152, 152, 152);\n overflow: hidden;\n padding-right: 10px;\n}\n\n.timeline-details-warning {\n background-color: rgba(250, 209, 209, 0.48);\n}\n\n.timeline-details-warning .timeline-details-view-row-title {\n color: red;\n}\n\n.timeline-details-warning .timeline-details-view-row-value {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.timeline-details-view-row-value {\n -webkit-user-select: text;\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n\n.timeline-details-view-row-value .stack-preview-container {\n line-height: 11px;\n}\n\n.timeline-details-view-pie-chart-wrapper {\n margin: 4px 0;\n}\n\n.timeline-details-view-pie-chart {\n margin-top: 5px;\n}\n\n.timeline-details-view-row-stack-trace {\n padding: 4px 0;\n line-height: inherit;\n}\n\n.timeline-details-view-row-stack-trace div {\n white-space: nowrap;\n text-overflow: ellipsis;\n line-height: 12px;\n}\n\n.timeline-flamechart {\n overflow: hidden;\n}\n\n.timeline-flamechart-resizer {\n flex: 8px 0 0;\n background-color: var(--toolbar-bg-color);\n border: 1px #a3a3a3;\n border-style: solid none;\n display: flex;\n flex-direction: row;\n align-items: flex-end;\n justify-content: center;\n}\n\n.timeline-network-resizer-disabled > .timeline-flamechart-resizer {\n display: none;\n}\n\n.timeline-flamechart-resizer:after {\n content: \"...\";\n font-size: 14px;\n margin-bottom: -1px;\n}\n\n.timeline-layers-view > div:last-child,\n.timeline-layers-view-properties > div:last-child {\n background-color: #eee;\n}\n\n.timeline-layers-view-properties table {\n width: 100%;\n border-collapse: collapse;\n}\n\n.timeline-layers-view-properties td {\n border: 1px solid #e1e1e1;\n line-height: 22px;\n}\n\n.timeline-paint-profiler-log-split > div:last-child {\n background-color: #eee;\n z-index: 0;\n}\n\n.timeline-filmstrip-preview > img {\n margin-top: 5px;\n max-width: 500px;\n max-height: 300px;\n cursor: pointer;\n border: 1px solid #ddd;\n}\n\n.timeline-tree-view {\n display: flex;\n overflow: hidden;\n}\n\n.timeline-tree-view .toolbar {\n background-color: var(--toolbar-bg-color);\n border-bottom: var(--divider-border);\n}\n\n.timeline-tree-view .data-grid {\n border: none;\n flex: auto;\n}\n\n.timeline-tree-view .data-grid .data-container {\n overflow-y: scroll;\n}\n\n.timeline-tree-view .data-grid.data-grid-fits-viewport .corner {\n display: table-cell;\n}\n\n.timeline-tree-view .data-grid table.data {\n background: white;\n}\n\n.timeline-tree-view .data-grid tr:not(.selected) .highlight {\n background-color: rgb(255, 230, 179);\n}\n\n.timeline-tree-view .data-grid tr:hover td:not(.bottom-filler-td) {\n background-color: rgba(0, 0, 0, 0.1);\n}\n\n.timeline-tree-view .data-grid td.numeric-column {\n text-align: right;\n position: relative;\n}\n\n.timeline-tree-view .data-grid div.background-percent-bar {\n float: right;\n}\n\n.timeline-tree-view .data-grid span.percent-column {\n color: #888;\n width: 45px;\n display: inline-block;\n}\n\n.timeline-tree-view .data-grid tr.selected span {\n color: inherit;\n}\n\n.timeline-tree-view .data-grid .name-container {\n display: flex;\n align-items: center;\n padding-left: 2px;\n}\n\n.timeline-tree-view .data-grid .name-container div {\n flex: none;\n}\n\n.timeline-tree-view .data-grid .name-container .activity-icon {\n width: 12px;\n height: 12px;\n border: 1px solid rgba(0, 0, 0, 0.05);\n margin: 3px 0;\n}\n\n.timeline-tree-view .data-grid .name-container .activity-icon-container {\n margin-right: 3px;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n overflow: hidden;\n}\n\n.timeline-tree-view .data-grid .name-container .activity-warning::after {\n content: \"[deopt]\";\n margin: 0 4px;\n line-height: 12px;\n font-size: 10px;\n color: #777;\n}\n\n.timeline-tree-view .data-grid tr.selected .name-container .activity-warning::after {\n color: white;\n}\n\n.timeline-tree-view .data-grid .name-container .activity-link {\n flex: auto;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n margin-left: 5px;\n}\n\n.timeline-tree-view .data-grid .background-bar-container {\n position: absolute;\n left: 3px;\n right: 0;\n}\n\n.timeline-tree-view .data-grid .background-bar {\n float: right;\n height: 18px;\n background-color: hsla(43, 84%, 64%, 0.2);\n border-bottom: 1px solid hsl(43, 84%, 64%);\n}\n\n.timeline-tree-view .data-grid .selected .background-bar {\n background-color: rgba(255, 255, 255, 0.3);\n border-bottom-color: rgba(255, 255, 255, 0.9);\n}\n\n.timeline-tree-view .timeline-details-view-body .full-widget-dimmed-banner {\n background-color: inherit;\n}\n\n.timeline-details .filter-input-field {\n width: 120px;\n}\n\n.timeline-tree-view .data-grid .header-container {\n height: 21px;\n}\n\n.timeline-tree-view .data-grid .data-container {\n top: 21px;\n}\n\n.timeline-stack-view-header {\n height: 27px;\n background-color: var(--toolbar-bg-color);\n padding: 6px 10px;\n color: #5a5a5a;\n white-space: nowrap;\n border-bottom: var(--divider-border);\n}\n\n.timeline-landing-page {\n position: absolute;\n background-color: white;\n justify-content: center;\n align-items: center;\n overflow: auto;\n font-size: 13px;\n color: #777;\n}\n\n.timeline-landing-page > div {\n max-width: 450px;\n margin: 10px;\n}\n\n.timeline-landing-page > div > p {\n flex: none;\n white-space: pre-line;\n}\n\n/*# sourceURL=timeline/timelinePanel.css */";Root.Runtime.cachedResources["timeline/timelinePaintProfiler.css"]="/*\n * Copyright 2016 The Chromium Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style license that can be\n * found in the LICENSE file.\n */\n\n.paint-profiler-image-view {\n overflow: hidden;\n}\n\n.paint-profiler-image-view .paint-profiler-image-container {\n -webkit-transform-origin: 0 0;\n}\n\n.paint-profiler-image-view .paint-profiler-image-container div {\n border-color: rgba(100, 100, 100, 0.4);\n border-style: solid;\n z-index: 100;\n position: absolute;\n top: 0;\n left: 0;\n}\n\n.paint-profiler-image-view img {\n border: solid 1px black;\n}\n\n/*# sourceURL=timeline/timelinePaintProfiler.css */";Root.Runtime.cachedResources["timeline/timelineStatusDialog.css"]="/*\n * Copyright (c) 2015 The Chromium Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style license that can be\n * found in the LICENSE file.\n */\n\n.timeline-status-dialog {\n display: flex;\n flex-direction: column;\n padding: 16px 16px 12px 16px;\n align-self: center;\n background-color: white;\n box-shadow: var(--drop-shadow);\n}\n\n.status-dialog-line {\n margin: 2px;\n height: 14px;\n display: flex;\n align-items: baseline;\n}\n\n.status-dialog-line .label {\n display: inline-block;\n width: 80px;\n text-align: right;\n color: #aaa;\n margin-right: 10px;\n}\n\n.timeline-status-dialog .progress .indicator-container {\n display: inline-block;\n width: 200px;\n height: 8px;\n background-color: #f4f4f4;\n display: inline-block;\n}\n\n.timeline-status-dialog .progress .indicator {\n background-color: rgb(112, 166, 255);\n height: 100%;\n width: 0;\n margin: 0;\n}\n\n.timeline-status-dialog .stop-button {\n margin-top: 8px;\n height: 100%;\n align-self: flex-end;\n}\n\n.timeline-status-dialog .stop-button button {\n min-width: 80px;\n}\n\n/*# sourceURL=timeline/timelineStatusDialog.css */";