LayerViewer.LayerDetailsView=class extends UI.Widget{constructor(layerViewHost){super(true);this.registerRequiredCSS('layer_viewer/layerDetailsView.css');this._layerViewHost=layerViewHost;this._layerViewHost.registerView(this);this._emptyWidget=new UI.EmptyWidget(Common.UIString('Select a layer to see its details'));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 LayerViewer.LayerView.ScrollRectSelection(this._selection.layer(),index));}
_onPaintProfilerButtonClicked(){if(this._selection.type()===LayerViewer.LayerView.Selection.Type.Snapshot||this._selection.layer())
this.dispatchEventToListeners(LayerViewer.LayerDetailsView.Events.PaintProfilerRequested,this._selection);}
_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=Common.UIString('%s %d × %d (at %d, %d)',LayerViewer.LayerDetailsView._slowScrollRectNames.get(scrollRect.type),scrollRect.rect.x,scrollRect.rect.y,scrollRect.rect.width,scrollRect.rect.height);element.addEventListener('click',this._onScrollRectClicked.bind(this,index),false);}
_formatStickyAncestorLayer(title,layer){if(!layer)
return'';const node=layer.nodeForSelfOrAncestor();const name=node?node.simpleSelector():Common.UIString('<unnamed>');return Common.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=Common.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=Common.UIString('Containing Block %d × %d (at %d, %d)',containingBlockRect.width,containingBlockRect.height,containingBlockRect.x,containingBlockRect.y);this._createStickyAncestorChild(Common.UIString('Nearest Layer Shifting Sticky Box'),constraint.nearestLayerShiftingStickyBox());this._createStickyAncestorChild(Common.UIString('Nearest Layer Shifting Containing Block'),constraint.nearestLayerShiftingContainingBlock());}
update(){const layer=this._selection&&this._selection.layer();if(!layer){this._tableElement.remove();this._paintProfilerButton.remove();this._emptyWidget.show(this.contentElement);return;}
this._emptyWidget.detach();this.contentElement.appendChild(this._tableElement);this.contentElement.appendChild(this._paintProfilerButton);this._sizeCell.textContent=Common.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.requestCompositingReasons().then(this._updateCompositingReasons.bind(this));this._scrollRectsCell.removeChildren();layer.scrollRects().forEach(this._createScrollRectElement.bind(this));this._populateStickyPositionConstraintCell(layer.stickyPositionConstraint());const snapshot=this._selection.type()===LayerViewer.LayerView.Selection.Type.Snapshot?(this._selection).snapshot():null;this._paintProfilerButton.classList.toggle('hidden',!snapshot);}
_buildContent(){this._tableElement=this.contentElement.createChild('table');this._tbodyElement=this._tableElement.createChild('tbody');this._sizeCell=this._createRow(Common.UIString('Size'));this._compositingReasonsCell=this._createRow(Common.UIString('Compositing Reasons'));this._memoryEstimateCell=this._createRow(Common.UIString('Memory estimate'));this._paintCountCell=this._createRow(Common.UIString('Paint count'));this._scrollRectsCell=this._createRow(Common.UIString('Slow scroll regions'));this._stickyPositionConstraintCell=this._createRow(Common.UIString('Sticky position constraint'));this._paintProfilerButton=this.contentElement.createChild('a','hidden link');this._paintProfilerButton.textContent=Common.UIString('Paint Profiler');this._paintProfilerButton.addEventListener('click',this._onPaintProfilerButtonClicked.bind(this));}
_createRow(title){const tr=this._tbodyElement.createChild('tr');const titleCell=tr.createChild('td');titleCell.textContent=title;return tr.createChild('td');}
_updateCompositingReasons(compositingReasons){if(!compositingReasons||!compositingReasons.length){this._compositingReasonsCell.textContent='n/a';return;}
this._compositingReasonsCell.removeChildren();const list=this._compositingReasonsCell.createChild('ul');for(let i=0;i<compositingReasons.length;++i){let text=LayerViewer.LayerDetailsView.CompositingReasonDetail[compositingReasons[i]]||compositingReasons[i];if(/\s.*[^.]$/.test(text))
text+='.';list.createChild('li').textContent=text;}}};LayerViewer.LayerDetailsView.Events={PaintProfilerRequested:Symbol('PaintProfilerRequested')};LayerViewer.LayerDetailsView.CompositingReasonDetail={'transform3D':Common.UIString('Composition due to association with an element with a CSS 3D transform.'),'video':Common.UIString('Composition due to association with a <video> element.'),'canvas':Common.UIString('Composition due to the element being a <canvas> element.'),'plugin':Common.UIString('Composition due to association with a plugin.'),'iFrame':Common.UIString('Composition due to association with an <iframe> element.'),'backfaceVisibilityHidden':Common.UIString('Composition due to association with an element with a "backface-visibility: hidden" style.'),'animation':Common.UIString('Composition due to association with an animated element.'),'filters':Common.UIString('Composition due to association with an element with CSS filters applied.'),'scrollDependentPosition':Common.UIString('Composition due to association with an element with a "position: fixed" or "position: sticky" style.'),'overflowScrollingTouch':Common.UIString('Composition due to association with an element with a "overflow-scrolling: touch" style.'),'blending':Common.UIString('Composition due to association with an element that has blend mode other than "normal".'),'assumedOverlap':Common.UIString('Composition due to association with an element that may overlap other composited elements.'),'overlap':Common.UIString('Composition due to association with an element overlapping other composited elements.'),'negativeZIndexChildren':Common.UIString('Composition due to association with an element with descendants that have a negative z-index.'),'transformWithCompositedDescendants':Common.UIString('Composition due to association with an element with composited descendants.'),'opacityWithCompositedDescendants':Common.UIString('Composition due to association with an element with opacity applied and composited descendants.'),'maskWithCompositedDescendants':Common.UIString('Composition due to association with a masked element and composited descendants.'),'reflectionWithCompositedDescendants':Common.UIString('Composition due to association with an element with a reflection and composited descendants.'),'filterWithCompositedDescendants':Common.UIString('Composition due to association with an element with CSS filters applied and composited descendants.'),'blendingWithCompositedDescendants':Common.UIString('Composition due to association with an element with CSS blending applied and composited descendants.'),'clipsCompositingDescendants':Common.UIString('Composition due to association with an element clipping compositing descendants.'),'perspective':Common.UIString('Composition due to association with an element with perspective applied.'),'preserve3D':Common.UIString('Composition due to association with an element with a "transform-style: preserve-3d" style.'),'root':Common.UIString('Root layer.'),'layerForClip':Common.UIString('Layer for clip.'),'layerForScrollbar':Common.UIString('Layer for scrollbar.'),'layerForScrollingContainer':Common.UIString('Layer for scrolling container.'),'layerForForeground':Common.UIString('Layer for foreground.'),'layerForBackground':Common.UIString('Layer for background.'),'layerForMask':Common.UIString('Layer for mask.'),'layerForVideoOverlay':Common.UIString('Layer for video overlay.'),};LayerViewer.LayerDetailsView._slowScrollRectNames=new Map([[SDK.Layer.ScrollRectType.NonFastScrollable,Common.UIString('Non fast scrollable')],[SDK.Layer.ScrollRectType.TouchEventHandler,Common.UIString('Touch event handler')],[SDK.Layer.ScrollRectType.WheelEventHandler,Common.UIString('Wheel event handler')],[SDK.Layer.ScrollRectType.RepaintsOnScroll,Common.UIString('Repaints on scroll')]]);;LayerViewer.LayerTreeOutline=class extends Common.Object{constructor(layerViewHost){super();this._layerViewHost=layerViewHost;this._layerViewHost.registerView(this);this._treeOutline=new UI.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);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[LayerViewer.LayerTreeElement._symbol];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[LayerViewer.LayerTreeElement._symbol];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[LayerViewer.LayerTreeElement._symbol];let parentLayer=layer.parent();while(parentLayer&&parentLayer!==root&&!parentLayer.drawsContent()&&!showInternalLayers)
parentLayer=parentLayer.parent();const parent=layer===root?this._treeOutline.rootElement():parentLayer[LayerViewer.LayerTreeElement._symbol];if(!parent){console.assert(false,'Parent is not in the tree');return;}
if(!node){node=new LayerViewer.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[LayerViewer.LayerTreeElement._symbol].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 UI.ContextMenu(event);this._layerViewHost.showContextMenu(contextMenu,selection);}
_selectionForNode(node){return node&&node._layer?new LayerViewer.LayerView.LayerSelection(node._layer):null;}};LayerViewer.LayerTreeElement=class extends UI.TreeElement{constructor(tree,layer){super();this._treeOutline=tree;this._layer=layer;this._layer[LayerViewer.LayerTreeElement._symbol]=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=Common.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);}};LayerViewer.LayerTreeElement._symbol=Symbol('layer');;LayerViewer.LayerView=function(){};LayerViewer.LayerView.prototype={hoverObject(selection){},selectObject(selection){},setLayerTree(layerTree){}};LayerViewer.LayerView.Selection=class{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;}};LayerViewer.LayerView.Selection.Type={Layer:Symbol('Layer'),ScrollRect:Symbol('ScrollRect'),Snapshot:Symbol('Snapshot')};LayerViewer.LayerView.LayerSelection=class extends LayerViewer.LayerView.Selection{constructor(layer){console.assert(layer,'LayerSelection with empty layer');super(LayerViewer.LayerView.Selection.Type.Layer,layer);}
_isEqual(other){return other._type===LayerViewer.LayerView.Selection.Type.Layer&&other.layer().id()===this.layer().id();}};LayerViewer.LayerView.ScrollRectSelection=class extends LayerViewer.LayerView.Selection{constructor(layer,scrollRectIndex){super(LayerViewer.LayerView.Selection.Type.ScrollRect,layer);this.scrollRectIndex=scrollRectIndex;}
_isEqual(other){return other._type===LayerViewer.LayerView.Selection.Type.ScrollRect&&this.layer().id()===other.layer().id()&&this.scrollRectIndex===other.scrollRectIndex;}};LayerViewer.LayerView.SnapshotSelection=class extends LayerViewer.LayerView.Selection{constructor(layer,snapshot){super(LayerViewer.LayerView.Selection.Type.Snapshot,layer);this._snapshot=snapshot;}
_isEqual(other){return other._type===LayerViewer.LayerView.Selection.Type.Snapshot&&this.layer().id()===other.layer().id()&&this._snapshot===other._snapshot;}
snapshot(){return this._snapshot;}};LayerViewer.LayerViewHost=class{constructor(){this._views=[];this._selectedObject=null;this._hoveredObject=null;this._showInternalLayersSetting=Common.settings.createSetting('layersShowInternalLayers',false);}
registerView(layerView){this._views.push(layerView);}
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(LayerViewer.LayerView.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(LayerViewer.LayerView.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(Common.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;}
SDK.OverlayModel.hideDOMNodeHighlight();}};;LayerViewer.Layers3DView=class extends UI.VBox{constructor(layerViewHost){super(true);this.registerRequiredCSS('layer_viewer/layers3DView.css');this.contentElement.classList.add('layers-3d-view');this._failBanner=new UI.VBox();this._failBanner.element.classList.add('full-widget-dimmed-banner');this._failBanner.element.createTextChild(Common.UIString('Layer information is not yet available.'));this._layerViewHost=layerViewHost;this._layerViewHost.registerView(this);this._transformController=new LayerViewer.TransformController(this.contentElement);this._transformController.addEventListener(LayerViewer.TransformController.Events.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);this._lastSelection={};this._layerTree=null;this._textureManager=new LayerViewer.LayerTextureManager(this._update.bind(this));this._chromeTextures=[];this._rects=[];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;}
UI.loadImage(imageURL).then(image=>{const texture=image&&LayerViewer.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(LayerViewer.Layers3DView.OutlineType.Hovered,selection);}
selectObject(selection){this._setOutline(LayerViewer.Layers3DView.OutlineType.Hovered,null);this._setOutline(LayerViewer.Layers3DView.OutlineType.Selected,selection);}
snapshotForSelection(selection){if(selection.type()===LayerViewer.LayerView.Selection.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,LayerViewer.Layers3DView.FragmentShader);this._createShader(this._gl.VERTEX_SHADER,LayerViewer.Layers3DView.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=Number.constrain(this._scale,0.1,1);if(textureScale!==this._oldTextureScale){this._oldTextureScale=textureScale;this._textureManager.setScale(textureScale);this.dispatchEventToListeners(LayerViewer.Layers3DView.Events.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=UI.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){UI.loadImage(url).then(image=>{this._chromeTextures[index]=image&&LayerViewer.LayerTextureManager._createTextureForImage(this._gl,image)||undefined;});}
loadChromeTexture.call(this,LayerViewer.Layers3DView.ChromeTexture.Left,'Images/chromeLeft.png');loadChromeTexture.call(this,LayerViewer.Layers3DView.ChromeTexture.Middle,'Images/chromeMiddle.png');loadChromeTexture.call(this,LayerViewer.Layers3DView.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()]*LayerViewer.Layers3DView.LayerSpacing;}
_calculateScrollRectDepth(layer,index){return this._depthForLayer(layer)+index*LayerViewer.Layers3DView.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 LayerViewer.LayerView.LayerSelection(layer);const rect=new LayerViewer.Layers3DView.Rectangle(selection);rect.setVertices(layer.quad(),this._depthForLayer(layer));this._appendRect(rect);this._updateDimensionsForAutoscale(layer);}
_appendRect(rect){const selection=rect.relatedObject;const isSelected=LayerViewer.LayerView.Selection.isEqual(this._lastSelection[LayerViewer.Layers3DView.OutlineType.Selected],selection);const isHovered=LayerViewer.LayerView.Selection.isEqual(this._lastSelection[LayerViewer.Layers3DView.OutlineType.Hovered],selection);if(isSelected){rect.borderColor=LayerViewer.Layers3DView.SelectedBorderColor;}else if(isHovered){rect.borderColor=LayerViewer.Layers3DView.HoveredBorderColor;const fillColor=rect.fillColor||[255,255,255,1];const maskColor=LayerViewer.Layers3DView.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=LayerViewer.Layers3DView.BorderColor;}
rect.lineWidth=isSelected?LayerViewer.Layers3DView.SelectedBorderWidth:LayerViewer.Layers3DView.BorderWidth;this._rects.push(rect);}
_calculateLayerScrollRects(layer){const scrollRects=layer.scrollRects();for(let i=0;i<scrollRects.length;++i){const selection=new LayerViewer.LayerView.ScrollRectSelection(layer,i);const rect=new LayerViewer.Layers3DView.Rectangle(selection);rect.calculateVerticesFromRect(layer,scrollRects[i].rect,this._calculateScrollRectDepth(layer,i));rect.fillColor=LayerViewer.Layers3DView.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 LayerViewer.LayerView.SnapshotSelection(layer,{rect:tile.rect,snapshot:tile.snapshot});const rect=new LayerViewer.Layers3DView.Rectangle(selection);rect.calculateVerticesFromRect(layer,tile.rect,this._depthForLayer(layer)+1);rect.texture=tile.texture;this._appendRect(rect);}}
_calculateRects(){this._rects=[];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 LayerViewer.LayerView.LayerSelection(layer);const rect=new LayerViewer.Layers3DView.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=!Common.moduleSetting('frameViewerHideChromeWindow').get()&&this._chromeTextures.length>=3&&this._chromeTextures.indexOf(undefined)<0;const z=(this._maxDepth+1)*LayerViewer.Layers3DView.LayerSpacing;const borderWidth=Math.ceil(LayerViewer.Layers3DView.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,LayerViewer.Layers3DView.ViewportBorderColor);if(!drawChrome)
return;const borderAdjustment=LayerViewer.Layers3DView.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===LayerViewer.Layers3DView.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=Common.UIString('Can\'t display layers,');fragment.createChild('div').textContent=Common.UIString('WebGL support is disabled in your browser.');fragment.appendChild(UI.formatLocalized('Check %s for possible reasons.',[UI.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=Common.settings.createSetting(name,value);setting.setTitle(Common.UIString(caption));setting.addChangeListener(this._update,this);toolbar.appendToolbarItem(new UI.ToolbarSettingCheckbox(setting));return setting;}
_initToolbar(){this._panelToolbar=this._transformController.toolbar();this.contentElement.appendChild(this._panelToolbar.element);this._showSlowScrollRectsSetting=this._createVisibilitySetting('Slow scroll rects','frameViewerShowSlowScrollRects',true,this._panelToolbar);this._showPaintsSetting=this._createVisibilitySetting('Paints','frameViewerShowPaints',true,this._panelToolbar);this._showPaintsSetting.addChangeListener(this._updatePaints,this);Common.moduleSetting('frameViewerHideChromeWindow').addChangeListener(this._update,this);}
_onContextMenu(event){const contextMenu=new UI.ContextMenu(event);contextMenu.defaultSection().appendItem(Common.UIString('Reset View'),this._transformController.resetAndNotify.bind(this._transformController),false);const selection=this._selectionFromEventPoint(event);if(selection&&selection.type()===LayerViewer.LayerView.Selection.Type.Snapshot){contextMenu.defaultSection().appendItem(Common.UIString('Show Paint Profiler'),this.dispatchEventToListeners.bind(this,LayerViewer.Layers3DView.Events.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()===LayerViewer.LayerView.Selection.Type.Snapshot||selection.layer()))
this.dispatchEventToListeners(LayerViewer.Layers3DView.Events.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();}};LayerViewer.Layers3DView.LayerStyle;LayerViewer.Layers3DView.OutlineType={Hovered:'hovered',Selected:'selected'};LayerViewer.Layers3DView.Events={PaintProfilerRequested:Symbol('PaintProfilerRequested'),ScaleChanged:Symbol('ScaleChanged')};LayerViewer.Layers3DView.ChromeTexture={Left:0,Middle:1,Right:2};LayerViewer.Layers3DView.ScrollRectTitles={RepaintsOnScroll:Common.UIString('repaints on scroll'),TouchEventHandler:Common.UIString('touch event listener'),WheelEventHandler:Common.UIString('mousewheel event listener')};LayerViewer.Layers3DView.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'+'}';LayerViewer.Layers3DView.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'+'}';LayerViewer.Layers3DView.HoveredBorderColor=[0,0,255,1];LayerViewer.Layers3DView.SelectedBorderColor=[0,255,0,1];LayerViewer.Layers3DView.BorderColor=[0,0,0,1];LayerViewer.Layers3DView.ViewportBorderColor=[160,160,160,1];LayerViewer.Layers3DView.ScrollRectBackgroundColor=[178,100,100,0.6];LayerViewer.Layers3DView.HoveredImageMaskColor=[200,200,255,1];LayerViewer.Layers3DView.BorderWidth=1;LayerViewer.Layers3DView.SelectedBorderWidth=2;LayerViewer.Layers3DView.ViewportBorderWidth=3;LayerViewer.Layers3DView.LayerSpacing=20;LayerViewer.Layers3DView.ScrollRectSpacing=4;LayerViewer.LayerTextureManager=class{constructor(textureUpdatedCallback){this._textureUpdatedCallback=textureUpdatedCallback;this._throttler=new Common.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 LayerViewer.LayerTextureManager.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);}}}};LayerViewer.Layers3DView.Rectangle=class{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]=UI.Geometry.multiplyVectorByMatrixAndNormalize(new UI.Geometry.Vector(this.vertices[i*3],this.vertices[i*3+1],this.vertices[i*3+2]),matrix);}
const normal=UI.Geometry.crossProduct(UI.Geometry.subtract(points[1],points[0]),UI.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 UI.Geometry.Vector(x0,y0,t);const tVects=points.map(UI.Geometry.subtract.bind(null,pt));for(i=0;i<tVects.length;++i){const product=UI.Geometry.scalarProduct(normal,UI.Geometry.crossProduct(tVects[i],tVects[(i+1)%tVects.length]));if(product<0)
return undefined;}
return t;}};LayerViewer.LayerTextureManager.Tile=class{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 UI.loadImage(imageURL);this.texture=image&&LayerViewer.LayerTextureManager._createTextureForImage(glContext,image);}};;LayerViewer.PaintProfilerView=class extends UI.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=Common.UIString('Profiling\u2026');this._pieChart=new PerfUI.PieChart(55,this._formatPieChartTime.bind(this),true);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 PerfUI.OverviewGrid.Window(this._canvasContainer);this._selectionWindow.addEventListener(PerfUI.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(LayerViewer.PaintProfilerView._categories)
return LayerViewer.PaintProfilerView._categories;LayerViewer.PaintProfilerView._categories={shapes:new LayerViewer.PaintProfilerCategory('shapes',Common.UIString('Shapes'),'rgb(255, 161, 129)'),bitmap:new LayerViewer.PaintProfilerCategory('bitmap',Common.UIString('Bitmap'),'rgb(136, 196, 255)'),text:new LayerViewer.PaintProfilerCategory('text',Common.UIString('Text'),'rgb(180, 255, 137)'),misc:new LayerViewer.PaintProfilerCategory('misc',Common.UIString('Misc'),'rgb(206, 160, 255)')};return LayerViewer.PaintProfilerView._categories;}
static _initLogItemCategories(){if(LayerViewer.PaintProfilerView._logItemCategoriesMap)
return LayerViewer.PaintProfilerView._logItemCategoriesMap;const categories=LayerViewer.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'];LayerViewer.PaintProfilerView._logItemCategoriesMap=logItemCategories;return logItemCategories;}
static _categoryForLogItem(logItem){const method=logItem.method.toTitleCase();const logItemCategories=LayerViewer.PaintProfilerView._initLogItemCategories();let result=logItemCategories[method];if(!result){result=LayerViewer.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(LayerViewer.PaintProfilerView._categoryForLogItem);if(!this._snapshot){this._update();this._pieChart.setTotal(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=LayerViewer.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(LayerViewer.PaintProfilerView.Events.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=LayerViewer.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.setTotal(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=Number.constrain(barLeft*this._samplesPerBar,0,this._log.length-1);const stepRight=Number.constrain(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);}};LayerViewer.PaintProfilerView.Events={WindowChanged:Symbol('WindowChanged')};LayerViewer.PaintProfilerCommandLogView=class extends UI.ThrottledWidget{constructor(){super();this.setMinimumSize(100,25);this.element.classList.add('overflow-auto');this._treeOutline=new UI.TreeOutlineInShadow();this.element.appendChild(this._treeOutline.element);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 LayerViewer.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();}};LayerViewer.LogTreeElement=class extends UI.TreeElement{constructor(ownerView,logItem){super('',!!logItem.params);this._logItem=logItem;this._ownerView=ownerView;this._filled=false;}
onattach(){this._update();}
onpopulate(){for(const param in this._logItem.params)
LayerViewer.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;}};LayerViewer.LogPropertyTreeElement=class extends UI.TreeElement{constructor(property){super();this._property=property;}
static _appendLogPropertyItem(element,name,value){const treeElement=new LayerViewer.LogPropertyTreeElement({name:name,value:value});element.appendChild(treeElement);if(value&&typeof value==='object'){for(const property in value)
LayerViewer.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;}};LayerViewer.PaintProfilerCategory=class{constructor(name,title,color){this.name=name;this.title=title;this.color=color;}};;LayerViewer.TransformController=class extends Common.Object{constructor(element,disableRotate){super();this._shortcuts={};this.element=element;if(this.element.tabIndex<0)
this.element.tabIndex=0;this._registerShortcuts();UI.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('keyup',this._onKeyUp.bind(this),false);element.addEventListener('mousewheel',this._onMouseWheel.bind(this),false);this._minScale=0;this._maxScale=Infinity;this._controlPanelToolbar=new UI.Toolbar('transform-control-panel');this._modeButtons={};if(!disableRotate){const panModeButton=new UI.ToolbarToggle(Common.UIString('Pan mode (X)'),'largeicon-pan');panModeButton.addEventListener(UI.ToolbarButton.Events.Click,this._setMode.bind(this,LayerViewer.TransformController.Modes.Pan));this._modeButtons[LayerViewer.TransformController.Modes.Pan]=panModeButton;this._controlPanelToolbar.appendToolbarItem(panModeButton);const rotateModeButton=new UI.ToolbarToggle(Common.UIString('Rotate mode (V)'),'largeicon-rotate');rotateModeButton.addEventListener(UI.ToolbarButton.Events.Click,this._setMode.bind(this,LayerViewer.TransformController.Modes.Rotate));this._modeButtons[LayerViewer.TransformController.Modes.Rotate]=rotateModeButton;this._controlPanelToolbar.appendToolbarItem(rotateModeButton);}
this._setMode(LayerViewer.TransformController.Modes.Pan);const resetButton=new UI.ToolbarButton(Common.UIString('Reset transform (0)'),'largeicon-center');resetButton.addEventListener(UI.ToolbarButton.Events.Click,this.resetAndNotify.bind(this,undefined));this._controlPanelToolbar.appendToolbarItem(resetButton);this._reset();}
toolbar(){return this._controlPanelToolbar;}
_onKeyDown(event){if(event.keyCode===UI.KeyboardShortcut.Keys.Shift.code){this._toggleMode();return;}
const shortcutKey=UI.KeyboardShortcut.makeKeyFromEventIgnoringModifiers(event);const handler=this._shortcuts[shortcutKey];if(handler&&handler(event))
event.consume();}
_onKeyUp(event){if(event.keyCode===UI.KeyboardShortcut.Keys.Shift.code)
this._toggleMode();}
_addShortcuts(keys,handler){for(let i=0;i<keys.length;++i)
this._shortcuts[keys[i].key]=handler;}
_registerShortcuts(){this._addShortcuts(UI.ShortcutsScreen.LayersPanelShortcuts.ResetView,this.resetAndNotify.bind(this));this._addShortcuts(UI.ShortcutsScreen.LayersPanelShortcuts.PanMode,this._setMode.bind(this,LayerViewer.TransformController.Modes.Pan));this._addShortcuts(UI.ShortcutsScreen.LayersPanelShortcuts.RotateMode,this._setMode.bind(this,LayerViewer.TransformController.Modes.Rotate));const zoomFactor=1.1;this._addShortcuts(UI.ShortcutsScreen.LayersPanelShortcuts.ZoomIn,this._onKeyboardZoom.bind(this,zoomFactor));this._addShortcuts(UI.ShortcutsScreen.LayersPanelShortcuts.ZoomOut,this._onKeyboardZoom.bind(this,1/zoomFactor));this._addShortcuts(UI.ShortcutsScreen.LayersPanelShortcuts.Up,this._onKeyboardPanOrRotate.bind(this,0,-1));this._addShortcuts(UI.ShortcutsScreen.LayersPanelShortcuts.Down,this._onKeyboardPanOrRotate.bind(this,0,1));this._addShortcuts(UI.ShortcutsScreen.LayersPanelShortcuts.Left,this._onKeyboardPanOrRotate.bind(this,-1,0));this._addShortcuts(UI.ShortcutsScreen.LayersPanelShortcuts.Right,this._onKeyboardPanOrRotate.bind(this,1,0));}
_postChangeEvent(){this.dispatchEventToListeners(LayerViewer.TransformController.Events.TransformChanged);}
_reset(){this._scale=1;this._offsetX=0;this._offsetY=0;this._rotateX=0;this._rotateY=0;}
_toggleMode(){this._setMode(this._mode===LayerViewer.TransformController.Modes.Pan?LayerViewer.TransformController.Modes.Rotate:LayerViewer.TransformController.Modes.Pan);}
_setMode(mode){if(this._mode===mode)
return;this._mode=mode;this._updateModeButtons();this.element.focus();}
_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=Number.constrain(this._scale,minScale,maxScale);}
clampOffsets(minX,maxX,minY,maxY){this._offsetX=Number.constrain(this._offsetX,minX,maxX);this._offsetY=Number.constrain(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=Number.constrain(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===LayerViewer.TransformController.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===LayerViewer.TransformController.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;}};LayerViewer.TransformController.Events={TransformChanged:Symbol('TransformChanged')};LayerViewer.TransformController.Modes={Pan:'Pan',Rotate:'Rotate',};;Runtime.cachedResources["layer_viewer/layers3DView.css"]="/*\n * Copyright 2016 The Chromium Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style license that can be\n * found in the LICENSE file.\n */\n\n.layers-3d-view {\n    overflow: hidden;\n    -webkit-user-select: none;\n}\n\ncanvas {\n    flex: 1 1;\n}\n\n/*# sourceURL=layer_viewer/layers3DView.css */";Runtime.cachedResources["layer_viewer/paintProfiler.css"]="/*\n * Copyright 2016 The Chromium Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style license that can be\n * found in the LICENSE file.\n */\n\n.paint-profiler-overview {\n    background-color: #eee;\n}\n\n.paint-profiler-canvas-container {\n    flex: auto;\n    position: relative;\n}\n\n.paint-profiler-pie-chart {\n    width: 60px !important;\n    height: 60px !important;\n    padding: 2px;\n    overflow: hidden;\n    font-size: 10px;\n}\n\n.paint-profiler-canvas-container canvas {\n    z-index: 200;\n    background-color: white;\n    opacity: 0.95;\n    height: 100%;\n    width: 100%;\n}\n\n.paint-profiler-canvas-container .overview-grid-dividers-background,\n.paint-profiler-canvas-container .overview-grid-window {\n    bottom: 0;\n    height: auto;\n}\n\n.paint-profiler-canvas-container .overview-grid-window-resizer {\n    z-index: 2000;\n}\n\n/*# sourceURL=layer_viewer/paintProfiler.css */";Runtime.cachedResources["layer_viewer/layerDetailsView.css"]="/*\n * Copyright 2016 The Chromium Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style license that can be\n * found in the LICENSE file.\n */\n\ntable td {\n    padding-left: 8px;\n}\n\ntable td:first-child {\n    font-weight: bold;\n}\n\n.scroll-rect.active {\n    background-color: rgba(100, 100, 100, 0.2);\n}\n\nul {\n    list-style: none;\n    -webkit-padding-start: 0;\n    -webkit-margin-before: 0;\n    -webkit-margin-after: 0;\n}\n\na {\n    padding: 8px;\n    display: block;\n}\n\n/*# sourceURL=layer_viewer/layerDetailsView.css */";