import{ChartViewport,ChartViewportDelegate}from'./ChartViewport.js';import{Calculator,TimelineGrid}from'./TimelineGrid.js';export class FlameChartDelegate{windowChanged(startTime,endTime,animate){}
updateRangeSelection(startTime,endTime){}
updateSelectedGroup(flameChart,group){}}
export class FlameChart extends UI.VBox{constructor(dataProvider,flameChartDelegate,groupExpansionSetting){super(true);this.registerRequiredCSS('perf_ui/flameChart.css');this.contentElement.classList.add('flame-chart-main-pane');this._groupExpansionSetting=groupExpansionSetting;this._groupExpansionState=groupExpansionSetting&&groupExpansionSetting.get()||{};this._flameChartDelegate=flameChartDelegate;this._useWebGL=Root.Runtime.experiments.isEnabled('timelineWebGL');this._chartViewport=new ChartViewport(this);this._chartViewport.show(this.contentElement);this._dataProvider=dataProvider;this._viewportElement=this._chartViewport.viewportElement;if(this._useWebGL){this._canvasGL=(this._viewportElement.createChild('canvas','fill'));this._initWebGL();}
this._canvas=(this._viewportElement.createChild('canvas','fill'));this._canvas.tabIndex=0;UI.ARIAUtils.setAccessibleName(this._canvas,ls`Flame Chart`);UI.ARIAUtils.markAsTree(this._canvas);this.setDefaultFocusedElement(this._canvas);this._canvas.classList.add('flame-chart-canvas');this._canvas.addEventListener('mousemove',this._onMouseMove.bind(this),false);this._canvas.addEventListener('mouseout',this._onMouseOut.bind(this),false);this._canvas.addEventListener('click',this._onClick.bind(this),false);this._canvas.addEventListener('keydown',this._onKeyDown.bind(this),false);this._entryInfo=this._viewportElement.createChild('div','flame-chart-entry-info');this._markerHighlighElement=this._viewportElement.createChild('div','flame-chart-marker-highlight-element');this._highlightElement=this._viewportElement.createChild('div','flame-chart-highlight-element');this._selectedElement=this._viewportElement.createChild('div','flame-chart-selected-element');this._canvas.addEventListener('focus',()=>{this._selectedElement.classList.remove('flame-chart-unfocused-selected-element');this.dispatchEventToListeners(Events.CanvasFocused);},false);this._canvas.addEventListener('blur',()=>{this._selectedElement.classList.add('flame-chart-unfocused-selected-element');},false);UI.installDragHandle(this._viewportElement,this._startDragging.bind(this),this._dragging.bind(this),this._endDragging.bind(this),null);this._rulerEnabled=true;this._rangeSelectionStart=0;this._rangeSelectionEnd=0;this._barHeight=17;this._textBaseline=5;this._textPadding=5;this._markerRadius=6;this._chartViewport.setWindowTimes(dataProvider.minimumBoundary(),dataProvider.minimumBoundary()+dataProvider.totalTime());this._headerLeftPadding=6;this._arrowSide=8;this._expansionArrowIndent=this._headerLeftPadding+this._arrowSide/2;this._headerLabelXPadding=3;this._headerLabelYPadding=2;this._highlightedMarkerIndex=-1;this._highlightedEntryIndex=-1;this._selectedEntryIndex=-1;this._rawTimelineDataLength=0;this._textWidth=new Map();this._markerPositions=new Map();this._lastMouseOffsetX=0;this._selectedGroup=-1;this._keyboardFocusedGroup=-1;this._selectedGroupBackroundColor=self.UI.themeSupport.patchColorText(Colors.SelectedGroupBackground,UI.ThemeSupport.ColorUsage.Background);this._selectedGroupBorderColor=self.UI.themeSupport.patchColorText(Colors.SelectedGroupBorder,UI.ThemeSupport.ColorUsage.Background);}
willHide(){this.hideHighlight();}
setBarHeight(value){this._barHeight=value;}
setTextBaseline(value){this._textBaseline=value;}
setTextPadding(value){this._textPadding=value;}
enableRuler(enable){this._rulerEnabled=enable;}
alwaysShowVerticalScroll(){this._chartViewport.alwaysShowVerticalScroll();}
disableRangeSelection(){this._chartViewport.disableRangeSelection();}
highlightEntry(entryIndex){if(this._highlightedEntryIndex===entryIndex){return;}
if(!this._dataProvider.entryColor(entryIndex)){return;}
this._highlightedEntryIndex=entryIndex;this._updateElementPosition(this._highlightElement,this._highlightedEntryIndex);this.dispatchEventToListeners(Events.EntryHighlighted,entryIndex);}
hideHighlight(){this._entryInfo.removeChildren();this._highlightedEntryIndex=-1;this._updateElementPosition(this._highlightElement,this._highlightedEntryIndex);this.dispatchEventToListeners(Events.EntryHighlighted,-1);}
_resetCanvas(){const ratio=window.devicePixelRatio;const width=Math.round(this._offsetWidth*ratio);const height=Math.round(this._offsetHeight*ratio);this._canvas.width=width;this._canvas.height=height;this._canvas.style.width=`${width / ratio}px`;this._canvas.style.height=`${height / ratio}px`;if(this._useWebGL){this._canvasGL.width=width;this._canvasGL.height=height;this._canvasGL.style.width=`${width / ratio}px`;this._canvasGL.style.height=`${height / ratio}px`;}}
windowChanged(startTime,endTime,animate){this._flameChartDelegate.windowChanged(startTime,endTime,animate);}
updateRangeSelection(startTime,endTime){this._flameChartDelegate.updateRangeSelection(startTime,endTime);}
setSize(width,height){this._offsetWidth=width;this._offsetHeight=height;}
_startDragging(event){this.hideHighlight();this._maxDragOffset=0;this._dragStartX=event.pageX;this._dragStartY=event.pageY;return true;}
_dragging(event){const dx=event.pageX-this._dragStartX;const dy=event.pageY-this._dragStartY;this._maxDragOffset=Math.max(this._maxDragOffset,Math.sqrt(dx*dx+dy*dy));}
_endDragging(event){this._updateHighlight();}
_timelineData(){if(!this._dataProvider){return null;}
const timelineData=this._dataProvider.timelineData();if(timelineData!==this._rawTimelineData||timelineData.entryStartTimes.length!==this._rawTimelineDataLength){this._processTimelineData(timelineData);}
return this._rawTimelineData;}
_revealEntry(entryIndex){const timelineData=this._timelineData();if(!timelineData){return;}
const timeLeft=this._chartViewport.windowLeftTime();const timeRight=this._chartViewport.windowRightTime();const entryStartTime=timelineData.entryStartTimes[entryIndex];const entryTotalTime=timelineData.entryTotalTimes[entryIndex];const entryEndTime=entryStartTime+entryTotalTime;let minEntryTimeWindow=Math.min(entryTotalTime,timeRight-timeLeft);const level=timelineData.entryLevels[entryIndex];this._chartViewport.setScrollOffset(this._levelToOffset(level),this._levelHeight(level));const minVisibleWidthPx=30;const futurePixelToTime=(timeRight-timeLeft)/this._offsetWidth;minEntryTimeWindow=Math.max(minEntryTimeWindow,futurePixelToTime*minVisibleWidthPx);if(timeLeft>entryEndTime){const delta=timeLeft-entryEndTime+minEntryTimeWindow;this.windowChanged(timeLeft-delta,timeRight-delta,true);}else if(timeRight<entryStartTime){const delta=entryStartTime-timeRight+minEntryTimeWindow;this.windowChanged(timeLeft+delta,timeRight+delta,true);}}
setWindowTimes(startTime,endTime,animate){this._chartViewport.setWindowTimes(startTime,endTime,animate);this._updateHighlight();}
_onMouseMove(event){this._lastMouseOffsetX=event.offsetX;this._lastMouseOffsetY=event.offsetY;if(!this._enabled()){return;}
if(this._chartViewport.isDragging()){return;}
if(this._coordinatesToGroupIndex(event.offsetX,event.offsetY,true)>=0){this.hideHighlight();this._viewportElement.style.cursor='pointer';return;}
this._updateHighlight();}
_updateHighlight(){const entryIndex=this._coordinatesToEntryIndex(this._lastMouseOffsetX,this._lastMouseOffsetY);if(entryIndex===-1){this.hideHighlight();const group=this._coordinatesToGroupIndex(this._lastMouseOffsetX,this._lastMouseOffsetY,false);if(group>=0&&this._rawTimelineData.groups[group].selectable){this._viewportElement.style.cursor='pointer';}else{this._viewportElement.style.cursor='default';}
return;}
if(this._chartViewport.isDragging()){return;}
this._updatePopover(entryIndex);this._viewportElement.style.cursor=this._dataProvider.canJumpToEntry(entryIndex)?'pointer':'default';this.highlightEntry(entryIndex);}
_onMouseOut(){this._lastMouseOffsetX=-1;this._lastMouseOffsetY=-1;this.hideHighlight();}
_updatePopover(entryIndex){if(entryIndex===this._highlightedEntryIndex){this._updatePopoverOffset();return;}
this._entryInfo.removeChildren();const popoverElement=this._dataProvider.prepareHighlightedEntryInfo(entryIndex);if(popoverElement){this._entryInfo.appendChild(popoverElement);this._updatePopoverOffset();}}
_updatePopoverOffset(){const mouseX=this._lastMouseOffsetX;const mouseY=this._lastMouseOffsetY;const parentWidth=this._entryInfo.parentElement.clientWidth;const parentHeight=this._entryInfo.parentElement.clientHeight;const infoWidth=this._entryInfo.clientWidth;const infoHeight=this._entryInfo.clientHeight;const offsetX=10;const offsetY=6;let x;let y;for(let quadrant=0;quadrant<4;++quadrant){const dx=quadrant&2?-offsetX-infoWidth:offsetX;const dy=quadrant&1?-offsetY-infoHeight:offsetY;x=Number.constrain(mouseX+dx,0,parentWidth-infoWidth);y=Number.constrain(mouseY+dy,0,parentHeight-infoHeight);if(x>=mouseX||mouseX>=x+infoWidth||y>=mouseY||mouseY>=y+infoHeight){break;}}
this._entryInfo.style.left=x+'px';this._entryInfo.style.top=y+'px';}
_onClick(event){this.focus();const clickThreshold=5;if(this._maxDragOffset>clickThreshold){return;}
this._selectGroup(this._coordinatesToGroupIndex(event.offsetX,event.offsetY,false));this._toggleGroupExpand(this._coordinatesToGroupIndex(event.offsetX,event.offsetY,true));const timelineData=this._timelineData();if(event.shiftKey&&this._highlightedEntryIndex!==-1&&timelineData){const start=timelineData.entryStartTimes[this._highlightedEntryIndex];const end=start+timelineData.entryTotalTimes[this._highlightedEntryIndex];this._chartViewport.setRangeSelection(start,end);}else{this._chartViewport.onClick(event);this.dispatchEventToListeners(Events.EntryInvoked,this._highlightedEntryIndex);}}
_selectGroup(groupIndex){if(groupIndex<0||this._selectedGroup===groupIndex){return;}
const groups=this._rawTimelineData.groups;this._keyboardFocusedGroup=groupIndex;this._scrollGroupIntoView(groupIndex);const groupName=groups[groupIndex].name;if(!groups[groupIndex].selectable){this._deselectAllGroups();UI.ARIAUtils.alert(ls`${groupName} hovered`,this._canvas);}else{this._selectedGroup=groupIndex;this._flameChartDelegate.updateSelectedGroup(this,groups[groupIndex]);this._resetCanvas();this._draw();UI.ARIAUtils.alert(ls`${groupName} selected`,this._canvas);}}
_deselectAllGroups(){this._selectedGroup=-1;this._flameChartDelegate.updateSelectedGroup(this,null);this._resetCanvas();this._draw();}
_deselectAllEntries(){this._selectedEntryIndex=-1;this._resetCanvas();this._draw();}
_isGroupFocused(index){return index===this._selectedGroup||index===this._keyboardFocusedGroup;}
_scrollGroupIntoView(index){if(index<0){return;}
const groups=this._rawTimelineData.groups;const groupOffsets=this._groupOffsets;const groupTop=groupOffsets[index];let nextOffset=groupOffsets[index+1];if(index===groups.length-1){nextOffset+=groups[index].style.padding;}
const scrollTop=index===0?0:groupTop;const scrollHeight=Math.min(nextOffset-scrollTop,this._chartViewport.chartHeight());this._chartViewport.setScrollOffset(scrollTop,scrollHeight);}
_toggleGroupExpand(groupIndex){if(groupIndex<0||!this._isGroupCollapsible(groupIndex)){return;}
this._expandGroup(groupIndex,!this._rawTimelineData.groups[groupIndex].expanded);}
_expandGroup(groupIndex,setExpanded=true,propagatedExpand=false){if(groupIndex<0||!this._isGroupCollapsible(groupIndex)){return;}
const groups=this._rawTimelineData.groups;const group=groups[groupIndex];group.expanded=setExpanded;this._groupExpansionState[group.name]=group.expanded;if(this._groupExpansionSetting){this._groupExpansionSetting.set(this._groupExpansionState);}
this._updateLevelPositions();this._updateHighlight();if(!group.expanded){const timelineData=this._timelineData();const level=timelineData.entryLevels[this._selectedEntryIndex];if(this._selectedEntryIndex>=0&&level>=group.startLevel&&(groupIndex>=groups.length-1||groups[groupIndex+1].startLevel>level)){this._selectedEntryIndex=-1;}}
this._updateHeight();this._resetCanvas();this._draw();this._scrollGroupIntoView(groupIndex);if(!propagatedExpand){const groupName=groups[groupIndex].name;const content=group.expanded?ls`${groupName} expanded`:ls`${groupName} collapsed`;UI.ARIAUtils.alert(content,this._canvas);}}
_onKeyDown(e){if(!UI.KeyboardShortcut.hasNoModifiers(e)||!this._timelineData()){return;}
const eventHandled=this._handleSelectionNavigation(e);if(!eventHandled&&this._rawTimelineData&&this._rawTimelineData.groups){this._handleKeyboardGroupNavigation(e);}}
_handleKeyboardGroupNavigation(e){let handled=false;let entrySelected=false;if(e.code==='ArrowUp'){handled=this._selectPreviousGroup();}else if(e.code==='ArrowDown'){handled=this._selectNextGroup();}else if(e.code==='ArrowLeft'){if(this._keyboardFocusedGroup>=0){this._expandGroup(this._keyboardFocusedGroup,false);handled=true;}}else if(e.code==='ArrowRight'){if(this._keyboardFocusedGroup>=0){this._expandGroup(this._keyboardFocusedGroup,true);this._selectFirstChild();handled=true;}}else if(isEnterKey(e)){entrySelected=this._selectFirstEntryInCurrentGroup();handled=entrySelected;}
if(handled&&!entrySelected){this._deselectAllEntries();}
if(handled){e.consume(true);}}
_selectFirstEntryInCurrentGroup(){const allGroups=this._rawTimelineData.groups;if(this._keyboardFocusedGroup<0){return false;}
const group=allGroups[this._keyboardFocusedGroup];const startLevelInGroup=group.startLevel;if(startLevelInGroup<0){return false;}
if(this._keyboardFocusedGroup<allGroups.length-1&&allGroups[this._keyboardFocusedGroup+1].startLevel===startLevelInGroup){return false;}
const firstEntryIndex=this._timelineLevels[startLevelInGroup][0];this._expandGroup(this._keyboardFocusedGroup,true);this.setSelectedEntry(firstEntryIndex);return true;}
_selectPreviousGroup(){if(this._keyboardFocusedGroup<=0){return false;}
const groupIndexToSelect=this._getGroupIndexToSelect(-1);this._selectGroup(groupIndexToSelect);return true;}
_selectNextGroup(){if(this._keyboardFocusedGroup>=this._rawTimelineData.groups.length-1){return false;}
const groupIndexToSelect=this._getGroupIndexToSelect(1);this._selectGroup(groupIndexToSelect);return true;}
_getGroupIndexToSelect(offset){const allGroups=this._rawTimelineData.groups;let groupIndexToSelect=this._keyboardFocusedGroup;let groupName,groupWithSubNestingLevel;do{groupIndexToSelect+=offset;groupName=this._rawTimelineData.groups[groupIndexToSelect].name;groupWithSubNestingLevel=this._keyboardFocusedGroup!==-1&&allGroups[groupIndexToSelect].style.nestingLevel>allGroups[this._keyboardFocusedGroup].style.nestingLevel;}while(groupIndexToSelect>0&&groupIndexToSelect<allGroups.length-1&&(!groupName||groupWithSubNestingLevel));return groupIndexToSelect;}
_selectFirstChild(){const allGroups=this._rawTimelineData.groups;if(this._keyboardFocusedGroup<0||this._keyboardFocusedGroup>=allGroups.length-1){return;}
const groupIndexToSelect=this._keyboardFocusedGroup+1;if(allGroups[groupIndexToSelect].style.nestingLevel>allGroups[this._keyboardFocusedGroup].style.nestingLevel){this._selectGroup(groupIndexToSelect);}}
_handleSelectionNavigation(e){if(this._selectedEntryIndex===-1){return false;}
const timelineData=this._timelineData();if(!timelineData){return false;}
function timeComparator(time,entryIndex){return time-timelineData.entryStartTimes[entryIndex];}
function entriesIntersect(entry1,entry2){const start1=timelineData.entryStartTimes[entry1];const start2=timelineData.entryStartTimes[entry2];const end1=start1+timelineData.entryTotalTimes[entry1];const end2=start2+timelineData.entryTotalTimes[entry2];return start1<end2&&start2<end1;}
const keys=UI.KeyboardShortcut.Keys;if(e.keyCode===keys.Left.code||e.keyCode===keys.Right.code){const level=timelineData.entryLevels[this._selectedEntryIndex];const levelIndexes=this._timelineLevels[level];let indexOnLevel=levelIndexes.lowerBound(this._selectedEntryIndex);indexOnLevel+=e.keyCode===keys.Left.code?-1:1;e.consume(true);if(indexOnLevel>=0&&indexOnLevel<levelIndexes.length){this.dispatchEventToListeners(Events.EntrySelected,levelIndexes[indexOnLevel]);}
return true;}
if(e.keyCode===keys.Up.code||e.keyCode===keys.Down.code){let level=timelineData.entryLevels[this._selectedEntryIndex];level+=e.keyCode===keys.Up.code?-1:1;if(level<0||level>=this._timelineLevels.length){this._deselectAllEntries();e.consume(true);return true;}
const entryTime=timelineData.entryStartTimes[this._selectedEntryIndex]+
timelineData.entryTotalTimes[this._selectedEntryIndex]/2;const levelIndexes=this._timelineLevels[level];let indexOnLevel=levelIndexes.upperBound(entryTime,timeComparator)-1;if(!entriesIntersect(this._selectedEntryIndex,levelIndexes[indexOnLevel])){++indexOnLevel;if(indexOnLevel>=levelIndexes.length||!entriesIntersect(this._selectedEntryIndex,levelIndexes[indexOnLevel])){if(e.code==='ArrowDown'){return false;}
this._deselectAllEntries();e.consume(true);return true;}}
e.consume(true);this.dispatchEventToListeners(Events.EntrySelected,levelIndexes[indexOnLevel]);return true;}
if(isEnterKey(e)){e.consume(true);this.dispatchEventToListeners(Events.EntryInvoked,this._selectedEntryIndex);return true;}
return false;}
_coordinatesToEntryIndex(x,y){if(x<0||y<0){return-1;}
const timelineData=this._timelineData();if(!timelineData){return-1;}
y+=this._chartViewport.scrollOffset();const cursorLevel=this._visibleLevelOffsets.upperBound(y)-1;if(cursorLevel<0||!this._visibleLevels[cursorLevel]){return-1;}
const offsetFromLevel=y-this._visibleLevelOffsets[cursorLevel];if(offsetFromLevel>this._levelHeight(cursorLevel)){return-1;}
for(const[index,pos]of this._markerPositions){if(timelineData.entryLevels[index]!==cursorLevel){continue;}
if(pos.x<=x&&x<pos.x+pos.width){return(index);}}
const entryStartTimes=timelineData.entryStartTimes;const entriesOnLevel=this._timelineLevels[cursorLevel];if(!entriesOnLevel||!entriesOnLevel.length){return-1;}
const cursorTime=this._chartViewport.pixelToTime(x);const indexOnLevel=Math.max(entriesOnLevel.upperBound(cursorTime,(time,entryIndex)=>time-entryStartTimes[entryIndex])-1,0);function checkEntryHit(entryIndex){if(entryIndex===undefined){return false;}
const startTime=entryStartTimes[entryIndex];const duration=timelineData.entryTotalTimes[entryIndex];const startX=this._chartViewport.timeToPosition(startTime);const endX=this._chartViewport.timeToPosition(startTime+duration);const barThresholdPx=3;return startX-barThresholdPx<x&&x<endX+barThresholdPx;}
let entryIndex=entriesOnLevel[indexOnLevel];if(checkEntryHit.call(this,entryIndex)){return entryIndex;}
entryIndex=entriesOnLevel[indexOnLevel+1];if(checkEntryHit.call(this,entryIndex)){return entryIndex;}
return-1;}
_coordinatesToGroupIndex(x,y,headerOnly){if(x<0||y<0){return-1;}
y+=this._chartViewport.scrollOffset();const groups=this._rawTimelineData.groups||[];const group=this._groupOffsets.upperBound(y)-1;if(group<0||group>=groups.length){return-1;}
const height=headerOnly?groups[group].style.height:this._groupOffsets[group+1]-this._groupOffsets[group];if(y-this._groupOffsets[group]>=height){return-1;}
if(!headerOnly){return group;}
const context=(this._canvas.getContext('2d'));context.save();context.font=groups[group].style.font;const right=this._headerLeftPadding+this._labelWidthForGroup(context,groups[group]);context.restore();if(x>right){return-1;}
return group;}
_markerIndexAtPosition(x){const markers=this._timelineData().markers;if(!markers){return-1;}
const accurracyOffsetPx=4;const time=this._chartViewport.pixelToTime(x);const leftTime=this._chartViewport.pixelToTime(x-accurracyOffsetPx);const rightTime=this._chartViewport.pixelToTime(x+accurracyOffsetPx);const left=this._markerIndexBeforeTime(leftTime);let markerIndex=-1;let distance=Infinity;for(let i=left;i<markers.length&&markers[i].startTime()<rightTime;i++){const nextDistance=Math.abs(markers[i].startTime()-time);if(nextDistance<distance){markerIndex=i;distance=nextDistance;}}
return markerIndex;}
_markerIndexBeforeTime(time){return this._timelineData().markers.lowerBound(time,(markerTimestamp,marker)=>markerTimestamp-marker.startTime());}
_draw(){const timelineData=this._timelineData();if(!timelineData){return;}
const width=this._offsetWidth;const height=this._offsetHeight;const context=(this._canvas.getContext('2d'));context.save();const ratio=window.devicePixelRatio;const top=this._chartViewport.scrollOffset();context.scale(ratio,ratio);context.fillStyle='rgba(0, 0, 0, 0)';context.fillRect(0,0,width,height);context.translate(0,-top);const defaultFont='11px '+Host.fontFamily();context.font=defaultFont;const entryTotalTimes=timelineData.entryTotalTimes;const entryStartTimes=timelineData.entryStartTimes;const entryLevels=timelineData.entryLevels;const timeToPixel=this._chartViewport.timeToPixel();const titleIndices=[];const markerIndices=[];const textPadding=this._textPadding;const minTextWidth=2*textPadding+UI.measureTextWidth(context,'\u2026');const minTextWidthDuration=this._chartViewport.pixelToTimeOffset(minTextWidth);const minVisibleBarLevel=Math.max(this._visibleLevelOffsets.upperBound(top)-1,0);this._markerPositions.clear();const colorBuckets=new Map();for(let level=minVisibleBarLevel;level<this._dataProvider.maxStackDepth();++level){if(this._levelToOffset(level)>top+height){break;}
if(!this._visibleLevels[level]){continue;}
const levelIndexes=this._timelineLevels[level];const rightIndexOnLevel=levelIndexes.lowerBound(this._chartViewport.windowRightTime(),(time,entryIndex)=>time-entryStartTimes[entryIndex])-
1;let lastDrawOffset=Infinity;for(let entryIndexOnLevel=rightIndexOnLevel;entryIndexOnLevel>=0;--entryIndexOnLevel){const entryIndex=levelIndexes[entryIndexOnLevel];const duration=entryTotalTimes[entryIndex];if(isNaN(duration)){markerIndices.push(entryIndex);continue;}
if(duration>=minTextWidthDuration||this._forceDecorationCache[entryIndex]){titleIndices.push(entryIndex);}
const entryStartTime=entryStartTimes[entryIndex];const entryOffsetRight=entryStartTime+duration;if(entryOffsetRight<=this._chartViewport.windowLeftTime()){break;}
if(this._useWebGL){continue;}
const barX=this._timeToPositionClipped(entryStartTime);if(barX>=lastDrawOffset){continue;}
lastDrawOffset=barX;const color=this._entryColorsCache[entryIndex];let bucket=colorBuckets.get(color);if(!bucket){bucket=[];colorBuckets.set(color,bucket);}
bucket.push(entryIndex);}}
if(this._useWebGL){this._drawGL();}else{context.save();this._forEachGroupInViewport((offset,index,group,isFirst,groupHeight)=>{if(this._isGroupFocused(index)){context.fillStyle=this._selectedGroupBackroundColor;context.fillRect(0,offset,width,groupHeight-group.style.padding);}});context.restore();for(const[color,indexes]of colorBuckets){context.beginPath();for(let i=0;i<indexes.length;++i){const entryIndex=indexes[i];const duration=entryTotalTimes[entryIndex];if(isNaN(duration)){continue;}
const entryStartTime=entryStartTimes[entryIndex];const barX=this._timeToPositionClipped(entryStartTime);const barLevel=entryLevels[entryIndex];const barHeight=this._levelHeight(barLevel);const barY=this._levelToOffset(barLevel);const barRight=this._timeToPositionClipped(entryStartTime+duration);const barWidth=Math.max(barRight-barX,1);context.rect(barX,barY,barWidth-0.4,barHeight-1);}
context.fillStyle=color;context.fill();}}
context.textBaseline='alphabetic';context.beginPath();let lastMarkerLevel=-1;let lastMarkerX=-Infinity;for(let m=markerIndices.length-1;m>=0;--m){const entryIndex=markerIndices[m];const title=this._dataProvider.entryTitle(entryIndex);if(!title){continue;}
const entryStartTime=entryStartTimes[entryIndex];const level=entryLevels[entryIndex];if(lastMarkerLevel!==level){lastMarkerX=-Infinity;}
const x=Math.max(this._chartViewport.timeToPosition(entryStartTime),lastMarkerX);const y=this._levelToOffset(level);const h=this._levelHeight(level);const padding=4;const width=Math.ceil(UI.measureTextWidth(context,title))+2*padding;lastMarkerX=x+width+1;lastMarkerLevel=level;this._markerPositions.set(entryIndex,{x,width});context.fillStyle=this._dataProvider.entryColor(entryIndex);context.fillRect(x,y,width,h-1);context.fillStyle='white';context.fillText(title,x+padding,y+h-this._textBaseline);}
context.strokeStyle='rgba(0, 0, 0, 0.2)';context.stroke();for(let i=0;i<titleIndices.length;++i){const entryIndex=titleIndices[i];const entryStartTime=entryStartTimes[entryIndex];const barX=this._timeToPositionClipped(entryStartTime);const barRight=Math.min(this._timeToPositionClipped(entryStartTime+entryTotalTimes[entryIndex]),width)+1;const barWidth=barRight-barX;const barLevel=entryLevels[entryIndex];const barY=this._levelToOffset(barLevel);let text=this._dataProvider.entryTitle(entryIndex);if(text&&text.length){context.font=this._dataProvider.entryFont(entryIndex)||defaultFont;text=UI.trimTextMiddle(context,text,barWidth-2*textPadding);}
const unclippedBarX=this._chartViewport.timeToPosition(entryStartTime);const barHeight=this._levelHeight(barLevel);if(this._dataProvider.decorateEntry(entryIndex,context,text,barX,barY,barWidth,barHeight,unclippedBarX,timeToPixel)){continue;}
if(!text||!text.length){continue;}
context.fillStyle=this._dataProvider.textColor(entryIndex);context.fillText(text,barX+textPadding,barY+barHeight-this._textBaseline);}
context.restore();this._drawGroupHeaders(width,height);this._drawFlowEvents(context,width,height);this._drawMarkers();const dividersData=TimelineGrid.calculateGridOffsets(this);TimelineGrid.drawCanvasGrid(context,dividersData);if(this._rulerEnabled){TimelineGrid.drawCanvasHeaders(context,dividersData,time=>this.formatValue(time,dividersData.precision),3,HeaderHeight);}
this._updateElementPosition(this._highlightElement,this._highlightedEntryIndex);this._updateElementPosition(this._selectedElement,this._selectedEntryIndex);this._updateMarkerHighlight();}
_initWebGL(){const gl=(this._canvasGL.getContext('webgl'));if(!gl){console.error('Failed to obtain WebGL context.');this._useWebGL=false;return;}
const vertexShaderSource=`
      attribute vec2 aVertexPosition;
      attribute float aVertexColor;

      uniform vec2 uScalingFactor;
      uniform vec2 uShiftVector;

      varying mediump vec2 vPalettePosition;

      void main() {
        vec2 shiftedPosition = aVertexPosition - uShiftVector;
        gl_Position = vec4(shiftedPosition * uScalingFactor + vec2(-1.0, 1.0), 0.0, 1.0);
        vPalettePosition = vec2(aVertexColor, 0.5);
      }`;const fragmentShaderSource=`
      varying mediump vec2 vPalettePosition;
      uniform sampler2D uSampler;

      void main() {
        gl_FragColor = texture2D(uSampler, vPalettePosition);
      }`;function loadShader(gl,type,source){const shader=gl.createShader(type);gl.shaderSource(shader,source);gl.compileShader(shader);if(gl.getShaderParameter(shader,gl.COMPILE_STATUS)){return shader;}
console.error('Shader compile error: '+gl.getShaderInfoLog(shader));gl.deleteShader(shader);return null;}
const vertexShader=loadShader(gl,gl.VERTEX_SHADER,vertexShaderSource);const fragmentShader=loadShader(gl,gl.FRAGMENT_SHADER,fragmentShaderSource);const shaderProgram=gl.createProgram();gl.attachShader(shaderProgram,vertexShader);gl.attachShader(shaderProgram,fragmentShader);gl.linkProgram(shaderProgram);if(gl.getProgramParameter(shaderProgram,gl.LINK_STATUS)){this._shaderProgram=shaderProgram;gl.useProgram(shaderProgram);}else{console.error('Unable to initialize the shader program: '+gl.getProgramInfoLog(shaderProgram));this._shaderProgram=null;}
this._vertexBuffer=gl.createBuffer();this._colorBuffer=gl.createBuffer();this._uScalingFactor=gl.getUniformLocation(shaderProgram,'uScalingFactor');this._uShiftVector=gl.getUniformLocation(shaderProgram,'uShiftVector');const uSampler=gl.getUniformLocation(shaderProgram,'uSampler');gl.uniform1i(uSampler,0);this._aVertexPosition=gl.getAttribLocation(this._shaderProgram,'aVertexPosition');this._aVertexColor=gl.getAttribLocation(this._shaderProgram,'aVertexColor');gl.enableVertexAttribArray(this._aVertexPosition);gl.enableVertexAttribArray(this._aVertexColor);}
_setupGLGeometry(){const gl=(this._canvasGL.getContext('webgl'));if(!gl){return;}
const timelineData=this._timelineData();if(!timelineData){return;}
const entryTotalTimes=timelineData.entryTotalTimes;const entryStartTimes=timelineData.entryStartTimes;const entryLevels=timelineData.entryLevels;const verticesPerBar=6;const vertexArray=new Float32Array(entryTotalTimes.length*verticesPerBar*2);let colorArray=new Uint8Array(entryTotalTimes.length*verticesPerBar);let vertex=0;const parsedColorCache=new Map();const colors=[];const collapsedOverviewLevels=new Array(this._visibleLevels.length);const groups=this._rawTimelineData.groups||[];this._forEachGroup((offset,index,group)=>{if(group.style.useFirstLineForOverview||!this._isGroupCollapsible(index)||group.expanded){return;}
let nextGroup=index+1;while(nextGroup<groups.length&&groups[nextGroup].style.nestingLevel>group.style.nestingLevel){++nextGroup;}
const endLevel=nextGroup<groups.length?groups[nextGroup].startLevel:this._dataProvider.maxStackDepth();for(let i=group.startLevel;i<endLevel;++i){collapsedOverviewLevels[i]=offset;}});for(let i=0;i<entryTotalTimes.length;++i){const level=entryLevels[i];const collapsedGroupOffset=collapsedOverviewLevels[level];if(!this._visibleLevels[level]&&!collapsedGroupOffset){continue;}
const color=this._entryColorsCache[i];if(!color){continue;}
let colorIndex=parsedColorCache.get(color);if(colorIndex===undefined){const rgba=Common.Color.parse(color).canonicalRGBA();rgba[3]=Math.round(rgba[3]*255);colorIndex=colors.length/4;colors.push(...rgba);if(colorIndex===256){colorArray=new Uint16Array(colorArray);}
parsedColorCache.set(color,colorIndex);}
for(let j=0;j<verticesPerBar;++j){colorArray[vertex+j]=colorIndex;}
const vpos=vertex*2;const x0=entryStartTimes[i]-this._minimumBoundary;const x1=x0+entryTotalTimes[i];const y0=collapsedGroupOffset||this._levelToOffset(level);const y1=y0+this._levelHeight(level)-1;vertexArray[vpos+0]=x0;vertexArray[vpos+1]=y0;vertexArray[vpos+2]=x1;vertexArray[vpos+3]=y0;vertexArray[vpos+4]=x0;vertexArray[vpos+5]=y1;vertexArray[vpos+6]=x0;vertexArray[vpos+7]=y1;vertexArray[vpos+8]=x1;vertexArray[vpos+9]=y0;vertexArray[vpos+10]=x1;vertexArray[vpos+11]=y1;vertex+=verticesPerBar;}
this._vertexCount=vertex;const paletteTexture=gl.createTexture();gl.bindTexture(gl.TEXTURE_2D,paletteTexture);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST);gl.activeTexture(gl.TEXTURE0);const numColors=colors.length/4;const useShortForColors=numColors>=256;const width=!useShortForColors?256:Math.min(1<<16,gl.getParameter(gl.MAX_TEXTURE_SIZE));console.assert(numColors<=width,'Too many colors');const height=1;const colorIndexType=useShortForColors?gl.UNSIGNED_SHORT:gl.UNSIGNED_BYTE;if(useShortForColors){const factor=(1<<16)/width;for(let i=0;i<vertex;++i){colorArray[i]*=factor;}}
const pixels=new Uint8Array(width*4);pixels.set(colors);gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,width,height,0,gl.RGBA,gl.UNSIGNED_BYTE,pixels);gl.bindBuffer(gl.ARRAY_BUFFER,this._vertexBuffer);gl.bufferData(gl.ARRAY_BUFFER,vertexArray,gl.STATIC_DRAW);gl.vertexAttribPointer(this._aVertexPosition,2,gl.FLOAT,false,0,0);gl.bindBuffer(gl.ARRAY_BUFFER,this._colorBuffer);gl.bufferData(gl.ARRAY_BUFFER,colorArray,gl.STATIC_DRAW);gl.vertexAttribPointer(this._aVertexColor,1,colorIndexType,true,0,0);}
_drawGL(){const gl=(this._canvasGL.getContext('webgl'));if(!gl){return;}
const timelineData=this._timelineData();if(!timelineData){return;}
if(!this._prevTimelineData||timelineData.entryTotalTimes!==this._prevTimelineData.entryTotalTimes){this._prevTimelineData=timelineData;this._setupGLGeometry();}
gl.viewport(0,0,this._canvasGL.width,this._canvasGL.height);if(!this._vertexCount){return;}
const viewportScale=[2.0/this.boundarySpan(),-2.0*window.devicePixelRatio/this._canvasGL.height];const viewportShift=[this.minimumBoundary()-this.zeroTime(),this._chartViewport.scrollOffset()];gl.uniform2fv(this._uScalingFactor,viewportScale);gl.uniform2fv(this._uShiftVector,viewportShift);gl.drawArrays(gl.TRIANGLES,0,this._vertexCount);}
_drawGroupHeaders(width,height){const context=(this._canvas.getContext('2d'));const top=this._chartViewport.scrollOffset();const ratio=window.devicePixelRatio;const groups=this._rawTimelineData.groups||[];if(!groups.length){return;}
const groupOffsets=this._groupOffsets;const lastGroupOffset=Array.prototype.peekLast.call(groupOffsets);const colorUsage=UI.ThemeSupport.ColorUsage;context.save();context.scale(ratio,ratio);context.translate(0,-top);const defaultFont='11px '+Host.fontFamily();context.font=defaultFont;context.fillStyle=self.UI.themeSupport.patchColorText('#fff',colorUsage.Background);this._forEachGroupInViewport((offset,index,group)=>{const paddingHeight=group.style.padding;if(paddingHeight<5){return;}
context.fillRect(0,offset-paddingHeight+2,width,paddingHeight-4);});if(groups.length&&lastGroupOffset<top+height){context.fillRect(0,lastGroupOffset+2,width,top+height-lastGroupOffset);}
context.strokeStyle=self.UI.themeSupport.patchColorText('#eee',colorUsage.Background);context.beginPath();this._forEachGroupInViewport((offset,index,group,isFirst)=>{if(isFirst||group.style.padding<4){return;}
hLine(offset-2.5);});hLine(lastGroupOffset+1.5);context.stroke();this._forEachGroupInViewport((offset,index,group)=>{if(group.style.useFirstLineForOverview){return;}
if(!this._isGroupCollapsible(index)||group.expanded){if(!group.style.shareHeaderLine&&this._isGroupFocused(index)){context.fillStyle=group.style.backgroundColor;context.fillRect(0,offset,width,group.style.height);}
return;}
if(this._useWebGL){return;}
let nextGroup=index+1;while(nextGroup<groups.length&&groups[nextGroup].style.nestingLevel>group.style.nestingLevel){nextGroup++;}
const endLevel=nextGroup<groups.length?groups[nextGroup].startLevel:this._dataProvider.maxStackDepth();this._drawCollapsedOverviewForGroup(group,offset,endLevel);});context.save();this._forEachGroupInViewport((offset,index,group)=>{context.font=group.style.font;if(this._isGroupCollapsible(index)&&!group.expanded||group.style.shareHeaderLine){const width=this._labelWidthForGroup(context,group)+2;if(this._isGroupFocused(index)){context.fillStyle=this._selectedGroupBackroundColor;}else{context.fillStyle=Common.Color.parse(group.style.backgroundColor).setAlpha(0.8).asString(null);}
context.fillRect(this._headerLeftPadding-this._headerLabelXPadding,offset+this._headerLabelYPadding,width,group.style.height-2*this._headerLabelYPadding);}
context.fillStyle=group.style.color;context.fillText(group.name,Math.floor(this._expansionArrowIndent*(group.style.nestingLevel+1)+this._arrowSide),offset+group.style.height-this._textBaseline);});context.restore();context.fillStyle=self.UI.themeSupport.patchColorText('#6e6e6e',colorUsage.Foreground);context.beginPath();this._forEachGroupInViewport((offset,index,group)=>{if(this._isGroupCollapsible(index)){drawExpansionArrow.call(this,this._expansionArrowIndent*(group.style.nestingLevel+1),offset+group.style.height-this._textBaseline-this._arrowSide/2,!!group.expanded);}});context.fill();context.strokeStyle=self.UI.themeSupport.patchColorText('#ddd',colorUsage.Background);context.beginPath();context.stroke();this._forEachGroupInViewport((offset,index,group,isFirst,groupHeight)=>{if(this._isGroupFocused(index)){const lineWidth=2;const bracketLength=10;context.fillStyle=this._selectedGroupBorderColor;context.fillRect(0,offset-lineWidth,lineWidth,groupHeight-group.style.padding+2*lineWidth);context.fillRect(0,offset-lineWidth,bracketLength,lineWidth);context.fillRect(0,offset+groupHeight-group.style.padding,bracketLength,lineWidth);}});context.restore();function hLine(y){context.moveTo(0,y);context.lineTo(width,y);}
function drawExpansionArrow(x,y,expanded){const arrowHeight=this._arrowSide*Math.sqrt(3)/2;const arrowCenterOffset=Math.round(arrowHeight/2);context.save();context.translate(x,y);context.rotate(expanded?Math.PI/2:0);context.moveTo(-arrowCenterOffset,-this._arrowSide/2);context.lineTo(-arrowCenterOffset,this._arrowSide/2);context.lineTo(arrowHeight-arrowCenterOffset,0);context.restore();}}
_forEachGroup(callback){const groups=this._rawTimelineData.groups||[];if(!groups.length){return;}
const groupOffsets=this._groupOffsets;const groupStack=[{nestingLevel:-1,visible:true}];for(let i=0;i<groups.length;++i){const groupTop=groupOffsets[i];const group=groups[i];let firstGroup=true;while(groupStack.peekLast().nestingLevel>=group.style.nestingLevel){groupStack.pop();firstGroup=false;}
const parentGroupVisible=groupStack.peekLast().visible;const thisGroupVisible=parentGroupVisible&&(!this._isGroupCollapsible(i)||group.expanded);groupStack.push({nestingLevel:group.style.nestingLevel,visible:thisGroupVisible});const nextOffset=i===groups.length-1?groupOffsets[i+1]+group.style.padding:groupOffsets[i+1];if(!parentGroupVisible){continue;}
callback(groupTop,i,group,firstGroup,nextOffset-groupTop);}}
_forEachGroupInViewport(callback){const top=this._chartViewport.scrollOffset();this._forEachGroup((groupTop,index,group,firstGroup,height)=>{if(groupTop-group.style.padding>top+this._offsetHeight){return;}
if(groupTop+height<top){return;}
callback(groupTop,index,group,firstGroup,height);});}
_labelWidthForGroup(context,group){return UI.measureTextWidth(context,group.name)+this._expansionArrowIndent*(group.style.nestingLevel+1)+
2*this._headerLabelXPadding;}
_drawCollapsedOverviewForGroup(group,y,endLevel){const range=new Common.SegmentedRange(mergeCallback);const timeWindowLeft=this._chartViewport.windowLeftTime();const timeWindowRight=this._chartViewport.windowRightTime();const context=(this._canvas.getContext('2d'));const barHeight=group.style.height;const entryStartTimes=this._rawTimelineData.entryStartTimes;const entryTotalTimes=this._rawTimelineData.entryTotalTimes;const timeToPixel=this._chartViewport.timeToPixel();for(let level=group.startLevel;level<endLevel;++level){const levelIndexes=this._timelineLevels[level];const rightIndexOnLevel=levelIndexes.lowerBound(timeWindowRight,(time,entryIndex)=>time-entryStartTimes[entryIndex])-1;let lastDrawOffset=Infinity;for(let entryIndexOnLevel=rightIndexOnLevel;entryIndexOnLevel>=0;--entryIndexOnLevel){const entryIndex=levelIndexes[entryIndexOnLevel];const entryStartTime=entryStartTimes[entryIndex];const barX=this._timeToPositionClipped(entryStartTime);const entryEndTime=entryStartTime+entryTotalTimes[entryIndex];if(isNaN(entryEndTime)||barX>=lastDrawOffset){continue;}
if(entryEndTime<=timeWindowLeft){break;}
lastDrawOffset=barX;const color=this._entryColorsCache[entryIndex];const endBarX=this._timeToPositionClipped(entryEndTime);if(group.style.useDecoratorsForOverview&&this._dataProvider.forceDecoration(entryIndex)){const unclippedBarX=this._chartViewport.timeToPosition(entryStartTime);const barWidth=endBarX-barX;context.beginPath();context.fillStyle=color;context.fillRect(barX,y,barWidth,barHeight-1);this._dataProvider.decorateEntry(entryIndex,context,'',barX,y,barWidth,barHeight,unclippedBarX,timeToPixel);continue;}
range.append(new Common.Segment(barX,endBarX,color));}}
const segments=range.segments().slice().sort((a,b)=>a.data.localeCompare(b.data));let lastColor;context.beginPath();for(let i=0;i<segments.length;++i){const segment=segments[i];if(lastColor!==segments[i].data){context.fill();context.beginPath();lastColor=segments[i].data;context.fillStyle=lastColor;}
context.rect(segment.begin,y,segment.end-segment.begin,barHeight);}
context.fill();function mergeCallback(a,b){return a.data===b.data&&a.end+0.4>b.end?a:null;}}
_drawFlowEvents(context,width,height){context.save();const ratio=window.devicePixelRatio;const top=this._chartViewport.scrollOffset();const arrowWidth=6;context.scale(ratio,ratio);context.translate(0,-top);context.fillStyle='#7f5050';context.strokeStyle='#7f5050';const td=this._timelineData();const endIndex=td.flowStartTimes.lowerBound(this._chartViewport.windowRightTime());context.lineWidth=0.5;for(let i=0;i<endIndex;++i){if(!td.flowEndTimes[i]||td.flowEndTimes[i]<this._chartViewport.windowLeftTime()){continue;}
const startX=this._chartViewport.timeToPosition(td.flowStartTimes[i]);const endX=this._chartViewport.timeToPosition(td.flowEndTimes[i]);const startLevel=td.flowStartLevels[i];const endLevel=td.flowEndLevels[i];const startY=this._levelToOffset(startLevel)+this._levelHeight(startLevel)/2;const endY=this._levelToOffset(endLevel)+this._levelHeight(endLevel)/2;const segment=Math.min((endX-startX)/4,40);const distanceTime=td.flowEndTimes[i]-td.flowStartTimes[i];const distanceY=(endY-startY)/10;const spread=30;const lineY=distanceTime<1?startY:spread+Math.max(0,startY+distanceY*(i%spread));const p=[];p.push({x:startX,y:startY});p.push({x:startX+arrowWidth,y:startY});p.push({x:startX+segment+2*arrowWidth,y:startY});p.push({x:startX+segment,y:lineY});p.push({x:startX+segment*2,y:lineY});p.push({x:endX-segment*2,y:lineY});p.push({x:endX-segment,y:lineY});p.push({x:endX-segment-2*arrowWidth,y:endY});p.push({x:endX-arrowWidth,y:endY});context.beginPath();context.moveTo(p[0].x,p[0].y);context.lineTo(p[1].x,p[1].y);context.bezierCurveTo(p[2].x,p[2].y,p[3].x,p[3].y,p[4].x,p[4].y);context.lineTo(p[5].x,p[5].y);context.bezierCurveTo(p[6].x,p[6].y,p[7].x,p[7].y,p[8].x,p[8].y);context.stroke();context.beginPath();context.arc(startX,startY,2,-Math.PI/2,Math.PI/2,false);context.fill();context.beginPath();context.moveTo(endX,endY);context.lineTo(endX-arrowWidth,endY-3);context.lineTo(endX-arrowWidth,endY+3);context.fill();}
context.restore();}
_drawMarkers(){const markers=this._timelineData().markers;const left=this._markerIndexBeforeTime(this.minimumBoundary());const rightBoundary=this.maximumBoundary();const timeToPixel=this._chartViewport.timeToPixel();const context=(this._canvas.getContext('2d'));context.save();const ratio=window.devicePixelRatio;context.scale(ratio,ratio);context.translate(0,3);const height=HeaderHeight-1;for(let i=left;i<markers.length;i++){const timestamp=markers[i].startTime();if(timestamp>rightBoundary){break;}
markers[i].draw(context,this._chartViewport.timeToPosition(timestamp),height,timeToPixel);}
context.restore();}
_updateMarkerHighlight(){const element=this._markerHighlighElement;if(element.parentElement){element.remove();}
const markerIndex=this._highlightedMarkerIndex;if(markerIndex===-1){return;}
const marker=this._timelineData().markers[markerIndex];const barX=this._timeToPositionClipped(marker.startTime());element.title=marker.title();const style=element.style;style.left=barX+'px';style.backgroundColor=marker.color();this._viewportElement.appendChild(element);}
_processTimelineData(timelineData){if(!timelineData){this._timelineLevels=null;this._visibleLevelOffsets=null;this._visibleLevels=null;this._groupOffsets=null;this._rawTimelineData=null;this._forceDecorationCache=null;this._entryColorsCache=null;this._rawTimelineDataLength=0;this._selectedGroup=-1;this._keyboardFocusedGroup=-1;this._flameChartDelegate.updateSelectedGroup(this,null);return;}
this._rawTimelineData=timelineData;this._rawTimelineDataLength=timelineData.entryStartTimes.length;this._forceDecorationCache=new Int8Array(this._rawTimelineDataLength);this._entryColorsCache=new Array(this._rawTimelineDataLength);for(let i=0;i<this._rawTimelineDataLength;++i){this._forceDecorationCache[i]=this._dataProvider.forceDecoration(i)?1:0;this._entryColorsCache[i]=this._dataProvider.entryColor(i);}
const entryCounters=new Uint32Array(this._dataProvider.maxStackDepth()+1);for(let i=0;i<timelineData.entryLevels.length;++i){++entryCounters[timelineData.entryLevels[i]];}
const levelIndexes=new Array(entryCounters.length);for(let i=0;i<levelIndexes.length;++i){levelIndexes[i]=new Uint32Array(entryCounters[i]);entryCounters[i]=0;}
for(let i=0;i<timelineData.entryLevels.length;++i){const level=timelineData.entryLevels[i];levelIndexes[level][entryCounters[level]++]=i;}
this._timelineLevels=levelIndexes;const groups=this._rawTimelineData.groups||[];for(let i=0;i<groups.length;++i){const expanded=this._groupExpansionState[groups[i].name];if(expanded!==undefined){groups[i].expanded=expanded;}}
this._updateLevelPositions();this._updateHeight();this._selectedGroup=timelineData.selectedGroup?groups.indexOf(timelineData.selectedGroup):-1;this._keyboardFocusedGroup=this._selectedGroup;this._flameChartDelegate.updateSelectedGroup(this,timelineData.selectedGroup);}
_updateLevelPositions(){const levelCount=this._dataProvider.maxStackDepth();const groups=this._rawTimelineData.groups||[];this._visibleLevelOffsets=new Uint32Array(levelCount+1);this._visibleLevelHeights=new Uint32Array(levelCount);this._visibleLevels=new Uint16Array(levelCount);this._groupOffsets=new Uint32Array(groups.length+1);let groupIndex=-1;let currentOffset=this._rulerEnabled?HeaderHeight+2:2;let visible=true;const groupStack=[{nestingLevel:-1,visible:true}];const lastGroupLevel=Math.max(levelCount,groups.length?groups.peekLast().startLevel+1:0);let level;for(level=0;level<lastGroupLevel;++level){let parentGroupIsVisible=true;let style;while(groupIndex<groups.length-1&&level===groups[groupIndex+1].startLevel){++groupIndex;style=groups[groupIndex].style;let nextLevel=true;while(groupStack.peekLast().nestingLevel>=style.nestingLevel){groupStack.pop();nextLevel=false;}
const thisGroupIsVisible=groupIndex>=0&&this._isGroupCollapsible(groupIndex)?groups[groupIndex].expanded:true;parentGroupIsVisible=groupStack.peekLast().visible;visible=thisGroupIsVisible&&parentGroupIsVisible;groupStack.push({nestingLevel:style.nestingLevel,visible:visible});if(parentGroupIsVisible){currentOffset+=nextLevel?0:style.padding;}
this._groupOffsets[groupIndex]=currentOffset;if(parentGroupIsVisible&&!style.shareHeaderLine){currentOffset+=style.height;}}
if(level>=levelCount){continue;}
const isFirstOnLevel=groupIndex>=0&&level===groups[groupIndex].startLevel;const thisLevelIsVisible=parentGroupIsVisible&&(visible||isFirstOnLevel&&groups[groupIndex].style.useFirstLineForOverview);let height;if(groupIndex>=0){const group=groups[groupIndex];const styleB=group.style;height=isFirstOnLevel&&!styleB.shareHeaderLine||(styleB.collapsible&&!group.expanded)?styleB.height:(styleB.itemsHeight||this._barHeight);}else{height=this._barHeight;}
this._visibleLevels[level]=thisLevelIsVisible;this._visibleLevelOffsets[level]=currentOffset;this._visibleLevelHeights[level]=height;if(thisLevelIsVisible||(parentGroupIsVisible&&style&&style.shareHeaderLine&&isFirstOnLevel)){currentOffset+=this._visibleLevelHeights[level];}}
if(groupIndex>=0){this._groupOffsets[groupIndex+1]=currentOffset;}
this._visibleLevelOffsets[level]=currentOffset;if(this._useWebGL){this._setupGLGeometry();}}
_isGroupCollapsible(index){const groups=this._rawTimelineData.groups||[];const style=groups[index].style;if(!style.shareHeaderLine||!style.collapsible){return!!style.collapsible;}
const isLastGroup=index+1>=groups.length;if(!isLastGroup&&groups[index+1].style.nestingLevel>style.nestingLevel){return true;}
const nextGroupLevel=isLastGroup?this._dataProvider.maxStackDepth():groups[index+1].startLevel;if(nextGroupLevel!==groups[index].startLevel+1){return true;}
return style.height!==style.itemsHeight;}
setSelectedEntry(entryIndex){if(this._selectedEntryIndex===entryIndex){return;}
if(entryIndex!==-1){this._chartViewport.hideRangeSelection();}
this._selectedEntryIndex=entryIndex;this._revealEntry(entryIndex);this._updateElementPosition(this._selectedElement,this._selectedEntryIndex);}
_updateElementPosition(element,entryIndex){const elementMinWidthPx=2;element.classList.add('hidden');if(entryIndex===-1){return;}
const timelineData=this._timelineData();const startTime=timelineData.entryStartTimes[entryIndex];const duration=timelineData.entryTotalTimes[entryIndex];let barX=0;let barWidth=0;let visible=true;if(Number.isNaN(duration)){const position=this._markerPositions.get(entryIndex);if(position){barX=position.x;barWidth=position.width;}else{visible=false;}}else{barX=this._chartViewport.timeToPosition(startTime);barWidth=duration*this._chartViewport.timeToPixel();}
if(barX+barWidth<=0||barX>=this._offsetWidth){return;}
const barCenter=barX+barWidth/2;barWidth=Math.max(barWidth,elementMinWidthPx);barX=barCenter-barWidth/2;const entryLevel=timelineData.entryLevels[entryIndex];const barY=this._levelToOffset(entryLevel)-this._chartViewport.scrollOffset();const barHeight=this._levelHeight(entryLevel);const style=element.style;style.left=barX+'px';style.top=barY+'px';style.width=barWidth+'px';style.height=barHeight-1+'px';element.classList.toggle('hidden',!visible);this._viewportElement.appendChild(element);}
_timeToPositionClipped(time){return Number.constrain(this._chartViewport.timeToPosition(time),0,this._offsetWidth);}
_levelToOffset(level){return this._visibleLevelOffsets[level];}
_levelHeight(level){return this._visibleLevelHeights[level];}
_updateBoundaries(){this._totalTime=this._dataProvider.totalTime();this._minimumBoundary=this._dataProvider.minimumBoundary();this._chartViewport.setBoundaries(this._minimumBoundary,this._totalTime);}
_updateHeight(){const height=this._levelToOffset(this._dataProvider.maxStackDepth())+2;this._chartViewport.setContentHeight(height);}
onResize(){this.scheduleUpdate();}
update(){if(!this._timelineData()){return;}
this._resetCanvas();this._updateHeight();this._updateBoundaries();this._draw();if(!this._chartViewport.isDragging()){this._updateHighlight();}}
reset(){this._chartViewport.reset();this._rawTimelineData=null;this._rawTimelineDataLength=0;this._highlightedMarkerIndex=-1;this._highlightedEntryIndex=-1;this._selectedEntryIndex=-1;this._textWidth=new Map();this._chartViewport.scheduleUpdate();}
scheduleUpdate(){this._chartViewport.scheduleUpdate();}
_enabled(){return this._rawTimelineDataLength!==0;}
computePosition(time){return this._chartViewport.timeToPosition(time);}
formatValue(value,precision){return this._dataProvider.formatValue(value-this.zeroTime(),precision);}
maximumBoundary(){return this._chartViewport.windowRightTime();}
minimumBoundary(){return this._chartViewport.windowLeftTime();}
zeroTime(){return this._dataProvider.minimumBoundary();}
boundarySpan(){return this.maximumBoundary()-this.minimumBoundary();}}
export const HeaderHeight=15;export const MinimalTimeWindowMs=0.5;export class TimelineData{constructor(entryLevels,entryTotalTimes,entryStartTimes,groups){this.entryLevels=entryLevels;this.entryTotalTimes=entryTotalTimes;this.entryStartTimes=entryStartTimes;this.groups=groups;this.markers=[];this.flowStartTimes=[];this.flowStartLevels=[];this.flowEndTimes=[];this.flowEndLevels=[];this.selectedGroup=null;}}
export class FlameChartDataProvider{minimumBoundary(){}
totalTime(){}
formatValue(value,precision){}
maxStackDepth(){}
timelineData(){}
prepareHighlightedEntryInfo(entryIndex){}
canJumpToEntry(entryIndex){}
entryTitle(entryIndex){}
entryFont(entryIndex){}
entryColor(entryIndex){}
decorateEntry(entryIndex,context,text,barX,barY,barWidth,barHeight,unclippedBarX,timeToPixelRatio){}
forceDecoration(entryIndex){}
textColor(entryIndex){}}
export class FlameChartMarker{startTime(){}
color(){}
title(){}
draw(context,x,height,pixelsPerMillisecond){}}
export const Events={CanvasFocused:Symbol('CanvasFocused'),EntryInvoked:Symbol('EntryInvoked'),EntrySelected:Symbol('EntrySelected'),EntryHighlighted:Symbol('EntryHighlighted')};export const Colors={SelectedGroupBackground:'hsl(215, 85%, 98%)',SelectedGroupBorder:'hsl(216, 68%, 54%)',};