import{Settings,UIString,ObjectWrapper,Throttler}from'../common/common.js';import{OverlayModel,LayerTreeBase}from'../sdk/sdk.js';import{Widget,EmptyWidget,ARIAUtils,TreeOutline,ContextMenu,UIUtils,Toolbar,KeyboardShortcut,ShortcutsScreen,Geometry,XLink,ThrottledWidget}from'../ui/ui.js';import{NumberUtilities}from'../platform/platform.js';import{PieChart,OverviewGrid}from'../perf_ui/perf_ui.js';class LayerView{hoverObject(selection){}
selectObject(selection){}
setLayerTree(layerTree){}}
class Selection{constructor(type,layer){this._type=type;this._layer=layer;}
static isEqual(a,b){return a&&b?a._isEqual(b):a===b;}
type(){return this._type;}
layer(){return this._layer;}
_isEqual(other){return false;}}
const Type={Layer:Symbol('Layer'),ScrollRect:Symbol('ScrollRect'),Snapshot:Symbol('Snapshot')};class LayerSelection extends Selection{constructor(layer){console.assert(layer,'LayerSelection with empty layer');super(Type.Layer,layer);}
_isEqual(other){return other._type===Type.Layer&&other.layer().id()===this.layer().id();}}
class ScrollRectSelection extends Selection{constructor(layer,scrollRectIndex){super(Type.ScrollRect,layer);this.scrollRectIndex=scrollRectIndex;}
_isEqual(other){return other._type===Type.ScrollRect&&this.layer().id()===other.layer().id()&&this.scrollRectIndex===other.scrollRectIndex;}}
class SnapshotSelection extends Selection{constructor(layer,snapshot){super(Type.Snapshot,layer);this._snapshot=snapshot;}
_isEqual(other){return other._type===Type.Snapshot&&this.layer().id()===other.layer().id()&&this._snapshot===other._snapshot;}
snapshot(){return this._snapshot;}}
class LayerViewHost{constructor(){this._views=[];this._selectedObject=null;this._hoveredObject=null;this._showInternalLayersSetting=Settings.Settings.instance().createSetting('layersShowInternalLayers',false);}
registerView(layerView){this._views.push(layerView);}
setLayerSnapshotMap(snapshotLayers){this._snapshotLayers=snapshotLayers;}
getLayerSnapshotMap(){return this._snapshotLayers;}
setLayerTree(layerTree){this._target=layerTree.target();const selectedLayer=this._selectedObject&&this._selectedObject.layer();if(selectedLayer&&(!layerTree||!layerTree.layerById(selectedLayer.id()))){this.selectObject(null);}
const hoveredLayer=this._hoveredObject&&this._hoveredObject.layer();if(hoveredLayer&&(!layerTree||!layerTree.layerById(hoveredLayer.id()))){this.hoverObject(null);}
for(const view of this._views){view.setLayerTree(layerTree);}}
hoverObject(selection){if(Selection.isEqual(this._hoveredObject,selection)){return;}
this._hoveredObject=selection;const layer=selection&&selection.layer();this._toggleNodeHighlight(layer?layer.nodeForSelfOrAncestor():null);for(const view of this._views){view.hoverObject(selection);}}
selectObject(selection){if(Selection.isEqual(this._selectedObject,selection)){return;}
this._selectedObject=selection;for(const view of this._views){view.selectObject(selection);}}
selection(){return this._selectedObject;}
showContextMenu(contextMenu,selection){contextMenu.defaultSection().appendCheckboxItem(UIString.UIString('Show internal layers'),this._toggleShowInternalLayers.bind(this),this._showInternalLayersSetting.get());const node=selection&&selection.layer()&&selection.layer().nodeForSelfOrAncestor();if(node){contextMenu.appendApplicableItems(node);}
contextMenu.show();}
showInternalLayersSetting(){return this._showInternalLayersSetting;}
_toggleShowInternalLayers(){this._showInternalLayersSetting.set(!this._showInternalLayersSetting.get());}
_toggleNodeHighlight(node){if(node){node.highlightForTwoSeconds();return;}
OverlayModel.OverlayModel.hideDOMNodeHighlight();}}
var LayerViewHost$1=Object.freeze({__proto__:null,LayerView:LayerView,Selection:Selection,Type:Type,LayerSelection:LayerSelection,ScrollRectSelection:ScrollRectSelection,SnapshotSelection:SnapshotSelection,LayerViewHost:LayerViewHost});class LayerDetailsView extends Widget.Widget{constructor(layerViewHost){super(true);this.registerRequiredCSS('layer_viewer/layerDetailsView.css');this._layerViewHost=layerViewHost;this._layerViewHost.registerView(this);this._emptyWidget=new EmptyWidget.EmptyWidget(UIString.UIString('Select a layer to see its details'));this._layerSnapshotMap=this._layerViewHost.getLayerSnapshotMap();this._buildContent();}
hoverObject(selection){}
selectObject(selection){this._selection=selection;if(this.isShowing()){this.update();}}
setLayerTree(layerTree){}
wasShown(){super.wasShown();this.update();}
_onScrollRectClicked(index,event){if(event.which!==1){return;}
this._layerViewHost.selectObject(new ScrollRectSelection(this._selection.layer(),index));}
_invokeProfilerLink(){const snapshotSelection=this._selection.type()===Type.Snapshot?this._selection:this._layerSnapshotMap.get(this._selection.layer());if(snapshotSelection){this.dispatchEventToListeners(Events.PaintProfilerRequested,snapshotSelection);}}
_createScrollRectElement(scrollRect,index){if(index){this._scrollRectsCell.createTextChild(', ');}
const element=this._scrollRectsCell.createChild('span','scroll-rect');if(this._selection.scrollRectIndex===index){element.classList.add('active');}
element.textContent=UIString.UIString('%s %d × %d (at %d, %d)',slowScrollRectNames.get(scrollRect.type),scrollRect.rect.width,scrollRect.rect.height,scrollRect.rect.x,scrollRect.rect.y);element.addEventListener('click',this._onScrollRectClicked.bind(this,index),false);}
_formatStickyAncestorLayer(title,layer){if(!layer){return'';}
const node=layer.nodeForSelfOrAncestor();const name=node?node.simpleSelector():UIString.UIString('<unnamed>');return UIString.UIString('%s: %s (%s)',title,name,layer.id());}
_createStickyAncestorChild(title,layer){if(!layer){return;}
this._stickyPositionConstraintCell.createTextChild(', ');const child=this._stickyPositionConstraintCell.createChild('span');child.textContent=this._formatStickyAncestorLayer(title,layer);}
_populateStickyPositionConstraintCell(constraint){this._stickyPositionConstraintCell.removeChildren();if(!constraint){return;}
const stickyBoxRect=constraint.stickyBoxRect();const stickyBoxRectElement=this._stickyPositionConstraintCell.createChild('span');stickyBoxRectElement.textContent=UIString.UIString('Sticky Box %d × %d (at %d, %d)',stickyBoxRect.width,stickyBoxRect.height,stickyBoxRect.x,stickyBoxRect.y);this._stickyPositionConstraintCell.createTextChild(', ');const containingBlockRect=constraint.containingBlockRect();const containingBlockRectElement=this._stickyPositionConstraintCell.createChild('span');containingBlockRectElement.textContent=UIString.UIString('Containing Block %d × %d (at %d, %d)',containingBlockRect.width,containingBlockRect.height,containingBlockRect.x,containingBlockRect.y);this._createStickyAncestorChild(UIString.UIString('Nearest Layer Shifting Sticky Box'),constraint.nearestLayerShiftingStickyBox());this._createStickyAncestorChild(UIString.UIString('Nearest Layer Shifting Containing Block'),constraint.nearestLayerShiftingContainingBlock());}
update(){const layer=this._selection&&this._selection.layer();if(!layer){this._tableElement.remove();this._paintProfilerLink.remove();this._emptyWidget.show(this.contentElement);return;}
this._emptyWidget.detach();this.contentElement.appendChild(this._tableElement);this.contentElement.appendChild(this._paintProfilerLink);this._sizeCell.textContent=UIString.UIString('%d × %d (at %d,%d)',layer.width(),layer.height(),layer.offsetX(),layer.offsetY());this._paintCountCell.parentElement.classList.toggle('hidden',!layer.paintCount());this._paintCountCell.textContent=layer.paintCount();this._memoryEstimateCell.textContent=Number.bytesToString(layer.gpuMemoryUsage());layer.requestCompositingReasonIds().then(this._updateCompositingReasons.bind(this));this._scrollRectsCell.removeChildren();layer.scrollRects().forEach(this._createScrollRectElement.bind(this));this._populateStickyPositionConstraintCell(layer.stickyPositionConstraint());const snapshot=this._selection.type()===Type.Snapshot?(this._selection).snapshot():null;this._paintProfilerLink.classList.toggle('hidden',!(this._layerSnapshotMap.has(layer)||snapshot));}
_buildContent(){this._tableElement=this.contentElement.createChild('table');this._tbodyElement=this._tableElement.createChild('tbody');this._sizeCell=this._createRow(UIString.UIString('Size'));this._compositingReasonsCell=this._createRow(UIString.UIString('Compositing Reasons'));this._memoryEstimateCell=this._createRow(UIString.UIString('Memory estimate'));this._paintCountCell=this._createRow(UIString.UIString('Paint count'));this._scrollRectsCell=this._createRow(UIString.UIString('Slow scroll regions'));this._stickyPositionConstraintCell=this._createRow(UIString.UIString('Sticky position constraint'));this._paintProfilerLink=this.contentElement.createChild('span','hidden devtools-link link-margin');ARIAUtils.markAsLink(this._paintProfilerLink);this._paintProfilerLink.textContent=ls`Paint Profiler`;this._paintProfilerLink.tabIndex=0;this._paintProfilerLink.addEventListener('click',e=>{e.consume(true);this._invokeProfilerLink();});this._paintProfilerLink.addEventListener('keydown',event=>{if(isEnterKey(event)){event.consume();this._invokeProfilerLink();}});}
_createRow(title){const tr=this._tbodyElement.createChild('tr');const titleCell=tr.createChild('td');titleCell.textContent=title;return tr.createChild('td');}
_updateCompositingReasons(compositingReasonIds){if(!compositingReasonIds||!compositingReasonIds.length){this._compositingReasonsCell.textContent='n/a';return;}
this._compositingReasonsCell.removeChildren();const list=this._compositingReasonsCell.createChild('ul');const compositingReasons=LayerDetailsView.getCompositingReasons(compositingReasonIds);for(const compositingReason of compositingReasons){list.createChild('li').textContent=compositingReason;}}
static getCompositingReasons(compositingReasonIds){const compositingReasons=[];for(const compositingReasonId of compositingReasonIds){const compositingReason=compositingReasonIdToReason.get(compositingReasonId);if(compositingReason){compositingReasons.push(compositingReason);}else{console.error(`Compositing reason id '${compositingReasonId}' is not recognized.`);}}
return compositingReasons;}}
const compositingReasonIdToReason=new Map([['transform3D',ls`Has a 3d transform.`],['video',ls`Is an accelerated video.`],['canvas',ls`Is an accelerated canvas, or is a display list backed canvas that was promoted to a layer based on a performance heuristic.`],['plugin',ls`Is an accelerated plugin.`],['iFrame',ls`Is an accelerated iFrame.`],['backfaceVisibilityHidden',ls`Has backface-visibility: hidden.`],['activeTransformAnimation',ls`Has an active accelerated transform animation or transition.`],['activeOpacityAnimation',ls`Has an active accelerated opacity animation or transition.`],['activeFilterAnimation',ls`Has an active accelerated filter animation or transition.`],['activeBackdropFilterAnimation',ls`Has an active accelerated backdrop filter animation or transition.`],['immersiveArOverlay',ls`Is DOM overlay for WebXR immersive-ar mode.`],['scrollDependentPosition',ls`Is fixed or sticky position.`],['overflowScrolling',ls`Is a scrollable overflow element.`],['overflowScrollingParent',ls`Scroll parent is not an ancestor.`],['outOfFlowClipping',ls`Has clipping ancestor.`],['videoOverlay',ls`Is overlay controls for video.`],['willChangeTransform',ls`Has a will-change: transform compositing hint.`],['willChangeOpacity',ls`Has a will-change: opacity compositing hint.`],['willChangeOther',ls`Has a will-change compositing hint other than transform and opacity.`],['backdropFilter',ls`Has a backdrop filter.`],['rootScroller',ls`Is the document.rootScroller.`],['assumedOverlap',ls`Might overlap other composited content.`],['overlap',ls`Overlaps other composited content.`],['negativeZIndexChildren',ls`Parent with composited negative z-index content.`],['squashingDisallowed',ls`Layer was separately composited because it could not be squashed.`],['opacityWithCompositedDescendants',ls`Has opacity that needs to be applied by compositor because of composited descendants.`],['maskWithCompositedDescendants',ls`Has a mask that needs to be known by compositor because of composited descendants.`],['reflectionWithCompositedDescendants',ls`Has a reflection that needs to be known by compositor because of composited descendants.`],['filterWithCompositedDescendants',ls`Has a filter effect that needs to be known by compositor because of composited descendants.`],['blendingWithCompositedDescendants',ls`Has a blending effect that needs to be known by compositor because of composited descendants.`],['clipsCompositingDescendants',ls`Has a clip that needs to be known by compositor because of composited descendants.`],['perspectiveWith3DDescendants',ls`Has a perspective transform that needs to be known by compositor because of 3d descendants.`],['preserve3DWith3DDescendants',ls`Has a preserves-3d property that needs to be known by compositor because of 3d descendants.`],['isolateCompositedDescendants',ls`Should isolate descendants to apply a blend effect.`],['positionFixedWithCompositedDescendants',ls`Is a position:fixed element with composited descendants.`],['root',ls`Is the root layer.`],['layerForHorizontalScrollbar',ls`Secondary layer, the horizontal scrollbar layer.`],['layerForVerticalScrollbar',ls`Secondary layer, the vertical scrollbar layer.`],['layerForOverflowControlsHost',ls`Secondary layer, the overflow controls host layer.`],['layerForScrollCorner',ls`Secondary layer, the scroll corner layer.`],['layerForScrollingContents',ls`Secondary layer, to house contents that can be scrolled.`],['layerForScrollingContainer',ls`Secondary layer, used to position the scrolling contents while scrolling.`],['layerForSquashingContents',ls`Secondary layer, home for a group of squashable content.`],['layerForSquashingContainer',ls`Secondary layer, no-op layer to place the squashing layer correctly in the composited layer tree.`],['layerForForeground',ls`Secondary layer, to contain any normal flow and positive z-index contents on top of a negative z-index layer.`],['layerForMask',ls`Secondary layer, to contain the mask contents.`],['layerForDecoration',ls`Layer painted on top of other layers as decoration.`],['layerForOther',ls`Layer for link highlight, frame overlay, etc.`]]);const Events={PaintProfilerRequested:Symbol('PaintProfilerRequested')};const slowScrollRectNames=new Map([[LayerTreeBase.Layer.ScrollRectType.NonFastScrollable,UIString.UIString('Non fast scrollable')],[LayerTreeBase.Layer.ScrollRectType.TouchEventHandler,UIString.UIString('Touch event handler')],[LayerTreeBase.Layer.ScrollRectType.WheelEventHandler,UIString.UIString('Wheel event handler')],[LayerTreeBase.Layer.ScrollRectType.RepaintsOnScroll,UIString.UIString('Repaints on scroll')],[LayerTreeBase.Layer.ScrollRectType.MainThreadScrollingReason,UIString.UIString('Main thread scrolling reason')]]);var LayerDetailsView$1=Object.freeze({__proto__:null,LayerDetailsView:LayerDetailsView,Events:Events,slowScrollRectNames:slowScrollRectNames});const layerSymbol=Symbol('layer');class LayerTreeOutline extends ObjectWrapper.ObjectWrapper{constructor(layerViewHost){super();this._layerViewHost=layerViewHost;this._layerViewHost.registerView(this);this._treeOutline=new TreeOutline.TreeOutlineInShadow();this._treeOutline.element.classList.add('layer-tree','overflow-auto');this._treeOutline.element.addEventListener('mousemove',this._onMouseMove.bind(this),false);this._treeOutline.element.addEventListener('mouseout',this._onMouseMove.bind(this),false);this._treeOutline.element.addEventListener('contextmenu',this._onContextMenu.bind(this),true);ARIAUtils.setAccessibleName(this._treeOutline.contentElement,ls`Layers Tree Pane`);this._lastHoveredNode=null;this.element=this._treeOutline.element;this._layerViewHost.showInternalLayersSetting().addChangeListener(this._update,this);}
focus(){this._treeOutline.focus();}
selectObject(selection){this.hoverObject(null);const layer=selection&&selection.layer();const node=layer&&layer[layerSymbol];if(node){node.revealAndSelect(true);}else if(this._treeOutline.selectedTreeElement){this._treeOutline.selectedTreeElement.deselect();}}
hoverObject(selection){const layer=selection&&selection.layer();const node=layer&&layer[layerSymbol];if(node===this._lastHoveredNode){return;}
if(this._lastHoveredNode){this._lastHoveredNode.setHovered(false);}
if(node){node.setHovered(true);}
this._lastHoveredNode=node;}
setLayerTree(layerTree){this._layerTree=layerTree;this._update();}
_update(){const showInternalLayers=this._layerViewHost.showInternalLayersSetting().get();const seenLayers=new Map();let root=null;if(this._layerTree){if(!showInternalLayers){root=this._layerTree.contentRoot();}
if(!root){root=this._layerTree.root();}}
function updateLayer(layer){if(!layer.drawsContent()&&!showInternalLayers){return;}
if(seenLayers.get(layer)){console.assert(false,'Duplicate layer: '+layer.id());}
seenLayers.set(layer,true);let node=layer[layerSymbol];let parentLayer=layer.parent();while(parentLayer&&parentLayer!==root&&!parentLayer.drawsContent()&&!showInternalLayers){parentLayer=parentLayer.parent();}
const parent=layer===root?this._treeOutline.rootElement():parentLayer[layerSymbol];if(!parent){console.assert(false,'Parent is not in the tree');return;}
if(!node){node=new LayerTreeElement(this,layer);parent.appendChild(node);if(!layer.drawsContent()){node.expand();}}else{if(node.parent!==parent){const oldSelection=this._treeOutline.selectedTreeElement;if(node.parent){node.parent.removeChild(node);}
parent.appendChild(node);if(oldSelection!==this._treeOutline.selectedTreeElement){oldSelection.select();}}
node._update();}}
if(root){this._layerTree.forEachLayer(updateLayer.bind(this),root);}
const rootElement=this._treeOutline.rootElement();for(let node=rootElement.firstChild();node&&!node.root;){if(seenLayers.get(node._layer)){node=node.traverseNextTreeElement(false);}else{const nextNode=node.nextSibling||node.parent;node.parent.removeChild(node);if(node===this._lastHoveredNode){this._lastHoveredNode=null;}
node=nextNode;}}
if(!this._treeOutline.selectedTreeElement){const elementToSelect=this._layerTree.contentRoot()||this._layerTree.root();if(elementToSelect){elementToSelect[layerSymbol].revealAndSelect(true);}}}
_onMouseMove(event){const node=this._treeOutline.treeElementFromEvent(event);if(node===this._lastHoveredNode){return;}
this._layerViewHost.hoverObject(this._selectionForNode(node));}
_selectedNodeChanged(node){this._layerViewHost.selectObject(this._selectionForNode(node));}
_onContextMenu(event){const selection=this._selectionForNode(this._treeOutline.treeElementFromEvent(event));const contextMenu=new ContextMenu.ContextMenu(event);const layer=selection&&selection.layer();if(layer){this._layerSnapshotMap=this._layerViewHost.getLayerSnapshotMap();if(this._layerSnapshotMap.has(layer)){contextMenu.defaultSection().appendItem(ls`Show Paint Profiler`,this.dispatchEventToListeners.bind(this,Events$1.PaintProfilerRequested,selection),false);}}
this._layerViewHost.showContextMenu(contextMenu,selection);}
_selectionForNode(node){return node&&node._layer?new LayerSelection(node._layer):null;}}
const Events$1={PaintProfilerRequested:Symbol('PaintProfilerRequested')};class LayerTreeElement extends TreeOutline.TreeElement{constructor(tree,layer){super();this._treeOutline=tree;this._layer=layer;this._layer[layerSymbol]=this;this._update();}
_update(){const node=this._layer.nodeForSelfOrAncestor();const title=createDocumentFragment();title.createTextChild(node?node.simpleSelector():'#'+this._layer.id());const details=title.createChild('span','dimmed');details.textContent=UIString.UIString(' (%d × %d)',this._layer.width(),this._layer.height());this.title=title;}
onselect(){this._treeOutline._selectedNodeChanged(this);return false;}
setHovered(hovered){this.listItemElement.classList.toggle('hovered',hovered);}}
var LayerTreeOutline$1=Object.freeze({__proto__:null,layerSymbol:layerSymbol,LayerTreeOutline:LayerTreeOutline,Events:Events$1,LayerTreeElement:LayerTreeElement});class TransformController extends ObjectWrapper.ObjectWrapper{constructor(element,disableRotate){super();this._shortcuts={};this.element=element;this._registerShortcuts();UIUtils.installDragHandle(element,this._onDragStart.bind(this),this._onDrag.bind(this),this._onDragEnd.bind(this),'move',null);element.addEventListener('keydown',this._onKeyDown.bind(this),false);element.addEventListener('mousewheel',this._onMouseWheel.bind(this),false);this._minScale=0;this._maxScale=Infinity;this._controlPanelToolbar=new Toolbar.Toolbar('transform-control-panel');this._modeButtons={};if(!disableRotate){const panModeButton=new Toolbar.ToolbarToggle(UIString.UIString('Pan mode (X)'),'largeicon-pan');panModeButton.addEventListener(Toolbar.ToolbarButton.Events.Click,this._setMode.bind(this,Modes.Pan));this._modeButtons[Modes.Pan]=panModeButton;this._controlPanelToolbar.appendToolbarItem(panModeButton);const rotateModeButton=new Toolbar.ToolbarToggle(UIString.UIString('Rotate mode (V)'),'largeicon-rotate');rotateModeButton.addEventListener(Toolbar.ToolbarButton.Events.Click,this._setMode.bind(this,Modes.Rotate));this._modeButtons[Modes.Rotate]=rotateModeButton;this._controlPanelToolbar.appendToolbarItem(rotateModeButton);}
this._setMode(Modes.Pan);const resetButton=new Toolbar.ToolbarButton(UIString.UIString('Reset transform (0)'),'largeicon-center');resetButton.addEventListener(Toolbar.ToolbarButton.Events.Click,this.resetAndNotify.bind(this,undefined));this._controlPanelToolbar.appendToolbarItem(resetButton);this._reset();}
toolbar(){return this._controlPanelToolbar;}
_onKeyDown(event){const shortcutKey=KeyboardShortcut.KeyboardShortcut.makeKeyFromEventIgnoringModifiers(event);const handler=this._shortcuts[shortcutKey];if(handler&&handler(event)){event.consume();}}
_addShortcuts(keys,handler){for(let i=0;i<keys.length;++i){this._shortcuts[keys[i].key]=handler;}}
_registerShortcuts(){this._addShortcuts(ShortcutsScreen.LayersPanelShortcuts.ResetView,this.resetAndNotify.bind(this));this._addShortcuts(ShortcutsScreen.LayersPanelShortcuts.PanMode,this._setMode.bind(this,Modes.Pan));this._addShortcuts(ShortcutsScreen.LayersPanelShortcuts.RotateMode,this._setMode.bind(this,Modes.Rotate));const zoomFactor=1.1;this._addShortcuts(ShortcutsScreen.LayersPanelShortcuts.ZoomIn,this._onKeyboardZoom.bind(this,zoomFactor));this._addShortcuts(ShortcutsScreen.LayersPanelShortcuts.ZoomOut,this._onKeyboardZoom.bind(this,1/zoomFactor));this._addShortcuts(ShortcutsScreen.LayersPanelShortcuts.Up,this._onKeyboardPanOrRotate.bind(this,0,-1));this._addShortcuts(ShortcutsScreen.LayersPanelShortcuts.Down,this._onKeyboardPanOrRotate.bind(this,0,1));this._addShortcuts(ShortcutsScreen.LayersPanelShortcuts.Left,this._onKeyboardPanOrRotate.bind(this,-1,0));this._addShortcuts(ShortcutsScreen.LayersPanelShortcuts.Right,this._onKeyboardPanOrRotate.bind(this,1,0));}
_postChangeEvent(){this.dispatchEventToListeners(Events$2.TransformChanged);}
_reset(){this._scale=1;this._offsetX=0;this._offsetY=0;this._rotateX=0;this._rotateY=0;}
_setMode(mode){if(this._mode===mode){return;}
this._mode=mode;this._updateModeButtons();}
_updateModeButtons(){for(const mode in this._modeButtons){this._modeButtons[mode].setToggled(mode===this._mode);}}
resetAndNotify(event){this._reset();this._postChangeEvent();if(event){event.preventDefault();}
this.element.focus();}
setScaleConstraints(minScale,maxScale){this._minScale=minScale;this._maxScale=maxScale;this._scale=NumberUtilities.clamp(this._scale,minScale,maxScale);}
clampOffsets(minX,maxX,minY,maxY){this._offsetX=NumberUtilities.clamp(this._offsetX,minX,maxX);this._offsetY=NumberUtilities.clamp(this._offsetY,minY,maxY);}
scale(){return this._scale;}
offsetX(){return this._offsetX;}
offsetY(){return this._offsetY;}
rotateX(){return this._rotateX;}
rotateY(){return this._rotateY;}
_onScale(scaleFactor,x,y){scaleFactor=NumberUtilities.clamp(this._scale*scaleFactor,this._minScale,this._maxScale)/this._scale;this._scale*=scaleFactor;this._offsetX-=(x-this._offsetX)*(scaleFactor-1);this._offsetY-=(y-this._offsetY)*(scaleFactor-1);this._postChangeEvent();}
_onPan(offsetX,offsetY){this._offsetX+=offsetX;this._offsetY+=offsetY;this._postChangeEvent();}
_onRotate(rotateX,rotateY){this._rotateX=rotateX;this._rotateY=rotateY;this._postChangeEvent();}
_onKeyboardZoom(zoomFactor){this._onScale(zoomFactor,this.element.clientWidth/2,this.element.clientHeight/2);}
_onKeyboardPanOrRotate(xMultiplier,yMultiplier){const panStepInPixels=6;const rotateStepInDegrees=5;if(this._mode===Modes.Rotate){this._onRotate(this._rotateX+yMultiplier*rotateStepInDegrees,this._rotateY+xMultiplier*rotateStepInDegrees);}else{this._onPan(xMultiplier*panStepInPixels,yMultiplier*panStepInPixels);}}
_onMouseWheel(event){const zoomFactor=1.1;const mouseWheelZoomSpeed=1/120;const scaleFactor=Math.pow(zoomFactor,event.wheelDeltaY*mouseWheelZoomSpeed);this._onScale(scaleFactor,event.clientX-this.element.totalOffsetLeft(),event.clientY-this.element.totalOffsetTop());}
_onDrag(event){if(this._mode===Modes.Rotate){this._onRotate(this._oldRotateX+(this._originY-event.clientY)/this.element.clientHeight*180,this._oldRotateY-(this._originX-event.clientX)/this.element.clientWidth*180);}else{this._onPan(event.clientX-this._originX,event.clientY-this._originY);this._originX=event.clientX;this._originY=event.clientY;}}
_onDragStart(event){this.element.focus();this._originX=event.clientX;this._originY=event.clientY;this._oldRotateX=this._rotateX;this._oldRotateY=this._rotateY;return true;}
_onDragEnd(){delete this._originX;delete this._originY;delete this._oldRotateX;delete this._oldRotateY;}}
const Events$2={TransformChanged:Symbol('TransformChanged')};const Modes={Pan:'Pan',Rotate:'Rotate',};var TransformController$1=Object.freeze({__proto__:null,TransformController:TransformController,Events:Events$2,Modes:Modes});class Layers3DView extends Widget.VBox{constructor(layerViewHost){super(true);this.registerRequiredCSS('layer_viewer/layers3DView.css');this.contentElement.classList.add('layers-3d-view');this._failBanner=new Widget.VBox();this._failBanner.element.classList.add('full-widget-dimmed-banner');this._failBanner.element.createTextChild(UIString.UIString('Layer information is not yet available.'));this._layerViewHost=layerViewHost;this._layerViewHost.registerView(this);this._transformController=new TransformController(this.contentElement);this._transformController.addEventListener(Events$2.TransformChanged,this._update,this);this._initToolbar();this._canvasElement=this.contentElement.createChild('canvas');this._canvasElement.tabIndex=0;this._canvasElement.addEventListener('dblclick',this._onDoubleClick.bind(this),false);this._canvasElement.addEventListener('mousedown',this._onMouseDown.bind(this),false);this._canvasElement.addEventListener('mouseup',this._onMouseUp.bind(this),false);this._canvasElement.addEventListener('mouseleave',this._onMouseMove.bind(this),false);this._canvasElement.addEventListener('mousemove',this._onMouseMove.bind(this),false);this._canvasElement.addEventListener('contextmenu',this._onContextMenu.bind(this),false);ARIAUtils.setAccessibleName(this._canvasElement,ls`3D Layers View`);this._lastSelection={};this._layerTree=null;this._textureManager=new LayerTextureManager(this._update.bind(this));this._chromeTextures=[];this._rects=[];this._snapshotLayers=new Map();this._layerViewHost.setLayerSnapshotMap(this._snapshotLayers);this._layerViewHost.showInternalLayersSetting().addChangeListener(this._update,this);}
setLayerTree(layerTree){this._layerTree=layerTree;this._layerTexture=null;delete this._oldTextureScale;if(this._showPaints()){this._textureManager.setLayerTree(layerTree);}
this._update();}
showImageForLayer(layer,imageURL){if(!imageURL){this._layerTexture=null;this._update();return;}
UIUtils.loadImage(imageURL).then(image=>{const texture=image&&LayerTextureManager._createTextureForImage(this._gl,image);this._layerTexture=texture?{layer:layer,texture:texture}:null;this._update();});}
onResize(){this._resizeCanvas();this._update();}
willHide(){this._textureManager.suspend();}
wasShown(){this._textureManager.resume();if(!this._needsUpdate){return;}
this._resizeCanvas();this._update();}
updateLayerSnapshot(layer){this._textureManager.layerNeedsUpdate(layer);}
_setOutline(type,selection){this._lastSelection[type]=selection;this._update();}
hoverObject(selection){this._setOutline(OutlineType.Hovered,selection);}
selectObject(selection){this._setOutline(OutlineType.Hovered,null);this._setOutline(OutlineType.Selected,selection);}
snapshotForSelection(selection){if(selection.type()===Type.Snapshot){const snapshotWithRect=(selection).snapshot();snapshotWithRect.snapshot.addReference();return(Promise.resolve(snapshotWithRect));}
if(selection.layer()){const promise=selection.layer().snapshots()[0];if(promise){return promise;}}
return(Promise.resolve(null));}
_initGL(canvas){const gl=canvas.getContext('webgl');if(!gl){return null;}
gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA);gl.enable(gl.BLEND);gl.clearColor(0.0,0.0,0.0,0.0);gl.enable(gl.DEPTH_TEST);return gl;}
_createShader(type,script){const shader=this._gl.createShader(type);this._gl.shaderSource(shader,script);this._gl.compileShader(shader);this._gl.attachShader(this._shaderProgram,shader);}
_initShaders(){this._shaderProgram=this._gl.createProgram();this._createShader(this._gl.FRAGMENT_SHADER,FragmentShader);this._createShader(this._gl.VERTEX_SHADER,VertexShader);this._gl.linkProgram(this._shaderProgram);this._gl.useProgram(this._shaderProgram);this._shaderProgram.vertexPositionAttribute=this._gl.getAttribLocation(this._shaderProgram,'aVertexPosition');this._gl.enableVertexAttribArray(this._shaderProgram.vertexPositionAttribute);this._shaderProgram.vertexColorAttribute=this._gl.getAttribLocation(this._shaderProgram,'aVertexColor');this._gl.enableVertexAttribArray(this._shaderProgram.vertexColorAttribute);this._shaderProgram.textureCoordAttribute=this._gl.getAttribLocation(this._shaderProgram,'aTextureCoord');this._gl.enableVertexAttribArray(this._shaderProgram.textureCoordAttribute);this._shaderProgram.pMatrixUniform=this._gl.getUniformLocation(this._shaderProgram,'uPMatrix');this._shaderProgram.samplerUniform=this._gl.getUniformLocation(this._shaderProgram,'uSampler');}
_resizeCanvas(){this._canvasElement.width=this._canvasElement.offsetWidth*window.devicePixelRatio;this._canvasElement.height=this._canvasElement.offsetHeight*window.devicePixelRatio;}
_updateTransformAndConstraints(){const paddingFraction=0.1;const viewport=this._layerTree.viewportSize();const baseWidth=viewport?viewport.width:this._dimensionsForAutoscale.width;const baseHeight=viewport?viewport.height:this._dimensionsForAutoscale.height;const canvasWidth=this._canvasElement.width;const canvasHeight=this._canvasElement.height;const paddingX=canvasWidth*paddingFraction;const paddingY=canvasHeight*paddingFraction;const scaleX=(canvasWidth-2*paddingX)/baseWidth;const scaleY=(canvasHeight-2*paddingY)/baseHeight;const viewScale=Math.min(scaleX,scaleY);const minScaleConstraint=Math.min(baseWidth/this._dimensionsForAutoscale.width,baseHeight/this._dimensionsForAutoscale.width)/2;this._transformController.setScaleConstraints(minScaleConstraint,10/viewScale);const scale=this._transformController.scale();const rotateX=this._transformController.rotateX();const rotateY=this._transformController.rotateY();this._scale=scale*viewScale;const textureScale=NumberUtilities.clamp(this._scale,0.1,1);if(textureScale!==this._oldTextureScale){this._oldTextureScale=textureScale;this._textureManager.setScale(textureScale);this.dispatchEventToListeners(Events$3.ScaleChanged,textureScale);}
const scaleAndRotationMatrix=new WebKitCSSMatrix().scale(scale,scale,scale).translate(canvasWidth/2,canvasHeight/2,0).rotate(rotateX,rotateY,0).scale(viewScale,viewScale,viewScale).translate(-baseWidth/2,-baseHeight/2,0);let bounds;for(let i=0;i<this._rects.length;++i){bounds=Geometry.boundsForTransformedPoints(scaleAndRotationMatrix,this._rects[i].vertices,bounds);}
this._transformController.clampOffsets((paddingX-bounds.maxX)/window.devicePixelRatio,(canvasWidth-paddingX-bounds.minX)/window.devicePixelRatio,(paddingY-bounds.maxY)/window.devicePixelRatio,(canvasHeight-paddingY-bounds.minY)/window.devicePixelRatio);const offsetX=this._transformController.offsetX()*window.devicePixelRatio;const offsetY=this._transformController.offsetY()*window.devicePixelRatio;this._projectionMatrix=new WebKitCSSMatrix().translate(offsetX,offsetY,0).multiply(scaleAndRotationMatrix);const glProjectionMatrix=new WebKitCSSMatrix().scale(1,-1,-1).translate(-1,-1,0).scale(2/this._canvasElement.width,2/this._canvasElement.height,1/1000000).multiply(this._projectionMatrix);this._gl.uniformMatrix4fv(this._shaderProgram.pMatrixUniform,false,this._arrayFromMatrix(glProjectionMatrix));}
_arrayFromMatrix(m){return new Float32Array([m.m11,m.m12,m.m13,m.m14,m.m21,m.m22,m.m23,m.m24,m.m31,m.m32,m.m33,m.m34,m.m41,m.m42,m.m43,m.m44]);}
_initWhiteTexture(){this._whiteTexture=this._gl.createTexture();this._gl.bindTexture(this._gl.TEXTURE_2D,this._whiteTexture);const whitePixel=new Uint8Array([255,255,255,255]);this._gl.texImage2D(this._gl.TEXTURE_2D,0,this._gl.RGBA,1,1,0,this._gl.RGBA,this._gl.UNSIGNED_BYTE,whitePixel);}
_initChromeTextures(){function loadChromeTexture(index,url){UIUtils.loadImage(url).then(image=>{this._chromeTextures[index]=image&&LayerTextureManager._createTextureForImage(this._gl,image)||undefined;});}
loadChromeTexture.call(this,ChromeTexture.Left,'Images/chromeLeft.png');loadChromeTexture.call(this,ChromeTexture.Middle,'Images/chromeMiddle.png');loadChromeTexture.call(this,ChromeTexture.Right,'Images/chromeRight.png');}
_initGLIfNecessary(){if(this._gl){return this._gl;}
this._gl=this._initGL(this._canvasElement);if(!this._gl){return null;}
this._initShaders();this._initWhiteTexture();this._initChromeTextures();this._textureManager.setContext(this._gl);return this._gl;}
_calculateDepthsAndVisibility(){this._depthByLayerId={};let depth=0;const showInternalLayers=this._layerViewHost.showInternalLayersSetting().get();const root=showInternalLayers?this._layerTree.root():(this._layerTree.contentRoot()||this._layerTree.root());const queue=[root];this._depthByLayerId[root.id()]=0;this._visibleLayers=new Set();while(queue.length>0){const layer=queue.shift();if(showInternalLayers||layer.drawsContent()){this._visibleLayers.add(layer);}
const children=layer.children();for(let i=0;i<children.length;++i){this._depthByLayerId[children[i].id()]=++depth;queue.push(children[i]);}}
this._maxDepth=depth;}
_depthForLayer(layer){return this._depthByLayerId[layer.id()]*LayerSpacing;}
_calculateScrollRectDepth(layer,index){return this._depthForLayer(layer)+index*ScrollRectSpacing+1;}
_updateDimensionsForAutoscale(layer){this._dimensionsForAutoscale.width=Math.max(layer.width(),this._dimensionsForAutoscale.width);this._dimensionsForAutoscale.height=Math.max(layer.height(),this._dimensionsForAutoscale.height);}
_calculateLayerRect(layer){if(!this._visibleLayers.has(layer)){return;}
const selection=new LayerSelection(layer);const rect=new Rectangle(selection);rect.setVertices(layer.quad(),this._depthForLayer(layer));this._appendRect(rect);this._updateDimensionsForAutoscale(layer);}
_appendRect(rect){const selection=rect.relatedObject;const isSelected=Selection.isEqual(this._lastSelection[OutlineType.Selected],selection);const isHovered=Selection.isEqual(this._lastSelection[OutlineType.Hovered],selection);if(isSelected){rect.borderColor=SelectedBorderColor;}else if(isHovered){rect.borderColor=HoveredBorderColor;const fillColor=rect.fillColor||[255,255,255,1];const maskColor=HoveredImageMaskColor;rect.fillColor=[fillColor[0]*maskColor[0]/255,fillColor[1]*maskColor[1]/255,fillColor[2]*maskColor[2]/255,fillColor[3]*maskColor[3]];}else{rect.borderColor=BorderColor;}
rect.lineWidth=isSelected?SelectedBorderWidth:BorderWidth;this._rects.push(rect);}
_calculateLayerScrollRects(layer){const scrollRects=layer.scrollRects();for(let i=0;i<scrollRects.length;++i){const selection=new ScrollRectSelection(layer,i);const rect=new Rectangle(selection);rect.calculateVerticesFromRect(layer,scrollRects[i].rect,this._calculateScrollRectDepth(layer,i));rect.fillColor=ScrollRectBackgroundColor;this._appendRect(rect);}}
_calculateLayerTileRects(layer){const tiles=this._textureManager.tilesForLayer(layer);for(let i=0;i<tiles.length;++i){const tile=tiles[i];if(!tile.texture){continue;}
const selection=new SnapshotSelection(layer,{rect:tile.rect,snapshot:tile.snapshot});const rect=new Rectangle(selection);if(!this._snapshotLayers.has(layer)){this._snapshotLayers.set(layer,selection);}
rect.calculateVerticesFromRect(layer,tile.rect,this._depthForLayer(layer)+1);rect.texture=tile.texture;this._appendRect(rect);}}
_calculateRects(){this._rects=[];this._snapshotLayers.clear();this._dimensionsForAutoscale={width:0,height:0};this._layerTree.forEachLayer(this._calculateLayerRect.bind(this));if(this._showSlowScrollRectsSetting.get()){this._layerTree.forEachLayer(this._calculateLayerScrollRects.bind(this));}
if(this._layerTexture&&this._visibleLayers.has(this._layerTexture.layer)){const layer=this._layerTexture.layer;const selection=new LayerSelection(layer);const rect=new Rectangle(selection);rect.setVertices(layer.quad(),this._depthForLayer(layer));rect.texture=this._layerTexture.texture;this._appendRect(rect);}else if(this._showPaints()){this._layerTree.forEachLayer(this._calculateLayerTileRects.bind(this));}}
_makeColorsArray(color){let colors=[];const normalizedColor=[color[0]/255,color[1]/255,color[2]/255,color[3]];for(let i=0;i<4;i++){colors=colors.concat(normalizedColor);}
return colors;}
_setVertexAttribute(attribute,array,length){const gl=this._gl;const buffer=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,buffer);gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(array),gl.STATIC_DRAW);gl.vertexAttribPointer(attribute,length,gl.FLOAT,false,0,0);}
_drawRectangle(vertices,mode,color,texture){const gl=this._gl;const white=[255,255,255,1];color=color||white;this._setVertexAttribute(this._shaderProgram.vertexPositionAttribute,vertices,3);this._setVertexAttribute(this._shaderProgram.textureCoordAttribute,[0,1,1,1,1,0,0,0],2);this._setVertexAttribute(this._shaderProgram.vertexColorAttribute,this._makeColorsArray(color),color.length);if(texture){gl.activeTexture(gl.TEXTURE0);gl.bindTexture(gl.TEXTURE_2D,texture);gl.uniform1i(this._shaderProgram.samplerUniform,0);}else{gl.bindTexture(gl.TEXTURE_2D,this._whiteTexture);}
const numberOfVertices=vertices.length/3;gl.drawArrays(mode,0,numberOfVertices);}
_drawTexture(vertices,texture,color){this._drawRectangle(vertices,this._gl.TRIANGLE_FAN,color,texture);}
_drawViewportAndChrome(){const viewport=this._layerTree.viewportSize();if(!viewport){return;}
const drawChrome=!Settings.Settings.instance().moduleSetting('frameViewerHideChromeWindow').get()&&this._chromeTextures.length>=3&&this._chromeTextures.indexOf(undefined)<0;const z=(this._maxDepth+1)*LayerSpacing;const borderWidth=Math.ceil(ViewportBorderWidth*this._scale);let vertices=[viewport.width,0,z,viewport.width,viewport.height,z,0,viewport.height,z,0,0,z];this._gl.lineWidth(borderWidth);this._drawRectangle(vertices,drawChrome?this._gl.LINE_STRIP:this._gl.LINE_LOOP,ViewportBorderColor);if(!drawChrome){return;}
const borderAdjustment=ViewportBorderWidth/2;const viewportWidth=this._layerTree.viewportSize().width+2*borderAdjustment;const chromeHeight=this._chromeTextures[0].image.naturalHeight;const middleFragmentWidth=viewportWidth-this._chromeTextures[0].image.naturalWidth-this._chromeTextures[2].image.naturalWidth;let x=-borderAdjustment;const y=-chromeHeight;for(let i=0;i<this._chromeTextures.length;++i){const width=i===ChromeTexture.Middle?middleFragmentWidth:this._chromeTextures[i].image.naturalWidth;if(width<0||x+width>viewportWidth){break;}
vertices=[x,y,z,x+width,y,z,x+width,y+chromeHeight,z,x,y+chromeHeight,z];this._drawTexture(vertices,(this._chromeTextures[i]));x+=width;}}
_drawViewRect(rect){const vertices=rect.vertices;if(rect.texture){this._drawTexture(vertices,rect.texture,rect.fillColor||undefined);}else if(rect.fillColor){this._drawRectangle(vertices,this._gl.TRIANGLE_FAN,rect.fillColor);}
this._gl.lineWidth(rect.lineWidth);if(rect.borderColor){this._drawRectangle(vertices,this._gl.LINE_LOOP,rect.borderColor);}}
_update(){if(!this.isShowing()){this._needsUpdate=true;return;}
if(!this._layerTree||!this._layerTree.root()){this._failBanner.show(this.contentElement);return;}
const gl=this._initGLIfNecessary();if(!gl){this._failBanner.element.removeChildren();this._failBanner.element.appendChild(this._webglDisabledBanner());this._failBanner.show(this.contentElement);return;}
this._failBanner.detach();this._gl.viewportWidth=this._canvasElement.width;this._gl.viewportHeight=this._canvasElement.height;this._calculateDepthsAndVisibility();this._calculateRects();this._updateTransformAndConstraints();gl.viewport(0,0,gl.viewportWidth,gl.viewportHeight);gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);this._rects.forEach(this._drawViewRect.bind(this));this._drawViewportAndChrome();}
_webglDisabledBanner(){const fragment=this.contentElement.ownerDocument.createDocumentFragment();fragment.createChild('div').textContent=UIString.UIString('Can\'t display layers,');fragment.createChild('div').textContent=UIString.UIString('WebGL support is disabled in your browser.');fragment.appendChild(UIUtils.formatLocalized('Check %s for possible reasons.',[XLink.XLink.create('about:gpu')]));return fragment;}
_selectionFromEventPoint(event){if(!this._layerTree){return null;}
let closestIntersectionPoint=Infinity;let closestObject=null;const projectionMatrix=new WebKitCSSMatrix().scale(1,-1,-1).translate(-1,-1,0).multiply(this._projectionMatrix);const x0=(event.clientX-this._canvasElement.totalOffsetLeft())*window.devicePixelRatio;const y0=-(event.clientY-this._canvasElement.totalOffsetTop())*window.devicePixelRatio;function checkIntersection(rect){if(!rect.relatedObject){return;}
const t=rect.intersectWithLine(projectionMatrix,x0,y0);if(t<closestIntersectionPoint){closestIntersectionPoint=t;closestObject=rect.relatedObject;}}
this._rects.forEach(checkIntersection);return closestObject;}
_createVisibilitySetting(caption,name,value,toolbar){const setting=Settings.Settings.instance().createSetting(name,value);setting.setTitle(UIString.UIString(caption));setting.addChangeListener(this._update,this);toolbar.appendToolbarItem(new Toolbar.ToolbarSettingCheckbox(setting));return setting;}
_initToolbar(){this._panelToolbar=this._transformController.toolbar();this.contentElement.appendChild(this._panelToolbar.element);this._showSlowScrollRectsSetting=this._createVisibilitySetting(ls`Slow scroll rects`,'frameViewerShowSlowScrollRects',true,this._panelToolbar);this._showPaintsSetting=this._createVisibilitySetting(ls`Paints`,'frameViewerShowPaints',true,this._panelToolbar);this._showPaintsSetting.addChangeListener(this._updatePaints,this);Settings.Settings.instance().moduleSetting('frameViewerHideChromeWindow').addChangeListener(this._update,this);}
_onContextMenu(event){const contextMenu=new ContextMenu.ContextMenu(event);contextMenu.defaultSection().appendItem(UIString.UIString('Reset View'),this._transformController.resetAndNotify.bind(this._transformController),false);const selection=this._selectionFromEventPoint(event);if(selection&&selection.type()===Type.Snapshot){contextMenu.defaultSection().appendItem(UIString.UIString('Show Paint Profiler'),this.dispatchEventToListeners.bind(this,Events$3.PaintProfilerRequested,selection),false);}
this._layerViewHost.showContextMenu(contextMenu,selection);}
_onMouseMove(event){if(event.which){return;}
this._layerViewHost.hoverObject(this._selectionFromEventPoint(event));}
_onMouseDown(event){this._mouseDownX=event.clientX;this._mouseDownY=event.clientY;}
_onMouseUp(event){const maxDistanceInPixels=6;if(this._mouseDownX&&Math.abs(event.clientX-this._mouseDownX)<maxDistanceInPixels&&Math.abs(event.clientY-this._mouseDownY)<maxDistanceInPixels){this._layerViewHost.selectObject(this._selectionFromEventPoint(event));}
delete this._mouseDownX;delete this._mouseDownY;}
_onDoubleClick(event){const selection=this._selectionFromEventPoint(event);if(selection&&(selection.type()===Type.Snapshot||selection.layer())){this.dispatchEventToListeners(Events$3.PaintProfilerRequested,selection);}
event.stopPropagation();}
_updatePaints(){if(this._showPaints()){this._textureManager.setLayerTree(this._layerTree);this._textureManager.forceUpdate();}else{this._textureManager.reset();}
this._update();}
_showPaints(){return this._showPaintsSetting.get();}}
const OutlineType={Hovered:'hovered',Selected:'selected'};const Events$3={PaintProfilerRequested:Symbol('PaintProfilerRequested'),ScaleChanged:Symbol('ScaleChanged')};const ChromeTexture={Left:0,Middle:1,Right:2};const ScrollRectTitles={RepaintsOnScroll:UIString.UIString('repaints on scroll'),TouchEventHandler:UIString.UIString('touch event listener'),WheelEventHandler:UIString.UIString('mousewheel event listener')};const FragmentShader=''+'precision mediump float;\n'+'varying vec4 vColor;\n'+'varying vec2 vTextureCoord;\n'+'uniform sampler2D uSampler;\n'+'void main(void)\n'+'{\n'+'    gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)) * vColor;\n'+'}';const VertexShader=''+'attribute vec3 aVertexPosition;\n'+'attribute vec2 aTextureCoord;\n'+'attribute vec4 aVertexColor;\n'+'uniform mat4 uPMatrix;\n'+'varying vec2 vTextureCoord;\n'+'varying vec4 vColor;\n'+'void main(void)\n'+'{\n'+'gl_Position = uPMatrix * vec4(aVertexPosition, 1.0);\n'+'vColor = aVertexColor;\n'+'vTextureCoord = aTextureCoord;\n'+'}';const HoveredBorderColor=[0,0,255,1];const SelectedBorderColor=[0,255,0,1];const BorderColor=[0,0,0,1];const ViewportBorderColor=[160,160,160,1];const ScrollRectBackgroundColor=[178,100,100,0.6];const HoveredImageMaskColor=[200,200,255,1];const BorderWidth=1;const SelectedBorderWidth=2;const ViewportBorderWidth=3;const LayerSpacing=20;const ScrollRectSpacing=4;class LayerTextureManager{constructor(textureUpdatedCallback){this._textureUpdatedCallback=textureUpdatedCallback;this._throttler=new Throttler.Throttler(0);this._scale=0;this._active=false;this.reset();}
static _createTextureForImage(gl,image){const texture=gl.createTexture();texture.image=image;gl.bindTexture(gl.TEXTURE_2D,texture);gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1);gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,texture.image);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);gl.bindTexture(gl.TEXTURE_2D,null);return texture;}
reset(){if(this._tilesByLayer){this.setLayerTree(null);}
this._tilesByLayer=new Map();this._queue=[];}
setContext(glContext){this._gl=glContext;if(this._scale){this._updateTextures();}}
suspend(){this._active=false;}
resume(){this._active=true;if(this._queue.length){this._update();}}
setLayerTree(layerTree){const newLayers=new Set();const oldLayers=Array.from(this._tilesByLayer.keys());if(layerTree){layerTree.forEachLayer(layer=>{if(!layer.drawsContent()){return;}
newLayers.add(layer);if(!this._tilesByLayer.has(layer)){this._tilesByLayer.set(layer,[]);this.layerNeedsUpdate(layer);}});}
if(!oldLayers.length){this.forceUpdate();}
for(const layer of oldLayers){if(newLayers.has(layer)){continue;}
this._tilesByLayer.get(layer).forEach(tile=>tile.dispose());this._tilesByLayer.delete(layer);}}
_setSnapshotsForLayer(layer,snapshots){const oldSnapshotsToTiles=new Map((this._tilesByLayer.get(layer)||[]).map(tile=>[tile.snapshot,tile]));const newTiles=[];const reusedTiles=[];for(const snapshot of snapshots){const oldTile=oldSnapshotsToTiles.get(snapshot);if(oldTile){reusedTiles.push(oldTile);oldSnapshotsToTiles.delete(oldTile);}else{newTiles.push(new Tile(snapshot));}}
this._tilesByLayer.set(layer,reusedTiles.concat(newTiles));for(const tile of oldSnapshotsToTiles.values()){tile.dispose();}
if(!this._gl||!this._scale){return Promise.resolve();}
return Promise.all(newTiles.map(tile=>tile.update(this._gl,this._scale))).then(this._textureUpdatedCallback);}
setScale(scale){if(this._scale&&this._scale>=scale){return;}
this._scale=scale;this._updateTextures();}
tilesForLayer(layer){return this._tilesByLayer.get(layer)||[];}
layerNeedsUpdate(layer){if(this._queue.indexOf(layer)<0){this._queue.push(layer);}
if(this._active){this._throttler.schedule(this._update.bind(this));}}
forceUpdate(){this._queue.forEach(layer=>this._updateLayer(layer));this._queue=[];this._update();}
_update(){const layer=this._queue.shift();if(!layer){return Promise.resolve();}
if(this._queue.length){this._throttler.schedule(this._update.bind(this));}
return this._updateLayer(layer);}
_updateLayer(layer){return Promise.all(layer.snapshots()).then(snapshots=>this._setSnapshotsForLayer(layer,snapshots.filter(snapshot=>!!snapshot)));}
_updateTextures(){if(!this._gl){return;}
if(!this._scale){return;}
for(const tiles of this._tilesByLayer.values()){for(const tile of tiles){const promise=tile.updateScale(this._gl,this._scale);if(promise){promise.then(this._textureUpdatedCallback);}}}}}
class Rectangle{constructor(relatedObject){this.relatedObject=relatedObject;this.lineWidth=1;this.borderColor=null;this.fillColor=null;this.texture=null;}
setVertices(quad,z){this.vertices=[quad[0],quad[1],z,quad[2],quad[3],z,quad[4],quad[5],z,quad[6],quad[7],z];}
_calculatePointOnQuad(quad,ratioX,ratioY){const x0=quad[0];const y0=quad[1];const x1=quad[2];const y1=quad[3];const x2=quad[4];const y2=quad[5];const x3=quad[6];const y3=quad[7];const firstSidePointX=x0+ratioX*(x1-x0);const firstSidePointY=y0+ratioX*(y1-y0);const thirdSidePointX=x3+ratioX*(x2-x3);const thirdSidePointY=y3+ratioX*(y2-y3);const x=firstSidePointX+ratioY*(thirdSidePointX-firstSidePointX);const y=firstSidePointY+ratioY*(thirdSidePointY-firstSidePointY);return[x,y];}
calculateVerticesFromRect(layer,rect,z){const quad=layer.quad();const rx1=rect.x/layer.width();const rx2=(rect.x+rect.width)/layer.width();const ry1=rect.y/layer.height();const ry2=(rect.y+rect.height)/layer.height();const rectQuad=this._calculatePointOnQuad(quad,rx1,ry1).concat(this._calculatePointOnQuad(quad,rx2,ry1)).concat(this._calculatePointOnQuad(quad,rx2,ry2)).concat(this._calculatePointOnQuad(quad,rx1,ry2));this.setVertices(rectQuad,z);}
intersectWithLine(matrix,x0,y0){let i;const points=[];for(i=0;i<4;++i){points[i]=Geometry.multiplyVectorByMatrixAndNormalize(new Geometry.Vector(this.vertices[i*3],this.vertices[i*3+1],this.vertices[i*3+2]),matrix);}
const normal=Geometry.crossProduct(Geometry.subtract(points[1],points[0]),Geometry.subtract(points[2],points[1]));const A=normal.x;const B=normal.y;const C=normal.z;const D=-(A*points[0].x+B*points[0].y+C*points[0].z);const t=-(D+A*x0+B*y0)/C;const pt=new Geometry.Vector(x0,y0,t);const tVects=points.map(Geometry.subtract.bind(null,pt));for(i=0;i<tVects.length;++i){const product=Geometry.scalarProduct(normal,Geometry.crossProduct(tVects[i],tVects[(i+1)%tVects.length]));if(product<0){return undefined;}}
return t;}}
class Tile{constructor(snapshotWithRect){this.snapshot=snapshotWithRect.snapshot;this.rect=snapshotWithRect.rect;this.scale=0;this.texture=null;}
dispose(){this.snapshot.release();if(this.texture){this._gl.deleteTexture(this.texture);this.texture=null;}}
updateScale(glContext,scale){if(this.texture&&this.scale>=scale){return null;}
return this.update(glContext,scale);}
async update(glContext,scale){this._gl=glContext;this.scale=scale;const imageURL=await this.snapshot.replay(scale);const image=imageURL?await UIUtils.loadImage(imageURL):null;this.texture=image?LayerTextureManager._createTextureForImage(glContext,image):null;}}
var Layers3DView$1=Object.freeze({__proto__:null,Layers3DView:Layers3DView,OutlineType:OutlineType,Events:Events$3,ChromeTexture:ChromeTexture,ScrollRectTitles:ScrollRectTitles,FragmentShader:FragmentShader,VertexShader:VertexShader,HoveredBorderColor:HoveredBorderColor,SelectedBorderColor:SelectedBorderColor,BorderColor:BorderColor,ViewportBorderColor:ViewportBorderColor,ScrollRectBackgroundColor:ScrollRectBackgroundColor,HoveredImageMaskColor:HoveredImageMaskColor,BorderWidth:BorderWidth,SelectedBorderWidth:SelectedBorderWidth,ViewportBorderWidth:ViewportBorderWidth,LayerSpacing:LayerSpacing,ScrollRectSpacing:ScrollRectSpacing,LayerTextureManager:LayerTextureManager,Rectangle:Rectangle,Tile:Tile});class PaintProfilerView extends Widget.HBox{constructor(showImageCallback){super(true);this.registerRequiredCSS('layer_viewer/paintProfiler.css');this.contentElement.classList.add('paint-profiler-overview');this._canvasContainer=this.contentElement.createChild('div','paint-profiler-canvas-container');this._progressBanner=this.contentElement.createChild('div','full-widget-dimmed-banner hidden');this._progressBanner.textContent=UIString.UIString('Profiling…');this._pieChart=new PieChart.PieChart({chartName:ls`Profiling Results`,size:55,formatter:this._formatPieChartTime.bind(this)});this._pieChart.element.classList.add('paint-profiler-pie-chart');this.contentElement.appendChild(this._pieChart.element);this._showImageCallback=showImageCallback;this._canvas=this._canvasContainer.createChild('canvas','fill');this._context=this._canvas.getContext('2d');this._selectionWindow=new OverviewGrid.Window(this._canvasContainer);this._selectionWindow.addEventListener(OverviewGrid.Events.WindowChanged,this._onWindowChanged,this);this._innerBarWidth=4*window.devicePixelRatio;this._minBarHeight=window.devicePixelRatio;this._barPaddingWidth=2*window.devicePixelRatio;this._outerBarWidth=this._innerBarWidth+this._barPaddingWidth;this._pendingScale=1;this._scale=this._pendingScale;this._reset();}
static categories(){if(PaintProfilerView._categories){return PaintProfilerView._categories;}
PaintProfilerView._categories={shapes:new PaintProfilerCategory('shapes',UIString.UIString('Shapes'),'rgb(255, 161, 129)'),bitmap:new PaintProfilerCategory('bitmap',UIString.UIString('Bitmap'),'rgb(136, 196, 255)'),text:new PaintProfilerCategory('text',UIString.UIString('Text'),'rgb(180, 255, 137)'),misc:new PaintProfilerCategory('misc',UIString.UIString('Misc'),'rgb(206, 160, 255)')};return PaintProfilerView._categories;}
static _initLogItemCategories(){if(PaintProfilerView._logItemCategoriesMap){return PaintProfilerView._logItemCategoriesMap;}
const categories=PaintProfilerView.categories();const logItemCategories={};logItemCategories['Clear']=categories['misc'];logItemCategories['DrawPaint']=categories['misc'];logItemCategories['DrawData']=categories['misc'];logItemCategories['SetMatrix']=categories['misc'];logItemCategories['PushCull']=categories['misc'];logItemCategories['PopCull']=categories['misc'];logItemCategories['Translate']=categories['misc'];logItemCategories['Scale']=categories['misc'];logItemCategories['Concat']=categories['misc'];logItemCategories['Restore']=categories['misc'];logItemCategories['SaveLayer']=categories['misc'];logItemCategories['Save']=categories['misc'];logItemCategories['BeginCommentGroup']=categories['misc'];logItemCategories['AddComment']=categories['misc'];logItemCategories['EndCommentGroup']=categories['misc'];logItemCategories['ClipRect']=categories['misc'];logItemCategories['ClipRRect']=categories['misc'];logItemCategories['ClipPath']=categories['misc'];logItemCategories['ClipRegion']=categories['misc'];logItemCategories['DrawPoints']=categories['shapes'];logItemCategories['DrawRect']=categories['shapes'];logItemCategories['DrawOval']=categories['shapes'];logItemCategories['DrawRRect']=categories['shapes'];logItemCategories['DrawPath']=categories['shapes'];logItemCategories['DrawVertices']=categories['shapes'];logItemCategories['DrawDRRect']=categories['shapes'];logItemCategories['DrawBitmap']=categories['bitmap'];logItemCategories['DrawBitmapRectToRect']=categories['bitmap'];logItemCategories['DrawBitmapMatrix']=categories['bitmap'];logItemCategories['DrawBitmapNine']=categories['bitmap'];logItemCategories['DrawSprite']=categories['bitmap'];logItemCategories['DrawPicture']=categories['bitmap'];logItemCategories['DrawText']=categories['text'];logItemCategories['DrawPosText']=categories['text'];logItemCategories['DrawPosTextH']=categories['text'];logItemCategories['DrawTextOnPath']=categories['text'];PaintProfilerView._logItemCategoriesMap=logItemCategories;return logItemCategories;}
static _categoryForLogItem(logItem){const method=logItem.method.toTitleCase();const logItemCategories=PaintProfilerView._initLogItemCategories();let result=logItemCategories[method];if(!result){result=PaintProfilerView.categories()['misc'];logItemCategories[method]=result;}
return result;}
onResize(){this._update();}
async setSnapshotAndLog(snapshot,log,clipRect){this._reset();this._snapshot=snapshot;if(this._snapshot){this._snapshot.addReference();}
this._log=log;this._logCategories=this._log.map(PaintProfilerView._categoryForLogItem);if(!this._snapshot){this._update();this._pieChart.initializeWithTotal(0);this._selectionWindow.setEnabled(false);return;}
this._selectionWindow.setEnabled(true);this._progressBanner.classList.remove('hidden');this._updateImage();const profiles=await snapshot.profile(clipRect);this._progressBanner.classList.add('hidden');this._profiles=profiles;this._update();this._updatePieChart();}
setScale(scale){const needsUpdate=scale>this._scale;const predictiveGrowthFactor=2;this._pendingScale=Math.min(1,scale*predictiveGrowthFactor);if(needsUpdate&&this._snapshot){this._updateImage();}}
_update(){this._canvas.width=this._canvasContainer.clientWidth*window.devicePixelRatio;this._canvas.height=this._canvasContainer.clientHeight*window.devicePixelRatio;this._samplesPerBar=0;if(!this._profiles||!this._profiles.length){return;}
const maxBars=Math.floor((this._canvas.width-2*this._barPaddingWidth)/this._outerBarWidth);const sampleCount=this._log.length;this._samplesPerBar=Math.ceil(sampleCount/maxBars);let maxBarTime=0;const barTimes=[];const barHeightByCategory=[];let heightByCategory={};for(let i=0,lastBarIndex=0,lastBarTime=0;i<sampleCount;){let categoryName=(this._logCategories[i]&&this._logCategories[i].name)||'misc';const sampleIndex=this._log[i].commandIndex;for(let row=0;row<this._profiles.length;row++){const sample=this._profiles[row][sampleIndex];lastBarTime+=sample;heightByCategory[categoryName]=(heightByCategory[categoryName]||0)+sample;}
++i;if(i-lastBarIndex===this._samplesPerBar||i===sampleCount){const factor=this._profiles.length*(i-lastBarIndex);lastBarTime/=factor;for(categoryName in heightByCategory){heightByCategory[categoryName]/=factor;}
barTimes.push(lastBarTime);barHeightByCategory.push(heightByCategory);if(lastBarTime>maxBarTime){maxBarTime=lastBarTime;}
lastBarTime=0;heightByCategory={};lastBarIndex=i;}}
const paddingHeight=4*window.devicePixelRatio;const scale=(this._canvas.height-paddingHeight-this._minBarHeight)/maxBarTime;for(let i=0;i<barTimes.length;++i){for(const categoryName in barHeightByCategory[i]){barHeightByCategory[i][categoryName]*=(barTimes[i]*scale+this._minBarHeight)/barTimes[i];}
this._renderBar(i,barHeightByCategory[i]);}}
_renderBar(index,heightByCategory){const categories=PaintProfilerView.categories();let currentHeight=0;const x=this._barPaddingWidth+index*this._outerBarWidth;for(const categoryName in categories){if(!heightByCategory[categoryName]){continue;}
currentHeight+=heightByCategory[categoryName];const y=this._canvas.height-currentHeight;this._context.fillStyle=categories[categoryName].color;this._context.fillRect(x,y,this._innerBarWidth,heightByCategory[categoryName]);}}
_onWindowChanged(){this.dispatchEventToListeners(Events$4.WindowChanged);this._updatePieChart();if(this._updateImageTimer){return;}
this._updateImageTimer=setTimeout(this._updateImage.bind(this),100);}
_updatePieChart(){const window=this.selectionWindow();if(!this._profiles||!this._profiles.length||!window){return;}
let totalTime=0;const timeByCategory={};for(let i=window.left;i<window.right;++i){const logEntry=this._log[i];const category=PaintProfilerView._categoryForLogItem(logEntry);timeByCategory[category.color]=timeByCategory[category.color]||0;for(let j=0;j<this._profiles.length;++j){const time=this._profiles[j][logEntry.commandIndex];totalTime+=time;timeByCategory[category.color]+=time;}}
this._pieChart.initializeWithTotal(totalTime/this._profiles.length);for(const color in timeByCategory){this._pieChart.addSlice(timeByCategory[color]/this._profiles.length,color);}}
_formatPieChartTime(value){return Number.millisToString(value*1000,true);}
selectionWindow(){if(!this._log){return null;}
const screenLeft=this._selectionWindow.windowLeft*this._canvas.width;const screenRight=this._selectionWindow.windowRight*this._canvas.width;const barLeft=Math.floor(screenLeft/this._outerBarWidth);const barRight=Math.floor((screenRight+this._innerBarWidth-this._barPaddingWidth/2)/this._outerBarWidth);const stepLeft=NumberUtilities.clamp(barLeft*this._samplesPerBar,0,this._log.length-1);const stepRight=NumberUtilities.clamp(barRight*this._samplesPerBar,0,this._log.length);return{left:stepLeft,right:stepRight};}
_updateImage(){delete this._updateImageTimer;let left;let right;const window=this.selectionWindow();if(this._profiles&&this._profiles.length&&window){left=this._log[window.left].commandIndex;right=this._log[window.right-1].commandIndex;}
const scale=this._pendingScale;this._snapshot.replay(scale,left,right).then(image=>{if(!image){return;}
this._scale=scale;this._showImageCallback(image);});}
_reset(){if(this._snapshot){this._snapshot.release();}
this._snapshot=null;this._profiles=null;this._selectionWindow.reset();this._selectionWindow.setEnabled(false);}}
const Events$4={WindowChanged:Symbol('WindowChanged')};class PaintProfilerCommandLogView extends ThrottledWidget.ThrottledWidget{constructor(){super();this.setMinimumSize(100,25);this.element.classList.add('overflow-auto');this._treeOutline=new TreeOutline.TreeOutlineInShadow();ARIAUtils.setAccessibleName(this._treeOutline.contentElement,ls`Command Log`);this.element.appendChild(this._treeOutline.element);this.setDefaultFocusedElement(this._treeOutline.contentElement);this._log=[];}
setCommandLog(log){this._log=log;this._treeItemCache=new Map();this.updateWindow({left:0,right:this._log.length});}
_appendLogItem(logItem){let treeElement=this._treeItemCache.get(logItem);if(!treeElement){treeElement=new LogTreeElement(this,logItem);this._treeItemCache.set(logItem,treeElement);}else if(treeElement.parent){return;}
this._treeOutline.appendChild(treeElement);}
updateWindow(selectionWindow){this._selectionWindow=selectionWindow;this.update();}
doUpdate(){if(!this._selectionWindow||!this._log.length){this._treeOutline.removeChildren();return Promise.resolve();}
const root=this._treeOutline.rootElement();for(;;){const child=root.firstChild();if(!child||child._logItem.commandIndex>=this._selectionWindow.left){break;}
root.removeChildAtIndex(0);}
for(;;){const child=root.lastChild();if(!child||child._logItem.commandIndex<this._selectionWindow.right){break;}
root.removeChildAtIndex(root.children().length-1);}
for(let i=this._selectionWindow.left,right=this._selectionWindow.right;i<right;++i){this._appendLogItem(this._log[i]);}
return Promise.resolve();}}
class LogTreeElement extends TreeOutline.TreeElement{constructor(ownerView,logItem){super('',!!logItem.params);this._logItem=logItem;this._ownerView=ownerView;this._filled=false;}
onattach(){this._update();}
async onpopulate(){for(const param in this._logItem.params){LogPropertyTreeElement._appendLogPropertyItem(this,param,this._logItem.params[param]);}}
_paramToString(param,name){if(typeof param!=='object'){return typeof param==='string'&&param.length>100?name:JSON.stringify(param);}
let str='';let keyCount=0;for(const key in param){if(++keyCount>4||typeof param[key]==='object'||(typeof param[key]==='string'&&param[key].length>100)){return name;}
if(str){str+=', ';}
str+=param[key];}
return str;}
_paramsToString(params){let str='';for(const key in params){if(str){str+=', ';}
str+=this._paramToString(params[key],key);}
return str;}
_update(){const title=createDocumentFragment();title.createTextChild(this._logItem.method+'('+this._paramsToString(this._logItem.params)+')');this.title=title;}}
class LogPropertyTreeElement extends TreeOutline.TreeElement{constructor(property){super();this._property=property;}
static _appendLogPropertyItem(element,name,value){const treeElement=new LogPropertyTreeElement({name:name,value:value});element.appendChild(treeElement);if(value&&typeof value==='object'){for(const property in value){LogPropertyTreeElement._appendLogPropertyItem(treeElement,property,value[property]);}}}
onattach(){const title=createDocumentFragment();const nameElement=title.createChild('span','name');nameElement.textContent=this._property.name;const separatorElement=title.createChild('span','separator');separatorElement.textContent=': ';if(this._property.value===null||typeof this._property.value!=='object'){const valueElement=title.createChild('span','value');valueElement.textContent=JSON.stringify(this._property.value);valueElement.classList.add('cm-js-'+(this._property.value===null?'null':typeof this._property.value));}
this.title=title;}}
class PaintProfilerCategory{constructor(name,title,color){this.name=name;this.title=title;this.color=color;}}
var PaintProfilerView$1=Object.freeze({__proto__:null,PaintProfilerView:PaintProfilerView,Events:Events$4,PaintProfilerCommandLogView:PaintProfilerCommandLogView,LogTreeElement:LogTreeElement,LogPropertyTreeElement:LogPropertyTreeElement,PaintProfilerCategory:PaintProfilerCategory});export{LayerDetailsView$1 as LayerDetailsView,LayerTreeOutline$1 as LayerTreeOutline,LayerViewHost$1 as LayerViewHost,Layers3DView$1 as Layers3DView,PaintProfilerView$1 as PaintProfilerView,TransformController$1 as TransformController};