Index: third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js |
diff --git a/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js b/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js |
index dd732f287b572d585166798a705e5debb1c64d07..b21772bd822be71d417d8126955648ec7f235695 100644 |
--- a/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js |
+++ b/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js |
@@ -27,37 +27,38 @@ |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
- |
/** |
- * @constructor |
- * @extends {WebInspector.VBox} |
- * @param {!WebInspector.LayerViewHost} layerViewHost |
* @implements {WebInspector.LayerView} |
+ * @unrestricted |
*/ |
-WebInspector.Layers3DView = function(layerViewHost) |
-{ |
- WebInspector.VBox.call(this, true); |
- this.registerRequiredCSS("layer_viewer/layers3DView.css"); |
- this.contentElement.classList.add("layers-3d-view"); |
+WebInspector.Layers3DView = class extends WebInspector.VBox { |
+ /** |
+ * @param {!WebInspector.LayerViewHost} layerViewHost |
+ */ |
+ constructor(layerViewHost) { |
+ super(true); |
+ this.registerRequiredCSS('layer_viewer/layers3DView.css'); |
+ this.contentElement.classList.add('layers-3d-view'); |
this._failBanner = new WebInspector.VBox(); |
- this._failBanner.element.classList.add("full-widget-dimmed-banner"); |
- this._failBanner.element.createTextChild(WebInspector.UIString("Layer information is not yet available.")); |
+ this._failBanner.element.classList.add('full-widget-dimmed-banner'); |
+ this._failBanner.element.createTextChild(WebInspector.UIString('Layer information is not yet available.')); |
this._layerViewHost = layerViewHost; |
this._layerViewHost.registerView(this); |
this._transformController = new WebInspector.TransformController(this.contentElement); |
- this._transformController.addEventListener(WebInspector.TransformController.Events.TransformChanged, this._update, this); |
+ this._transformController.addEventListener( |
+ WebInspector.TransformController.Events.TransformChanged, this._update, this); |
this._initToolbar(); |
- this._canvasElement = this.contentElement.createChild("canvas"); |
+ 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._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; |
@@ -69,6 +70,697 @@ WebInspector.Layers3DView = function(layerViewHost) |
this._rects = []; |
this._layerViewHost.showInternalLayersSetting().addChangeListener(this._update, this); |
+ } |
+ |
+ /** |
+ * @param {?WebInspector.LayerTreeBase} layerTree |
+ * @override |
+ */ |
+ setLayerTree(layerTree) { |
+ this._layerTree = layerTree; |
+ this._layerTexture = null; |
+ delete this._oldTextureScale; |
+ if (this._showPaints()) |
+ this._textureManager.setLayerTree(layerTree); |
+ this._update(); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layer} layer |
+ * @param {string=} imageURL |
+ */ |
+ showImageForLayer(layer, imageURL) { |
+ if (!imageURL) { |
+ this._layerTexture = null; |
+ this._update(); |
+ return; |
+ } |
+ WebInspector.loadImage(imageURL).then(image => { |
+ var texture = image && WebInspector.LayerTextureManager._createTextureForImage(this._gl, image); |
+ this._layerTexture = texture ? {layer: layer, texture: texture} : null; |
+ this._update(); |
+ }); |
+ } |
+ |
+ /** |
+ * @override |
+ */ |
+ onResize() { |
+ this._resizeCanvas(); |
+ this._update(); |
+ } |
+ |
+ /** |
+ * @override |
+ */ |
+ willHide() { |
+ this._textureManager.suspend(); |
+ } |
+ |
+ /** |
+ * @override |
+ */ |
+ wasShown() { |
+ this._textureManager.resume(); |
+ if (!this._needsUpdate) |
+ return; |
+ this._resizeCanvas(); |
+ this._update(); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layer} layer |
+ */ |
+ updateLayerSnapshot(layer) { |
+ this._textureManager.layerNeedsUpdate(layer); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layers3DView.OutlineType} type |
+ * @param {?WebInspector.LayerView.Selection} selection |
+ */ |
+ _setOutline(type, selection) { |
+ this._lastSelection[type] = selection; |
+ this._update(); |
+ } |
+ |
+ /** |
+ * @param {?WebInspector.LayerView.Selection} selection |
+ * @override |
+ */ |
+ hoverObject(selection) { |
+ this._setOutline(WebInspector.Layers3DView.OutlineType.Hovered, selection); |
+ } |
+ |
+ /** |
+ * @param {?WebInspector.LayerView.Selection} selection |
+ * @override |
+ */ |
+ selectObject(selection) { |
+ this._setOutline(WebInspector.Layers3DView.OutlineType.Hovered, null); |
+ this._setOutline(WebInspector.Layers3DView.OutlineType.Selected, selection); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.LayerView.Selection} selection |
+ * @return {!Promise<?WebInspector.SnapshotWithRect>} |
+ */ |
+ snapshotForSelection(selection) { |
+ if (selection.type() === WebInspector.LayerView.Selection.Type.Snapshot) { |
+ var snapshotWithRect = /** @type {!WebInspector.LayerView.SnapshotSelection} */ (selection).snapshot(); |
+ snapshotWithRect.snapshot.addReference(); |
+ return /** @type {!Promise<?WebInspector.SnapshotWithRect>} */ (Promise.resolve(snapshotWithRect)); |
+ } |
+ if (selection.layer()) { |
+ var promise = selection.layer().snapshots()[0]; |
+ if (promise) |
+ return promise; |
+ } |
+ return /** @type {!Promise<?WebInspector.SnapshotWithRect>} */ (Promise.resolve(null)); |
+ } |
+ |
+ /** |
+ * @param {!Element} canvas |
+ * @return {?WebGLRenderingContext} |
+ */ |
+ _initGL(canvas) { |
+ var 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; |
+ } |
+ |
+ /** |
+ * @param {!Object} type |
+ * @param {string} script |
+ */ |
+ _createShader(type, script) { |
+ var 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, WebInspector.Layers3DView.FragmentShader); |
+ this._createShader(this._gl.VERTEX_SHADER, WebInspector.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() { |
+ var paddingFraction = 0.1; |
+ var viewport = this._layerTree.viewportSize(); |
+ var root = this._layerTree.root(); |
+ var baseWidth = viewport ? viewport.width : this._dimensionsForAutoscale.width; |
+ var baseHeight = viewport ? viewport.height : this._dimensionsForAutoscale.height; |
+ var canvasWidth = this._canvasElement.width; |
+ var canvasHeight = this._canvasElement.height; |
+ var paddingX = canvasWidth * paddingFraction; |
+ var paddingY = canvasHeight * paddingFraction; |
+ var scaleX = (canvasWidth - 2 * paddingX) / baseWidth; |
+ var scaleY = (canvasHeight - 2 * paddingY) / baseHeight; |
+ var viewScale = Math.min(scaleX, scaleY); |
+ var minScaleConstraint = |
+ Math.min(baseWidth / this._dimensionsForAutoscale.width, baseHeight / this._dimensionsForAutoscale.width) / 2; |
+ this._transformController.setScaleConstraints( |
+ minScaleConstraint, |
+ 10 / viewScale); // 1/viewScale is 1:1 in terms of pixels, so allow zooming to 10x of native size |
+ var scale = this._transformController.scale(); |
+ var rotateX = this._transformController.rotateX(); |
+ var rotateY = this._transformController.rotateY(); |
+ |
+ this._scale = scale * viewScale; |
+ var textureScale = Number.constrain(this._scale, 0.1, 1); |
+ if (textureScale !== this._oldTextureScale) { |
+ this._oldTextureScale = textureScale; |
+ this._textureManager.setScale(textureScale); |
+ this.dispatchEventToListeners(WebInspector.Layers3DView.Events.ScaleChanged, textureScale); |
+ } |
+ var 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); |
+ |
+ var bounds; |
+ for (var i = 0; i < this._rects.length; ++i) |
+ bounds = |
+ WebInspector.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); |
+ var offsetX = this._transformController.offsetX() * window.devicePixelRatio; |
+ var offsetY = this._transformController.offsetY() * window.devicePixelRatio; |
+ // Multiply to translation matrix on the right rather than translate (which would implicitly multiply on the left). |
+ this._projectionMatrix = new WebKitCSSMatrix().translate(offsetX, offsetY, 0).multiply(scaleAndRotationMatrix); |
+ |
+ var 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)); |
+ } |
+ |
+ /** |
+ * @param {!CSSMatrix} m |
+ * @return {!Float32Array} |
+ */ |
+ _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); |
+ var 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() { |
+ /** |
+ * @this {WebInspector.Layers3DView} |
+ * @param {!WebInspector.Layers3DView.ChromeTexture} index |
+ * @param {string} url |
+ */ |
+ function loadChromeTexture(index, url) { |
+ WebInspector.loadImage(url).then(image => { |
+ this._chromeTextures[index] = |
+ image && WebInspector.LayerTextureManager._createTextureForImage(this._gl, image) || undefined; |
+ }); |
+ } |
+ loadChromeTexture.call(this, WebInspector.Layers3DView.ChromeTexture.Left, 'Images/chromeLeft.png'); |
+ loadChromeTexture.call(this, WebInspector.Layers3DView.ChromeTexture.Middle, 'Images/chromeMiddle.png'); |
+ loadChromeTexture.call(this, WebInspector.Layers3DView.ChromeTexture.Right, 'Images/chromeRight.png'); |
+ } |
+ |
+ /** |
+ * @return {?WebGLRenderingContext} |
+ */ |
+ _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 = {}; |
+ var depth = 0; |
+ var showInternalLayers = this._layerViewHost.showInternalLayersSetting().get(); |
+ var root = showInternalLayers ? this._layerTree.root() : (this._layerTree.contentRoot() || this._layerTree.root()); |
+ var queue = [root]; |
+ this._depthByLayerId[root.id()] = 0; |
+ /** @type {!Set<!WebInspector.Layer>} */ |
+ this._visibleLayers = new Set(); |
+ while (queue.length > 0) { |
+ var layer = queue.shift(); |
+ if (showInternalLayers || layer.drawsContent()) |
+ this._visibleLayers.add(layer); |
+ var children = layer.children(); |
+ for (var i = 0; i < children.length; ++i) { |
+ this._depthByLayerId[children[i].id()] = ++depth; |
+ queue.push(children[i]); |
+ } |
+ } |
+ this._maxDepth = depth; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layer} layer |
+ * @return {number} |
+ */ |
+ _depthForLayer(layer) { |
+ return this._depthByLayerId[layer.id()] * WebInspector.Layers3DView.LayerSpacing; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layer} layer |
+ * @param {number} index |
+ * @return {number} |
+ */ |
+ _calculateScrollRectDepth(layer, index) { |
+ return this._depthForLayer(layer) + index * WebInspector.Layers3DView.ScrollRectSpacing + 1; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layer} layer |
+ */ |
+ _updateDimensionsForAutoscale(layer) { |
+ // We don't want to be precise, but rather pick something least affected by |
+ // animationtransforms, so that we don't change scale too often. So let's |
+ // disregard transforms, scrolling and relative layer positioning and choose |
+ // the largest dimensions of all layers. |
+ this._dimensionsForAutoscale.width = Math.max(layer.width(), this._dimensionsForAutoscale.width); |
+ this._dimensionsForAutoscale.height = Math.max(layer.height(), this._dimensionsForAutoscale.height); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layer} layer |
+ */ |
+ _calculateLayerRect(layer) { |
+ if (!this._visibleLayers.has(layer)) |
+ return; |
+ var selection = new WebInspector.LayerView.LayerSelection(layer); |
+ var rect = new WebInspector.Layers3DView.Rectangle(selection); |
+ rect.setVertices(layer.quad(), this._depthForLayer(layer)); |
+ this._appendRect(rect); |
+ this._updateDimensionsForAutoscale(layer); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layers3DView.Rectangle} rect |
+ */ |
+ _appendRect(rect) { |
+ var selection = rect.relatedObject; |
+ var isSelected = WebInspector.LayerView.Selection.isEqual( |
+ this._lastSelection[WebInspector.Layers3DView.OutlineType.Selected], selection); |
+ var isHovered = WebInspector.LayerView.Selection.isEqual( |
+ this._lastSelection[WebInspector.Layers3DView.OutlineType.Hovered], selection); |
+ if (isSelected) { |
+ rect.borderColor = WebInspector.Layers3DView.SelectedBorderColor; |
+ } else if (isHovered) { |
+ rect.borderColor = WebInspector.Layers3DView.HoveredBorderColor; |
+ var fillColor = rect.fillColor || [255, 255, 255, 1]; |
+ var maskColor = WebInspector.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 = WebInspector.Layers3DView.BorderColor; |
+ } |
+ rect.lineWidth = isSelected ? WebInspector.Layers3DView.SelectedBorderWidth : WebInspector.Layers3DView.BorderWidth; |
+ this._rects.push(rect); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layer} layer |
+ */ |
+ _calculateLayerScrollRects(layer) { |
+ var scrollRects = layer.scrollRects(); |
+ for (var i = 0; i < scrollRects.length; ++i) { |
+ var selection = new WebInspector.LayerView.ScrollRectSelection(layer, i); |
+ var rect = new WebInspector.Layers3DView.Rectangle(selection); |
+ rect.calculateVerticesFromRect(layer, scrollRects[i].rect, this._calculateScrollRectDepth(layer, i)); |
+ rect.fillColor = WebInspector.Layers3DView.ScrollRectBackgroundColor; |
+ this._appendRect(rect); |
+ } |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layer} layer |
+ */ |
+ _calculateLayerTileRects(layer) { |
+ var tiles = this._textureManager.tilesForLayer(layer); |
+ for (var i = 0; i < tiles.length; ++i) { |
+ var tile = tiles[i]; |
+ if (!tile.texture) |
+ continue; |
+ var selection = new WebInspector.LayerView.SnapshotSelection(layer, {rect: tile.rect, snapshot: tile.snapshot}); |
+ var rect = new WebInspector.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)) { |
+ var layer = this._layerTexture.layer; |
+ var selection = new WebInspector.LayerView.LayerSelection(layer); |
+ var rect = new WebInspector.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)); |
+ } |
+ } |
+ |
+ /** |
+ * @param {!Array.<number>} color |
+ * @return {!Array.<number>} |
+ */ |
+ _makeColorsArray(color) { |
+ var colors = []; |
+ var normalizedColor = [color[0] / 255, color[1] / 255, color[2] / 255, color[3]]; |
+ for (var i = 0; i < 4; i++) |
+ colors = colors.concat(normalizedColor); |
+ return colors; |
+ } |
+ |
+ /** |
+ * @param {!Object} attribute |
+ * @param {!Array.<number>} array |
+ * @param {number} length |
+ */ |
+ _setVertexAttribute(attribute, array, length) { |
+ var gl = this._gl; |
+ var 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); |
+ } |
+ |
+ /** |
+ * @param {!Array.<number>} vertices |
+ * @param {number} mode |
+ * @param {!Array.<number>=} color |
+ * @param {!Object=} texture |
+ */ |
+ _drawRectangle(vertices, mode, color, texture) { |
+ var gl = this._gl; |
+ var 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); |
+ } |
+ |
+ var numberOfVertices = vertices.length / 3; |
+ gl.drawArrays(mode, 0, numberOfVertices); |
+ } |
+ |
+ /** |
+ * @param {!Array.<number>} vertices |
+ * @param {!WebGLTexture} texture |
+ * @param {!Array.<number>=} color |
+ */ |
+ _drawTexture(vertices, texture, color) { |
+ this._drawRectangle(vertices, this._gl.TRIANGLE_FAN, color, texture); |
+ } |
+ |
+ _drawViewportAndChrome() { |
+ var viewport = this._layerTree.viewportSize(); |
+ if (!viewport) |
+ return; |
+ |
+ var drawChrome = !WebInspector.moduleSetting('frameViewerHideChromeWindow').get() && |
+ this._chromeTextures.length >= 3 && this._chromeTextures.indexOf(undefined) < 0; |
+ var z = (this._maxDepth + 1) * WebInspector.Layers3DView.LayerSpacing; |
+ var borderWidth = Math.ceil(WebInspector.Layers3DView.ViewportBorderWidth * this._scale); |
+ var 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, WebInspector.Layers3DView.ViewportBorderColor); |
+ |
+ if (!drawChrome) |
+ return; |
+ |
+ var borderAdjustment = WebInspector.Layers3DView.ViewportBorderWidth / 2; |
+ var viewportWidth = this._layerTree.viewportSize().width + 2 * borderAdjustment; |
+ var chromeHeight = this._chromeTextures[0].image.naturalHeight; |
+ var middleFragmentWidth = |
+ viewportWidth - this._chromeTextures[0].image.naturalWidth - this._chromeTextures[2].image.naturalWidth; |
+ var x = -borderAdjustment; |
+ var y = -chromeHeight; |
+ for (var i = 0; i < this._chromeTextures.length; ++i) { |
+ var width = i === WebInspector.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, /** @type {!WebGLTexture} */ (this._chromeTextures[i])); |
+ x += width; |
+ } |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layers3DView.Rectangle} rect |
+ */ |
+ _drawViewRect(rect) { |
+ var 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; |
+ } |
+ var 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(); |
+ } |
+ |
+ /** |
+ * @return {!Node} |
+ */ |
+ _webglDisabledBanner() { |
+ var fragment = this.contentElement.ownerDocument.createDocumentFragment(); |
+ fragment.createChild('div').textContent = WebInspector.UIString('Can\'t display layers,'); |
+ fragment.createChild('div').textContent = WebInspector.UIString('WebGL support is disabled in your browser.'); |
+ fragment.appendChild(WebInspector.formatLocalized( |
+ 'Check %s for possible reasons.', [WebInspector.linkifyURLAsNode('about:gpu', undefined, undefined, true)])); |
+ return fragment; |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ * @return {?WebInspector.LayerView.Selection} |
+ */ |
+ _selectionFromEventPoint(event) { |
+ if (!this._layerTree) |
+ return null; |
+ var closestIntersectionPoint = Infinity; |
+ var closestObject = null; |
+ var projectionMatrix = new WebKitCSSMatrix().scale(1, -1, -1).translate(-1, -1, 0).multiply(this._projectionMatrix); |
+ var x0 = (event.clientX - this._canvasElement.totalOffsetLeft()) * window.devicePixelRatio; |
+ var y0 = -(event.clientY - this._canvasElement.totalOffsetTop()) * window.devicePixelRatio; |
+ |
+ /** |
+ * @param {!WebInspector.Layers3DView.Rectangle} rect |
+ */ |
+ function checkIntersection(rect) { |
+ if (!rect.relatedObject) |
+ return; |
+ var t = rect.intersectWithLine(projectionMatrix, x0, y0); |
+ if (t < closestIntersectionPoint) { |
+ closestIntersectionPoint = t; |
+ closestObject = rect.relatedObject; |
+ } |
+ } |
+ |
+ this._rects.forEach(checkIntersection); |
+ return closestObject; |
+ } |
+ |
+ /** |
+ * @param {string} caption |
+ * @param {string} name |
+ * @param {boolean} value |
+ * @param {!WebInspector.Toolbar} toolbar |
+ * @return {!WebInspector.Setting} |
+ */ |
+ _createVisibilitySetting(caption, name, value, toolbar) { |
+ var checkbox = new WebInspector.ToolbarCheckbox(WebInspector.UIString(caption)); |
+ toolbar.appendToolbarItem(checkbox); |
+ var setting = WebInspector.settings.createSetting(name, value); |
+ WebInspector.SettingsUI.bindCheckbox(checkbox.inputElement, setting); |
+ setting.addChangeListener(this._update, this); |
+ 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); |
+ WebInspector.moduleSetting('frameViewerHideChromeWindow').addChangeListener(this._update, this); |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _onContextMenu(event) { |
+ var contextMenu = new WebInspector.ContextMenu(event); |
+ contextMenu.appendItem( |
+ WebInspector.UIString('Reset View'), this._transformController.resetAndNotify.bind(this._transformController), |
+ false); |
+ var selection = this._selectionFromEventPoint(event); |
+ if (selection && selection.type() === WebInspector.LayerView.Selection.Type.Snapshot) |
+ contextMenu.appendItem( |
+ WebInspector.UIString('Show Paint Profiler'), |
+ this.dispatchEventToListeners.bind( |
+ this, WebInspector.Layers3DView.Events.PaintProfilerRequested, selection.snapshot()), |
+ false); |
+ this._layerViewHost.showContextMenu(contextMenu, selection); |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _onMouseMove(event) { |
+ if (event.which) |
+ return; |
+ this._layerViewHost.hoverObject(this._selectionFromEventPoint(event)); |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _onMouseDown(event) { |
+ this._mouseDownX = event.clientX; |
+ this._mouseDownY = event.clientY; |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _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; |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _onDoubleClick(event) { |
+ var selection = this._selectionFromEventPoint(event); |
+ if (selection && (selection.type() === WebInspector.LayerView.Selection.Type.Snapshot || selection.layer())) |
+ this.dispatchEventToListeners(WebInspector.Layers3DView.Events.PaintProfilerRequested, selection); |
+ event.stopPropagation(); |
+ } |
+ |
+ _updatePaints() { |
+ if (this._showPaints()) { |
+ this._textureManager.setLayerTree(this._layerTree); |
+ this._textureManager.forceUpdate(); |
+ } else { |
+ this._textureManager.reset(); |
+ } |
+ this._update(); |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ _showPaints() { |
+ return this._showPaintsSetting.get(); |
+ } |
}; |
/** @typedef {{borderColor: !Array<number>, borderWidth: number}} */ |
@@ -78,8 +770,8 @@ WebInspector.Layers3DView.LayerStyle; |
* @enum {string} |
*/ |
WebInspector.Layers3DView.OutlineType = { |
- Hovered: "hovered", |
- Selected: "selected" |
+ Hovered: 'hovered', |
+ Selected: 'selected' |
}; |
/** |
@@ -87,51 +779,51 @@ WebInspector.Layers3DView.OutlineType = { |
*/ |
/** @enum {symbol} */ |
WebInspector.Layers3DView.Events = { |
- PaintProfilerRequested: Symbol("PaintProfilerRequested"), |
- ScaleChanged: Symbol("ScaleChanged") |
+ PaintProfilerRequested: Symbol('PaintProfilerRequested'), |
+ ScaleChanged: Symbol('ScaleChanged') |
}; |
/** |
* @enum {number} |
*/ |
WebInspector.Layers3DView.ChromeTexture = { |
- Left: 0, |
- Middle: 1, |
- Right: 2 |
+ Left: 0, |
+ Middle: 1, |
+ Right: 2 |
}; |
/** |
* @enum {string} |
*/ |
WebInspector.Layers3DView.ScrollRectTitles = { |
- RepaintsOnScroll: WebInspector.UIString("repaints on scroll"), |
- TouchEventHandler: WebInspector.UIString("touch event listener"), |
- WheelEventHandler: WebInspector.UIString("mousewheel event listener") |
+ RepaintsOnScroll: WebInspector.UIString('repaints on scroll'), |
+ TouchEventHandler: WebInspector.UIString('touch event listener'), |
+ WheelEventHandler: WebInspector.UIString('mousewheel event listener') |
}; |
-WebInspector.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" + |
- "}"; |
- |
-WebInspector.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" + |
- "}"; |
+WebInspector.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' + |
+ '}'; |
+ |
+WebInspector.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' + |
+ '}'; |
WebInspector.Layers3DView.HoveredBorderColor = [0, 0, 255, 1]; |
WebInspector.Layers3DView.SelectedBorderColor = [0, 255, 0, 1]; |
@@ -146,894 +838,201 @@ WebInspector.Layers3DView.ViewportBorderWidth = 3; |
WebInspector.Layers3DView.LayerSpacing = 20; |
WebInspector.Layers3DView.ScrollRectSpacing = 4; |
-WebInspector.Layers3DView.prototype = { |
- /** |
- * @param {?WebInspector.LayerTreeBase} layerTree |
- * @override |
- */ |
- setLayerTree: function(layerTree) |
- { |
- this._layerTree = layerTree; |
- this._layerTexture = null; |
- delete this._oldTextureScale; |
- if (this._showPaints()) |
- this._textureManager.setLayerTree(layerTree); |
- this._update(); |
- }, |
- |
- /** |
- * @param {!WebInspector.Layer} layer |
- * @param {string=} imageURL |
- */ |
- showImageForLayer: function(layer, imageURL) |
- { |
- if (!imageURL) { |
- this._layerTexture = null; |
- this._update(); |
- return; |
- } |
- WebInspector.loadImage(imageURL).then(image => { |
- var texture = image && WebInspector.LayerTextureManager._createTextureForImage(this._gl, image); |
- this._layerTexture = texture ? {layer: layer, texture: texture} : null; |
- this._update(); |
- }); |
- }, |
- |
- onResize: function() |
- { |
- this._resizeCanvas(); |
- this._update(); |
- }, |
- |
- /** |
- * @override |
- */ |
- willHide: function() |
- { |
- this._textureManager.suspend(); |
- }, |
- |
- /** |
- * @override |
- */ |
- wasShown: function() |
- { |
- this._textureManager.resume(); |
- if (!this._needsUpdate) |
- return; |
- this._resizeCanvas(); |
- this._update(); |
- }, |
- |
- /** |
- * @param {!WebInspector.Layer} layer |
- */ |
- updateLayerSnapshot: function(layer) |
- { |
- this._textureManager.layerNeedsUpdate(layer); |
- }, |
- |
- /** |
- * @param {!WebInspector.Layers3DView.OutlineType} type |
- * @param {?WebInspector.LayerView.Selection} selection |
- */ |
- _setOutline: function(type, selection) |
- { |
- this._lastSelection[type] = selection; |
- this._update(); |
- }, |
- |
- /** |
- * @param {?WebInspector.LayerView.Selection} selection |
- * @override |
- */ |
- hoverObject: function(selection) |
- { |
- this._setOutline(WebInspector.Layers3DView.OutlineType.Hovered, selection); |
- }, |
- |
- /** |
- * @param {?WebInspector.LayerView.Selection} selection |
- * @override |
- */ |
- selectObject: function(selection) |
- { |
- this._setOutline(WebInspector.Layers3DView.OutlineType.Hovered, null); |
- this._setOutline(WebInspector.Layers3DView.OutlineType.Selected, selection); |
- }, |
- |
- /** |
- * @param {!WebInspector.LayerView.Selection} selection |
- * @return {!Promise<?WebInspector.SnapshotWithRect>} |
- */ |
- snapshotForSelection: function(selection) |
- { |
- if (selection.type() === WebInspector.LayerView.Selection.Type.Snapshot) { |
- var snapshotWithRect = /** @type {!WebInspector.LayerView.SnapshotSelection} */ (selection).snapshot(); |
- snapshotWithRect.snapshot.addReference(); |
- return /** @type {!Promise<?WebInspector.SnapshotWithRect>} */ (Promise.resolve(snapshotWithRect)); |
- } |
- if (selection.layer()) { |
- var promise = selection.layer().snapshots()[0]; |
- if (promise) |
- return promise; |
- } |
- return /** @type {!Promise<?WebInspector.SnapshotWithRect>} */ (Promise.resolve(null)); |
- }, |
- |
- /** |
- * @param {!Element} canvas |
- * @return {?WebGLRenderingContext} |
- */ |
- _initGL: function(canvas) |
- { |
- var 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; |
- }, |
- |
- /** |
- * @param {!Object} type |
- * @param {string} script |
- */ |
- _createShader: function(type, script) |
- { |
- var shader = this._gl.createShader(type); |
- this._gl.shaderSource(shader, script); |
- this._gl.compileShader(shader); |
- this._gl.attachShader(this._shaderProgram, shader); |
- }, |
- |
- _initShaders: function() |
- { |
- this._shaderProgram = this._gl.createProgram(); |
- this._createShader(this._gl.FRAGMENT_SHADER, WebInspector.Layers3DView.FragmentShader); |
- this._createShader(this._gl.VERTEX_SHADER, WebInspector.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: function() |
- { |
- this._canvasElement.width = this._canvasElement.offsetWidth * window.devicePixelRatio; |
- this._canvasElement.height = this._canvasElement.offsetHeight * window.devicePixelRatio; |
- }, |
- |
- _updateTransformAndConstraints: function() |
- { |
- var paddingFraction = 0.1; |
- var viewport = this._layerTree.viewportSize(); |
- var root = this._layerTree.root(); |
- var baseWidth = viewport ? viewport.width : this._dimensionsForAutoscale.width; |
- var baseHeight = viewport ? viewport.height : this._dimensionsForAutoscale.height; |
- var canvasWidth = this._canvasElement.width; |
- var canvasHeight = this._canvasElement.height; |
- var paddingX = canvasWidth * paddingFraction; |
- var paddingY = canvasHeight * paddingFraction; |
- var scaleX = (canvasWidth - 2 * paddingX) / baseWidth; |
- var scaleY = (canvasHeight - 2 * paddingY) / baseHeight; |
- var viewScale = Math.min(scaleX, scaleY); |
- var minScaleConstraint = Math.min(baseWidth / this._dimensionsForAutoscale.width, baseHeight / this._dimensionsForAutoscale.width) / 2; |
- this._transformController.setScaleConstraints(minScaleConstraint, 10 / viewScale); // 1/viewScale is 1:1 in terms of pixels, so allow zooming to 10x of native size |
- var scale = this._transformController.scale(); |
- var rotateX = this._transformController.rotateX(); |
- var rotateY = this._transformController.rotateY(); |
- |
- this._scale = scale * viewScale; |
- var textureScale = Number.constrain(this._scale, 0.1, 1); |
- if (textureScale !== this._oldTextureScale) { |
- this._oldTextureScale = textureScale; |
- this._textureManager.setScale(textureScale); |
- this.dispatchEventToListeners(WebInspector.Layers3DView.Events.ScaleChanged, textureScale); |
- } |
- var 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); |
- |
- var bounds; |
- for (var i = 0; i < this._rects.length; ++i) |
- bounds = WebInspector.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); |
- var offsetX = this._transformController.offsetX() * window.devicePixelRatio; |
- var offsetY = this._transformController.offsetY() * window.devicePixelRatio; |
- // Multiply to translation matrix on the right rather than translate (which would implicitly multiply on the left). |
- this._projectionMatrix = new WebKitCSSMatrix().translate(offsetX, offsetY, 0).multiply(scaleAndRotationMatrix); |
- |
- var 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)); |
- }, |
- |
- /** |
- * @param {!CSSMatrix} m |
- * @return {!Float32Array} |
- */ |
- _arrayFromMatrix: function(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: function() |
- { |
- this._whiteTexture = this._gl.createTexture(); |
- this._gl.bindTexture(this._gl.TEXTURE_2D, this._whiteTexture); |
- var 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() |
- { |
- /** |
- * @this {WebInspector.Layers3DView} |
- * @param {!WebInspector.Layers3DView.ChromeTexture} index |
- * @param {string} url |
- */ |
- function loadChromeTexture(index, url) |
- { |
- WebInspector.loadImage(url).then(image => { |
- this._chromeTextures[index] = image && WebInspector.LayerTextureManager._createTextureForImage(this._gl, image) || undefined; |
- }); |
- } |
- loadChromeTexture.call(this, WebInspector.Layers3DView.ChromeTexture.Left, "Images/chromeLeft.png"); |
- loadChromeTexture.call(this, WebInspector.Layers3DView.ChromeTexture.Middle, "Images/chromeMiddle.png"); |
- loadChromeTexture.call(this, WebInspector.Layers3DView.ChromeTexture.Right, "Images/chromeRight.png"); |
- }, |
- |
- /** |
- * @return {?WebGLRenderingContext} |
- */ |
- _initGLIfNecessary: function() |
- { |
- 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: function() |
- { |
- this._depthByLayerId = {}; |
- var depth = 0; |
- var showInternalLayers = this._layerViewHost.showInternalLayersSetting().get(); |
- var root = showInternalLayers ? this._layerTree.root() : (this._layerTree.contentRoot() || this._layerTree.root()); |
- var queue = [root]; |
- this._depthByLayerId[root.id()] = 0; |
- /** @type {!Set<!WebInspector.Layer>} */ |
- this._visibleLayers = new Set(); |
- while (queue.length > 0) { |
- var layer = queue.shift(); |
- if (showInternalLayers || layer.drawsContent()) |
- this._visibleLayers.add(layer); |
- var children = layer.children(); |
- for (var i = 0; i < children.length; ++i) { |
- this._depthByLayerId[children[i].id()] = ++depth; |
- queue.push(children[i]); |
- } |
- } |
- this._maxDepth = depth; |
- }, |
- |
- /** |
- * @param {!WebInspector.Layer} layer |
- * @return {number} |
- */ |
- _depthForLayer: function(layer) |
- { |
- return this._depthByLayerId[layer.id()] * WebInspector.Layers3DView.LayerSpacing; |
- }, |
- |
- /** |
- * @param {!WebInspector.Layer} layer |
- * @param {number} index |
- * @return {number} |
- */ |
- _calculateScrollRectDepth: function(layer, index) |
- { |
- return this._depthForLayer(layer) + index * WebInspector.Layers3DView.ScrollRectSpacing + 1; |
- }, |
- |
- /** |
- * @param {!WebInspector.Layer} layer |
- */ |
- _updateDimensionsForAutoscale: function(layer) |
- { |
- // We don't want to be precise, but rather pick something least affected by |
- // animationtransforms, so that we don't change scale too often. So let's |
- // disregard transforms, scrolling and relative layer positioning and choose |
- // the largest dimensions of all layers. |
- this._dimensionsForAutoscale.width = Math.max(layer.width(), this._dimensionsForAutoscale.width); |
- this._dimensionsForAutoscale.height = Math.max(layer.height(), this._dimensionsForAutoscale.height); |
- }, |
- |
- /** |
- * @param {!WebInspector.Layer} layer |
- */ |
- _calculateLayerRect: function(layer) |
- { |
- if (!this._visibleLayers.has(layer)) |
- return; |
- var selection = new WebInspector.LayerView.LayerSelection(layer); |
- var rect = new WebInspector.Layers3DView.Rectangle(selection); |
- rect.setVertices(layer.quad(), this._depthForLayer(layer)); |
- this._appendRect(rect); |
- this._updateDimensionsForAutoscale(layer); |
- }, |
- |
- /** |
- * @param {!WebInspector.Layers3DView.Rectangle} rect |
- */ |
- _appendRect: function(rect) |
- { |
- var selection = rect.relatedObject; |
- var isSelected = WebInspector.LayerView.Selection.isEqual(this._lastSelection[WebInspector.Layers3DView.OutlineType.Selected], selection); |
- var isHovered = WebInspector.LayerView.Selection.isEqual(this._lastSelection[WebInspector.Layers3DView.OutlineType.Hovered], selection); |
- if (isSelected) { |
- rect.borderColor = WebInspector.Layers3DView.SelectedBorderColor; |
- } else if (isHovered) { |
- rect.borderColor = WebInspector.Layers3DView.HoveredBorderColor; |
- var fillColor = rect.fillColor || [255, 255, 255, 1]; |
- var maskColor = WebInspector.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 = WebInspector.Layers3DView.BorderColor; |
- } |
- rect.lineWidth = isSelected ? WebInspector.Layers3DView.SelectedBorderWidth : WebInspector.Layers3DView.BorderWidth; |
- this._rects.push(rect); |
- }, |
- |
- /** |
- * @param {!WebInspector.Layer} layer |
- */ |
- _calculateLayerScrollRects: function(layer) |
- { |
- var scrollRects = layer.scrollRects(); |
- for (var i = 0; i < scrollRects.length; ++i) { |
- var selection = new WebInspector.LayerView.ScrollRectSelection(layer, i); |
- var rect = new WebInspector.Layers3DView.Rectangle(selection); |
- rect.calculateVerticesFromRect(layer, scrollRects[i].rect, this._calculateScrollRectDepth(layer, i)); |
- rect.fillColor = WebInspector.Layers3DView.ScrollRectBackgroundColor; |
- this._appendRect(rect); |
- } |
- }, |
- |
- /** |
- * @param {!WebInspector.Layer} layer |
- */ |
- _calculateLayerTileRects: function(layer) |
- { |
- var tiles = this._textureManager.tilesForLayer(layer); |
- for (var i = 0; i < tiles.length; ++i) { |
- var tile = tiles[i]; |
- if (!tile.texture) |
- continue; |
- var selection = new WebInspector.LayerView.SnapshotSelection(layer, {rect: tile.rect, snapshot: tile.snapshot}); |
- var rect = new WebInspector.Layers3DView.Rectangle(selection); |
- rect.calculateVerticesFromRect(layer, tile.rect, this._depthForLayer(layer) + 1); |
- rect.texture = tile.texture; |
- this._appendRect(rect); |
- } |
- }, |
- |
- _calculateRects: function() |
- { |
- 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)) { |
- var layer = this._layerTexture.layer; |
- var selection = new WebInspector.LayerView.LayerSelection(layer); |
- var rect = new WebInspector.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)); |
- } |
- }, |
- |
- /** |
- * @param {!Array.<number>} color |
- * @return {!Array.<number>} |
- */ |
- _makeColorsArray: function(color) |
- { |
- var colors = []; |
- var normalizedColor = [color[0] / 255, color[1] / 255, color[2] / 255, color[3]]; |
- for (var i = 0; i < 4; i++) |
- colors = colors.concat(normalizedColor); |
- return colors; |
- }, |
- |
- /** |
- * @param {!Object} attribute |
- * @param {!Array.<number>} array |
- * @param {number} length |
- */ |
- _setVertexAttribute: function(attribute, array, length) |
- { |
- var gl = this._gl; |
- var 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); |
- }, |
- |
- /** |
- * @param {!Array.<number>} vertices |
- * @param {number} mode |
- * @param {!Array.<number>=} color |
- * @param {!Object=} texture |
- */ |
- _drawRectangle: function(vertices, mode, color, texture) |
- { |
- var gl = this._gl; |
- var 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); |
- } |
- |
- var numberOfVertices = vertices.length / 3; |
- gl.drawArrays(mode, 0, numberOfVertices); |
- }, |
- |
- /** |
- * @param {!Array.<number>} vertices |
- * @param {!WebGLTexture} texture |
- * @param {!Array.<number>=} color |
- */ |
- _drawTexture: function(vertices, texture, color) |
- { |
- this._drawRectangle(vertices, this._gl.TRIANGLE_FAN, color, texture); |
- }, |
- |
- _drawViewportAndChrome: function() |
- { |
- var viewport = this._layerTree.viewportSize(); |
- if (!viewport) |
- return; |
- |
- var drawChrome = !WebInspector.moduleSetting("frameViewerHideChromeWindow").get() && this._chromeTextures.length >= 3 && this._chromeTextures.indexOf(undefined) < 0; |
- var z = (this._maxDepth + 1) * WebInspector.Layers3DView.LayerSpacing; |
- var borderWidth = Math.ceil(WebInspector.Layers3DView.ViewportBorderWidth * this._scale); |
- var 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, WebInspector.Layers3DView.ViewportBorderColor); |
- |
- if (!drawChrome) |
- return; |
- |
- var borderAdjustment = WebInspector.Layers3DView.ViewportBorderWidth / 2; |
- var viewportWidth = this._layerTree.viewportSize().width + 2 * borderAdjustment; |
- var chromeHeight = this._chromeTextures[0].image.naturalHeight; |
- var middleFragmentWidth = viewportWidth - this._chromeTextures[0].image.naturalWidth - this._chromeTextures[2].image.naturalWidth; |
- var x = -borderAdjustment; |
- var y = -chromeHeight; |
- for (var i = 0; i < this._chromeTextures.length; ++i) { |
- var width = i === WebInspector.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, /** @type {!WebGLTexture} */ (this._chromeTextures[i])); |
- x += width; |
- } |
- }, |
- |
- /** |
- * @param {!WebInspector.Layers3DView.Rectangle} rect |
- */ |
- _drawViewRect: function(rect) |
- { |
- var 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: function() |
- { |
- if (!this.isShowing()) { |
- this._needsUpdate = true; |
- return; |
- } |
- if (!this._layerTree || !this._layerTree.root()) { |
- this._failBanner.show(this.contentElement); |
- return; |
- } |
- var 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(); |
- }, |
- |
- /** |
- * @return {!Node} |
- */ |
- _webglDisabledBanner: function() |
- { |
- var fragment = this.contentElement.ownerDocument.createDocumentFragment(); |
- fragment.createChild("div").textContent = WebInspector.UIString("Can't display layers,"); |
- fragment.createChild("div").textContent = WebInspector.UIString("WebGL support is disabled in your browser."); |
- fragment.appendChild(WebInspector.formatLocalized("Check %s for possible reasons.", [WebInspector.linkifyURLAsNode("about:gpu", undefined, undefined, true)])); |
- return fragment; |
- }, |
- |
- /** |
- * @param {!Event} event |
- * @return {?WebInspector.LayerView.Selection} |
- */ |
- _selectionFromEventPoint: function(event) |
- { |
- if (!this._layerTree) |
- return null; |
- var closestIntersectionPoint = Infinity; |
- var closestObject = null; |
- var projectionMatrix = new WebKitCSSMatrix().scale(1, -1, -1).translate(-1, -1, 0).multiply(this._projectionMatrix); |
- var x0 = (event.clientX - this._canvasElement.totalOffsetLeft()) * window.devicePixelRatio; |
- var y0 = -(event.clientY - this._canvasElement.totalOffsetTop()) * window.devicePixelRatio; |
- |
- /** |
- * @param {!WebInspector.Layers3DView.Rectangle} rect |
- */ |
- function checkIntersection(rect) |
- { |
- if (!rect.relatedObject) |
- return; |
- var t = rect.intersectWithLine(projectionMatrix, x0, y0); |
- if (t < closestIntersectionPoint) { |
- closestIntersectionPoint = t; |
- closestObject = rect.relatedObject; |
- } |
- } |
- |
- this._rects.forEach(checkIntersection); |
- return closestObject; |
- }, |
- |
- /** |
- * @param {string} caption |
- * @param {string} name |
- * @param {boolean} value |
- * @param {!WebInspector.Toolbar} toolbar |
- * @return {!WebInspector.Setting} |
- */ |
- _createVisibilitySetting: function(caption, name, value, toolbar) |
- { |
- var checkbox = new WebInspector.ToolbarCheckbox(WebInspector.UIString(caption)); |
- toolbar.appendToolbarItem(checkbox); |
- var setting = WebInspector.settings.createSetting(name, value); |
- WebInspector.SettingsUI.bindCheckbox(checkbox.inputElement, setting); |
- setting.addChangeListener(this._update, this); |
- return setting; |
- }, |
- |
- _initToolbar: function() |
- { |
- 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); |
- WebInspector.moduleSetting("frameViewerHideChromeWindow").addChangeListener(this._update, this); |
- }, |
- |
- /** |
- * @param {!Event} event |
- */ |
- _onContextMenu: function(event) |
- { |
- var contextMenu = new WebInspector.ContextMenu(event); |
- contextMenu.appendItem(WebInspector.UIString("Reset View"), this._transformController.resetAndNotify.bind(this._transformController), false); |
- var selection = this._selectionFromEventPoint(event); |
- if (selection && selection.type() === WebInspector.LayerView.Selection.Type.Snapshot) |
- contextMenu.appendItem(WebInspector.UIString("Show Paint Profiler"), this.dispatchEventToListeners.bind(this, WebInspector.Layers3DView.Events.PaintProfilerRequested, selection.snapshot()), false); |
- this._layerViewHost.showContextMenu(contextMenu, selection); |
- }, |
- |
- /** |
- * @param {!Event} event |
- */ |
- _onMouseMove: function(event) |
- { |
- if (event.which) |
- return; |
- this._layerViewHost.hoverObject(this._selectionFromEventPoint(event)); |
- }, |
- |
- /** |
- * @param {!Event} event |
- */ |
- _onMouseDown: function(event) |
- { |
- this._mouseDownX = event.clientX; |
- this._mouseDownY = event.clientY; |
- }, |
- |
- /** |
- * @param {!Event} event |
- */ |
- _onMouseUp: function(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; |
- }, |
- |
- /** |
- * @param {!Event} event |
- */ |
- _onDoubleClick: function(event) |
- { |
- var selection = this._selectionFromEventPoint(event); |
- if (selection && (selection.type() === WebInspector.LayerView.Selection.Type.Snapshot || selection.layer())) |
- this.dispatchEventToListeners(WebInspector.Layers3DView.Events.PaintProfilerRequested, selection); |
- event.stopPropagation(); |
- }, |
- |
- _updatePaints: function() |
- { |
- if (this._showPaints()) { |
- this._textureManager.setLayerTree(this._layerTree); |
- this._textureManager.forceUpdate(); |
- } else { |
- this._textureManager.reset(); |
- } |
- this._update(); |
- }, |
- |
- /** |
- * @return {boolean} |
- */ |
- _showPaints: function() |
- { |
- return this._showPaintsSetting.get(); |
- }, |
- |
- __proto__: WebInspector.VBox.prototype |
-}; |
- |
/** |
- * @constructor |
- * @param {function()} textureUpdatedCallback |
+ * @unrestricted |
*/ |
-WebInspector.LayerTextureManager = function(textureUpdatedCallback) |
-{ |
+WebInspector.LayerTextureManager = class { |
+ /** |
+ * @param {function()} textureUpdatedCallback |
+ */ |
+ constructor(textureUpdatedCallback) { |
this._textureUpdatedCallback = textureUpdatedCallback; |
this._throttler = new WebInspector.Throttler(0); |
this._scale = 0; |
this._active = false; |
this.reset(); |
-}; |
- |
-WebInspector.LayerTextureManager.prototype = { |
- reset: function() |
- { |
- if (this._tilesByLayer) |
- this.setLayerTree(null); |
- |
- /** @type {!Map<!WebInspector.Layer, !Array<!WebInspector.LayerTextureManager.Tile>>} */ |
- this._tilesByLayer = new Map(); |
- /** @type {!Array<!WebInspector.Layer>} */ |
- this._queue = []; |
- }, |
- |
- /** |
- * @param {!WebGLRenderingContext} glContext |
- */ |
- setContext: function(glContext) |
- { |
- this._gl = glContext; |
- if (this._scale) |
- this._updateTextures(); |
- }, |
- |
- suspend: function() |
- { |
- this._active = false; |
- }, |
- |
- resume: function() |
- { |
- this._active = true; |
- if (this._queue.length) |
- this._update(); |
- }, |
- |
- /** |
- * @param {?WebInspector.LayerTreeBase} layerTree |
- */ |
- setLayerTree: function(layerTree) |
- { |
- var newLayers = new Set(); |
- var 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 (var layer of oldLayers) { |
- if (newLayers.has(layer)) |
- continue; |
- this._tilesByLayer.get(layer).forEach(tile => tile.dispose()); |
- this._tilesByLayer.delete(layer); |
- } |
- }, |
- |
- /** |
- * @param {!WebInspector.Layer} layer |
- * @param {!Array<!WebInspector.SnapshotWithRect>} snapshots |
- * @return {!Promise} |
- */ |
- _setSnapshotsForLayer: function(layer, snapshots) |
- { |
- var oldSnapshotsToTiles = new Map((this._tilesByLayer.get(layer) || []).map(tile => [tile.snapshot, tile])); |
- var newTiles = []; |
- var reusedTiles = []; |
- for (var snapshot of snapshots) { |
- var oldTile = oldSnapshotsToTiles.get(snapshot); |
- if (oldTile) { |
- reusedTiles.push(oldTile); |
- oldSnapshotsToTiles.delete(oldTile); |
- } else { |
- newTiles.push(new WebInspector.LayerTextureManager.Tile(snapshot)); |
- } |
- } |
- this._tilesByLayer.set(layer, reusedTiles.concat(newTiles)); |
- for (var 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); |
- }, |
- |
- /** |
- * @param {number} scale |
- */ |
- setScale: function(scale) |
- { |
- if (this._scale && this._scale >= scale) |
- return; |
- this._scale = scale; |
- this._updateTextures(); |
- }, |
- |
- /** |
- * @param {!WebInspector.Layer} layer |
- * @return {!Array<!WebInspector.LayerTextureManager.Tile>} |
- */ |
- tilesForLayer: function(layer) |
- { |
- return this._tilesByLayer.get(layer) || []; |
- }, |
- |
- /** |
- * @param {!WebInspector.Layer} layer |
- */ |
- layerNeedsUpdate: function(layer) |
- { |
- if (this._queue.indexOf(layer) < 0) |
- this._queue.push(layer); |
- if (this._active) |
- this._throttler.schedule(this._update.bind(this)); |
- }, |
- |
- forceUpdate: function() |
- { |
- this._queue.forEach(layer => this._updateLayer(layer)); |
- this._queue = []; |
- this._throttler.flush(); |
- }, |
- |
- /** |
- * @return {!Promise} |
- */ |
- _update: function() |
- { |
- var layer = this._queue.shift(); |
- if (!layer) |
- return Promise.resolve(); |
- if (this._queue.length) |
- this._throttler.schedule(this._update.bind(this)); |
- return this._updateLayer(layer); |
- }, |
- |
- /** |
- * @param {!WebInspector.Layer} layer |
- * @return {!Promise} |
- */ |
- _updateLayer: function(layer) |
- { |
- return Promise.all(layer.snapshots()).then(snapshots => |
- this._setSnapshotsForLayer(layer, snapshots.filter(snapshot => !!snapshot))); |
- }, |
- |
- _updateTextures: function() |
- { |
- if (!this._gl) |
- return; |
- if (!this._scale) |
- return; |
- |
- for (var tiles of this._tilesByLayer.values()) { |
- for (var tile of tiles) { |
- var promise = tile.updateScale(this._gl, this._scale); |
- if (promise) |
- promise.then(this._textureUpdatedCallback); |
- } |
+ } |
+ |
+ /** |
+ * @param {!Image} image |
+ * @param {!WebGLRenderingContext} gl |
+ * @return {!WebGLTexture} texture |
+ */ |
+ static _createTextureForImage(gl, image) { |
+ var 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); |
+ |
+ /** @type {!Map<!WebInspector.Layer, !Array<!WebInspector.LayerTextureManager.Tile>>} */ |
+ this._tilesByLayer = new Map(); |
+ /** @type {!Array<!WebInspector.Layer>} */ |
+ this._queue = []; |
+ } |
+ |
+ /** |
+ * @param {!WebGLRenderingContext} glContext |
+ */ |
+ setContext(glContext) { |
+ this._gl = glContext; |
+ if (this._scale) |
+ this._updateTextures(); |
+ } |
+ |
+ suspend() { |
+ this._active = false; |
+ } |
+ |
+ resume() { |
+ this._active = true; |
+ if (this._queue.length) |
+ this._update(); |
+ } |
+ |
+ /** |
+ * @param {?WebInspector.LayerTreeBase} layerTree |
+ */ |
+ setLayerTree(layerTree) { |
+ var newLayers = new Set(); |
+ var 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 (var layer of oldLayers) { |
+ if (newLayers.has(layer)) |
+ continue; |
+ this._tilesByLayer.get(layer).forEach(tile => tile.dispose()); |
+ this._tilesByLayer.delete(layer); |
+ } |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layer} layer |
+ * @param {!Array<!WebInspector.SnapshotWithRect>} snapshots |
+ * @return {!Promise} |
+ */ |
+ _setSnapshotsForLayer(layer, snapshots) { |
+ var oldSnapshotsToTiles = new Map((this._tilesByLayer.get(layer) || []).map(tile => [tile.snapshot, tile])); |
+ var newTiles = []; |
+ var reusedTiles = []; |
+ for (var snapshot of snapshots) { |
+ var oldTile = oldSnapshotsToTiles.get(snapshot); |
+ if (oldTile) { |
+ reusedTiles.push(oldTile); |
+ oldSnapshotsToTiles.delete(oldTile); |
+ } else { |
+ newTiles.push(new WebInspector.LayerTextureManager.Tile(snapshot)); |
+ } |
+ } |
+ this._tilesByLayer.set(layer, reusedTiles.concat(newTiles)); |
+ for (var 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); |
+ } |
+ |
+ /** |
+ * @param {number} scale |
+ */ |
+ setScale(scale) { |
+ if (this._scale && this._scale >= scale) |
+ return; |
+ this._scale = scale; |
+ this._updateTextures(); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layer} layer |
+ * @return {!Array<!WebInspector.LayerTextureManager.Tile>} |
+ */ |
+ tilesForLayer(layer) { |
+ return this._tilesByLayer.get(layer) || []; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layer} 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._throttler.flush(); |
+ } |
+ |
+ /** |
+ * @return {!Promise} |
+ */ |
+ _update() { |
+ var layer = this._queue.shift(); |
+ if (!layer) |
+ return Promise.resolve(); |
+ if (this._queue.length) |
+ this._throttler.schedule(this._update.bind(this)); |
+ return this._updateLayer(layer); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layer} layer |
+ * @return {!Promise} |
+ */ |
+ _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 (var tiles of this._tilesByLayer.values()) { |
+ for (var tile of tiles) { |
+ var promise = tile.updateScale(this._gl, this._scale); |
+ if (promise) |
+ promise.then(this._textureUpdatedCallback); |
+ } |
} |
+ } |
}; |
/** |
- * @constructor |
- * @param {?WebInspector.LayerView.Selection} relatedObject |
+ * @unrestricted |
*/ |
-WebInspector.Layers3DView.Rectangle = function(relatedObject) |
-{ |
+WebInspector.Layers3DView.Rectangle = class { |
+ /** |
+ * @param {?WebInspector.LayerView.Selection} relatedObject |
+ */ |
+ constructor(relatedObject) { |
this.relatedObject = relatedObject; |
/** @type {number} */ |
this.lineWidth = 1; |
@@ -1043,170 +1042,150 @@ WebInspector.Layers3DView.Rectangle = function(relatedObject) |
this.fillColor = null; |
/** @type {?WebGLTexture} */ |
this.texture = null; |
-}; |
- |
-WebInspector.Layers3DView.Rectangle.prototype = { |
- /** |
- * @param {!Array.<number>} quad |
- * @param {number} z |
- */ |
- setVertices: function(quad, z) |
- { |
- this.vertices = [quad[0], quad[1], z, quad[2], quad[3], z, quad[4], quad[5], z, quad[6], quad[7], z]; |
- }, |
- |
- /** |
- * Finds coordinates of point on layer quad, having offsets (ratioX * width) and (ratioY * height) |
- * from the left corner of the initial layer rect, where width and heigth are layer bounds. |
- * @param {!Array.<number>} quad |
- * @param {number} ratioX |
- * @param {number} ratioY |
- * @return {!Array.<number>} |
- */ |
- _calculatePointOnQuad: function(quad, ratioX, ratioY) |
- { |
- var x0 = quad[0]; |
- var y0 = quad[1]; |
- var x1 = quad[2]; |
- var y1 = quad[3]; |
- var x2 = quad[4]; |
- var y2 = quad[5]; |
- var x3 = quad[6]; |
- var y3 = quad[7]; |
- // Point on the first quad side clockwise |
- var firstSidePointX = x0 + ratioX * (x1 - x0); |
- var firstSidePointY = y0 + ratioX * (y1 - y0); |
- // Point on the third quad side clockwise |
- var thirdSidePointX = x3 + ratioX * (x2 - x3); |
- var thirdSidePointY = y3 + ratioX * (y2 - y3); |
- var x = firstSidePointX + ratioY * (thirdSidePointX - firstSidePointX); |
- var y = firstSidePointY + ratioY * (thirdSidePointY - firstSidePointY); |
- return [x, y]; |
- }, |
- |
- /** |
- * @param {!WebInspector.Layer} layer |
- * @param {!DOMAgent.Rect} rect |
- * @param {number} z |
- */ |
- calculateVerticesFromRect: function(layer, rect, z) |
- { |
- var quad = layer.quad(); |
- var rx1 = rect.x / layer.width(); |
- var rx2 = (rect.x + rect.width) / layer.width(); |
- var ry1 = rect.y / layer.height(); |
- var ry2 = (rect.y + rect.height) / layer.height(); |
- var 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); |
- }, |
- |
- /** |
- * Intersects quad with given transform matrix and line l(t) = (x0, y0, t) |
- * @param {!CSSMatrix} matrix |
- * @param {number} x0 |
- * @param {number} y0 |
- * @return {(number|undefined)} |
- */ |
- intersectWithLine: function(matrix, x0, y0) |
- { |
- var i; |
- // Vertices of the quad with transform matrix applied |
- var points = []; |
- for (i = 0; i < 4; ++i) |
- points[i] = WebInspector.Geometry.multiplyVectorByMatrixAndNormalize(new WebInspector.Geometry.Vector(this.vertices[i * 3], this.vertices[i * 3 + 1], this.vertices[i * 3 + 2]), matrix); |
- // Calculating quad plane normal |
- var normal = WebInspector.Geometry.crossProduct(WebInspector.Geometry.subtract(points[1], points[0]), WebInspector.Geometry.subtract(points[2], points[1])); |
- // General form of the equation of the quad plane: A * x + B * y + C * z + D = 0 |
- var A = normal.x; |
- var B = normal.y; |
- var C = normal.z; |
- var D = -(A * points[0].x + B * points[0].y + C * points[0].z); |
- // Finding t from the equation |
- var t = -(D + A * x0 + B * y0) / C; |
- // Point of the intersection |
- var pt = new WebInspector.Geometry.Vector(x0, y0, t); |
- // Vectors from the intersection point to vertices of the quad |
- var tVects = points.map(WebInspector.Geometry.subtract.bind(null, pt)); |
- // Intersection point lies inside of the polygon if scalar products of normal of the plane and |
- // cross products of successive tVects are all nonstrictly above or all nonstrictly below zero |
- for (i = 0; i < tVects.length; ++i) { |
- var product = WebInspector.Geometry.scalarProduct(normal, WebInspector.Geometry.crossProduct(tVects[i], tVects[(i + 1) % tVects.length])); |
- if (product < 0) |
- return undefined; |
- } |
- return t; |
+ } |
+ |
+ /** |
+ * @param {!Array.<number>} quad |
+ * @param {number} z |
+ */ |
+ 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]; |
+ } |
+ |
+ /** |
+ * Finds coordinates of point on layer quad, having offsets (ratioX * width) and (ratioY * height) |
+ * from the left corner of the initial layer rect, where width and heigth are layer bounds. |
+ * @param {!Array.<number>} quad |
+ * @param {number} ratioX |
+ * @param {number} ratioY |
+ * @return {!Array.<number>} |
+ */ |
+ _calculatePointOnQuad(quad, ratioX, ratioY) { |
+ var x0 = quad[0]; |
+ var y0 = quad[1]; |
+ var x1 = quad[2]; |
+ var y1 = quad[3]; |
+ var x2 = quad[4]; |
+ var y2 = quad[5]; |
+ var x3 = quad[6]; |
+ var y3 = quad[7]; |
+ // Point on the first quad side clockwise |
+ var firstSidePointX = x0 + ratioX * (x1 - x0); |
+ var firstSidePointY = y0 + ratioX * (y1 - y0); |
+ // Point on the third quad side clockwise |
+ var thirdSidePointX = x3 + ratioX * (x2 - x3); |
+ var thirdSidePointY = y3 + ratioX * (y2 - y3); |
+ var x = firstSidePointX + ratioY * (thirdSidePointX - firstSidePointX); |
+ var y = firstSidePointY + ratioY * (thirdSidePointY - firstSidePointY); |
+ return [x, y]; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.Layer} layer |
+ * @param {!DOMAgent.Rect} rect |
+ * @param {number} z |
+ */ |
+ calculateVerticesFromRect(layer, rect, z) { |
+ var quad = layer.quad(); |
+ var rx1 = rect.x / layer.width(); |
+ var rx2 = (rect.x + rect.width) / layer.width(); |
+ var ry1 = rect.y / layer.height(); |
+ var ry2 = (rect.y + rect.height) / layer.height(); |
+ var 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); |
+ } |
+ |
+ /** |
+ * Intersects quad with given transform matrix and line l(t) = (x0, y0, t) |
+ * @param {!CSSMatrix} matrix |
+ * @param {number} x0 |
+ * @param {number} y0 |
+ * @return {(number|undefined)} |
+ */ |
+ intersectWithLine(matrix, x0, y0) { |
+ var i; |
+ // Vertices of the quad with transform matrix applied |
+ var points = []; |
+ for (i = 0; i < 4; ++i) |
+ points[i] = WebInspector.Geometry.multiplyVectorByMatrixAndNormalize( |
+ new WebInspector.Geometry.Vector(this.vertices[i * 3], this.vertices[i * 3 + 1], this.vertices[i * 3 + 2]), |
+ matrix); |
+ // Calculating quad plane normal |
+ var normal = WebInspector.Geometry.crossProduct( |
+ WebInspector.Geometry.subtract(points[1], points[0]), WebInspector.Geometry.subtract(points[2], points[1])); |
+ // General form of the equation of the quad plane: A * x + B * y + C * z + D = 0 |
+ var A = normal.x; |
+ var B = normal.y; |
+ var C = normal.z; |
+ var D = -(A * points[0].x + B * points[0].y + C * points[0].z); |
+ // Finding t from the equation |
+ var t = -(D + A * x0 + B * y0) / C; |
+ // Point of the intersection |
+ var pt = new WebInspector.Geometry.Vector(x0, y0, t); |
+ // Vectors from the intersection point to vertices of the quad |
+ var tVects = points.map(WebInspector.Geometry.subtract.bind(null, pt)); |
+ // Intersection point lies inside of the polygon if scalar products of normal of the plane and |
+ // cross products of successive tVects are all nonstrictly above or all nonstrictly below zero |
+ for (i = 0; i < tVects.length; ++i) { |
+ var product = WebInspector.Geometry.scalarProduct( |
+ normal, WebInspector.Geometry.crossProduct(tVects[i], tVects[(i + 1) % tVects.length])); |
+ if (product < 0) |
+ return undefined; |
} |
+ return t; |
+ } |
}; |
-/** |
- * @param {!Image} image |
- * @param {!WebGLRenderingContext} gl |
- * @return {!WebGLTexture} texture |
- */ |
-WebInspector.LayerTextureManager._createTextureForImage = function(gl, image) |
-{ |
- var 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; |
-}; |
/** |
- * @constructor |
- * @param {!WebInspector.SnapshotWithRect} snapshotWithRect |
+ * @unrestricted |
*/ |
-WebInspector.LayerTextureManager.Tile = function(snapshotWithRect) |
-{ |
+WebInspector.LayerTextureManager.Tile = class { |
+ /** |
+ * @param {!WebInspector.SnapshotWithRect} snapshotWithRect |
+ */ |
+ constructor(snapshotWithRect) { |
this.snapshot = snapshotWithRect.snapshot; |
this.rect = snapshotWithRect.rect; |
this.scale = 0; |
/** @type {?WebGLTexture} */ |
this.texture = null; |
-}; |
+ } |
-WebInspector.LayerTextureManager.Tile.prototype = { |
- dispose: function() |
- { |
- this.snapshot.release(); |
- if (this.texture) { |
- this._gl.deleteTexture(this.texture); |
- this.texture = null; |
- } |
- }, |
- |
- /** |
- * @param {!WebGLRenderingContext} glContext |
- * @param {number} scale |
- * @return {?Promise} |
- */ |
- updateScale: function(glContext, scale) |
- { |
- if (this.texture && this.scale >= scale) |
- return null; |
- return this.update(glContext, scale); |
- }, |
- |
- /** |
- * @param {!WebGLRenderingContext} glContext |
- * @param {number} scale |
- * @return {!Promise} |
- */ |
- update: function(glContext, scale) |
- { |
- this._gl = glContext; |
- this.scale = scale; |
- return this.snapshot.replay(null, null, scale) |
- .then(imageURL => imageURL && WebInspector.loadImage(imageURL)) |
- .then(image => { |
- this.texture = image && WebInspector.LayerTextureManager._createTextureForImage(glContext, image); |
- }); |
+ dispose() { |
+ this.snapshot.release(); |
+ if (this.texture) { |
+ this._gl.deleteTexture(this.texture); |
+ this.texture = null; |
} |
+ } |
+ |
+ /** |
+ * @param {!WebGLRenderingContext} glContext |
+ * @param {number} scale |
+ * @return {?Promise} |
+ */ |
+ updateScale(glContext, scale) { |
+ if (this.texture && this.scale >= scale) |
+ return null; |
+ return this.update(glContext, scale); |
+ } |
+ |
+ /** |
+ * @param {!WebGLRenderingContext} glContext |
+ * @param {number} scale |
+ * @return {!Promise} |
+ */ |
+ update(glContext, scale) { |
+ this._gl = glContext; |
+ this.scale = scale; |
+ return this.snapshot.replay(null, null, scale) |
+ .then(imageURL => imageURL && WebInspector.loadImage(imageURL)) |
+ .then(image => { |
+ this.texture = image && WebInspector.LayerTextureManager._createTextureForImage(glContext, image); |
+ }); |
+ } |
}; |