OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2014 Google Inc. All rights reserved. | 2 * Copyright (C) 2014 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
11 * copyright notice, this list of conditions and the following disclaimer | 11 * copyright notice, this list of conditions and the following disclaimer |
12 * in the documentation and/or other materials provided with the | 12 * in the documentation and/or other materials provided with the |
13 * distribution. | 13 * distribution. |
14 * * Neither the name of Google Inc. nor the names of its | 14 * * Neither the name of Google Inc. nor the names of its |
15 * contributors may be used to endorse or promote products derived from | 15 * contributors may be used to endorse or promote products derived from |
16 * this software without specific prior written permission. | 16 * this software without specific prior written permission. |
17 * | 17 * |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | |
31 /** | 30 /** |
32 * @constructor | |
33 * @extends {WebInspector.VBox} | |
34 * @param {!WebInspector.LayerViewHost} layerViewHost | |
35 * @implements {WebInspector.LayerView} | 31 * @implements {WebInspector.LayerView} |
| 32 * @unrestricted |
36 */ | 33 */ |
37 WebInspector.Layers3DView = function(layerViewHost) | 34 WebInspector.Layers3DView = class extends WebInspector.VBox { |
38 { | 35 /** |
39 WebInspector.VBox.call(this, true); | 36 * @param {!WebInspector.LayerViewHost} layerViewHost |
40 this.registerRequiredCSS("layer_viewer/layers3DView.css"); | 37 */ |
41 this.contentElement.classList.add("layers-3d-view"); | 38 constructor(layerViewHost) { |
| 39 super(true); |
| 40 this.registerRequiredCSS('layer_viewer/layers3DView.css'); |
| 41 this.contentElement.classList.add('layers-3d-view'); |
42 this._failBanner = new WebInspector.VBox(); | 42 this._failBanner = new WebInspector.VBox(); |
43 this._failBanner.element.classList.add("full-widget-dimmed-banner"); | 43 this._failBanner.element.classList.add('full-widget-dimmed-banner'); |
44 this._failBanner.element.createTextChild(WebInspector.UIString("Layer inform
ation is not yet available.")); | 44 this._failBanner.element.createTextChild(WebInspector.UIString('Layer inform
ation is not yet available.')); |
45 | 45 |
46 this._layerViewHost = layerViewHost; | 46 this._layerViewHost = layerViewHost; |
47 this._layerViewHost.registerView(this); | 47 this._layerViewHost.registerView(this); |
48 | 48 |
49 this._transformController = new WebInspector.TransformController(this.conten
tElement); | 49 this._transformController = new WebInspector.TransformController(this.conten
tElement); |
50 this._transformController.addEventListener(WebInspector.TransformController.
Events.TransformChanged, this._update, this); | 50 this._transformController.addEventListener( |
| 51 WebInspector.TransformController.Events.TransformChanged, this._update,
this); |
51 this._initToolbar(); | 52 this._initToolbar(); |
52 | 53 |
53 this._canvasElement = this.contentElement.createChild("canvas"); | 54 this._canvasElement = this.contentElement.createChild('canvas'); |
54 this._canvasElement.tabIndex = 0; | 55 this._canvasElement.tabIndex = 0; |
55 this._canvasElement.addEventListener("dblclick", this._onDoubleClick.bind(th
is), false); | 56 this._canvasElement.addEventListener('dblclick', this._onDoubleClick.bind(th
is), false); |
56 this._canvasElement.addEventListener("mousedown", this._onMouseDown.bind(thi
s), false); | 57 this._canvasElement.addEventListener('mousedown', this._onMouseDown.bind(thi
s), false); |
57 this._canvasElement.addEventListener("mouseup", this._onMouseUp.bind(this),
false); | 58 this._canvasElement.addEventListener('mouseup', this._onMouseUp.bind(this),
false); |
58 this._canvasElement.addEventListener("mouseleave", this._onMouseMove.bind(th
is), false); | 59 this._canvasElement.addEventListener('mouseleave', this._onMouseMove.bind(th
is), false); |
59 this._canvasElement.addEventListener("mousemove", this._onMouseMove.bind(thi
s), false); | 60 this._canvasElement.addEventListener('mousemove', this._onMouseMove.bind(thi
s), false); |
60 this._canvasElement.addEventListener("contextmenu", this._onContextMenu.bind
(this), false); | 61 this._canvasElement.addEventListener('contextmenu', this._onContextMenu.bind
(this), false); |
61 | 62 |
62 this._lastSelection = {}; | 63 this._lastSelection = {}; |
63 this._layerTree = null; | 64 this._layerTree = null; |
64 | 65 |
65 this._textureManager = new WebInspector.LayerTextureManager(this._update.bin
d(this)); | 66 this._textureManager = new WebInspector.LayerTextureManager(this._update.bin
d(this)); |
66 | 67 |
67 /** @type Array.<!WebGLTexture|undefined> */ | 68 /** @type Array.<!WebGLTexture|undefined> */ |
68 this._chromeTextures = []; | 69 this._chromeTextures = []; |
69 this._rects = []; | 70 this._rects = []; |
70 | 71 |
71 this._layerViewHost.showInternalLayersSetting().addChangeListener(this._upda
te, this); | 72 this._layerViewHost.showInternalLayersSetting().addChangeListener(this._upda
te, this); |
| 73 } |
| 74 |
| 75 /** |
| 76 * @param {?WebInspector.LayerTreeBase} layerTree |
| 77 * @override |
| 78 */ |
| 79 setLayerTree(layerTree) { |
| 80 this._layerTree = layerTree; |
| 81 this._layerTexture = null; |
| 82 delete this._oldTextureScale; |
| 83 if (this._showPaints()) |
| 84 this._textureManager.setLayerTree(layerTree); |
| 85 this._update(); |
| 86 } |
| 87 |
| 88 /** |
| 89 * @param {!WebInspector.Layer} layer |
| 90 * @param {string=} imageURL |
| 91 */ |
| 92 showImageForLayer(layer, imageURL) { |
| 93 if (!imageURL) { |
| 94 this._layerTexture = null; |
| 95 this._update(); |
| 96 return; |
| 97 } |
| 98 WebInspector.loadImage(imageURL).then(image => { |
| 99 var texture = image && WebInspector.LayerTextureManager._createTextureForI
mage(this._gl, image); |
| 100 this._layerTexture = texture ? {layer: layer, texture: texture} : null; |
| 101 this._update(); |
| 102 }); |
| 103 } |
| 104 |
| 105 /** |
| 106 * @override |
| 107 */ |
| 108 onResize() { |
| 109 this._resizeCanvas(); |
| 110 this._update(); |
| 111 } |
| 112 |
| 113 /** |
| 114 * @override |
| 115 */ |
| 116 willHide() { |
| 117 this._textureManager.suspend(); |
| 118 } |
| 119 |
| 120 /** |
| 121 * @override |
| 122 */ |
| 123 wasShown() { |
| 124 this._textureManager.resume(); |
| 125 if (!this._needsUpdate) |
| 126 return; |
| 127 this._resizeCanvas(); |
| 128 this._update(); |
| 129 } |
| 130 |
| 131 /** |
| 132 * @param {!WebInspector.Layer} layer |
| 133 */ |
| 134 updateLayerSnapshot(layer) { |
| 135 this._textureManager.layerNeedsUpdate(layer); |
| 136 } |
| 137 |
| 138 /** |
| 139 * @param {!WebInspector.Layers3DView.OutlineType} type |
| 140 * @param {?WebInspector.LayerView.Selection} selection |
| 141 */ |
| 142 _setOutline(type, selection) { |
| 143 this._lastSelection[type] = selection; |
| 144 this._update(); |
| 145 } |
| 146 |
| 147 /** |
| 148 * @param {?WebInspector.LayerView.Selection} selection |
| 149 * @override |
| 150 */ |
| 151 hoverObject(selection) { |
| 152 this._setOutline(WebInspector.Layers3DView.OutlineType.Hovered, selection); |
| 153 } |
| 154 |
| 155 /** |
| 156 * @param {?WebInspector.LayerView.Selection} selection |
| 157 * @override |
| 158 */ |
| 159 selectObject(selection) { |
| 160 this._setOutline(WebInspector.Layers3DView.OutlineType.Hovered, null); |
| 161 this._setOutline(WebInspector.Layers3DView.OutlineType.Selected, selection); |
| 162 } |
| 163 |
| 164 /** |
| 165 * @param {!WebInspector.LayerView.Selection} selection |
| 166 * @return {!Promise<?WebInspector.SnapshotWithRect>} |
| 167 */ |
| 168 snapshotForSelection(selection) { |
| 169 if (selection.type() === WebInspector.LayerView.Selection.Type.Snapshot) { |
| 170 var snapshotWithRect = /** @type {!WebInspector.LayerView.SnapshotSelectio
n} */ (selection).snapshot(); |
| 171 snapshotWithRect.snapshot.addReference(); |
| 172 return /** @type {!Promise<?WebInspector.SnapshotWithRect>} */ (Promise.re
solve(snapshotWithRect)); |
| 173 } |
| 174 if (selection.layer()) { |
| 175 var promise = selection.layer().snapshots()[0]; |
| 176 if (promise) |
| 177 return promise; |
| 178 } |
| 179 return /** @type {!Promise<?WebInspector.SnapshotWithRect>} */ (Promise.reso
lve(null)); |
| 180 } |
| 181 |
| 182 /** |
| 183 * @param {!Element} canvas |
| 184 * @return {?WebGLRenderingContext} |
| 185 */ |
| 186 _initGL(canvas) { |
| 187 var gl = canvas.getContext('webgl'); |
| 188 if (!gl) |
| 189 return null; |
| 190 gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); |
| 191 gl.enable(gl.BLEND); |
| 192 gl.clearColor(0.0, 0.0, 0.0, 0.0); |
| 193 gl.enable(gl.DEPTH_TEST); |
| 194 return gl; |
| 195 } |
| 196 |
| 197 /** |
| 198 * @param {!Object} type |
| 199 * @param {string} script |
| 200 */ |
| 201 _createShader(type, script) { |
| 202 var shader = this._gl.createShader(type); |
| 203 this._gl.shaderSource(shader, script); |
| 204 this._gl.compileShader(shader); |
| 205 this._gl.attachShader(this._shaderProgram, shader); |
| 206 } |
| 207 |
| 208 _initShaders() { |
| 209 this._shaderProgram = this._gl.createProgram(); |
| 210 this._createShader(this._gl.FRAGMENT_SHADER, WebInspector.Layers3DView.Fragm
entShader); |
| 211 this._createShader(this._gl.VERTEX_SHADER, WebInspector.Layers3DView.VertexS
hader); |
| 212 this._gl.linkProgram(this._shaderProgram); |
| 213 this._gl.useProgram(this._shaderProgram); |
| 214 |
| 215 this._shaderProgram.vertexPositionAttribute = this._gl.getAttribLocation(thi
s._shaderProgram, 'aVertexPosition'); |
| 216 this._gl.enableVertexAttribArray(this._shaderProgram.vertexPositionAttribute
); |
| 217 this._shaderProgram.vertexColorAttribute = this._gl.getAttribLocation(this._
shaderProgram, 'aVertexColor'); |
| 218 this._gl.enableVertexAttribArray(this._shaderProgram.vertexColorAttribute); |
| 219 this._shaderProgram.textureCoordAttribute = this._gl.getAttribLocation(this.
_shaderProgram, 'aTextureCoord'); |
| 220 this._gl.enableVertexAttribArray(this._shaderProgram.textureCoordAttribute); |
| 221 |
| 222 this._shaderProgram.pMatrixUniform = this._gl.getUniformLocation(this._shade
rProgram, 'uPMatrix'); |
| 223 this._shaderProgram.samplerUniform = this._gl.getUniformLocation(this._shade
rProgram, 'uSampler'); |
| 224 } |
| 225 |
| 226 _resizeCanvas() { |
| 227 this._canvasElement.width = this._canvasElement.offsetWidth * window.deviceP
ixelRatio; |
| 228 this._canvasElement.height = this._canvasElement.offsetHeight * window.devic
ePixelRatio; |
| 229 } |
| 230 |
| 231 _updateTransformAndConstraints() { |
| 232 var paddingFraction = 0.1; |
| 233 var viewport = this._layerTree.viewportSize(); |
| 234 var root = this._layerTree.root(); |
| 235 var baseWidth = viewport ? viewport.width : this._dimensionsForAutoscale.wid
th; |
| 236 var baseHeight = viewport ? viewport.height : this._dimensionsForAutoscale.h
eight; |
| 237 var canvasWidth = this._canvasElement.width; |
| 238 var canvasHeight = this._canvasElement.height; |
| 239 var paddingX = canvasWidth * paddingFraction; |
| 240 var paddingY = canvasHeight * paddingFraction; |
| 241 var scaleX = (canvasWidth - 2 * paddingX) / baseWidth; |
| 242 var scaleY = (canvasHeight - 2 * paddingY) / baseHeight; |
| 243 var viewScale = Math.min(scaleX, scaleY); |
| 244 var minScaleConstraint = |
| 245 Math.min(baseWidth / this._dimensionsForAutoscale.width, baseHeight / th
is._dimensionsForAutoscale.width) / 2; |
| 246 this._transformController.setScaleConstraints( |
| 247 minScaleConstraint, |
| 248 10 / viewScale); // 1/viewScale is 1:1 in terms of pixels, so allow zoo
ming to 10x of native size |
| 249 var scale = this._transformController.scale(); |
| 250 var rotateX = this._transformController.rotateX(); |
| 251 var rotateY = this._transformController.rotateY(); |
| 252 |
| 253 this._scale = scale * viewScale; |
| 254 var textureScale = Number.constrain(this._scale, 0.1, 1); |
| 255 if (textureScale !== this._oldTextureScale) { |
| 256 this._oldTextureScale = textureScale; |
| 257 this._textureManager.setScale(textureScale); |
| 258 this.dispatchEventToListeners(WebInspector.Layers3DView.Events.ScaleChange
d, textureScale); |
| 259 } |
| 260 var scaleAndRotationMatrix = new WebKitCSSMatrix() |
| 261 .scale(scale, scale, scale) |
| 262 .translate(canvasWidth / 2, canvasHeight /
2, 0) |
| 263 .rotate(rotateX, rotateY, 0) |
| 264 .scale(viewScale, viewScale, viewScale) |
| 265 .translate(-baseWidth / 2, -baseHeight / 2,
0); |
| 266 |
| 267 var bounds; |
| 268 for (var i = 0; i < this._rects.length; ++i) |
| 269 bounds = |
| 270 WebInspector.Geometry.boundsForTransformedPoints(scaleAndRotationMatri
x, this._rects[i].vertices, bounds); |
| 271 |
| 272 this._transformController.clampOffsets( |
| 273 (paddingX - bounds.maxX) / window.devicePixelRatio, |
| 274 (canvasWidth - paddingX - bounds.minX) / window.devicePixelRatio, |
| 275 (paddingY - bounds.maxY) / window.devicePixelRatio, |
| 276 (canvasHeight - paddingY - bounds.minY) / window.devicePixelRatio); |
| 277 var offsetX = this._transformController.offsetX() * window.devicePixelRatio; |
| 278 var offsetY = this._transformController.offsetY() * window.devicePixelRatio; |
| 279 // Multiply to translation matrix on the right rather than translate (which
would implicitly multiply on the left). |
| 280 this._projectionMatrix = new WebKitCSSMatrix().translate(offsetX, offsetY, 0
).multiply(scaleAndRotationMatrix); |
| 281 |
| 282 var glProjectionMatrix = new WebKitCSSMatrix() |
| 283 .scale(1, -1, -1) |
| 284 .translate(-1, -1, 0) |
| 285 .scale(2 / this._canvasElement.width, 2 / this.
_canvasElement.height, 1 / 1000000) |
| 286 .multiply(this._projectionMatrix); |
| 287 this._gl.uniformMatrix4fv(this._shaderProgram.pMatrixUniform, false, this._a
rrayFromMatrix(glProjectionMatrix)); |
| 288 } |
| 289 |
| 290 /** |
| 291 * @param {!CSSMatrix} m |
| 292 * @return {!Float32Array} |
| 293 */ |
| 294 _arrayFromMatrix(m) { |
| 295 return new Float32Array([ |
| 296 m.m11, m.m12, m.m13, m.m14, m.m21, m.m22, m.m23, m.m24, m.m31, m.m32, m.m3
3, m.m34, m.m41, m.m42, m.m43, m.m44 |
| 297 ]); |
| 298 } |
| 299 |
| 300 _initWhiteTexture() { |
| 301 this._whiteTexture = this._gl.createTexture(); |
| 302 this._gl.bindTexture(this._gl.TEXTURE_2D, this._whiteTexture); |
| 303 var whitePixel = new Uint8Array([255, 255, 255, 255]); |
| 304 this._gl.texImage2D( |
| 305 this._gl.TEXTURE_2D, 0, this._gl.RGBA, 1, 1, 0, this._gl.RGBA, this._gl.
UNSIGNED_BYTE, whitePixel); |
| 306 } |
| 307 |
| 308 _initChromeTextures() { |
| 309 /** |
| 310 * @this {WebInspector.Layers3DView} |
| 311 * @param {!WebInspector.Layers3DView.ChromeTexture} index |
| 312 * @param {string} url |
| 313 */ |
| 314 function loadChromeTexture(index, url) { |
| 315 WebInspector.loadImage(url).then(image => { |
| 316 this._chromeTextures[index] = |
| 317 image && WebInspector.LayerTextureManager._createTextureForImage(thi
s._gl, image) || undefined; |
| 318 }); |
| 319 } |
| 320 loadChromeTexture.call(this, WebInspector.Layers3DView.ChromeTexture.Left, '
Images/chromeLeft.png'); |
| 321 loadChromeTexture.call(this, WebInspector.Layers3DView.ChromeTexture.Middle,
'Images/chromeMiddle.png'); |
| 322 loadChromeTexture.call(this, WebInspector.Layers3DView.ChromeTexture.Right,
'Images/chromeRight.png'); |
| 323 } |
| 324 |
| 325 /** |
| 326 * @return {?WebGLRenderingContext} |
| 327 */ |
| 328 _initGLIfNecessary() { |
| 329 if (this._gl) |
| 330 return this._gl; |
| 331 this._gl = this._initGL(this._canvasElement); |
| 332 if (!this._gl) |
| 333 return null; |
| 334 this._initShaders(); |
| 335 this._initWhiteTexture(); |
| 336 this._initChromeTextures(); |
| 337 this._textureManager.setContext(this._gl); |
| 338 return this._gl; |
| 339 } |
| 340 |
| 341 _calculateDepthsAndVisibility() { |
| 342 this._depthByLayerId = {}; |
| 343 var depth = 0; |
| 344 var showInternalLayers = this._layerViewHost.showInternalLayersSetting().get
(); |
| 345 var root = showInternalLayers ? this._layerTree.root() : (this._layerTree.co
ntentRoot() || this._layerTree.root()); |
| 346 var queue = [root]; |
| 347 this._depthByLayerId[root.id()] = 0; |
| 348 /** @type {!Set<!WebInspector.Layer>} */ |
| 349 this._visibleLayers = new Set(); |
| 350 while (queue.length > 0) { |
| 351 var layer = queue.shift(); |
| 352 if (showInternalLayers || layer.drawsContent()) |
| 353 this._visibleLayers.add(layer); |
| 354 var children = layer.children(); |
| 355 for (var i = 0; i < children.length; ++i) { |
| 356 this._depthByLayerId[children[i].id()] = ++depth; |
| 357 queue.push(children[i]); |
| 358 } |
| 359 } |
| 360 this._maxDepth = depth; |
| 361 } |
| 362 |
| 363 /** |
| 364 * @param {!WebInspector.Layer} layer |
| 365 * @return {number} |
| 366 */ |
| 367 _depthForLayer(layer) { |
| 368 return this._depthByLayerId[layer.id()] * WebInspector.Layers3DView.LayerSpa
cing; |
| 369 } |
| 370 |
| 371 /** |
| 372 * @param {!WebInspector.Layer} layer |
| 373 * @param {number} index |
| 374 * @return {number} |
| 375 */ |
| 376 _calculateScrollRectDepth(layer, index) { |
| 377 return this._depthForLayer(layer) + index * WebInspector.Layers3DView.Scroll
RectSpacing + 1; |
| 378 } |
| 379 |
| 380 /** |
| 381 * @param {!WebInspector.Layer} layer |
| 382 */ |
| 383 _updateDimensionsForAutoscale(layer) { |
| 384 // We don't want to be precise, but rather pick something least affected by |
| 385 // animationtransforms, so that we don't change scale too often. So let's |
| 386 // disregard transforms, scrolling and relative layer positioning and choose |
| 387 // the largest dimensions of all layers. |
| 388 this._dimensionsForAutoscale.width = Math.max(layer.width(), this._dimension
sForAutoscale.width); |
| 389 this._dimensionsForAutoscale.height = Math.max(layer.height(), this._dimensi
onsForAutoscale.height); |
| 390 } |
| 391 |
| 392 /** |
| 393 * @param {!WebInspector.Layer} layer |
| 394 */ |
| 395 _calculateLayerRect(layer) { |
| 396 if (!this._visibleLayers.has(layer)) |
| 397 return; |
| 398 var selection = new WebInspector.LayerView.LayerSelection(layer); |
| 399 var rect = new WebInspector.Layers3DView.Rectangle(selection); |
| 400 rect.setVertices(layer.quad(), this._depthForLayer(layer)); |
| 401 this._appendRect(rect); |
| 402 this._updateDimensionsForAutoscale(layer); |
| 403 } |
| 404 |
| 405 /** |
| 406 * @param {!WebInspector.Layers3DView.Rectangle} rect |
| 407 */ |
| 408 _appendRect(rect) { |
| 409 var selection = rect.relatedObject; |
| 410 var isSelected = WebInspector.LayerView.Selection.isEqual( |
| 411 this._lastSelection[WebInspector.Layers3DView.OutlineType.Selected], sel
ection); |
| 412 var isHovered = WebInspector.LayerView.Selection.isEqual( |
| 413 this._lastSelection[WebInspector.Layers3DView.OutlineType.Hovered], sele
ction); |
| 414 if (isSelected) { |
| 415 rect.borderColor = WebInspector.Layers3DView.SelectedBorderColor; |
| 416 } else if (isHovered) { |
| 417 rect.borderColor = WebInspector.Layers3DView.HoveredBorderColor; |
| 418 var fillColor = rect.fillColor || [255, 255, 255, 1]; |
| 419 var maskColor = WebInspector.Layers3DView.HoveredImageMaskColor; |
| 420 rect.fillColor = [ |
| 421 fillColor[0] * maskColor[0] / 255, fillColor[1] * maskColor[1] / 255, fi
llColor[2] * maskColor[2] / 255, |
| 422 fillColor[3] * maskColor[3] |
| 423 ]; |
| 424 } else { |
| 425 rect.borderColor = WebInspector.Layers3DView.BorderColor; |
| 426 } |
| 427 rect.lineWidth = isSelected ? WebInspector.Layers3DView.SelectedBorderWidth
: WebInspector.Layers3DView.BorderWidth; |
| 428 this._rects.push(rect); |
| 429 } |
| 430 |
| 431 /** |
| 432 * @param {!WebInspector.Layer} layer |
| 433 */ |
| 434 _calculateLayerScrollRects(layer) { |
| 435 var scrollRects = layer.scrollRects(); |
| 436 for (var i = 0; i < scrollRects.length; ++i) { |
| 437 var selection = new WebInspector.LayerView.ScrollRectSelection(layer, i); |
| 438 var rect = new WebInspector.Layers3DView.Rectangle(selection); |
| 439 rect.calculateVerticesFromRect(layer, scrollRects[i].rect, this._calculate
ScrollRectDepth(layer, i)); |
| 440 rect.fillColor = WebInspector.Layers3DView.ScrollRectBackgroundColor; |
| 441 this._appendRect(rect); |
| 442 } |
| 443 } |
| 444 |
| 445 /** |
| 446 * @param {!WebInspector.Layer} layer |
| 447 */ |
| 448 _calculateLayerTileRects(layer) { |
| 449 var tiles = this._textureManager.tilesForLayer(layer); |
| 450 for (var i = 0; i < tiles.length; ++i) { |
| 451 var tile = tiles[i]; |
| 452 if (!tile.texture) |
| 453 continue; |
| 454 var selection = new WebInspector.LayerView.SnapshotSelection(layer, {rect:
tile.rect, snapshot: tile.snapshot}); |
| 455 var rect = new WebInspector.Layers3DView.Rectangle(selection); |
| 456 rect.calculateVerticesFromRect(layer, tile.rect, this._depthForLayer(layer
) + 1); |
| 457 rect.texture = tile.texture; |
| 458 this._appendRect(rect); |
| 459 } |
| 460 } |
| 461 |
| 462 _calculateRects() { |
| 463 this._rects = []; |
| 464 this._dimensionsForAutoscale = {width: 0, height: 0}; |
| 465 this._layerTree.forEachLayer(this._calculateLayerRect.bind(this)); |
| 466 |
| 467 if (this._showSlowScrollRectsSetting.get()) |
| 468 this._layerTree.forEachLayer(this._calculateLayerScrollRects.bind(this)); |
| 469 |
| 470 if (this._layerTexture && this._visibleLayers.has(this._layerTexture.layer))
{ |
| 471 var layer = this._layerTexture.layer; |
| 472 var selection = new WebInspector.LayerView.LayerSelection(layer); |
| 473 var rect = new WebInspector.Layers3DView.Rectangle(selection); |
| 474 rect.setVertices(layer.quad(), this._depthForLayer(layer)); |
| 475 rect.texture = this._layerTexture.texture; |
| 476 this._appendRect(rect); |
| 477 } else if (this._showPaints()) { |
| 478 this._layerTree.forEachLayer(this._calculateLayerTileRects.bind(this)); |
| 479 } |
| 480 } |
| 481 |
| 482 /** |
| 483 * @param {!Array.<number>} color |
| 484 * @return {!Array.<number>} |
| 485 */ |
| 486 _makeColorsArray(color) { |
| 487 var colors = []; |
| 488 var normalizedColor = [color[0] / 255, color[1] / 255, color[2] / 255, color
[3]]; |
| 489 for (var i = 0; i < 4; i++) |
| 490 colors = colors.concat(normalizedColor); |
| 491 return colors; |
| 492 } |
| 493 |
| 494 /** |
| 495 * @param {!Object} attribute |
| 496 * @param {!Array.<number>} array |
| 497 * @param {number} length |
| 498 */ |
| 499 _setVertexAttribute(attribute, array, length) { |
| 500 var gl = this._gl; |
| 501 var buffer = gl.createBuffer(); |
| 502 gl.bindBuffer(gl.ARRAY_BUFFER, buffer); |
| 503 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(array), gl.STATIC_DRAW); |
| 504 gl.vertexAttribPointer(attribute, length, gl.FLOAT, false, 0, 0); |
| 505 } |
| 506 |
| 507 /** |
| 508 * @param {!Array.<number>} vertices |
| 509 * @param {number} mode |
| 510 * @param {!Array.<number>=} color |
| 511 * @param {!Object=} texture |
| 512 */ |
| 513 _drawRectangle(vertices, mode, color, texture) { |
| 514 var gl = this._gl; |
| 515 var white = [255, 255, 255, 1]; |
| 516 color = color || white; |
| 517 this._setVertexAttribute(this._shaderProgram.vertexPositionAttribute, vertic
es, 3); |
| 518 this._setVertexAttribute(this._shaderProgram.textureCoordAttribute, [0, 1, 1
, 1, 1, 0, 0, 0], 2); |
| 519 this._setVertexAttribute(this._shaderProgram.vertexColorAttribute, this._mak
eColorsArray(color), color.length); |
| 520 |
| 521 if (texture) { |
| 522 gl.activeTexture(gl.TEXTURE0); |
| 523 gl.bindTexture(gl.TEXTURE_2D, texture); |
| 524 gl.uniform1i(this._shaderProgram.samplerUniform, 0); |
| 525 } else { |
| 526 gl.bindTexture(gl.TEXTURE_2D, this._whiteTexture); |
| 527 } |
| 528 |
| 529 var numberOfVertices = vertices.length / 3; |
| 530 gl.drawArrays(mode, 0, numberOfVertices); |
| 531 } |
| 532 |
| 533 /** |
| 534 * @param {!Array.<number>} vertices |
| 535 * @param {!WebGLTexture} texture |
| 536 * @param {!Array.<number>=} color |
| 537 */ |
| 538 _drawTexture(vertices, texture, color) { |
| 539 this._drawRectangle(vertices, this._gl.TRIANGLE_FAN, color, texture); |
| 540 } |
| 541 |
| 542 _drawViewportAndChrome() { |
| 543 var viewport = this._layerTree.viewportSize(); |
| 544 if (!viewport) |
| 545 return; |
| 546 |
| 547 var drawChrome = !WebInspector.moduleSetting('frameViewerHideChromeWindow').
get() && |
| 548 this._chromeTextures.length >= 3 && this._chromeTextures.indexOf(undefin
ed) < 0; |
| 549 var z = (this._maxDepth + 1) * WebInspector.Layers3DView.LayerSpacing; |
| 550 var borderWidth = Math.ceil(WebInspector.Layers3DView.ViewportBorderWidth *
this._scale); |
| 551 var vertices = [viewport.width, 0, z, viewport.width, viewport.height, z, 0,
viewport.height, z, 0, 0, z]; |
| 552 this._gl.lineWidth(borderWidth); |
| 553 this._drawRectangle( |
| 554 vertices, drawChrome ? this._gl.LINE_STRIP : this._gl.LINE_LOOP, WebInsp
ector.Layers3DView.ViewportBorderColor); |
| 555 |
| 556 if (!drawChrome) |
| 557 return; |
| 558 |
| 559 var borderAdjustment = WebInspector.Layers3DView.ViewportBorderWidth / 2; |
| 560 var viewportWidth = this._layerTree.viewportSize().width + 2 * borderAdjustm
ent; |
| 561 var chromeHeight = this._chromeTextures[0].image.naturalHeight; |
| 562 var middleFragmentWidth = |
| 563 viewportWidth - this._chromeTextures[0].image.naturalWidth - this._chrom
eTextures[2].image.naturalWidth; |
| 564 var x = -borderAdjustment; |
| 565 var y = -chromeHeight; |
| 566 for (var i = 0; i < this._chromeTextures.length; ++i) { |
| 567 var width = i === WebInspector.Layers3DView.ChromeTexture.Middle ? middleF
ragmentWidth : |
| 568 this._c
hromeTextures[i].image.naturalWidth; |
| 569 if (width < 0 || x + width > viewportWidth) |
| 570 break; |
| 571 vertices = [x, y, z, x + width, y, z, x + width, y + chromeHeight, z, x, y
+ chromeHeight, z]; |
| 572 this._drawTexture(vertices, /** @type {!WebGLTexture} */ (this._chromeText
ures[i])); |
| 573 x += width; |
| 574 } |
| 575 } |
| 576 |
| 577 /** |
| 578 * @param {!WebInspector.Layers3DView.Rectangle} rect |
| 579 */ |
| 580 _drawViewRect(rect) { |
| 581 var vertices = rect.vertices; |
| 582 if (rect.texture) |
| 583 this._drawTexture(vertices, rect.texture, rect.fillColor || undefined); |
| 584 else if (rect.fillColor) |
| 585 this._drawRectangle(vertices, this._gl.TRIANGLE_FAN, rect.fillColor); |
| 586 this._gl.lineWidth(rect.lineWidth); |
| 587 if (rect.borderColor) |
| 588 this._drawRectangle(vertices, this._gl.LINE_LOOP, rect.borderColor); |
| 589 } |
| 590 |
| 591 _update() { |
| 592 if (!this.isShowing()) { |
| 593 this._needsUpdate = true; |
| 594 return; |
| 595 } |
| 596 if (!this._layerTree || !this._layerTree.root()) { |
| 597 this._failBanner.show(this.contentElement); |
| 598 return; |
| 599 } |
| 600 var gl = this._initGLIfNecessary(); |
| 601 if (!gl) { |
| 602 this._failBanner.element.removeChildren(); |
| 603 this._failBanner.element.appendChild(this._webglDisabledBanner()); |
| 604 this._failBanner.show(this.contentElement); |
| 605 return; |
| 606 } |
| 607 this._failBanner.detach(); |
| 608 this._gl.viewportWidth = this._canvasElement.width; |
| 609 this._gl.viewportHeight = this._canvasElement.height; |
| 610 |
| 611 this._calculateDepthsAndVisibility(); |
| 612 this._calculateRects(); |
| 613 this._updateTransformAndConstraints(); |
| 614 |
| 615 gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); |
| 616 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); |
| 617 |
| 618 this._rects.forEach(this._drawViewRect.bind(this)); |
| 619 this._drawViewportAndChrome(); |
| 620 } |
| 621 |
| 622 /** |
| 623 * @return {!Node} |
| 624 */ |
| 625 _webglDisabledBanner() { |
| 626 var fragment = this.contentElement.ownerDocument.createDocumentFragment(); |
| 627 fragment.createChild('div').textContent = WebInspector.UIString('Can\'t disp
lay layers,'); |
| 628 fragment.createChild('div').textContent = WebInspector.UIString('WebGL suppo
rt is disabled in your browser.'); |
| 629 fragment.appendChild(WebInspector.formatLocalized( |
| 630 'Check %s for possible reasons.', [WebInspector.linkifyURLAsNode('about:
gpu', undefined, undefined, true)])); |
| 631 return fragment; |
| 632 } |
| 633 |
| 634 /** |
| 635 * @param {!Event} event |
| 636 * @return {?WebInspector.LayerView.Selection} |
| 637 */ |
| 638 _selectionFromEventPoint(event) { |
| 639 if (!this._layerTree) |
| 640 return null; |
| 641 var closestIntersectionPoint = Infinity; |
| 642 var closestObject = null; |
| 643 var projectionMatrix = new WebKitCSSMatrix().scale(1, -1, -1).translate(-1,
-1, 0).multiply(this._projectionMatrix); |
| 644 var x0 = (event.clientX - this._canvasElement.totalOffsetLeft()) * window.de
vicePixelRatio; |
| 645 var y0 = -(event.clientY - this._canvasElement.totalOffsetTop()) * window.de
vicePixelRatio; |
| 646 |
| 647 /** |
| 648 * @param {!WebInspector.Layers3DView.Rectangle} rect |
| 649 */ |
| 650 function checkIntersection(rect) { |
| 651 if (!rect.relatedObject) |
| 652 return; |
| 653 var t = rect.intersectWithLine(projectionMatrix, x0, y0); |
| 654 if (t < closestIntersectionPoint) { |
| 655 closestIntersectionPoint = t; |
| 656 closestObject = rect.relatedObject; |
| 657 } |
| 658 } |
| 659 |
| 660 this._rects.forEach(checkIntersection); |
| 661 return closestObject; |
| 662 } |
| 663 |
| 664 /** |
| 665 * @param {string} caption |
| 666 * @param {string} name |
| 667 * @param {boolean} value |
| 668 * @param {!WebInspector.Toolbar} toolbar |
| 669 * @return {!WebInspector.Setting} |
| 670 */ |
| 671 _createVisibilitySetting(caption, name, value, toolbar) { |
| 672 var checkbox = new WebInspector.ToolbarCheckbox(WebInspector.UIString(captio
n)); |
| 673 toolbar.appendToolbarItem(checkbox); |
| 674 var setting = WebInspector.settings.createSetting(name, value); |
| 675 WebInspector.SettingsUI.bindCheckbox(checkbox.inputElement, setting); |
| 676 setting.addChangeListener(this._update, this); |
| 677 return setting; |
| 678 } |
| 679 |
| 680 _initToolbar() { |
| 681 this._panelToolbar = this._transformController.toolbar(); |
| 682 this.contentElement.appendChild(this._panelToolbar.element); |
| 683 this._showSlowScrollRectsSetting = |
| 684 this._createVisibilitySetting('Slow scroll rects', 'frameViewerShowSlowS
crollRects', true, this._panelToolbar); |
| 685 this._showPaintsSetting = |
| 686 this._createVisibilitySetting('Paints', 'frameViewerShowPaints', true, t
his._panelToolbar); |
| 687 this._showPaintsSetting.addChangeListener(this._updatePaints, this); |
| 688 WebInspector.moduleSetting('frameViewerHideChromeWindow').addChangeListener(
this._update, this); |
| 689 } |
| 690 |
| 691 /** |
| 692 * @param {!Event} event |
| 693 */ |
| 694 _onContextMenu(event) { |
| 695 var contextMenu = new WebInspector.ContextMenu(event); |
| 696 contextMenu.appendItem( |
| 697 WebInspector.UIString('Reset View'), this._transformController.resetAndN
otify.bind(this._transformController), |
| 698 false); |
| 699 var selection = this._selectionFromEventPoint(event); |
| 700 if (selection && selection.type() === WebInspector.LayerView.Selection.Type.
Snapshot) |
| 701 contextMenu.appendItem( |
| 702 WebInspector.UIString('Show Paint Profiler'), |
| 703 this.dispatchEventToListeners.bind( |
| 704 this, WebInspector.Layers3DView.Events.PaintProfilerRequested, sel
ection.snapshot()), |
| 705 false); |
| 706 this._layerViewHost.showContextMenu(contextMenu, selection); |
| 707 } |
| 708 |
| 709 /** |
| 710 * @param {!Event} event |
| 711 */ |
| 712 _onMouseMove(event) { |
| 713 if (event.which) |
| 714 return; |
| 715 this._layerViewHost.hoverObject(this._selectionFromEventPoint(event)); |
| 716 } |
| 717 |
| 718 /** |
| 719 * @param {!Event} event |
| 720 */ |
| 721 _onMouseDown(event) { |
| 722 this._mouseDownX = event.clientX; |
| 723 this._mouseDownY = event.clientY; |
| 724 } |
| 725 |
| 726 /** |
| 727 * @param {!Event} event |
| 728 */ |
| 729 _onMouseUp(event) { |
| 730 const maxDistanceInPixels = 6; |
| 731 if (this._mouseDownX && Math.abs(event.clientX - this._mouseDownX) < maxDist
anceInPixels && |
| 732 Math.abs(event.clientY - this._mouseDownY) < maxDistanceInPixels) |
| 733 this._layerViewHost.selectObject(this._selectionFromEventPoint(event)); |
| 734 delete this._mouseDownX; |
| 735 delete this._mouseDownY; |
| 736 } |
| 737 |
| 738 /** |
| 739 * @param {!Event} event |
| 740 */ |
| 741 _onDoubleClick(event) { |
| 742 var selection = this._selectionFromEventPoint(event); |
| 743 if (selection && (selection.type() === WebInspector.LayerView.Selection.Type
.Snapshot || selection.layer())) |
| 744 this.dispatchEventToListeners(WebInspector.Layers3DView.Events.PaintProfil
erRequested, selection); |
| 745 event.stopPropagation(); |
| 746 } |
| 747 |
| 748 _updatePaints() { |
| 749 if (this._showPaints()) { |
| 750 this._textureManager.setLayerTree(this._layerTree); |
| 751 this._textureManager.forceUpdate(); |
| 752 } else { |
| 753 this._textureManager.reset(); |
| 754 } |
| 755 this._update(); |
| 756 } |
| 757 |
| 758 /** |
| 759 * @return {boolean} |
| 760 */ |
| 761 _showPaints() { |
| 762 return this._showPaintsSetting.get(); |
| 763 } |
72 }; | 764 }; |
73 | 765 |
74 /** @typedef {{borderColor: !Array<number>, borderWidth: number}} */ | 766 /** @typedef {{borderColor: !Array<number>, borderWidth: number}} */ |
75 WebInspector.Layers3DView.LayerStyle; | 767 WebInspector.Layers3DView.LayerStyle; |
76 | 768 |
77 /** | 769 /** |
78 * @enum {string} | 770 * @enum {string} |
79 */ | 771 */ |
80 WebInspector.Layers3DView.OutlineType = { | 772 WebInspector.Layers3DView.OutlineType = { |
81 Hovered: "hovered", | 773 Hovered: 'hovered', |
82 Selected: "selected" | 774 Selected: 'selected' |
83 }; | 775 }; |
84 | 776 |
85 /** | 777 /** |
86 * @enum {string} | 778 * @enum {string} |
87 */ | 779 */ |
88 /** @enum {symbol} */ | 780 /** @enum {symbol} */ |
89 WebInspector.Layers3DView.Events = { | 781 WebInspector.Layers3DView.Events = { |
90 PaintProfilerRequested: Symbol("PaintProfilerRequested"), | 782 PaintProfilerRequested: Symbol('PaintProfilerRequested'), |
91 ScaleChanged: Symbol("ScaleChanged") | 783 ScaleChanged: Symbol('ScaleChanged') |
92 }; | 784 }; |
93 | 785 |
94 /** | 786 /** |
95 * @enum {number} | 787 * @enum {number} |
96 */ | 788 */ |
97 WebInspector.Layers3DView.ChromeTexture = { | 789 WebInspector.Layers3DView.ChromeTexture = { |
98 Left: 0, | 790 Left: 0, |
99 Middle: 1, | 791 Middle: 1, |
100 Right: 2 | 792 Right: 2 |
101 }; | 793 }; |
102 | 794 |
103 /** | 795 /** |
104 * @enum {string} | 796 * @enum {string} |
105 */ | 797 */ |
106 WebInspector.Layers3DView.ScrollRectTitles = { | 798 WebInspector.Layers3DView.ScrollRectTitles = { |
107 RepaintsOnScroll: WebInspector.UIString("repaints on scroll"), | 799 RepaintsOnScroll: WebInspector.UIString('repaints on scroll'), |
108 TouchEventHandler: WebInspector.UIString("touch event listener"), | 800 TouchEventHandler: WebInspector.UIString('touch event listener'), |
109 WheelEventHandler: WebInspector.UIString("mousewheel event listener") | 801 WheelEventHandler: WebInspector.UIString('mousewheel event listener') |
110 }; | 802 }; |
111 | 803 |
112 WebInspector.Layers3DView.FragmentShader = "" + | 804 WebInspector.Layers3DView.FragmentShader = '' + |
113 "precision mediump float;\n" + | 805 'precision mediump float;\n' + |
114 "varying vec4 vColor;\n" + | 806 'varying vec4 vColor;\n' + |
115 "varying vec2 vTextureCoord;\n" + | 807 'varying vec2 vTextureCoord;\n' + |
116 "uniform sampler2D uSampler;\n" + | 808 'uniform sampler2D uSampler;\n' + |
117 "void main(void)\n" + | 809 'void main(void)\n' + |
118 "{\n" + | 810 '{\n' + |
119 " gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.
t)) * vColor;\n" + | 811 ' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.
t)) * vColor;\n' + |
120 "}"; | 812 '}'; |
121 | 813 |
122 WebInspector.Layers3DView.VertexShader = "" + | 814 WebInspector.Layers3DView.VertexShader = '' + |
123 "attribute vec3 aVertexPosition;\n" + | 815 'attribute vec3 aVertexPosition;\n' + |
124 "attribute vec2 aTextureCoord;\n" + | 816 'attribute vec2 aTextureCoord;\n' + |
125 "attribute vec4 aVertexColor;\n" + | 817 'attribute vec4 aVertexColor;\n' + |
126 "uniform mat4 uPMatrix;\n" + | 818 'uniform mat4 uPMatrix;\n' + |
127 "varying vec2 vTextureCoord;\n" + | 819 'varying vec2 vTextureCoord;\n' + |
128 "varying vec4 vColor;\n" + | 820 'varying vec4 vColor;\n' + |
129 "void main(void)\n" + | 821 'void main(void)\n' + |
130 "{\n" + | 822 '{\n' + |
131 "gl_Position = uPMatrix * vec4(aVertexPosition, 1.0);\n" + | 823 'gl_Position = uPMatrix * vec4(aVertexPosition, 1.0);\n' + |
132 "vColor = aVertexColor;\n" + | 824 'vColor = aVertexColor;\n' + |
133 "vTextureCoord = aTextureCoord;\n" + | 825 'vTextureCoord = aTextureCoord;\n' + |
134 "}"; | 826 '}'; |
135 | 827 |
136 WebInspector.Layers3DView.HoveredBorderColor = [0, 0, 255, 1]; | 828 WebInspector.Layers3DView.HoveredBorderColor = [0, 0, 255, 1]; |
137 WebInspector.Layers3DView.SelectedBorderColor = [0, 255, 0, 1]; | 829 WebInspector.Layers3DView.SelectedBorderColor = [0, 255, 0, 1]; |
138 WebInspector.Layers3DView.BorderColor = [0, 0, 0, 1]; | 830 WebInspector.Layers3DView.BorderColor = [0, 0, 0, 1]; |
139 WebInspector.Layers3DView.ViewportBorderColor = [160, 160, 160, 1]; | 831 WebInspector.Layers3DView.ViewportBorderColor = [160, 160, 160, 1]; |
140 WebInspector.Layers3DView.ScrollRectBackgroundColor = [178, 100, 100, 0.6]; | 832 WebInspector.Layers3DView.ScrollRectBackgroundColor = [178, 100, 100, 0.6]; |
141 WebInspector.Layers3DView.HoveredImageMaskColor = [200, 200, 255, 1]; | 833 WebInspector.Layers3DView.HoveredImageMaskColor = [200, 200, 255, 1]; |
142 WebInspector.Layers3DView.BorderWidth = 1; | 834 WebInspector.Layers3DView.BorderWidth = 1; |
143 WebInspector.Layers3DView.SelectedBorderWidth = 2; | 835 WebInspector.Layers3DView.SelectedBorderWidth = 2; |
144 WebInspector.Layers3DView.ViewportBorderWidth = 3; | 836 WebInspector.Layers3DView.ViewportBorderWidth = 3; |
145 | 837 |
146 WebInspector.Layers3DView.LayerSpacing = 20; | 838 WebInspector.Layers3DView.LayerSpacing = 20; |
147 WebInspector.Layers3DView.ScrollRectSpacing = 4; | 839 WebInspector.Layers3DView.ScrollRectSpacing = 4; |
148 | 840 |
149 WebInspector.Layers3DView.prototype = { | |
150 /** | |
151 * @param {?WebInspector.LayerTreeBase} layerTree | |
152 * @override | |
153 */ | |
154 setLayerTree: function(layerTree) | |
155 { | |
156 this._layerTree = layerTree; | |
157 this._layerTexture = null; | |
158 delete this._oldTextureScale; | |
159 if (this._showPaints()) | |
160 this._textureManager.setLayerTree(layerTree); | |
161 this._update(); | |
162 }, | |
163 | |
164 /** | |
165 * @param {!WebInspector.Layer} layer | |
166 * @param {string=} imageURL | |
167 */ | |
168 showImageForLayer: function(layer, imageURL) | |
169 { | |
170 if (!imageURL) { | |
171 this._layerTexture = null; | |
172 this._update(); | |
173 return; | |
174 } | |
175 WebInspector.loadImage(imageURL).then(image => { | |
176 var texture = image && WebInspector.LayerTextureManager._createTextu
reForImage(this._gl, image); | |
177 this._layerTexture = texture ? {layer: layer, texture: texture} : nu
ll; | |
178 this._update(); | |
179 }); | |
180 }, | |
181 | |
182 onResize: function() | |
183 { | |
184 this._resizeCanvas(); | |
185 this._update(); | |
186 }, | |
187 | |
188 /** | |
189 * @override | |
190 */ | |
191 willHide: function() | |
192 { | |
193 this._textureManager.suspend(); | |
194 }, | |
195 | |
196 /** | |
197 * @override | |
198 */ | |
199 wasShown: function() | |
200 { | |
201 this._textureManager.resume(); | |
202 if (!this._needsUpdate) | |
203 return; | |
204 this._resizeCanvas(); | |
205 this._update(); | |
206 }, | |
207 | |
208 /** | |
209 * @param {!WebInspector.Layer} layer | |
210 */ | |
211 updateLayerSnapshot: function(layer) | |
212 { | |
213 this._textureManager.layerNeedsUpdate(layer); | |
214 }, | |
215 | |
216 /** | |
217 * @param {!WebInspector.Layers3DView.OutlineType} type | |
218 * @param {?WebInspector.LayerView.Selection} selection | |
219 */ | |
220 _setOutline: function(type, selection) | |
221 { | |
222 this._lastSelection[type] = selection; | |
223 this._update(); | |
224 }, | |
225 | |
226 /** | |
227 * @param {?WebInspector.LayerView.Selection} selection | |
228 * @override | |
229 */ | |
230 hoverObject: function(selection) | |
231 { | |
232 this._setOutline(WebInspector.Layers3DView.OutlineType.Hovered, selectio
n); | |
233 }, | |
234 | |
235 /** | |
236 * @param {?WebInspector.LayerView.Selection} selection | |
237 * @override | |
238 */ | |
239 selectObject: function(selection) | |
240 { | |
241 this._setOutline(WebInspector.Layers3DView.OutlineType.Hovered, null); | |
242 this._setOutline(WebInspector.Layers3DView.OutlineType.Selected, selecti
on); | |
243 }, | |
244 | |
245 /** | |
246 * @param {!WebInspector.LayerView.Selection} selection | |
247 * @return {!Promise<?WebInspector.SnapshotWithRect>} | |
248 */ | |
249 snapshotForSelection: function(selection) | |
250 { | |
251 if (selection.type() === WebInspector.LayerView.Selection.Type.Snapshot)
{ | |
252 var snapshotWithRect = /** @type {!WebInspector.LayerView.SnapshotSe
lection} */ (selection).snapshot(); | |
253 snapshotWithRect.snapshot.addReference(); | |
254 return /** @type {!Promise<?WebInspector.SnapshotWithRect>} */ (Prom
ise.resolve(snapshotWithRect)); | |
255 } | |
256 if (selection.layer()) { | |
257 var promise = selection.layer().snapshots()[0]; | |
258 if (promise) | |
259 return promise; | |
260 } | |
261 return /** @type {!Promise<?WebInspector.SnapshotWithRect>} */ (Promise.
resolve(null)); | |
262 }, | |
263 | |
264 /** | |
265 * @param {!Element} canvas | |
266 * @return {?WebGLRenderingContext} | |
267 */ | |
268 _initGL: function(canvas) | |
269 { | |
270 var gl = canvas.getContext("webgl"); | |
271 if (!gl) | |
272 return null; | |
273 gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); | |
274 gl.enable(gl.BLEND); | |
275 gl.clearColor(0.0, 0.0, 0.0, 0.0); | |
276 gl.enable(gl.DEPTH_TEST); | |
277 return gl; | |
278 }, | |
279 | |
280 /** | |
281 * @param {!Object} type | |
282 * @param {string} script | |
283 */ | |
284 _createShader: function(type, script) | |
285 { | |
286 var shader = this._gl.createShader(type); | |
287 this._gl.shaderSource(shader, script); | |
288 this._gl.compileShader(shader); | |
289 this._gl.attachShader(this._shaderProgram, shader); | |
290 }, | |
291 | |
292 _initShaders: function() | |
293 { | |
294 this._shaderProgram = this._gl.createProgram(); | |
295 this._createShader(this._gl.FRAGMENT_SHADER, WebInspector.Layers3DView.F
ragmentShader); | |
296 this._createShader(this._gl.VERTEX_SHADER, WebInspector.Layers3DView.Ver
texShader); | |
297 this._gl.linkProgram(this._shaderProgram); | |
298 this._gl.useProgram(this._shaderProgram); | |
299 | |
300 this._shaderProgram.vertexPositionAttribute = this._gl.getAttribLocation
(this._shaderProgram, "aVertexPosition"); | |
301 this._gl.enableVertexAttribArray(this._shaderProgram.vertexPositionAttri
bute); | |
302 this._shaderProgram.vertexColorAttribute = this._gl.getAttribLocation(th
is._shaderProgram, "aVertexColor"); | |
303 this._gl.enableVertexAttribArray(this._shaderProgram.vertexColorAttribut
e); | |
304 this._shaderProgram.textureCoordAttribute = this._gl.getAttribLocation(t
his._shaderProgram, "aTextureCoord"); | |
305 this._gl.enableVertexAttribArray(this._shaderProgram.textureCoordAttribu
te); | |
306 | |
307 this._shaderProgram.pMatrixUniform = this._gl.getUniformLocation(this._s
haderProgram, "uPMatrix"); | |
308 this._shaderProgram.samplerUniform = this._gl.getUniformLocation(this._s
haderProgram, "uSampler"); | |
309 }, | |
310 | |
311 _resizeCanvas: function() | |
312 { | |
313 this._canvasElement.width = this._canvasElement.offsetWidth * window.dev
icePixelRatio; | |
314 this._canvasElement.height = this._canvasElement.offsetHeight * window.d
evicePixelRatio; | |
315 }, | |
316 | |
317 _updateTransformAndConstraints: function() | |
318 { | |
319 var paddingFraction = 0.1; | |
320 var viewport = this._layerTree.viewportSize(); | |
321 var root = this._layerTree.root(); | |
322 var baseWidth = viewport ? viewport.width : this._dimensionsForAutoscale
.width; | |
323 var baseHeight = viewport ? viewport.height : this._dimensionsForAutosca
le.height; | |
324 var canvasWidth = this._canvasElement.width; | |
325 var canvasHeight = this._canvasElement.height; | |
326 var paddingX = canvasWidth * paddingFraction; | |
327 var paddingY = canvasHeight * paddingFraction; | |
328 var scaleX = (canvasWidth - 2 * paddingX) / baseWidth; | |
329 var scaleY = (canvasHeight - 2 * paddingY) / baseHeight; | |
330 var viewScale = Math.min(scaleX, scaleY); | |
331 var minScaleConstraint = Math.min(baseWidth / this._dimensionsForAutosca
le.width, baseHeight / this._dimensionsForAutoscale.width) / 2; | |
332 this._transformController.setScaleConstraints(minScaleConstraint, 10 / v
iewScale); // 1/viewScale is 1:1 in terms of pixels, so allow zooming to 10x of
native size | |
333 var scale = this._transformController.scale(); | |
334 var rotateX = this._transformController.rotateX(); | |
335 var rotateY = this._transformController.rotateY(); | |
336 | |
337 this._scale = scale * viewScale; | |
338 var textureScale = Number.constrain(this._scale, 0.1, 1); | |
339 if (textureScale !== this._oldTextureScale) { | |
340 this._oldTextureScale = textureScale; | |
341 this._textureManager.setScale(textureScale); | |
342 this.dispatchEventToListeners(WebInspector.Layers3DView.Events.Scale
Changed, textureScale); | |
343 } | |
344 var scaleAndRotationMatrix = new WebKitCSSMatrix().scale(scale, scale, s
cale).translate(canvasWidth / 2, canvasHeight / 2, 0) | |
345 .rotate(rotateX, rotateY, 0).scale(viewScale, viewScale, viewScale).
translate(-baseWidth / 2, -baseHeight / 2, 0); | |
346 | |
347 var bounds; | |
348 for (var i = 0; i < this._rects.length; ++i) | |
349 bounds = WebInspector.Geometry.boundsForTransformedPoints(scaleAndRo
tationMatrix, this._rects[i].vertices, bounds); | |
350 | |
351 this._transformController.clampOffsets((paddingX - bounds.maxX) / window
.devicePixelRatio, (canvasWidth - paddingX - bounds.minX) / window.devicePixelRa
tio, | |
352 (paddingY - bounds.maxY) / window
.devicePixelRatio, (canvasHeight - paddingY - bounds.minY) / window.devicePixelR
atio); | |
353 var offsetX = this._transformController.offsetX() * window.devicePixelRa
tio; | |
354 var offsetY = this._transformController.offsetY() * window.devicePixelRa
tio; | |
355 // Multiply to translation matrix on the right rather than translate (wh
ich would implicitly multiply on the left). | |
356 this._projectionMatrix = new WebKitCSSMatrix().translate(offsetX, offset
Y, 0).multiply(scaleAndRotationMatrix); | |
357 | |
358 var glProjectionMatrix = new WebKitCSSMatrix().scale(1, -1, -1).translat
e(-1, -1, 0) | |
359 .scale(2 / this._canvasElement.width, 2 / this._canvasElement.height
, 1 / 1000000).multiply(this._projectionMatrix); | |
360 this._gl.uniformMatrix4fv(this._shaderProgram.pMatrixUniform, false, thi
s._arrayFromMatrix(glProjectionMatrix)); | |
361 }, | |
362 | |
363 /** | |
364 * @param {!CSSMatrix} m | |
365 * @return {!Float32Array} | |
366 */ | |
367 _arrayFromMatrix: function(m) | |
368 { | |
369 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]); | |
370 }, | |
371 | |
372 _initWhiteTexture: function() | |
373 { | |
374 this._whiteTexture = this._gl.createTexture(); | |
375 this._gl.bindTexture(this._gl.TEXTURE_2D, this._whiteTexture); | |
376 var whitePixel = new Uint8Array([255, 255, 255, 255]); | |
377 this._gl.texImage2D(this._gl.TEXTURE_2D, 0, this._gl.RGBA, 1, 1, 0, this
._gl.RGBA, this._gl.UNSIGNED_BYTE, whitePixel); | |
378 }, | |
379 | |
380 _initChromeTextures: function() | |
381 { | |
382 /** | |
383 * @this {WebInspector.Layers3DView} | |
384 * @param {!WebInspector.Layers3DView.ChromeTexture} index | |
385 * @param {string} url | |
386 */ | |
387 function loadChromeTexture(index, url) | |
388 { | |
389 WebInspector.loadImage(url).then(image => { | |
390 this._chromeTextures[index] = image && WebInspector.LayerTexture
Manager._createTextureForImage(this._gl, image) || undefined; | |
391 }); | |
392 } | |
393 loadChromeTexture.call(this, WebInspector.Layers3DView.ChromeTexture.Lef
t, "Images/chromeLeft.png"); | |
394 loadChromeTexture.call(this, WebInspector.Layers3DView.ChromeTexture.Mid
dle, "Images/chromeMiddle.png"); | |
395 loadChromeTexture.call(this, WebInspector.Layers3DView.ChromeTexture.Rig
ht, "Images/chromeRight.png"); | |
396 }, | |
397 | |
398 /** | |
399 * @return {?WebGLRenderingContext} | |
400 */ | |
401 _initGLIfNecessary: function() | |
402 { | |
403 if (this._gl) | |
404 return this._gl; | |
405 this._gl = this._initGL(this._canvasElement); | |
406 if (!this._gl) | |
407 return null; | |
408 this._initShaders(); | |
409 this._initWhiteTexture(); | |
410 this._initChromeTextures(); | |
411 this._textureManager.setContext(this._gl); | |
412 return this._gl; | |
413 }, | |
414 | |
415 _calculateDepthsAndVisibility: function() | |
416 { | |
417 this._depthByLayerId = {}; | |
418 var depth = 0; | |
419 var showInternalLayers = this._layerViewHost.showInternalLayersSetting()
.get(); | |
420 var root = showInternalLayers ? this._layerTree.root() : (this._layerTre
e.contentRoot() || this._layerTree.root()); | |
421 var queue = [root]; | |
422 this._depthByLayerId[root.id()] = 0; | |
423 /** @type {!Set<!WebInspector.Layer>} */ | |
424 this._visibleLayers = new Set(); | |
425 while (queue.length > 0) { | |
426 var layer = queue.shift(); | |
427 if (showInternalLayers || layer.drawsContent()) | |
428 this._visibleLayers.add(layer); | |
429 var children = layer.children(); | |
430 for (var i = 0; i < children.length; ++i) { | |
431 this._depthByLayerId[children[i].id()] = ++depth; | |
432 queue.push(children[i]); | |
433 } | |
434 } | |
435 this._maxDepth = depth; | |
436 }, | |
437 | |
438 /** | |
439 * @param {!WebInspector.Layer} layer | |
440 * @return {number} | |
441 */ | |
442 _depthForLayer: function(layer) | |
443 { | |
444 return this._depthByLayerId[layer.id()] * WebInspector.Layers3DView.Laye
rSpacing; | |
445 }, | |
446 | |
447 /** | |
448 * @param {!WebInspector.Layer} layer | |
449 * @param {number} index | |
450 * @return {number} | |
451 */ | |
452 _calculateScrollRectDepth: function(layer, index) | |
453 { | |
454 return this._depthForLayer(layer) + index * WebInspector.Layers3DView.Sc
rollRectSpacing + 1; | |
455 }, | |
456 | |
457 /** | |
458 * @param {!WebInspector.Layer} layer | |
459 */ | |
460 _updateDimensionsForAutoscale: function(layer) | |
461 { | |
462 // We don't want to be precise, but rather pick something least affected
by | |
463 // animationtransforms, so that we don't change scale too often. So let'
s | |
464 // disregard transforms, scrolling and relative layer positioning and ch
oose | |
465 // the largest dimensions of all layers. | |
466 this._dimensionsForAutoscale.width = Math.max(layer.width(), this._dimen
sionsForAutoscale.width); | |
467 this._dimensionsForAutoscale.height = Math.max(layer.height(), this._dim
ensionsForAutoscale.height); | |
468 }, | |
469 | |
470 /** | |
471 * @param {!WebInspector.Layer} layer | |
472 */ | |
473 _calculateLayerRect: function(layer) | |
474 { | |
475 if (!this._visibleLayers.has(layer)) | |
476 return; | |
477 var selection = new WebInspector.LayerView.LayerSelection(layer); | |
478 var rect = new WebInspector.Layers3DView.Rectangle(selection); | |
479 rect.setVertices(layer.quad(), this._depthForLayer(layer)); | |
480 this._appendRect(rect); | |
481 this._updateDimensionsForAutoscale(layer); | |
482 }, | |
483 | |
484 /** | |
485 * @param {!WebInspector.Layers3DView.Rectangle} rect | |
486 */ | |
487 _appendRect: function(rect) | |
488 { | |
489 var selection = rect.relatedObject; | |
490 var isSelected = WebInspector.LayerView.Selection.isEqual(this._lastSele
ction[WebInspector.Layers3DView.OutlineType.Selected], selection); | |
491 var isHovered = WebInspector.LayerView.Selection.isEqual(this._lastSelec
tion[WebInspector.Layers3DView.OutlineType.Hovered], selection); | |
492 if (isSelected) { | |
493 rect.borderColor = WebInspector.Layers3DView.SelectedBorderColor; | |
494 } else if (isHovered) { | |
495 rect.borderColor = WebInspector.Layers3DView.HoveredBorderColor; | |
496 var fillColor = rect.fillColor || [255, 255, 255, 1]; | |
497 var maskColor = WebInspector.Layers3DView.HoveredImageMaskColor; | |
498 rect.fillColor = [fillColor[0] * maskColor[0] / 255, fillColor[1] *
maskColor[1] / 255, fillColor[2] * maskColor[2] / 255, fillColor[3] * maskColor[
3]]; | |
499 } else { | |
500 rect.borderColor = WebInspector.Layers3DView.BorderColor; | |
501 } | |
502 rect.lineWidth = isSelected ? WebInspector.Layers3DView.SelectedBorderWi
dth : WebInspector.Layers3DView.BorderWidth; | |
503 this._rects.push(rect); | |
504 }, | |
505 | |
506 /** | |
507 * @param {!WebInspector.Layer} layer | |
508 */ | |
509 _calculateLayerScrollRects: function(layer) | |
510 { | |
511 var scrollRects = layer.scrollRects(); | |
512 for (var i = 0; i < scrollRects.length; ++i) { | |
513 var selection = new WebInspector.LayerView.ScrollRectSelection(layer
, i); | |
514 var rect = new WebInspector.Layers3DView.Rectangle(selection); | |
515 rect.calculateVerticesFromRect(layer, scrollRects[i].rect, this._cal
culateScrollRectDepth(layer, i)); | |
516 rect.fillColor = WebInspector.Layers3DView.ScrollRectBackgroundColor
; | |
517 this._appendRect(rect); | |
518 } | |
519 }, | |
520 | |
521 /** | |
522 * @param {!WebInspector.Layer} layer | |
523 */ | |
524 _calculateLayerTileRects: function(layer) | |
525 { | |
526 var tiles = this._textureManager.tilesForLayer(layer); | |
527 for (var i = 0; i < tiles.length; ++i) { | |
528 var tile = tiles[i]; | |
529 if (!tile.texture) | |
530 continue; | |
531 var selection = new WebInspector.LayerView.SnapshotSelection(layer,
{rect: tile.rect, snapshot: tile.snapshot}); | |
532 var rect = new WebInspector.Layers3DView.Rectangle(selection); | |
533 rect.calculateVerticesFromRect(layer, tile.rect, this._depthForLayer
(layer) + 1); | |
534 rect.texture = tile.texture; | |
535 this._appendRect(rect); | |
536 } | |
537 }, | |
538 | |
539 _calculateRects: function() | |
540 { | |
541 this._rects = []; | |
542 this._dimensionsForAutoscale = { width: 0, height: 0 }; | |
543 this._layerTree.forEachLayer(this._calculateLayerRect.bind(this)); | |
544 | |
545 if (this._showSlowScrollRectsSetting.get()) | |
546 this._layerTree.forEachLayer(this._calculateLayerScrollRects.bind(th
is)); | |
547 | |
548 if (this._layerTexture && this._visibleLayers.has(this._layerTexture.lay
er)) { | |
549 var layer = this._layerTexture.layer; | |
550 var selection = new WebInspector.LayerView.LayerSelection(layer); | |
551 var rect = new WebInspector.Layers3DView.Rectangle(selection); | |
552 rect.setVertices(layer.quad(), this._depthForLayer(layer)); | |
553 rect.texture = this._layerTexture.texture; | |
554 this._appendRect(rect); | |
555 } else if (this._showPaints()) { | |
556 this._layerTree.forEachLayer(this._calculateLayerTileRects.bind(this
)); | |
557 } | |
558 }, | |
559 | |
560 /** | |
561 * @param {!Array.<number>} color | |
562 * @return {!Array.<number>} | |
563 */ | |
564 _makeColorsArray: function(color) | |
565 { | |
566 var colors = []; | |
567 var normalizedColor = [color[0] / 255, color[1] / 255, color[2] / 255, c
olor[3]]; | |
568 for (var i = 0; i < 4; i++) | |
569 colors = colors.concat(normalizedColor); | |
570 return colors; | |
571 }, | |
572 | |
573 /** | |
574 * @param {!Object} attribute | |
575 * @param {!Array.<number>} array | |
576 * @param {number} length | |
577 */ | |
578 _setVertexAttribute: function(attribute, array, length) | |
579 { | |
580 var gl = this._gl; | |
581 var buffer = gl.createBuffer(); | |
582 gl.bindBuffer(gl.ARRAY_BUFFER, buffer); | |
583 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(array), gl.STATIC_DRAW); | |
584 gl.vertexAttribPointer(attribute, length, gl.FLOAT, false, 0, 0); | |
585 }, | |
586 | |
587 /** | |
588 * @param {!Array.<number>} vertices | |
589 * @param {number} mode | |
590 * @param {!Array.<number>=} color | |
591 * @param {!Object=} texture | |
592 */ | |
593 _drawRectangle: function(vertices, mode, color, texture) | |
594 { | |
595 var gl = this._gl; | |
596 var white = [255, 255, 255, 1]; | |
597 color = color || white; | |
598 this._setVertexAttribute(this._shaderProgram.vertexPositionAttribute, ve
rtices, 3); | |
599 this._setVertexAttribute(this._shaderProgram.textureCoordAttribute, [0,
1, 1, 1, 1, 0, 0, 0], 2); | |
600 this._setVertexAttribute(this._shaderProgram.vertexColorAttribute, this.
_makeColorsArray(color), color.length); | |
601 | |
602 if (texture) { | |
603 gl.activeTexture(gl.TEXTURE0); | |
604 gl.bindTexture(gl.TEXTURE_2D, texture); | |
605 gl.uniform1i(this._shaderProgram.samplerUniform, 0); | |
606 } else { | |
607 gl.bindTexture(gl.TEXTURE_2D, this._whiteTexture); | |
608 } | |
609 | |
610 var numberOfVertices = vertices.length / 3; | |
611 gl.drawArrays(mode, 0, numberOfVertices); | |
612 }, | |
613 | |
614 /** | |
615 * @param {!Array.<number>} vertices | |
616 * @param {!WebGLTexture} texture | |
617 * @param {!Array.<number>=} color | |
618 */ | |
619 _drawTexture: function(vertices, texture, color) | |
620 { | |
621 this._drawRectangle(vertices, this._gl.TRIANGLE_FAN, color, texture); | |
622 }, | |
623 | |
624 _drawViewportAndChrome: function() | |
625 { | |
626 var viewport = this._layerTree.viewportSize(); | |
627 if (!viewport) | |
628 return; | |
629 | |
630 var drawChrome = !WebInspector.moduleSetting("frameViewerHideChromeWindo
w").get() && this._chromeTextures.length >= 3 && this._chromeTextures.indexOf(un
defined) < 0; | |
631 var z = (this._maxDepth + 1) * WebInspector.Layers3DView.LayerSpacing; | |
632 var borderWidth = Math.ceil(WebInspector.Layers3DView.ViewportBorderWidt
h * this._scale); | |
633 var vertices = [viewport.width, 0, z, viewport.width, viewport.height, z
, 0, viewport.height, z, 0, 0, z]; | |
634 this._gl.lineWidth(borderWidth); | |
635 this._drawRectangle(vertices, drawChrome ? this._gl.LINE_STRIP : this._g
l.LINE_LOOP, WebInspector.Layers3DView.ViewportBorderColor); | |
636 | |
637 if (!drawChrome) | |
638 return; | |
639 | |
640 var borderAdjustment = WebInspector.Layers3DView.ViewportBorderWidth / 2
; | |
641 var viewportWidth = this._layerTree.viewportSize().width + 2 * borderAdj
ustment; | |
642 var chromeHeight = this._chromeTextures[0].image.naturalHeight; | |
643 var middleFragmentWidth = viewportWidth - this._chromeTextures[0].image.
naturalWidth - this._chromeTextures[2].image.naturalWidth; | |
644 var x = -borderAdjustment; | |
645 var y = -chromeHeight; | |
646 for (var i = 0; i < this._chromeTextures.length; ++i) { | |
647 var width = i === WebInspector.Layers3DView.ChromeTexture.Middle ? m
iddleFragmentWidth : this._chromeTextures[i].image.naturalWidth; | |
648 if (width < 0 || x + width > viewportWidth) | |
649 break; | |
650 vertices = [x, y, z, x + width, y, z, x + width, y + chromeHeight, z
, x, y + chromeHeight, z]; | |
651 this._drawTexture(vertices, /** @type {!WebGLTexture} */ (this._chro
meTextures[i])); | |
652 x += width; | |
653 } | |
654 }, | |
655 | |
656 /** | |
657 * @param {!WebInspector.Layers3DView.Rectangle} rect | |
658 */ | |
659 _drawViewRect: function(rect) | |
660 { | |
661 var vertices = rect.vertices; | |
662 if (rect.texture) | |
663 this._drawTexture(vertices, rect.texture, rect.fillColor || undefine
d); | |
664 else if (rect.fillColor) | |
665 this._drawRectangle(vertices, this._gl.TRIANGLE_FAN, rect.fillColor)
; | |
666 this._gl.lineWidth(rect.lineWidth); | |
667 if (rect.borderColor) | |
668 this._drawRectangle(vertices, this._gl.LINE_LOOP, rect.borderColor); | |
669 }, | |
670 | |
671 _update: function() | |
672 { | |
673 if (!this.isShowing()) { | |
674 this._needsUpdate = true; | |
675 return; | |
676 } | |
677 if (!this._layerTree || !this._layerTree.root()) { | |
678 this._failBanner.show(this.contentElement); | |
679 return; | |
680 } | |
681 var gl = this._initGLIfNecessary(); | |
682 if (!gl) { | |
683 this._failBanner.element.removeChildren(); | |
684 this._failBanner.element.appendChild(this._webglDisabledBanner()); | |
685 this._failBanner.show(this.contentElement); | |
686 return; | |
687 } | |
688 this._failBanner.detach(); | |
689 this._gl.viewportWidth = this._canvasElement.width; | |
690 this._gl.viewportHeight = this._canvasElement.height; | |
691 | |
692 this._calculateDepthsAndVisibility(); | |
693 this._calculateRects(); | |
694 this._updateTransformAndConstraints(); | |
695 | |
696 gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); | |
697 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); | |
698 | |
699 this._rects.forEach(this._drawViewRect.bind(this)); | |
700 this._drawViewportAndChrome(); | |
701 }, | |
702 | |
703 /** | |
704 * @return {!Node} | |
705 */ | |
706 _webglDisabledBanner: function() | |
707 { | |
708 var fragment = this.contentElement.ownerDocument.createDocumentFragment(
); | |
709 fragment.createChild("div").textContent = WebInspector.UIString("Can't d
isplay layers,"); | |
710 fragment.createChild("div").textContent = WebInspector.UIString("WebGL s
upport is disabled in your browser."); | |
711 fragment.appendChild(WebInspector.formatLocalized("Check %s for possible
reasons.", [WebInspector.linkifyURLAsNode("about:gpu", undefined, undefined, tr
ue)])); | |
712 return fragment; | |
713 }, | |
714 | |
715 /** | |
716 * @param {!Event} event | |
717 * @return {?WebInspector.LayerView.Selection} | |
718 */ | |
719 _selectionFromEventPoint: function(event) | |
720 { | |
721 if (!this._layerTree) | |
722 return null; | |
723 var closestIntersectionPoint = Infinity; | |
724 var closestObject = null; | |
725 var projectionMatrix = new WebKitCSSMatrix().scale(1, -1, -1).translate(
-1, -1, 0).multiply(this._projectionMatrix); | |
726 var x0 = (event.clientX - this._canvasElement.totalOffsetLeft()) * windo
w.devicePixelRatio; | |
727 var y0 = -(event.clientY - this._canvasElement.totalOffsetTop()) * windo
w.devicePixelRatio; | |
728 | |
729 /** | |
730 * @param {!WebInspector.Layers3DView.Rectangle} rect | |
731 */ | |
732 function checkIntersection(rect) | |
733 { | |
734 if (!rect.relatedObject) | |
735 return; | |
736 var t = rect.intersectWithLine(projectionMatrix, x0, y0); | |
737 if (t < closestIntersectionPoint) { | |
738 closestIntersectionPoint = t; | |
739 closestObject = rect.relatedObject; | |
740 } | |
741 } | |
742 | |
743 this._rects.forEach(checkIntersection); | |
744 return closestObject; | |
745 }, | |
746 | |
747 /** | |
748 * @param {string} caption | |
749 * @param {string} name | |
750 * @param {boolean} value | |
751 * @param {!WebInspector.Toolbar} toolbar | |
752 * @return {!WebInspector.Setting} | |
753 */ | |
754 _createVisibilitySetting: function(caption, name, value, toolbar) | |
755 { | |
756 var checkbox = new WebInspector.ToolbarCheckbox(WebInspector.UIString(ca
ption)); | |
757 toolbar.appendToolbarItem(checkbox); | |
758 var setting = WebInspector.settings.createSetting(name, value); | |
759 WebInspector.SettingsUI.bindCheckbox(checkbox.inputElement, setting); | |
760 setting.addChangeListener(this._update, this); | |
761 return setting; | |
762 }, | |
763 | |
764 _initToolbar: function() | |
765 { | |
766 this._panelToolbar = this._transformController.toolbar(); | |
767 this.contentElement.appendChild(this._panelToolbar.element); | |
768 this._showSlowScrollRectsSetting = this._createVisibilitySetting("Slow s
croll rects", "frameViewerShowSlowScrollRects", true, this._panelToolbar); | |
769 this._showPaintsSetting = this._createVisibilitySetting("Paints", "frame
ViewerShowPaints", true, this._panelToolbar); | |
770 this._showPaintsSetting.addChangeListener(this._updatePaints, this); | |
771 WebInspector.moduleSetting("frameViewerHideChromeWindow").addChangeListe
ner(this._update, this); | |
772 }, | |
773 | |
774 /** | |
775 * @param {!Event} event | |
776 */ | |
777 _onContextMenu: function(event) | |
778 { | |
779 var contextMenu = new WebInspector.ContextMenu(event); | |
780 contextMenu.appendItem(WebInspector.UIString("Reset View"), this._transf
ormController.resetAndNotify.bind(this._transformController), false); | |
781 var selection = this._selectionFromEventPoint(event); | |
782 if (selection && selection.type() === WebInspector.LayerView.Selection.T
ype.Snapshot) | |
783 contextMenu.appendItem(WebInspector.UIString("Show Paint Profiler"),
this.dispatchEventToListeners.bind(this, WebInspector.Layers3DView.Events.Paint
ProfilerRequested, selection.snapshot()), false); | |
784 this._layerViewHost.showContextMenu(contextMenu, selection); | |
785 }, | |
786 | |
787 /** | |
788 * @param {!Event} event | |
789 */ | |
790 _onMouseMove: function(event) | |
791 { | |
792 if (event.which) | |
793 return; | |
794 this._layerViewHost.hoverObject(this._selectionFromEventPoint(event)); | |
795 }, | |
796 | |
797 /** | |
798 * @param {!Event} event | |
799 */ | |
800 _onMouseDown: function(event) | |
801 { | |
802 this._mouseDownX = event.clientX; | |
803 this._mouseDownY = event.clientY; | |
804 }, | |
805 | |
806 /** | |
807 * @param {!Event} event | |
808 */ | |
809 _onMouseUp: function(event) | |
810 { | |
811 const maxDistanceInPixels = 6; | |
812 if (this._mouseDownX && Math.abs(event.clientX - this._mouseDownX) < max
DistanceInPixels && Math.abs(event.clientY - this._mouseDownY) < maxDistanceInPi
xels) | |
813 this._layerViewHost.selectObject(this._selectionFromEventPoint(event
)); | |
814 delete this._mouseDownX; | |
815 delete this._mouseDownY; | |
816 }, | |
817 | |
818 /** | |
819 * @param {!Event} event | |
820 */ | |
821 _onDoubleClick: function(event) | |
822 { | |
823 var selection = this._selectionFromEventPoint(event); | |
824 if (selection && (selection.type() === WebInspector.LayerView.Selection.
Type.Snapshot || selection.layer())) | |
825 this.dispatchEventToListeners(WebInspector.Layers3DView.Events.Paint
ProfilerRequested, selection); | |
826 event.stopPropagation(); | |
827 }, | |
828 | |
829 _updatePaints: function() | |
830 { | |
831 if (this._showPaints()) { | |
832 this._textureManager.setLayerTree(this._layerTree); | |
833 this._textureManager.forceUpdate(); | |
834 } else { | |
835 this._textureManager.reset(); | |
836 } | |
837 this._update(); | |
838 }, | |
839 | |
840 /** | |
841 * @return {boolean} | |
842 */ | |
843 _showPaints: function() | |
844 { | |
845 return this._showPaintsSetting.get(); | |
846 }, | |
847 | |
848 __proto__: WebInspector.VBox.prototype | |
849 }; | |
850 | |
851 /** | 841 /** |
852 * @constructor | 842 * @unrestricted |
853 * @param {function()} textureUpdatedCallback | |
854 */ | 843 */ |
855 WebInspector.LayerTextureManager = function(textureUpdatedCallback) | 844 WebInspector.LayerTextureManager = class { |
856 { | 845 /** |
| 846 * @param {function()} textureUpdatedCallback |
| 847 */ |
| 848 constructor(textureUpdatedCallback) { |
857 this._textureUpdatedCallback = textureUpdatedCallback; | 849 this._textureUpdatedCallback = textureUpdatedCallback; |
858 this._throttler = new WebInspector.Throttler(0); | 850 this._throttler = new WebInspector.Throttler(0); |
859 this._scale = 0; | 851 this._scale = 0; |
860 this._active = false; | 852 this._active = false; |
861 this.reset(); | 853 this.reset(); |
| 854 } |
| 855 |
| 856 /** |
| 857 * @param {!Image} image |
| 858 * @param {!WebGLRenderingContext} gl |
| 859 * @return {!WebGLTexture} texture |
| 860 */ |
| 861 static _createTextureForImage(gl, image) { |
| 862 var texture = gl.createTexture(); |
| 863 texture.image = image; |
| 864 gl.bindTexture(gl.TEXTURE_2D, texture); |
| 865 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); |
| 866 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.
image); |
| 867 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); |
| 868 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); |
| 869 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); |
| 870 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); |
| 871 gl.bindTexture(gl.TEXTURE_2D, null); |
| 872 return texture; |
| 873 } |
| 874 |
| 875 reset() { |
| 876 if (this._tilesByLayer) |
| 877 this.setLayerTree(null); |
| 878 |
| 879 /** @type {!Map<!WebInspector.Layer, !Array<!WebInspector.LayerTextureManage
r.Tile>>} */ |
| 880 this._tilesByLayer = new Map(); |
| 881 /** @type {!Array<!WebInspector.Layer>} */ |
| 882 this._queue = []; |
| 883 } |
| 884 |
| 885 /** |
| 886 * @param {!WebGLRenderingContext} glContext |
| 887 */ |
| 888 setContext(glContext) { |
| 889 this._gl = glContext; |
| 890 if (this._scale) |
| 891 this._updateTextures(); |
| 892 } |
| 893 |
| 894 suspend() { |
| 895 this._active = false; |
| 896 } |
| 897 |
| 898 resume() { |
| 899 this._active = true; |
| 900 if (this._queue.length) |
| 901 this._update(); |
| 902 } |
| 903 |
| 904 /** |
| 905 * @param {?WebInspector.LayerTreeBase} layerTree |
| 906 */ |
| 907 setLayerTree(layerTree) { |
| 908 var newLayers = new Set(); |
| 909 var oldLayers = Array.from(this._tilesByLayer.keys()); |
| 910 if (layerTree) { |
| 911 layerTree.forEachLayer(layer => { |
| 912 if (!layer.drawsContent()) |
| 913 return; |
| 914 newLayers.add(layer); |
| 915 if (!this._tilesByLayer.has(layer)) { |
| 916 this._tilesByLayer.set(layer, []); |
| 917 this.layerNeedsUpdate(layer); |
| 918 } |
| 919 }); |
| 920 } |
| 921 if (!oldLayers.length) |
| 922 this.forceUpdate(); |
| 923 for (var layer of oldLayers) { |
| 924 if (newLayers.has(layer)) |
| 925 continue; |
| 926 this._tilesByLayer.get(layer).forEach(tile => tile.dispose()); |
| 927 this._tilesByLayer.delete(layer); |
| 928 } |
| 929 } |
| 930 |
| 931 /** |
| 932 * @param {!WebInspector.Layer} layer |
| 933 * @param {!Array<!WebInspector.SnapshotWithRect>} snapshots |
| 934 * @return {!Promise} |
| 935 */ |
| 936 _setSnapshotsForLayer(layer, snapshots) { |
| 937 var oldSnapshotsToTiles = new Map((this._tilesByLayer.get(layer) || []).map(
tile => [tile.snapshot, tile])); |
| 938 var newTiles = []; |
| 939 var reusedTiles = []; |
| 940 for (var snapshot of snapshots) { |
| 941 var oldTile = oldSnapshotsToTiles.get(snapshot); |
| 942 if (oldTile) { |
| 943 reusedTiles.push(oldTile); |
| 944 oldSnapshotsToTiles.delete(oldTile); |
| 945 } else { |
| 946 newTiles.push(new WebInspector.LayerTextureManager.Tile(snapshot)); |
| 947 } |
| 948 } |
| 949 this._tilesByLayer.set(layer, reusedTiles.concat(newTiles)); |
| 950 for (var tile of oldSnapshotsToTiles.values()) |
| 951 tile.dispose(); |
| 952 if (!this._gl || !this._scale) |
| 953 return Promise.resolve(); |
| 954 return Promise.all(newTiles.map(tile => tile.update(this._gl, this._scale)))
.then(this._textureUpdatedCallback); |
| 955 } |
| 956 |
| 957 /** |
| 958 * @param {number} scale |
| 959 */ |
| 960 setScale(scale) { |
| 961 if (this._scale && this._scale >= scale) |
| 962 return; |
| 963 this._scale = scale; |
| 964 this._updateTextures(); |
| 965 } |
| 966 |
| 967 /** |
| 968 * @param {!WebInspector.Layer} layer |
| 969 * @return {!Array<!WebInspector.LayerTextureManager.Tile>} |
| 970 */ |
| 971 tilesForLayer(layer) { |
| 972 return this._tilesByLayer.get(layer) || []; |
| 973 } |
| 974 |
| 975 /** |
| 976 * @param {!WebInspector.Layer} layer |
| 977 */ |
| 978 layerNeedsUpdate(layer) { |
| 979 if (this._queue.indexOf(layer) < 0) |
| 980 this._queue.push(layer); |
| 981 if (this._active) |
| 982 this._throttler.schedule(this._update.bind(this)); |
| 983 } |
| 984 |
| 985 forceUpdate() { |
| 986 this._queue.forEach(layer => this._updateLayer(layer)); |
| 987 this._queue = []; |
| 988 this._throttler.flush(); |
| 989 } |
| 990 |
| 991 /** |
| 992 * @return {!Promise} |
| 993 */ |
| 994 _update() { |
| 995 var layer = this._queue.shift(); |
| 996 if (!layer) |
| 997 return Promise.resolve(); |
| 998 if (this._queue.length) |
| 999 this._throttler.schedule(this._update.bind(this)); |
| 1000 return this._updateLayer(layer); |
| 1001 } |
| 1002 |
| 1003 /** |
| 1004 * @param {!WebInspector.Layer} layer |
| 1005 * @return {!Promise} |
| 1006 */ |
| 1007 _updateLayer(layer) { |
| 1008 return Promise.all(layer.snapshots()) |
| 1009 .then(snapshots => this._setSnapshotsForLayer(layer, snapshots.filter(sn
apshot => !!snapshot))); |
| 1010 } |
| 1011 |
| 1012 _updateTextures() { |
| 1013 if (!this._gl) |
| 1014 return; |
| 1015 if (!this._scale) |
| 1016 return; |
| 1017 |
| 1018 for (var tiles of this._tilesByLayer.values()) { |
| 1019 for (var tile of tiles) { |
| 1020 var promise = tile.updateScale(this._gl, this._scale); |
| 1021 if (promise) |
| 1022 promise.then(this._textureUpdatedCallback); |
| 1023 } |
| 1024 } |
| 1025 } |
862 }; | 1026 }; |
863 | 1027 |
864 WebInspector.LayerTextureManager.prototype = { | |
865 reset: function() | |
866 { | |
867 if (this._tilesByLayer) | |
868 this.setLayerTree(null); | |
869 | |
870 /** @type {!Map<!WebInspector.Layer, !Array<!WebInspector.LayerTextureMa
nager.Tile>>} */ | |
871 this._tilesByLayer = new Map(); | |
872 /** @type {!Array<!WebInspector.Layer>} */ | |
873 this._queue = []; | |
874 }, | |
875 | |
876 /** | |
877 * @param {!WebGLRenderingContext} glContext | |
878 */ | |
879 setContext: function(glContext) | |
880 { | |
881 this._gl = glContext; | |
882 if (this._scale) | |
883 this._updateTextures(); | |
884 }, | |
885 | |
886 suspend: function() | |
887 { | |
888 this._active = false; | |
889 }, | |
890 | |
891 resume: function() | |
892 { | |
893 this._active = true; | |
894 if (this._queue.length) | |
895 this._update(); | |
896 }, | |
897 | |
898 /** | |
899 * @param {?WebInspector.LayerTreeBase} layerTree | |
900 */ | |
901 setLayerTree: function(layerTree) | |
902 { | |
903 var newLayers = new Set(); | |
904 var oldLayers = Array.from(this._tilesByLayer.keys()); | |
905 if (layerTree) { | |
906 layerTree.forEachLayer(layer => { | |
907 if (!layer.drawsContent()) | |
908 return; | |
909 newLayers.add(layer); | |
910 if (!this._tilesByLayer.has(layer)) { | |
911 this._tilesByLayer.set(layer, []); | |
912 this.layerNeedsUpdate(layer); | |
913 } | |
914 }); | |
915 } | |
916 if (!oldLayers.length) | |
917 this.forceUpdate(); | |
918 for (var layer of oldLayers) { | |
919 if (newLayers.has(layer)) | |
920 continue; | |
921 this._tilesByLayer.get(layer).forEach(tile => tile.dispose()); | |
922 this._tilesByLayer.delete(layer); | |
923 } | |
924 }, | |
925 | |
926 /** | |
927 * @param {!WebInspector.Layer} layer | |
928 * @param {!Array<!WebInspector.SnapshotWithRect>} snapshots | |
929 * @return {!Promise} | |
930 */ | |
931 _setSnapshotsForLayer: function(layer, snapshots) | |
932 { | |
933 var oldSnapshotsToTiles = new Map((this._tilesByLayer.get(layer) || []).
map(tile => [tile.snapshot, tile])); | |
934 var newTiles = []; | |
935 var reusedTiles = []; | |
936 for (var snapshot of snapshots) { | |
937 var oldTile = oldSnapshotsToTiles.get(snapshot); | |
938 if (oldTile) { | |
939 reusedTiles.push(oldTile); | |
940 oldSnapshotsToTiles.delete(oldTile); | |
941 } else { | |
942 newTiles.push(new WebInspector.LayerTextureManager.Tile(snapshot
)); | |
943 } | |
944 } | |
945 this._tilesByLayer.set(layer, reusedTiles.concat(newTiles)); | |
946 for (var tile of oldSnapshotsToTiles.values()) | |
947 tile.dispose(); | |
948 if (!this._gl || !this._scale) | |
949 return Promise.resolve(); | |
950 return Promise.all(newTiles.map(tile => tile.update(this._gl, this._scal
e))).then(this._textureUpdatedCallback); | |
951 }, | |
952 | |
953 /** | |
954 * @param {number} scale | |
955 */ | |
956 setScale: function(scale) | |
957 { | |
958 if (this._scale && this._scale >= scale) | |
959 return; | |
960 this._scale = scale; | |
961 this._updateTextures(); | |
962 }, | |
963 | |
964 /** | |
965 * @param {!WebInspector.Layer} layer | |
966 * @return {!Array<!WebInspector.LayerTextureManager.Tile>} | |
967 */ | |
968 tilesForLayer: function(layer) | |
969 { | |
970 return this._tilesByLayer.get(layer) || []; | |
971 }, | |
972 | |
973 /** | |
974 * @param {!WebInspector.Layer} layer | |
975 */ | |
976 layerNeedsUpdate: function(layer) | |
977 { | |
978 if (this._queue.indexOf(layer) < 0) | |
979 this._queue.push(layer); | |
980 if (this._active) | |
981 this._throttler.schedule(this._update.bind(this)); | |
982 }, | |
983 | |
984 forceUpdate: function() | |
985 { | |
986 this._queue.forEach(layer => this._updateLayer(layer)); | |
987 this._queue = []; | |
988 this._throttler.flush(); | |
989 }, | |
990 | |
991 /** | |
992 * @return {!Promise} | |
993 */ | |
994 _update: function() | |
995 { | |
996 var layer = this._queue.shift(); | |
997 if (!layer) | |
998 return Promise.resolve(); | |
999 if (this._queue.length) | |
1000 this._throttler.schedule(this._update.bind(this)); | |
1001 return this._updateLayer(layer); | |
1002 }, | |
1003 | |
1004 /** | |
1005 * @param {!WebInspector.Layer} layer | |
1006 * @return {!Promise} | |
1007 */ | |
1008 _updateLayer: function(layer) | |
1009 { | |
1010 return Promise.all(layer.snapshots()).then(snapshots => | |
1011 this._setSnapshotsForLayer(layer, snapshots.filter(snapshot => !!sna
pshot))); | |
1012 }, | |
1013 | |
1014 _updateTextures: function() | |
1015 { | |
1016 if (!this._gl) | |
1017 return; | |
1018 if (!this._scale) | |
1019 return; | |
1020 | |
1021 for (var tiles of this._tilesByLayer.values()) { | |
1022 for (var tile of tiles) { | |
1023 var promise = tile.updateScale(this._gl, this._scale); | |
1024 if (promise) | |
1025 promise.then(this._textureUpdatedCallback); | |
1026 } | |
1027 } | |
1028 } | |
1029 }; | |
1030 | |
1031 /** | 1028 /** |
1032 * @constructor | 1029 * @unrestricted |
1033 * @param {?WebInspector.LayerView.Selection} relatedObject | |
1034 */ | 1030 */ |
1035 WebInspector.Layers3DView.Rectangle = function(relatedObject) | 1031 WebInspector.Layers3DView.Rectangle = class { |
1036 { | 1032 /** |
| 1033 * @param {?WebInspector.LayerView.Selection} relatedObject |
| 1034 */ |
| 1035 constructor(relatedObject) { |
1037 this.relatedObject = relatedObject; | 1036 this.relatedObject = relatedObject; |
1038 /** @type {number} */ | 1037 /** @type {number} */ |
1039 this.lineWidth = 1; | 1038 this.lineWidth = 1; |
1040 /** @type {?Array.<number>} */ | 1039 /** @type {?Array.<number>} */ |
1041 this.borderColor = null; | 1040 this.borderColor = null; |
1042 /** @type {?Array.<number>} */ | 1041 /** @type {?Array.<number>} */ |
1043 this.fillColor = null; | 1042 this.fillColor = null; |
1044 /** @type {?WebGLTexture} */ | 1043 /** @type {?WebGLTexture} */ |
1045 this.texture = null; | 1044 this.texture = null; |
| 1045 } |
| 1046 |
| 1047 /** |
| 1048 * @param {!Array.<number>} quad |
| 1049 * @param {number} z |
| 1050 */ |
| 1051 setVertices(quad, z) { |
| 1052 this.vertices = [quad[0], quad[1], z, quad[2], quad[3], z, quad[4], quad[5],
z, quad[6], quad[7], z]; |
| 1053 } |
| 1054 |
| 1055 /** |
| 1056 * Finds coordinates of point on layer quad, having offsets (ratioX * width) a
nd (ratioY * height) |
| 1057 * from the left corner of the initial layer rect, where width and heigth are
layer bounds. |
| 1058 * @param {!Array.<number>} quad |
| 1059 * @param {number} ratioX |
| 1060 * @param {number} ratioY |
| 1061 * @return {!Array.<number>} |
| 1062 */ |
| 1063 _calculatePointOnQuad(quad, ratioX, ratioY) { |
| 1064 var x0 = quad[0]; |
| 1065 var y0 = quad[1]; |
| 1066 var x1 = quad[2]; |
| 1067 var y1 = quad[3]; |
| 1068 var x2 = quad[4]; |
| 1069 var y2 = quad[5]; |
| 1070 var x3 = quad[6]; |
| 1071 var y3 = quad[7]; |
| 1072 // Point on the first quad side clockwise |
| 1073 var firstSidePointX = x0 + ratioX * (x1 - x0); |
| 1074 var firstSidePointY = y0 + ratioX * (y1 - y0); |
| 1075 // Point on the third quad side clockwise |
| 1076 var thirdSidePointX = x3 + ratioX * (x2 - x3); |
| 1077 var thirdSidePointY = y3 + ratioX * (y2 - y3); |
| 1078 var x = firstSidePointX + ratioY * (thirdSidePointX - firstSidePointX); |
| 1079 var y = firstSidePointY + ratioY * (thirdSidePointY - firstSidePointY); |
| 1080 return [x, y]; |
| 1081 } |
| 1082 |
| 1083 /** |
| 1084 * @param {!WebInspector.Layer} layer |
| 1085 * @param {!DOMAgent.Rect} rect |
| 1086 * @param {number} z |
| 1087 */ |
| 1088 calculateVerticesFromRect(layer, rect, z) { |
| 1089 var quad = layer.quad(); |
| 1090 var rx1 = rect.x / layer.width(); |
| 1091 var rx2 = (rect.x + rect.width) / layer.width(); |
| 1092 var ry1 = rect.y / layer.height(); |
| 1093 var ry2 = (rect.y + rect.height) / layer.height(); |
| 1094 var rectQuad = this._calculatePointOnQuad(quad, rx1, ry1) |
| 1095 .concat(this._calculatePointOnQuad(quad, rx2, ry1)) |
| 1096 .concat(this._calculatePointOnQuad(quad, rx2, ry2)) |
| 1097 .concat(this._calculatePointOnQuad(quad, rx1, ry2)); |
| 1098 this.setVertices(rectQuad, z); |
| 1099 } |
| 1100 |
| 1101 /** |
| 1102 * Intersects quad with given transform matrix and line l(t) = (x0, y0, t) |
| 1103 * @param {!CSSMatrix} matrix |
| 1104 * @param {number} x0 |
| 1105 * @param {number} y0 |
| 1106 * @return {(number|undefined)} |
| 1107 */ |
| 1108 intersectWithLine(matrix, x0, y0) { |
| 1109 var i; |
| 1110 // Vertices of the quad with transform matrix applied |
| 1111 var points = []; |
| 1112 for (i = 0; i < 4; ++i) |
| 1113 points[i] = WebInspector.Geometry.multiplyVectorByMatrixAndNormalize( |
| 1114 new WebInspector.Geometry.Vector(this.vertices[i * 3], this.vertices[i
* 3 + 1], this.vertices[i * 3 + 2]), |
| 1115 matrix); |
| 1116 // Calculating quad plane normal |
| 1117 var normal = WebInspector.Geometry.crossProduct( |
| 1118 WebInspector.Geometry.subtract(points[1], points[0]), WebInspector.Geome
try.subtract(points[2], points[1])); |
| 1119 // General form of the equation of the quad plane: A * x + B * y + C * z + D
= 0 |
| 1120 var A = normal.x; |
| 1121 var B = normal.y; |
| 1122 var C = normal.z; |
| 1123 var D = -(A * points[0].x + B * points[0].y + C * points[0].z); |
| 1124 // Finding t from the equation |
| 1125 var t = -(D + A * x0 + B * y0) / C; |
| 1126 // Point of the intersection |
| 1127 var pt = new WebInspector.Geometry.Vector(x0, y0, t); |
| 1128 // Vectors from the intersection point to vertices of the quad |
| 1129 var tVects = points.map(WebInspector.Geometry.subtract.bind(null, pt)); |
| 1130 // Intersection point lies inside of the polygon if scalar products of norma
l of the plane and |
| 1131 // cross products of successive tVects are all nonstrictly above or all nons
trictly below zero |
| 1132 for (i = 0; i < tVects.length; ++i) { |
| 1133 var product = WebInspector.Geometry.scalarProduct( |
| 1134 normal, WebInspector.Geometry.crossProduct(tVects[i], tVects[(i + 1) %
tVects.length])); |
| 1135 if (product < 0) |
| 1136 return undefined; |
| 1137 } |
| 1138 return t; |
| 1139 } |
1046 }; | 1140 }; |
1047 | 1141 |
1048 WebInspector.Layers3DView.Rectangle.prototype = { | |
1049 /** | |
1050 * @param {!Array.<number>} quad | |
1051 * @param {number} z | |
1052 */ | |
1053 setVertices: function(quad, z) | |
1054 { | |
1055 this.vertices = [quad[0], quad[1], z, quad[2], quad[3], z, quad[4], quad
[5], z, quad[6], quad[7], z]; | |
1056 }, | |
1057 | |
1058 /** | |
1059 * Finds coordinates of point on layer quad, having offsets (ratioX * width)
and (ratioY * height) | |
1060 * from the left corner of the initial layer rect, where width and heigth ar
e layer bounds. | |
1061 * @param {!Array.<number>} quad | |
1062 * @param {number} ratioX | |
1063 * @param {number} ratioY | |
1064 * @return {!Array.<number>} | |
1065 */ | |
1066 _calculatePointOnQuad: function(quad, ratioX, ratioY) | |
1067 { | |
1068 var x0 = quad[0]; | |
1069 var y0 = quad[1]; | |
1070 var x1 = quad[2]; | |
1071 var y1 = quad[3]; | |
1072 var x2 = quad[4]; | |
1073 var y2 = quad[5]; | |
1074 var x3 = quad[6]; | |
1075 var y3 = quad[7]; | |
1076 // Point on the first quad side clockwise | |
1077 var firstSidePointX = x0 + ratioX * (x1 - x0); | |
1078 var firstSidePointY = y0 + ratioX * (y1 - y0); | |
1079 // Point on the third quad side clockwise | |
1080 var thirdSidePointX = x3 + ratioX * (x2 - x3); | |
1081 var thirdSidePointY = y3 + ratioX * (y2 - y3); | |
1082 var x = firstSidePointX + ratioY * (thirdSidePointX - firstSidePointX); | |
1083 var y = firstSidePointY + ratioY * (thirdSidePointY - firstSidePointY); | |
1084 return [x, y]; | |
1085 }, | |
1086 | |
1087 /** | |
1088 * @param {!WebInspector.Layer} layer | |
1089 * @param {!DOMAgent.Rect} rect | |
1090 * @param {number} z | |
1091 */ | |
1092 calculateVerticesFromRect: function(layer, rect, z) | |
1093 { | |
1094 var quad = layer.quad(); | |
1095 var rx1 = rect.x / layer.width(); | |
1096 var rx2 = (rect.x + rect.width) / layer.width(); | |
1097 var ry1 = rect.y / layer.height(); | |
1098 var ry2 = (rect.y + rect.height) / layer.height(); | |
1099 var rectQuad = this._calculatePointOnQuad(quad, rx1, ry1).concat(this._c
alculatePointOnQuad(quad, rx2, ry1)) | |
1100 .concat(this._calculatePointOnQuad(quad, rx2, ry2)).concat(this._cal
culatePointOnQuad(quad, rx1, ry2)); | |
1101 this.setVertices(rectQuad, z); | |
1102 }, | |
1103 | |
1104 /** | |
1105 * Intersects quad with given transform matrix and line l(t) = (x0, y0, t) | |
1106 * @param {!CSSMatrix} matrix | |
1107 * @param {number} x0 | |
1108 * @param {number} y0 | |
1109 * @return {(number|undefined)} | |
1110 */ | |
1111 intersectWithLine: function(matrix, x0, y0) | |
1112 { | |
1113 var i; | |
1114 // Vertices of the quad with transform matrix applied | |
1115 var points = []; | |
1116 for (i = 0; i < 4; ++i) | |
1117 points[i] = WebInspector.Geometry.multiplyVectorByMatrixAndNormalize
(new WebInspector.Geometry.Vector(this.vertices[i * 3], this.vertices[i * 3 + 1]
, this.vertices[i * 3 + 2]), matrix); | |
1118 // Calculating quad plane normal | |
1119 var normal = WebInspector.Geometry.crossProduct(WebInspector.Geometry.su
btract(points[1], points[0]), WebInspector.Geometry.subtract(points[2], points[1
])); | |
1120 // General form of the equation of the quad plane: A * x + B * y + C * z
+ D = 0 | |
1121 var A = normal.x; | |
1122 var B = normal.y; | |
1123 var C = normal.z; | |
1124 var D = -(A * points[0].x + B * points[0].y + C * points[0].z); | |
1125 // Finding t from the equation | |
1126 var t = -(D + A * x0 + B * y0) / C; | |
1127 // Point of the intersection | |
1128 var pt = new WebInspector.Geometry.Vector(x0, y0, t); | |
1129 // Vectors from the intersection point to vertices of the quad | |
1130 var tVects = points.map(WebInspector.Geometry.subtract.bind(null, pt)); | |
1131 // Intersection point lies inside of the polygon if scalar products of n
ormal of the plane and | |
1132 // cross products of successive tVects are all nonstrictly above or all
nonstrictly below zero | |
1133 for (i = 0; i < tVects.length; ++i) { | |
1134 var product = WebInspector.Geometry.scalarProduct(normal, WebInspect
or.Geometry.crossProduct(tVects[i], tVects[(i + 1) % tVects.length])); | |
1135 if (product < 0) | |
1136 return undefined; | |
1137 } | |
1138 return t; | |
1139 } | |
1140 }; | |
1141 | 1142 |
1142 /** | 1143 /** |
1143 * @param {!Image} image | 1144 * @unrestricted |
1144 * @param {!WebGLRenderingContext} gl | |
1145 * @return {!WebGLTexture} texture | |
1146 */ | 1145 */ |
1147 WebInspector.LayerTextureManager._createTextureForImage = function(gl, image) | 1146 WebInspector.LayerTextureManager.Tile = class { |
1148 { | 1147 /** |
1149 var texture = gl.createTexture(); | 1148 * @param {!WebInspector.SnapshotWithRect} snapshotWithRect |
1150 texture.image = image; | 1149 */ |
1151 gl.bindTexture(gl.TEXTURE_2D, texture); | 1150 constructor(snapshotWithRect) { |
1152 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); | |
1153 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.
image); | |
1154 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); | |
1155 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); | |
1156 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); | |
1157 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); | |
1158 gl.bindTexture(gl.TEXTURE_2D, null); | |
1159 return texture; | |
1160 }; | |
1161 | |
1162 /** | |
1163 * @constructor | |
1164 * @param {!WebInspector.SnapshotWithRect} snapshotWithRect | |
1165 */ | |
1166 WebInspector.LayerTextureManager.Tile = function(snapshotWithRect) | |
1167 { | |
1168 this.snapshot = snapshotWithRect.snapshot; | 1151 this.snapshot = snapshotWithRect.snapshot; |
1169 this.rect = snapshotWithRect.rect; | 1152 this.rect = snapshotWithRect.rect; |
1170 this.scale = 0; | 1153 this.scale = 0; |
1171 /** @type {?WebGLTexture} */ | 1154 /** @type {?WebGLTexture} */ |
1172 this.texture = null; | 1155 this.texture = null; |
| 1156 } |
| 1157 |
| 1158 dispose() { |
| 1159 this.snapshot.release(); |
| 1160 if (this.texture) { |
| 1161 this._gl.deleteTexture(this.texture); |
| 1162 this.texture = null; |
| 1163 } |
| 1164 } |
| 1165 |
| 1166 /** |
| 1167 * @param {!WebGLRenderingContext} glContext |
| 1168 * @param {number} scale |
| 1169 * @return {?Promise} |
| 1170 */ |
| 1171 updateScale(glContext, scale) { |
| 1172 if (this.texture && this.scale >= scale) |
| 1173 return null; |
| 1174 return this.update(glContext, scale); |
| 1175 } |
| 1176 |
| 1177 /** |
| 1178 * @param {!WebGLRenderingContext} glContext |
| 1179 * @param {number} scale |
| 1180 * @return {!Promise} |
| 1181 */ |
| 1182 update(glContext, scale) { |
| 1183 this._gl = glContext; |
| 1184 this.scale = scale; |
| 1185 return this.snapshot.replay(null, null, scale) |
| 1186 .then(imageURL => imageURL && WebInspector.loadImage(imageURL)) |
| 1187 .then(image => { |
| 1188 this.texture = image && WebInspector.LayerTextureManager._createTextur
eForImage(glContext, image); |
| 1189 }); |
| 1190 } |
1173 }; | 1191 }; |
1174 | |
1175 WebInspector.LayerTextureManager.Tile.prototype = { | |
1176 dispose: function() | |
1177 { | |
1178 this.snapshot.release(); | |
1179 if (this.texture) { | |
1180 this._gl.deleteTexture(this.texture); | |
1181 this.texture = null; | |
1182 } | |
1183 }, | |
1184 | |
1185 /** | |
1186 * @param {!WebGLRenderingContext} glContext | |
1187 * @param {number} scale | |
1188 * @return {?Promise} | |
1189 */ | |
1190 updateScale: function(glContext, scale) | |
1191 { | |
1192 if (this.texture && this.scale >= scale) | |
1193 return null; | |
1194 return this.update(glContext, scale); | |
1195 }, | |
1196 | |
1197 /** | |
1198 * @param {!WebGLRenderingContext} glContext | |
1199 * @param {number} scale | |
1200 * @return {!Promise} | |
1201 */ | |
1202 update: function(glContext, scale) | |
1203 { | |
1204 this._gl = glContext; | |
1205 this.scale = scale; | |
1206 return this.snapshot.replay(null, null, scale) | |
1207 .then(imageURL => imageURL && WebInspector.loadImage(imageURL)) | |
1208 .then(image => { | |
1209 this.texture = image && WebInspector.LayerTextureManager._create
TextureForImage(glContext, image); | |
1210 }); | |
1211 } | |
1212 }; | |
OLD | NEW |