2 * Copyright (C) 2014 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
33 * @extends {WebInspector.VBox}
34 * @param {!WebInspector.LayerTreeModel} model
36 WebInspector.Layers3DView = function(model)
38 WebInspector.VBox.call(this);
39 this.element.classList.add("layers-3d-view");
40 this._emptyView = new WebInspector.EmptyView(WebInspector.UIString("Not in the composited mode.\nConsider forcing composited mode in Settings."));
42 this._model.addEventListener(WebInspector.LayerTreeModel.Events.LayerTreeChanged, this._update, this);
43 this._model.addEventListener(WebInspector.LayerTreeModel.Events.LayerPainted, this._onLayerPainted, this);
44 this._canvasElement = this.element.createChild("canvas");
45 this._transformController = new WebInspector.TransformController(this._canvasElement);
46 this._transformController.addEventListener(WebInspector.TransformController.Events.TransformChanged, this._update, this);
47 this._canvasElement.addEventListener("dblclick", this._onDoubleClick.bind(this), false);
48 this._canvasElement.addEventListener("mousedown", this._onMouseDown.bind(this), false);
49 this._canvasElement.addEventListener("mouseup", this._onMouseUp.bind(this), false);
50 this._canvasElement.addEventListener("mouseout", this._onMouseMove.bind(this), false);
51 this._canvasElement.addEventListener("mousemove", this._onMouseMove.bind(this), false);
52 this._canvasElement.addEventListener("contextmenu", this._onContextMenu.bind(this), false);
53 this._lastActiveObject = {};
54 this._textureForLayer = {};
55 this._scrollRectQuadsForLayer = {};
57 WebInspector.settings.showPaintRects.addChangeListener(this._update, this);
63 WebInspector.Layers3DView.OutlineType = {
71 WebInspector.Layers3DView.Events = {
72 ObjectHovered: "ObjectHovered",
73 ObjectSelected: "ObjectSelected",
74 LayerSnapshotRequested: "LayerSnapshotRequested"
80 WebInspector.Layers3DView.ScrollRectTitles = {
81 RepaintsOnScroll: WebInspector.UIString("repaints on scroll"),
82 TouchEventHandler: WebInspector.UIString("touch event listener"),
83 WheelEventHandler: WebInspector.UIString("mousewheel event listener")
86 WebInspector.Layers3DView.FragmentShader = "\
87 precision mediump float;\
89 varying vec2 vTextureCoord;\
90 uniform sampler2D uSampler;\
93 gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)) * vColor;\
96 WebInspector.Layers3DView.VertexShader = "\
97 attribute vec3 aVertexPosition;\
98 attribute vec2 aTextureCoord;\
99 attribute vec4 aVertexColor;\
100 uniform mat4 uPMatrix;\
101 varying vec2 vTextureCoord;\
102 varying vec4 vColor;\
105 gl_Position = uPMatrix * vec4(aVertexPosition, 1.0);\
106 vColor = aVertexColor;\
107 vTextureCoord = aTextureCoord;\
110 WebInspector.Layers3DView.SelectedBackgroundColor = [20, 40, 110, 0.66];
111 WebInspector.Layers3DView.BackgroundColor = [0, 0, 0, 0];
112 WebInspector.Layers3DView.HoveredBorderColor = [0, 0, 255, 1];
113 WebInspector.Layers3DView.BorderColor = [0, 0, 0, 1];
114 WebInspector.Layers3DView.ScrollRectBackgroundColor = [178, 0, 0, 0.4];
115 WebInspector.Layers3DView.SelectedScrollRectBackgroundColor = [178, 0, 0, 0.6];
116 WebInspector.Layers3DView.ScrollRectBorderColor = [178, 0, 0, 1];
118 WebInspector.Layers3DView.LayerSpacing = 20;
119 WebInspector.Layers3DView.ScrollRectSpacing = 4;
121 WebInspector.Layers3DView.prototype = {
123 * @param {function(!Array.<!WebInspector.KeyboardShortcut.Descriptor>, function(?Event=))} registerShortcutDelegate
125 registerShortcuts: function(registerShortcutDelegate)
127 this._transformController.registerShortcuts(registerShortcutDelegate);
141 if (this._needsUpdate)
146 * @param {!WebInspector.Layers3DView.OutlineType} type
147 * @param {?WebInspector.LayersPanel.ActiveObject} activeObject
149 _setOutline: function(type, activeObject)
151 this._lastActiveObject[type] = activeObject;
156 * @param {!WebInspector.LayersPanel.ActiveObject} activeObject
158 hoverObject: function(activeObject)
160 this._setOutline(WebInspector.Layers3DView.OutlineType.Hovered, activeObject);
164 * @param {!WebInspector.LayersPanel.ActiveObject} activeObject
166 selectObject: function(activeObject)
168 this._setOutline(WebInspector.Layers3DView.OutlineType.Hovered, null);
169 this._setOutline(WebInspector.Layers3DView.OutlineType.Selected, activeObject);
173 * @param {!WebInspector.Layer} layer
174 * @param {string=} imageURL
176 showImageForLayer: function(layer, imageURL)
178 var texture = this._gl.createTexture();
179 texture.image = new Image();
180 texture.image.addEventListener("load", this._handleLoadedTexture.bind(this, texture, layer.id()), false);
181 texture.image.src = imageURL;
185 * @param {!Element} canvas
188 _initGL: function(canvas)
190 var gl = canvas.getContext("webgl");
191 gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
193 gl.clearColor(0.0, 0.0, 0.0, 0.0);
194 gl.enable(gl.DEPTH_TEST);
199 * @param {!Object} type
200 * @param {string} script
202 _createShader: function(type, script)
204 var shader = this._gl.createShader(type);
205 this._gl.shaderSource(shader, script);
206 this._gl.compileShader(shader);
207 this._gl.attachShader(this._shaderProgram, shader);
211 * @param {string} attributeName
212 * @param {string} glName
214 _enableVertexAttribArray: function(attributeName, glName)
216 this._shaderProgram[attributeName] = this._gl.getAttribLocation(this._shaderProgram, glName);
217 this._gl.enableVertexAttribArray(this._shaderProgram[attributeName]);
220 _initShaders: function()
222 this._shaderProgram = this._gl.createProgram();
223 this._createShader(this._gl.FRAGMENT_SHADER, WebInspector.Layers3DView.FragmentShader);
224 this._createShader(this._gl.VERTEX_SHADER, WebInspector.Layers3DView.VertexShader);
225 this._gl.linkProgram(this._shaderProgram);
226 this._gl.useProgram(this._shaderProgram);
228 this._shaderProgram.vertexPositionAttribute = this._gl.getAttribLocation(this._shaderProgram, "aVertexPosition");
229 this._gl.enableVertexAttribArray(this._shaderProgram.vertexPositionAttribute);
230 this._shaderProgram.vertexColorAttribute = this._gl.getAttribLocation(this._shaderProgram, "aVertexColor");
231 this._gl.enableVertexAttribArray(this._shaderProgram.vertexColorAttribute);
232 this._shaderProgram.textureCoordAttribute = this._gl.getAttribLocation(this._shaderProgram, "aTextureCoord");
233 this._gl.enableVertexAttribArray(this._shaderProgram.textureCoordAttribute);
235 this._shaderProgram.pMatrixUniform = this._gl.getUniformLocation(this._shaderProgram, "uPMatrix");
236 this._shaderProgram.samplerUniform = this._gl.getUniformLocation(this._shaderProgram, "uSampler");
239 _resizeCanvas: function()
241 this._canvasElement.width = this._canvasElement.offsetWidth * window.devicePixelRatio;
242 this._canvasElement.height = this._canvasElement.offsetHeight * window.devicePixelRatio;
243 this._gl.viewportWidth = this._canvasElement.width;
244 this._gl.viewportHeight = this._canvasElement.height;
248 * @return {!CSSMatrix}
250 _calculateProjectionMatrix: function()
252 var rootLayerPadding = 20;
253 var rootWidth = this._model.contentRoot().width();
254 var rootHeight = this._model.contentRoot().height();
255 var canvasWidth = this._canvasElement.width;
256 var canvasHeight = this._canvasElement.height;
257 var scaleX = (canvasWidth - rootLayerPadding) / rootWidth;
258 var scaleY = (canvasHeight - rootLayerPadding) / rootHeight;
259 var viewScale = Math.min(scaleX, scaleY);
260 var scale = this._transformController.scale();
261 var offsetX = this._transformController.offsetX() * window.devicePixelRatio;
262 var offsetY = this._transformController.offsetY() * window.devicePixelRatio;
263 var rotateX = this._transformController.rotateX();
264 var rotateY = this._transformController.rotateY();
265 return new WebKitCSSMatrix().translate(offsetX, offsetY, 0).scale(scale, scale, scale).translate(canvasWidth / 2, canvasHeight / 2, 0)
266 .rotate(rotateX, rotateY, 0).scale(viewScale, viewScale, viewScale).translate(-rootWidth / 2, -rootHeight / 2, 0);
269 _initProjectionMatrix: function()
271 this._pMatrix = new WebKitCSSMatrix().scale(1, -1, -1).translate(-1, -1, 0)
272 .scale(2 / this._canvasElement.width, 2 / this._canvasElement.height, 1 / 1000000).multiply(this._calculateProjectionMatrix());
273 this._gl.uniformMatrix4fv(this._shaderProgram.pMatrixUniform, false, this._arrayFromMatrix(this._pMatrix));
277 * @param {!Object} texture
278 * @param {string} layerId
280 _handleLoadedTexture: function(texture, layerId)
282 this._gl.bindTexture(this._gl.TEXTURE_2D, texture);
283 this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, true);
284 this._gl.texImage2D(this._gl.TEXTURE_2D, 0, this._gl.RGBA, this._gl.RGBA, this._gl.UNSIGNED_BYTE, texture.image);
285 this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER, this._gl.LINEAR);
286 this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, this._gl.LINEAR);
287 this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_S, this._gl.CLAMP_TO_EDGE);
288 this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_T, this._gl.CLAMP_TO_EDGE);
289 this._gl.bindTexture(this._gl.TEXTURE_2D, null);
290 this._textureForLayer = {};
291 this._textureForLayer[layerId] = texture;
295 _initWhiteTexture: function()
297 this._whiteTexture = this._gl.createTexture();
298 this._gl.bindTexture(this._gl.TEXTURE_2D, this._whiteTexture);
299 var whitePixel = new Uint8Array([255, 255, 255, 255]);
300 this._gl.texImage2D(this._gl.TEXTURE_2D, 0, this._gl.RGBA, 1, 1, 0, this._gl.RGBA, this._gl.UNSIGNED_BYTE, whitePixel);
303 _initGLIfNecessary: function()
307 this._gl = this._initGL(this._canvasElement);
309 this._initWhiteTexture();
314 * @param {!CSSMatrix} m
315 * @return {!Float32Array}
317 _arrayFromMatrix: function(m)
319 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]);
323 * @param {!Array.<number>} color
324 * @return {!Array.<number>}
326 _makeColorsArray: function(color)
329 var normalizedColor = [color[0] / 255, color[1] / 255, color[2] / 255, color[3]];
330 for (var i = 0; i < 4; i++) {
331 colors = colors.concat(normalizedColor);
337 * @param {!Object} attribute
338 * @param {!Array.<number>} array
339 * @param {!number} length
341 _setVertexAttribute: function(attribute, array, length)
344 var buffer = gl.createBuffer();
345 gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
346 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(array), gl.STATIC_DRAW);
347 gl.vertexAttribPointer(attribute, length, gl.FLOAT, false, 0, 0);
351 * @param {!Array.<number>} vertices
352 * @param {!Array.<number>} color
353 * @param {!Object} glMode
354 * @param {!Object=} texture
356 _drawRectangle: function(vertices, color, glMode, texture)
358 this._setVertexAttribute(this._shaderProgram.vertexPositionAttribute, vertices, 3);
359 this._setVertexAttribute(this._shaderProgram.textureCoordAttribute, [0, 1, 1, 1, 1, 0, 0, 0], 2);
362 var white = [255, 255, 255, 1];
363 this._setVertexAttribute(this._shaderProgram.vertexColorAttribute, this._makeColorsArray(white), white.length);
364 this._gl.activeTexture(this._gl.TEXTURE0);
365 this._gl.bindTexture(this._gl.TEXTURE_2D, texture);
366 this._gl.uniform1i(this._shaderProgram.samplerUniform, 0);
368 this._setVertexAttribute(this._shaderProgram.vertexColorAttribute, this._makeColorsArray(color), color.length);
369 this._gl.bindTexture(this._gl.TEXTURE_2D, this._whiteTexture);
372 var numberOfVertices = 4;
373 this._gl.drawArrays(glMode, 0, numberOfVertices);
377 * @param {!WebInspector.Layers3DView.OutlineType} type
378 * @param {!WebInspector.Layer} layer
379 * @param {number=} scrollRectIndex
381 _isObjectActive: function(type, layer, scrollRectIndex)
383 var activeObject = this._lastActiveObject[type];
384 return activeObject && activeObject.layer && activeObject.layer.id() === layer.id() && (typeof scrollRectIndex !== "number" || activeObject.scrollRectIndex === scrollRectIndex);
388 * @param {!WebInspector.Layer} layer
389 * @return {!{color: !Array.<number>, borderColor: !Array.<number>}}
391 _colorsForLayer: function(layer)
393 var isSelected = this._isObjectActive(WebInspector.Layers3DView.OutlineType.Selected, layer);
394 var isHovered = this._isObjectActive(WebInspector.Layers3DView.OutlineType.Hovered, layer);
395 var color = isSelected ? WebInspector.Layers3DView.SelectedBackgroundColor : WebInspector.Layers3DView.BackgroundColor;
396 var borderColor = isHovered ? WebInspector.Layers3DView.HoveredBorderColor : WebInspector.Layers3DView.BorderColor;
397 return {color: color, borderColor: borderColor};
401 * @param {!Array.<number>} quad
403 * @return {!Array.<number>}
405 _calculateVerticesForQuad: function(quad, z)
407 return [quad[0], quad[1], z, quad[2], quad[3], z, quad[4], quad[5], z, quad[6], quad[7], z];
411 * Finds coordinates of point on layer quad, having offsets (ratioX * width) and (ratioY * height)
412 * from the left corner of the initial layer rect, where width and heigth are layer bounds.
413 * @param {!Array.<number>} quad
414 * @param {number} ratioX
415 * @param {number} ratioY
416 * @return {!Array.<number>}
418 _calculatePointOnQuad: function(quad, ratioX, ratioY)
428 // Point on the first quad side clockwise
429 var firstSidePointX = x0 + ratioX * (x1 - x0);
430 var firstSidePointY = y0 + ratioX * (y1 - y0);
431 // Point on the third quad side clockwise
432 var thirdSidePointX = x3 + ratioX * (x2 - x3);
433 var thirdSidePointY = y3 + ratioX * (y2 - y3);
434 var x = firstSidePointX + ratioY * (thirdSidePointX - firstSidePointX);
435 var y = firstSidePointY + ratioY * (thirdSidePointY - firstSidePointY);
440 * @param {!WebInspector.Layer} layer
441 * @param {!DOMAgent.Rect} rect
442 * @return {!Array.<number>}
444 _calculateRectQuad: function(layer, rect)
446 var quad = layer.quad();
447 var rx1 = rect.x / layer.width();
448 var rx2 = (rect.x + rect.width) / layer.width();
449 var ry1 = rect.y / layer.height();
450 var ry2 = (rect.y + rect.height) / layer.height();
451 return this._calculatePointOnQuad(quad, rx1, ry1).concat(this._calculatePointOnQuad(quad, rx2, ry1))
452 .concat(this._calculatePointOnQuad(quad, rx2, ry2)).concat(this._calculatePointOnQuad(quad, rx1, ry2));
456 * @param {!WebInspector.Layer} layer
457 * @return {!Array.<!Array.<number>>}
459 _calculateScrollRectQuadsForLayer: function(layer)
462 for (var i = 0; i < layer.scrollRects().length; ++i)
463 quads.push(this._calculateRectQuad(layer, layer.scrollRects()[i].rect));
468 * @param {!WebInspector.Layer} layer
469 * @param {number} index
472 _calculateScrollRectDepth: function(layer, index)
474 return this._depthByLayerId[layer.id()] * WebInspector.Layers3DView.LayerSpacing + index * WebInspector.Layers3DView.ScrollRectSpacing + 1;
478 * @param {!WebInspector.Layer} layer
480 _drawLayer: function(layer)
484 if (this._isVisible[layer.id()]) {
485 vertices = this._calculateVerticesForQuad(layer.quad(), this._depthByLayerId[layer.id()] * WebInspector.Layers3DView.LayerSpacing);
486 var colors = this._colorsForLayer(layer);
487 this._drawRectangle(vertices, colors.color, gl.TRIANGLE_FAN, this._textureForLayer[layer.id()]);
488 this._drawRectangle(vertices, colors.borderColor, gl.LINE_LOOP);
490 this._scrollRectQuadsForLayer[layer.id()] = this._calculateScrollRectQuadsForLayer(layer);
491 var scrollRectQuads = this._scrollRectQuadsForLayer[layer.id()];
492 for (var i = 0; i < scrollRectQuads.length; ++i) {
493 vertices = this._calculateVerticesForQuad(scrollRectQuads[i], this._calculateScrollRectDepth(layer, i));
494 var isSelected = this._isObjectActive(WebInspector.Layers3DView.OutlineType.Selected, layer, i);
495 var color = isSelected ? WebInspector.Layers3DView.SelectedScrollRectBackgroundColor : WebInspector.Layers3DView.ScrollRectBackgroundColor;
496 this._drawRectangle(vertices, color, gl.TRIANGLE_FAN);
497 this._drawRectangle(vertices, WebInspector.Layers3DView.ScrollRectBorderColor, gl.LINE_LOOP);
501 _calculateDepths: function()
503 this._depthByLayerId = {};
504 this._isVisible = {};
506 var root = this._model.root();
508 this._depthByLayerId[root.id()] = 0;
509 this._isVisible[root.id()] = false;
510 while (queue.length > 0) {
511 var layer = queue.shift();
512 var children = layer.children();
513 for (var i = 0; i < children.length; ++i) {
514 this._depthByLayerId[children[i].id()] = ++depth;
515 this._isVisible[children[i].id()] = children[i] === this._model.contentRoot() || this._isVisible[layer.id()];
516 queue.push(children[i]);
524 if (!this.isShowing()) {
525 this._needsUpdate = true;
528 if (!this._model.contentRoot()) {
529 this._emptyView.show(this.element);
532 this._emptyView.detach();
534 var gl = this._initGLIfNecessary();
535 this._resizeCanvas();
536 this._initProjectionMatrix();
537 this._calculateDepths();
539 gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
540 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
542 this._model.forEachLayer(this._drawLayer.bind(this), this._model.root());
546 * @param {!WebInspector.Event} event
548 _onLayerPainted: function(event)
554 * Intersects quad with given transform matrix and line l(t) = (x0, y0, t)
555 * @param {!Array.<number>} vertices
556 * @param {!CSSMatrix} matrix
557 * @param {!number} x0
558 * @param {!number} y0
559 * @return {(number|undefined)}
561 _intersectLineAndRect: function(vertices, matrix, x0, y0)
565 // Vertices of the quad with transform matrix applied
567 for (i = 0; i < 4; ++i)
568 points[i] = WebInspector.Geometry.multiplyVectorByMatrixAndNormalize(new WebInspector.Geometry.Vector(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]), matrix);
569 // Calculating quad plane normal
570 var normal = WebInspector.Geometry.crossProduct(WebInspector.Geometry.subtract(points[1], points[0]), WebInspector.Geometry.subtract(points[2], points[1]));
571 // General form of the equation of the quad plane: A * x + B * y + C * z + D = 0
575 var D = -(A * points[0].x + B * points[0].y + C * points[0].z);
576 // Finding t from the equation
577 var t = -(D + A * x0 + B * y0) / C;
578 // Point of the intersection
579 var pt = new WebInspector.Geometry.Vector(x0, y0, t);
580 // Vectors from the intersection point to vertices of the quad
581 var tVects = points.map(WebInspector.Geometry.subtract.bind(null, pt));
582 // Intersection point lies inside of the polygon if scalar products of normal of the plane and
583 // cross products of successive tVects are all nonstrictly above or all nonstrictly below zero
584 for (i = 0; i < tVects.length; ++i) {
585 var product = WebInspector.Geometry.scalarProduct(normal, WebInspector.Geometry.crossProduct(tVects[i], tVects[(i + 1) % tVects.length]));
593 * @param {?Event} event
594 * @return {?WebInspector.LayersPanel.ActiveObject}
596 _layerFromEventPoint: function(event)
598 if (!this._model.contentRoot())
600 var closestIntersectionPoint = Infinity;
601 var closestLayer = null;
602 var projectionMatrix = new WebKitCSSMatrix().scale(1, -1, -1).translate(-1, -1, 0).multiply(this._calculateProjectionMatrix());
603 var x0 = (event.clientX - this._canvasElement.totalOffsetLeft()) * window.devicePixelRatio;
604 var y0 = -(event.clientY - this._canvasElement.totalOffsetTop()) * window.devicePixelRatio;
607 * @param {!WebInspector.Layer} layer
608 * @this {WebInspector.Layers3DView}
610 function checkIntersection(layer)
613 if (this._isVisible[layer.id()]) {
614 t = this._intersectLineAndRect(this._calculateVerticesForQuad(layer.quad(), this._depthByLayerId[layer.id()] * WebInspector.Layers3DView.LayerSpacing), projectionMatrix, x0, y0);
615 if (t < closestIntersectionPoint) {
616 closestIntersectionPoint = t;
617 closestLayer = {layer: layer};
620 var scrollRectQuads = this._scrollRectQuadsForLayer[layer.id()];
621 for (var i = 0; i < scrollRectQuads.length; ++i) {
622 t = this._intersectLineAndRect(this._calculateVerticesForQuad(scrollRectQuads[i], this._calculateScrollRectDepth(layer, i)), projectionMatrix, x0, y0);
623 if (t < closestIntersectionPoint) {
624 closestIntersectionPoint = t;
625 closestLayer = {layer: layer, scrollRectIndex: i};
630 this._model.forEachLayer(checkIntersection.bind(this), this._model.root());
635 * @param {?Event} event
637 _onContextMenu: function(event)
639 var layer = this._layerFromEventPoint(event).layer;
640 var node = layer ? layer.nodeForSelfOrAncestor() : null;
641 var contextMenu = new WebInspector.ContextMenu(event);
642 contextMenu.appendItem("Reset view", this._transformController._resetAndNotify.bind(this._transformController), false);
644 contextMenu.appendApplicableItems(node);
649 * @param {?Event} event
651 _onMouseMove: function(event)
655 this.dispatchEventToListeners(WebInspector.Layers3DView.Events.ObjectHovered, this._layerFromEventPoint(event));
659 * @param {?Event} event
661 _onMouseDown: function(event)
663 this._mouseDownX = event.clientX;
664 this._mouseDownY = event.clientY;
668 * @param {?Event} event
670 _onMouseUp: function(event)
672 const maxDistanceInPixels = 6;
673 if (this._mouseDownX && Math.abs(event.clientX - this._mouseDownX) < maxDistanceInPixels && Math.abs(event.clientY - this._mouseDownY) < maxDistanceInPixels)
674 this.dispatchEventToListeners(WebInspector.Layers3DView.Events.ObjectSelected, this._layerFromEventPoint(event));
675 delete this._mouseDownX;
676 delete this._mouseDownY;
680 * @param {?Event} event
682 _onDoubleClick: function(event)
684 var object = this._layerFromEventPoint(event);
685 if (object && object.layer)
686 this.dispatchEventToListeners(WebInspector.Layers3DView.Events.LayerSnapshotRequested, object.layer);
687 event.stopPropagation();
690 __proto__: WebInspector.VBox.prototype