LayerTreeModel.js 7.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. export default class LayerTreeModel extends SDK.SDKModel{constructor(target){super(target);this._layerTreeAgent=target.layerTreeAgent();target.registerLayerTreeDispatcher(new LayerTreeDispatcher(this));this._paintProfilerModel=(target.model(SDK.PaintProfilerModel));const resourceTreeModel=target.model(SDK.ResourceTreeModel);if(resourceTreeModel){resourceTreeModel.addEventListener(SDK.ResourceTreeModel.Events.MainFrameNavigated,this._onMainFrameNavigated,this);}
  2. this._layerTree=null;this._throttler=new Common.Throttler(20);}
  3. disable(){if(!this._enabled){return;}
  4. this._enabled=false;this._layerTreeAgent.disable();}
  5. enable(){if(this._enabled){return;}
  6. this._enabled=true;this._forceEnable();}
  7. _forceEnable(){this._lastPaintRectByLayerId={};if(!this._layerTree){this._layerTree=new AgentLayerTree(this);}
  8. this._layerTreeAgent.enable();}
  9. layerTree(){return this._layerTree;}
  10. async _layerTreeChanged(layers){if(!this._enabled){return;}
  11. this._throttler.schedule(this._innerSetLayers.bind(this,layers));}
  12. async _innerSetLayers(layers){const layerTree=(this._layerTree);await layerTree.setLayers(layers);for(const layerId in this._lastPaintRectByLayerId){const lastPaintRect=this._lastPaintRectByLayerId[layerId];const layer=layerTree.layerById(layerId);if(layer){(layer)._lastPaintRect=lastPaintRect;}}
  13. this._lastPaintRectByLayerId={};this.dispatchEventToListeners(Events.LayerTreeChanged);}
  14. _layerPainted(layerId,clipRect){if(!this._enabled){return;}
  15. const layerTree=(this._layerTree);const layer=(layerTree.layerById(layerId));if(!layer){this._lastPaintRectByLayerId[layerId]=clipRect;return;}
  16. layer._didPaint(clipRect);this.dispatchEventToListeners(Events.LayerPainted,layer);}
  17. _onMainFrameNavigated(){this._layerTree=null;if(this._enabled){this._forceEnable();}}}
  18. SDK.SDKModel.register(LayerTreeModel,SDK.Target.Capability.DOM,false);export const Events={LayerTreeChanged:Symbol('LayerTreeChanged'),LayerPainted:Symbol('LayerPainted'),};export class AgentLayerTree extends SDK.LayerTreeBase{constructor(layerTreeModel){super(layerTreeModel.target());this._layerTreeModel=layerTreeModel;}
  19. async setLayers(payload){if(!payload){this._innerSetLayers(payload);return;}
  20. const idsToResolve=new Set();for(let i=0;i<payload.length;++i){const backendNodeId=payload[i].backendNodeId;if(!backendNodeId||this.backendNodeIdToNode().has(backendNodeId)){continue;}
  21. idsToResolve.add(backendNodeId);}
  22. await this.resolveBackendNodeIds(idsToResolve);this._innerSetLayers(payload);}
  23. _innerSetLayers(layers){this.setRoot(null);this.setContentRoot(null);if(!layers){return;}
  24. let root;const oldLayersById=this._layersById;this._layersById={};for(let i=0;i<layers.length;++i){const layerId=layers[i].layerId;let layer=oldLayersById[layerId];if(layer){layer._reset(layers[i]);}else{layer=new AgentLayer(this._layerTreeModel,layers[i]);}
  25. this._layersById[layerId]=layer;const backendNodeId=layers[i].backendNodeId;if(backendNodeId){layer._setNode(this.backendNodeIdToNode().get(backendNodeId));}
  26. if(!this.contentRoot()&&layer.drawsContent()){this.setContentRoot(layer);}
  27. const parentId=layer.parentId();if(parentId){const parent=this._layersById[parentId];if(!parent){console.assert(parent,'missing parent '+parentId+' for layer '+layerId);}
  28. parent.addChild(layer);}else{if(root){console.assert(false,'Multiple root layers');}
  29. root=layer;}}
  30. if(root){this.setRoot(root);root._calculateQuad(new WebKitCSSMatrix());}}}
  31. export class AgentLayer{constructor(layerTreeModel,layerPayload){this._layerTreeModel=layerTreeModel;this._reset(layerPayload);}
  32. id(){return this._layerPayload.layerId;}
  33. parentId(){return this._layerPayload.parentLayerId;}
  34. parent(){return this._parent;}
  35. isRoot(){return!this.parentId();}
  36. children(){return this._children;}
  37. addChild(childParam){const child=(childParam);if(child._parent){console.assert(false,'Child already has a parent');}
  38. this._children.push(child);child._parent=this;}
  39. _setNode(node){this._node=node;}
  40. node(){return this._node;}
  41. nodeForSelfOrAncestor(){for(let layer=this;layer;layer=layer._parent){if(layer._node){return layer._node;}}
  42. return null;}
  43. offsetX(){return this._layerPayload.offsetX;}
  44. offsetY(){return this._layerPayload.offsetY;}
  45. width(){return this._layerPayload.width;}
  46. height(){return this._layerPayload.height;}
  47. transform(){return this._layerPayload.transform;}
  48. quad(){return this._quad;}
  49. anchorPoint(){return[this._layerPayload.anchorX||0,this._layerPayload.anchorY||0,this._layerPayload.anchorZ||0,];}
  50. invisible(){return this._layerPayload.invisible;}
  51. paintCount(){return this._paintCount||this._layerPayload.paintCount;}
  52. lastPaintRect(){return this._lastPaintRect;}
  53. scrollRects(){return this._scrollRects;}
  54. stickyPositionConstraint(){return this._stickyPositionConstraint;}
  55. async requestCompositingReasons(){const reasons=await this._layerTreeModel._layerTreeAgent.compositingReasons(this.id());return reasons||[];}
  56. drawsContent(){return this._layerPayload.drawsContent;}
  57. gpuMemoryUsage(){const bytesPerPixel=4;return this.drawsContent()?this.width()*this.height()*bytesPerPixel:0;}
  58. snapshots(){const promise=this._layerTreeModel._paintProfilerModel.makeSnapshot(this.id()).then(snapshot=>{if(!snapshot){return null;}
  59. return{rect:{x:0,y:0,width:this.width(),height:this.height()},snapshot:snapshot};});return[promise];}
  60. _didPaint(rect){this._lastPaintRect=rect;this._paintCount=this.paintCount()+1;this._image=null;}
  61. _reset(layerPayload){this._node=null;this._children=[];this._parent=null;this._paintCount=0;this._layerPayload=layerPayload;this._image=null;this._scrollRects=this._layerPayload.scrollRects||[];this._stickyPositionConstraint=this._layerPayload.stickyPositionConstraint?new SDK.Layer.StickyPositionConstraint(this._layerTreeModel.layerTree(),this._layerPayload.stickyPositionConstraint):null;}
  62. _matrixFromArray(a){function toFixed9(x){return x.toFixed(9);}
  63. return new WebKitCSSMatrix('matrix3d('+a.map(toFixed9).join(',')+')');}
  64. _calculateTransformToViewport(parentTransform){const offsetMatrix=new WebKitCSSMatrix().translate(this._layerPayload.offsetX,this._layerPayload.offsetY);let matrix=offsetMatrix;if(this._layerPayload.transform){const transformMatrix=this._matrixFromArray(this._layerPayload.transform);const anchorVector=new UI.Geometry.Vector(this._layerPayload.width*this.anchorPoint()[0],this._layerPayload.height*this.anchorPoint()[1],this.anchorPoint()[2]);const anchorPoint=UI.Geometry.multiplyVectorByMatrixAndNormalize(anchorVector,matrix);const anchorMatrix=new WebKitCSSMatrix().translate(-anchorPoint.x,-anchorPoint.y,-anchorPoint.z);matrix=anchorMatrix.inverse().multiply(transformMatrix.multiply(anchorMatrix.multiply(matrix)));}
  65. matrix=parentTransform.multiply(matrix);return matrix;}
  66. _createVertexArrayForRect(width,height){return[0,0,0,width,0,0,width,height,0,0,height,0];}
  67. _calculateQuad(parentTransform){const matrix=this._calculateTransformToViewport(parentTransform);this._quad=[];const vertices=this._createVertexArrayForRect(this._layerPayload.width,this._layerPayload.height);for(let i=0;i<4;++i){const point=UI.Geometry.multiplyVectorByMatrixAndNormalize(new UI.Geometry.Vector(vertices[i*3],vertices[i*3+1],vertices[i*3+2]),matrix);this._quad.push(point.x,point.y);}
  68. function calculateQuadForLayer(layer){layer._calculateQuad(matrix);}
  69. this._children.forEach(calculateQuadForLayer);}}
  70. class LayerTreeDispatcher{constructor(layerTreeModel){this._layerTreeModel=layerTreeModel;}
  71. layerTreeDidChange(layers){this._layerTreeModel._layerTreeChanged(layers||null);}
  72. layerPainted(layerId,clipRect){this._layerTreeModel._layerPainted(layerId,clipRect);}}
  73. self.Layers=self.Layers||{};Layers=Layers||{};Layers.LayerTreeModel=LayerTreeModel;Layers.LayerTreeModel.Events=Events;Layers.AgentLayerTree=AgentLayerTree;Layers.AgentLayer=AgentLayer;