OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2014 Google Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions are | |
6 * met: | |
7 * | |
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 | |
13 * distribution. | |
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. | |
17 * | |
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. | |
29 */ | |
30 | |
31 /** | |
32 * @constructor | |
33 * @extends {WebInspector.VBox} | |
34 * @param {!WebInspector.LayerViewHost} layerViewHost | |
35 * @implements {WebInspector.LayerView} | |
36 */ | |
37 WebInspector.Layers3DView = function(layerViewHost) | |
38 { | |
39 WebInspector.VBox.call(this); | |
40 this.element.classList.add("layers-3d-view"); | |
41 this._failBanner = new WebInspector.VBox(); | |
42 this._failBanner.element.classList.add("banner"); | |
43 this._failBanner.element.createTextChild(WebInspector.UIString("Layer inform
ation is not yet available.")); | |
44 | |
45 this._layerViewHost = layerViewHost; | |
46 this._layerViewHost.registerView(this); | |
47 | |
48 this._transformController = new WebInspector.TransformController(this.elemen
t); | |
49 this._transformController.addEventListener(WebInspector.TransformController.
Events.TransformChanged, this._update, this); | |
50 this._initToolbar(); | |
51 | |
52 this._canvasElement = this.element.createChild("canvas"); | |
53 this._canvasElement.tabIndex = 0; | |
54 this._canvasElement.addEventListener("dblclick", this._onDoubleClick.bind(th
is), false); | |
55 this._canvasElement.addEventListener("mousedown", this._onMouseDown.bind(thi
s), false); | |
56 this._canvasElement.addEventListener("mouseup", this._onMouseUp.bind(this),
false); | |
57 this._canvasElement.addEventListener("mouseleave", this._onMouseMove.bind(th
is), false); | |
58 this._canvasElement.addEventListener("mousemove", this._onMouseMove.bind(thi
s), false); | |
59 this._canvasElement.addEventListener("contextmenu", this._onContextMenu.bind
(this), false); | |
60 | |
61 this._lastSelection = {}; | |
62 this._layerTree = null; | |
63 this._textureManager = new WebInspector.LayerTextureManager(); | |
64 this._textureManager.addEventListener(WebInspector.LayerTextureManager.Event
s.TextureUpdated, this._update, this); | |
65 /** @type Array.<!WebGLTexture|undefined> */ | |
66 this._chromeTextures = []; | |
67 this._rects = []; | |
68 | |
69 this._layerViewHost.showInternalLayersSetting().addChangeListener(this._upda
te, this); | |
70 } | |
71 | |
72 /** @typedef {{borderColor: !Array.<number>, borderWidth: number}} */ | |
73 WebInspector.Layers3DView.LayerStyle; | |
74 | |
75 /** @typedef {{layerId: string, rect: !Array.<number>, snapshot: !WebInspector.P
aintProfilerSnapshot, traceEvent: !WebInspector.TracingModel.Event}} */ | |
76 WebInspector.Layers3DView.PaintTile; | |
77 | |
78 /** | |
79 * @enum {string} | |
80 */ | |
81 WebInspector.Layers3DView.OutlineType = { | |
82 Hovered: "hovered", | |
83 Selected: "selected" | |
84 } | |
85 | |
86 /** | |
87 * @enum {string} | |
88 */ | |
89 /** @enum {symbol} */ | |
90 WebInspector.Layers3DView.Events = { | |
91 LayerSnapshotRequested: Symbol("LayerSnapshotRequested"), | |
92 PaintProfilerRequested: Symbol("PaintProfilerRequested") | |
93 } | |
94 | |
95 /** | |
96 * @enum {number} | |
97 */ | |
98 WebInspector.Layers3DView.ChromeTexture = { | |
99 Left: 0, | |
100 Middle: 1, | |
101 Right: 2 | |
102 } | |
103 | |
104 /** | |
105 * @enum {string} | |
106 */ | |
107 WebInspector.Layers3DView.ScrollRectTitles = { | |
108 RepaintsOnScroll: WebInspector.UIString("repaints on scroll"), | |
109 TouchEventHandler: WebInspector.UIString("touch event listener"), | |
110 WheelEventHandler: WebInspector.UIString("mousewheel event listener") | |
111 } | |
112 | |
113 WebInspector.Layers3DView.FragmentShader = "" + | |
114 "precision mediump float;\n" + | |
115 "varying vec4 vColor;\n" + | |
116 "varying vec2 vTextureCoord;\n" + | |
117 "uniform sampler2D uSampler;\n" + | |
118 "void main(void)\n" + | |
119 "{\n" + | |
120 " gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.
t)) * vColor;\n" + | |
121 "}"; | |
122 | |
123 WebInspector.Layers3DView.VertexShader = "" + | |
124 "attribute vec3 aVertexPosition;\n" + | |
125 "attribute vec2 aTextureCoord;\n" + | |
126 "attribute vec4 aVertexColor;\n" + | |
127 "uniform mat4 uPMatrix;\n" + | |
128 "varying vec2 vTextureCoord;\n" + | |
129 "varying vec4 vColor;\n" + | |
130 "void main(void)\n" + | |
131 "{\n" + | |
132 "gl_Position = uPMatrix * vec4(aVertexPosition, 1.0);\n" + | |
133 "vColor = aVertexColor;\n" + | |
134 "vTextureCoord = aTextureCoord;\n" + | |
135 "}"; | |
136 | |
137 WebInspector.Layers3DView.HoveredBorderColor = [0, 0, 255, 1]; | |
138 WebInspector.Layers3DView.SelectedBorderColor = [0, 255, 0, 1]; | |
139 WebInspector.Layers3DView.BorderColor = [0, 0, 0, 1]; | |
140 WebInspector.Layers3DView.ViewportBorderColor = [160, 160, 160, 1]; | |
141 WebInspector.Layers3DView.ScrollRectBackgroundColor = [178, 100, 100, 0.6]; | |
142 WebInspector.Layers3DView.HoveredImageMaskColor = [200, 200, 255, 1]; | |
143 WebInspector.Layers3DView.BorderWidth = 1; | |
144 WebInspector.Layers3DView.SelectedBorderWidth = 2; | |
145 WebInspector.Layers3DView.ViewportBorderWidth = 3; | |
146 | |
147 WebInspector.Layers3DView.LayerSpacing = 20; | |
148 WebInspector.Layers3DView.ScrollRectSpacing = 4; | |
149 | |
150 WebInspector.Layers3DView.prototype = { | |
151 /** | |
152 * @param {?WebInspector.LayerTreeBase} layerTree | |
153 * @override | |
154 */ | |
155 setLayerTree: function(layerTree) | |
156 { | |
157 this._layerTree = layerTree; | |
158 this._textureManager.reset(); | |
159 this._update(); | |
160 }, | |
161 | |
162 /** | |
163 * @param {?Array.<!WebInspector.Layers3DView.PaintTile>} tiles | |
164 */ | |
165 setTiles: function(tiles) | |
166 { | |
167 this._textureManager.setTiles(tiles); | |
168 }, | |
169 | |
170 /** | |
171 * @param {!WebInspector.Layer} layer | |
172 * @param {string=} imageURL | |
173 */ | |
174 showImageForLayer: function(layer, imageURL) | |
175 { | |
176 if (imageURL) | |
177 this._textureManager.createTexture(onTextureCreated.bind(this), imag
eURL); | |
178 else | |
179 onTextureCreated.call(this, null); | |
180 | |
181 /** | |
182 * @this {WebInspector.Layers3DView} | |
183 * @param {?WebGLTexture} texture | |
184 */ | |
185 function onTextureCreated(texture) | |
186 { | |
187 this._layerTexture = texture ? {layerId: layer.id(), texture: textur
e} : null; | |
188 this._update(); | |
189 } | |
190 }, | |
191 | |
192 onResize: function() | |
193 { | |
194 this._resizeCanvas(); | |
195 this._update(); | |
196 }, | |
197 | |
198 wasShown: function() | |
199 { | |
200 if (!this._needsUpdate) | |
201 return; | |
202 this._resizeCanvas(); | |
203 this._update(); | |
204 }, | |
205 | |
206 /** | |
207 * @param {!WebInspector.Layers3DView.OutlineType} type | |
208 * @param {?WebInspector.LayerView.Selection} selection | |
209 */ | |
210 _setOutline: function(type, selection) | |
211 { | |
212 this._lastSelection[type] = selection; | |
213 this._update(); | |
214 }, | |
215 | |
216 /** | |
217 * @param {?WebInspector.LayerView.Selection} selection | |
218 * @override | |
219 */ | |
220 hoverObject: function(selection) | |
221 { | |
222 this._setOutline(WebInspector.Layers3DView.OutlineType.Hovered, selectio
n); | |
223 }, | |
224 | |
225 /** | |
226 * @param {?WebInspector.LayerView.Selection} selection | |
227 * @override | |
228 */ | |
229 selectObject: function(selection) | |
230 { | |
231 this._setOutline(WebInspector.Layers3DView.OutlineType.Hovered, null); | |
232 this._setOutline(WebInspector.Layers3DView.OutlineType.Selected, selecti
on); | |
233 }, | |
234 | |
235 /** | |
236 * @param {!Element} canvas | |
237 * @return {?WebGLRenderingContext} | |
238 */ | |
239 _initGL: function(canvas) | |
240 { | |
241 var gl = canvas.getContext("webgl"); | |
242 if (!gl) | |
243 return null; | |
244 gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); | |
245 gl.enable(gl.BLEND); | |
246 gl.clearColor(0.0, 0.0, 0.0, 0.0); | |
247 gl.enable(gl.DEPTH_TEST); | |
248 return gl; | |
249 }, | |
250 | |
251 /** | |
252 * @param {!Object} type | |
253 * @param {string} script | |
254 */ | |
255 _createShader: function(type, script) | |
256 { | |
257 var shader = this._gl.createShader(type); | |
258 this._gl.shaderSource(shader, script); | |
259 this._gl.compileShader(shader); | |
260 this._gl.attachShader(this._shaderProgram, shader); | |
261 }, | |
262 | |
263 _initShaders: function() | |
264 { | |
265 this._shaderProgram = this._gl.createProgram(); | |
266 this._createShader(this._gl.FRAGMENT_SHADER, WebInspector.Layers3DView.F
ragmentShader); | |
267 this._createShader(this._gl.VERTEX_SHADER, WebInspector.Layers3DView.Ver
texShader); | |
268 this._gl.linkProgram(this._shaderProgram); | |
269 this._gl.useProgram(this._shaderProgram); | |
270 | |
271 this._shaderProgram.vertexPositionAttribute = this._gl.getAttribLocation
(this._shaderProgram, "aVertexPosition"); | |
272 this._gl.enableVertexAttribArray(this._shaderProgram.vertexPositionAttri
bute); | |
273 this._shaderProgram.vertexColorAttribute = this._gl.getAttribLocation(th
is._shaderProgram, "aVertexColor"); | |
274 this._gl.enableVertexAttribArray(this._shaderProgram.vertexColorAttribut
e); | |
275 this._shaderProgram.textureCoordAttribute = this._gl.getAttribLocation(t
his._shaderProgram, "aTextureCoord"); | |
276 this._gl.enableVertexAttribArray(this._shaderProgram.textureCoordAttribu
te); | |
277 | |
278 this._shaderProgram.pMatrixUniform = this._gl.getUniformLocation(this._s
haderProgram, "uPMatrix"); | |
279 this._shaderProgram.samplerUniform = this._gl.getUniformLocation(this._s
haderProgram, "uSampler"); | |
280 }, | |
281 | |
282 _resizeCanvas: function() | |
283 { | |
284 this._canvasElement.width = this._canvasElement.offsetWidth * window.dev
icePixelRatio; | |
285 this._canvasElement.height = this._canvasElement.offsetHeight * window.d
evicePixelRatio; | |
286 }, | |
287 | |
288 _updateTransformAndConstraints: function() | |
289 { | |
290 var paddingFraction = 0.1; | |
291 var viewport = this._layerTree.viewportSize(); | |
292 var root = this._layerTree.root(); | |
293 var baseWidth = viewport ? viewport.width : this._dimensionsForAutoscale
.width; | |
294 var baseHeight = viewport ? viewport.height : this._dimensionsForAutosca
le.height; | |
295 var canvasWidth = this._canvasElement.width; | |
296 var canvasHeight = this._canvasElement.height; | |
297 var paddingX = canvasWidth * paddingFraction; | |
298 var paddingY = canvasHeight * paddingFraction; | |
299 var scaleX = (canvasWidth - 2 * paddingX) / baseWidth; | |
300 var scaleY = (canvasHeight - 2 * paddingY) / baseHeight; | |
301 var viewScale = Math.min(scaleX, scaleY); | |
302 var minScaleConstraint = Math.min(baseWidth / this._dimensionsForAutosca
le.width, baseHeight / this._dimensionsForAutoscale.width) / 2; | |
303 this._transformController.setScaleConstraints(minScaleConstraint, 10 / v
iewScale); // 1/viewScale is 1:1 in terms of pixels, so allow zooming to 10x of
native size | |
304 var scale = this._transformController.scale(); | |
305 var rotateX = this._transformController.rotateX(); | |
306 var rotateY = this._transformController.rotateY(); | |
307 this._scale = scale * viewScale; | |
308 var scaleAndRotationMatrix = new WebKitCSSMatrix().scale(scale, scale, s
cale).translate(canvasWidth / 2, canvasHeight / 2, 0) | |
309 .rotate(rotateX, rotateY, 0).scale(viewScale, viewScale, viewScale).
translate(-baseWidth / 2, -baseHeight / 2, 0); | |
310 | |
311 var bounds; | |
312 for (var i = 0; i < this._rects.length; ++i) | |
313 bounds = WebInspector.Geometry.boundsForTransformedPoints(scaleAndRo
tationMatrix, this._rects[i].vertices, bounds); | |
314 | |
315 this._transformController.clampOffsets((paddingX - bounds.maxX) / window
.devicePixelRatio, (canvasWidth - paddingX - bounds.minX) / window.devicePixelRa
tio, | |
316 (paddingY - bounds.maxY) / window
.devicePixelRatio, (canvasHeight - paddingY - bounds.minY) / window.devicePixelR
atio); | |
317 var offsetX = this._transformController.offsetX() * window.devicePixelRa
tio; | |
318 var offsetY = this._transformController.offsetY() * window.devicePixelRa
tio; | |
319 // Multiply to translation matrix on the right rather than translate (wh
ich would implicitly multiply on the left). | |
320 this._projectionMatrix = new WebKitCSSMatrix().translate(offsetX, offset
Y, 0).multiply(scaleAndRotationMatrix); | |
321 | |
322 var glProjectionMatrix = new WebKitCSSMatrix().scale(1, -1, -1).translat
e(-1, -1, 0) | |
323 .scale(2 / this._canvasElement.width, 2 / this._canvasElement.height
, 1 / 1000000).multiply(this._projectionMatrix); | |
324 this._gl.uniformMatrix4fv(this._shaderProgram.pMatrixUniform, false, thi
s._arrayFromMatrix(glProjectionMatrix)); | |
325 }, | |
326 | |
327 /** | |
328 * @param {!CSSMatrix} m | |
329 * @return {!Float32Array} | |
330 */ | |
331 _arrayFromMatrix: function(m) | |
332 { | |
333 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]); | |
334 }, | |
335 | |
336 _initWhiteTexture: function() | |
337 { | |
338 this._whiteTexture = this._gl.createTexture(); | |
339 this._gl.bindTexture(this._gl.TEXTURE_2D, this._whiteTexture); | |
340 var whitePixel = new Uint8Array([255, 255, 255, 255]); | |
341 this._gl.texImage2D(this._gl.TEXTURE_2D, 0, this._gl.RGBA, 1, 1, 0, this
._gl.RGBA, this._gl.UNSIGNED_BYTE, whitePixel); | |
342 }, | |
343 | |
344 _initChromeTextures: function() | |
345 { | |
346 /** | |
347 * @this {WebInspector.Layers3DView} | |
348 * @param {!WebInspector.Layers3DView.ChromeTexture} index | |
349 * @param {?WebGLTexture} value | |
350 */ | |
351 function saveChromeTexture(index, value) | |
352 { | |
353 this._chromeTextures[index] = value || undefined; | |
354 } | |
355 this._textureManager.createTexture(saveChromeTexture.bind(this, WebInspe
ctor.Layers3DView.ChromeTexture.Left), "Images/chromeLeft.png"); | |
356 this._textureManager.createTexture(saveChromeTexture.bind(this, WebInspe
ctor.Layers3DView.ChromeTexture.Middle), "Images/chromeMiddle.png"); | |
357 this._textureManager.createTexture(saveChromeTexture.bind(this, WebInspe
ctor.Layers3DView.ChromeTexture.Right), "Images/chromeRight.png"); | |
358 }, | |
359 | |
360 /** | |
361 * @return {?WebGLRenderingContext} | |
362 */ | |
363 _initGLIfNecessary: function() | |
364 { | |
365 if (this._gl) | |
366 return this._gl; | |
367 this._gl = this._initGL(this._canvasElement); | |
368 if (!this._gl) | |
369 return null; | |
370 this._initShaders(); | |
371 this._initWhiteTexture(); | |
372 this._initChromeTextures(); | |
373 this._textureManager.setContext(this._gl); | |
374 return this._gl; | |
375 }, | |
376 | |
377 _calculateDepthsAndVisibility: function() | |
378 { | |
379 this._depthByLayerId = {}; | |
380 var depth = 0; | |
381 var showInternalLayers = this._layerViewHost.showInternalLayersSetting()
.get(); | |
382 var root = showInternalLayers ? this._layerTree.root() : (this._layerTre
e.contentRoot() || this._layerTree.root()); | |
383 var queue = [root]; | |
384 this._depthByLayerId[root.id()] = 0; | |
385 this._visibleLayers = {}; | |
386 while (queue.length > 0) { | |
387 var layer = queue.shift(); | |
388 this._visibleLayers[layer.id()] = showInternalLayers || layer.drawsC
ontent(); | |
389 var children = layer.children(); | |
390 for (var i = 0; i < children.length; ++i) { | |
391 this._depthByLayerId[children[i].id()] = ++depth; | |
392 queue.push(children[i]); | |
393 } | |
394 } | |
395 this._maxDepth = depth; | |
396 }, | |
397 | |
398 /** | |
399 * @param {!WebInspector.Layer} layer | |
400 * @return {number} | |
401 */ | |
402 _depthForLayer: function(layer) | |
403 { | |
404 return this._depthByLayerId[layer.id()] * WebInspector.Layers3DView.Laye
rSpacing; | |
405 }, | |
406 | |
407 /** | |
408 * @param {!WebInspector.Layer} layer | |
409 * @param {number} index | |
410 * @return {number} | |
411 */ | |
412 _calculateScrollRectDepth: function(layer, index) | |
413 { | |
414 return this._depthForLayer(layer) + index * WebInspector.Layers3DView.Sc
rollRectSpacing + 1; | |
415 }, | |
416 | |
417 /** | |
418 * @param {!WebInspector.Layer} layer | |
419 */ | |
420 _updateDimensionsForAutoscale: function(layer) | |
421 { | |
422 // We don't want to be precise, but rather pick something least affected
by | |
423 // animationtransforms, so that we don't change scale too often. So let'
s | |
424 // disregard transforms, scrolling and relative layer positioning and ch
oose | |
425 // the largest dimensions of all layers. | |
426 this._dimensionsForAutoscale.width = Math.max(layer.width(), this._dimen
sionsForAutoscale.width); | |
427 this._dimensionsForAutoscale.height = Math.max(layer.height(), this._dim
ensionsForAutoscale.height); | |
428 }, | |
429 | |
430 /** | |
431 * @param {!WebInspector.Layer} layer | |
432 */ | |
433 _calculateLayerRect: function(layer) | |
434 { | |
435 if (!this._visibleLayers[layer.id()]) | |
436 return; | |
437 var selection = new WebInspector.LayerView.LayerSelection(layer); | |
438 var rect = new WebInspector.Layers3DView.Rectangle(selection); | |
439 rect.setVertices(layer.quad(), this._depthForLayer(layer)); | |
440 this._appendRect(rect); | |
441 this._updateDimensionsForAutoscale(layer); | |
442 }, | |
443 | |
444 /** | |
445 * @param {!WebInspector.Layers3DView.Rectangle} rect | |
446 */ | |
447 _appendRect: function(rect) | |
448 { | |
449 var selection = rect.relatedObject; | |
450 var isSelected = WebInspector.LayerView.Selection.isEqual(this._lastSele
ction[WebInspector.Layers3DView.OutlineType.Selected], selection); | |
451 var isHovered = WebInspector.LayerView.Selection.isEqual(this._lastSelec
tion[WebInspector.Layers3DView.OutlineType.Hovered], selection); | |
452 if (isSelected) { | |
453 rect.borderColor = WebInspector.Layers3DView.SelectedBorderColor; | |
454 } else if (isHovered) { | |
455 rect.borderColor = WebInspector.Layers3DView.HoveredBorderColor; | |
456 var fillColor = rect.fillColor || [255, 255, 255, 1]; | |
457 var maskColor = WebInspector.Layers3DView.HoveredImageMaskColor; | |
458 rect.fillColor = [fillColor[0] * maskColor[0] / 255, fillColor[1] *
maskColor[1] / 255, fillColor[2] * maskColor[2] / 255, fillColor[3] * maskColor[
3]]; | |
459 } else { | |
460 rect.borderColor = WebInspector.Layers3DView.BorderColor; | |
461 } | |
462 rect.lineWidth = isSelected ? WebInspector.Layers3DView.SelectedBorderWi
dth : WebInspector.Layers3DView.BorderWidth; | |
463 this._rects.push(rect); | |
464 }, | |
465 | |
466 /** | |
467 * @param {!WebInspector.Layer} layer | |
468 */ | |
469 _calculateLayerScrollRects: function(layer) | |
470 { | |
471 var scrollRects = layer.scrollRects(); | |
472 for (var i = 0; i < scrollRects.length; ++i) { | |
473 var selection = new WebInspector.LayerView.ScrollRectSelection(layer
, i); | |
474 var rect = new WebInspector.Layers3DView.Rectangle(selection); | |
475 rect.calculateVerticesFromRect(layer, scrollRects[i].rect, this._cal
culateScrollRectDepth(layer, i)); | |
476 rect.fillColor = WebInspector.Layers3DView.ScrollRectBackgroundColor
; | |
477 this._appendRect(rect); | |
478 } | |
479 }, | |
480 | |
481 /** | |
482 * @param {!WebInspector.Layer} layer | |
483 */ | |
484 _calculateLayerImageRect: function(layer) | |
485 { | |
486 var layerTexture = this._layerTexture; | |
487 if (layer.id() !== layerTexture.layerId) | |
488 return; | |
489 var selection = new WebInspector.LayerView.LayerSelection(layer); | |
490 var rect = new WebInspector.Layers3DView.Rectangle(selection); | |
491 rect.setVertices(layer.quad(), this._depthForLayer(layer)); | |
492 rect.texture = layerTexture.texture; | |
493 this._appendRect(rect); | |
494 }, | |
495 | |
496 /** | |
497 * @param {!WebInspector.Layer} layer | |
498 */ | |
499 _calculateLayerTileRects: function(layer) | |
500 { | |
501 var tiles = this._textureManager.tilesForLayer(layer.id()); | |
502 for (var i = 0; i < tiles.length; ++i) { | |
503 var tile = tiles[i]; | |
504 if (!tile.texture) | |
505 continue; | |
506 var selection = new WebInspector.LayerView.TileSelection(layer, tile
.traceEvent); | |
507 var rect = new WebInspector.Layers3DView.Rectangle(selection); | |
508 rect.calculateVerticesFromRect(layer, {x: tile.rect[0], y: tile.rect
[1], width: tile.rect[2], height: tile.rect[3]}, this._depthForLayer(layer) + 1)
; | |
509 rect.texture = tile.texture; | |
510 this._appendRect(rect); | |
511 } | |
512 }, | |
513 | |
514 _calculateRects: function() | |
515 { | |
516 this._rects = []; | |
517 this._dimensionsForAutoscale = { width: 0, height: 0 }; | |
518 this._layerTree.forEachLayer(this._calculateLayerRect.bind(this)); | |
519 | |
520 if (this._showSlowScrollRectsSetting.get()) | |
521 this._layerTree.forEachLayer(this._calculateLayerScrollRects.bind(th
is)); | |
522 | |
523 if (this._showPaintsSetting.get()) { | |
524 if (this._layerTexture) | |
525 this._layerTree.forEachLayer(this._calculateLayerImageRect.bind(
this)); | |
526 else | |
527 this._layerTree.forEachLayer(this._calculateLayerTileRects.bind(
this)); | |
528 } | |
529 }, | |
530 | |
531 /** | |
532 * @param {!Array.<number>} color | |
533 * @return {!Array.<number>} | |
534 */ | |
535 _makeColorsArray: function(color) | |
536 { | |
537 var colors = []; | |
538 var normalizedColor = [color[0] / 255, color[1] / 255, color[2] / 255, c
olor[3]]; | |
539 for (var i = 0; i < 4; i++) | |
540 colors = colors.concat(normalizedColor); | |
541 return colors; | |
542 }, | |
543 | |
544 /** | |
545 * @param {!Object} attribute | |
546 * @param {!Array.<number>} array | |
547 * @param {number} length | |
548 */ | |
549 _setVertexAttribute: function(attribute, array, length) | |
550 { | |
551 var gl = this._gl; | |
552 var buffer = gl.createBuffer(); | |
553 gl.bindBuffer(gl.ARRAY_BUFFER, buffer); | |
554 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(array), gl.STATIC_DRAW); | |
555 gl.vertexAttribPointer(attribute, length, gl.FLOAT, false, 0, 0); | |
556 }, | |
557 | |
558 /** | |
559 * @param {!Array.<number>} vertices | |
560 * @param {number} mode | |
561 * @param {!Array.<number>=} color | |
562 * @param {!Object=} texture | |
563 */ | |
564 _drawRectangle: function(vertices, mode, color, texture) | |
565 { | |
566 var gl = this._gl; | |
567 var white = [255, 255, 255, 1]; | |
568 color = color || white; | |
569 this._setVertexAttribute(this._shaderProgram.vertexPositionAttribute, ve
rtices, 3); | |
570 this._setVertexAttribute(this._shaderProgram.textureCoordAttribute, [0,
1, 1, 1, 1, 0, 0, 0], 2); | |
571 this._setVertexAttribute(this._shaderProgram.vertexColorAttribute, this.
_makeColorsArray(color), color.length); | |
572 | |
573 if (texture) { | |
574 gl.activeTexture(gl.TEXTURE0); | |
575 gl.bindTexture(gl.TEXTURE_2D, texture); | |
576 gl.uniform1i(this._shaderProgram.samplerUniform, 0); | |
577 } else { | |
578 gl.bindTexture(gl.TEXTURE_2D, this._whiteTexture); | |
579 } | |
580 | |
581 var numberOfVertices = vertices.length / 3; | |
582 gl.drawArrays(mode, 0, numberOfVertices); | |
583 }, | |
584 | |
585 /** | |
586 * @param {!Array.<number>} vertices | |
587 * @param {!WebGLTexture} texture | |
588 * @param {!Array.<number>=} color | |
589 */ | |
590 _drawTexture: function(vertices, texture, color) | |
591 { | |
592 this._drawRectangle(vertices, this._gl.TRIANGLE_FAN, color, texture); | |
593 }, | |
594 | |
595 _drawViewportAndChrome: function() | |
596 { | |
597 var viewport = this._layerTree.viewportSize(); | |
598 if (!viewport) | |
599 return; | |
600 | |
601 var drawChrome = !WebInspector.moduleSetting("frameViewerHideChromeWindo
w").get() && this._chromeTextures.length >= 3 && this._chromeTextures.indexOf(un
defined) < 0; | |
602 var z = (this._maxDepth + 1) * WebInspector.Layers3DView.LayerSpacing; | |
603 var borderWidth = Math.ceil(WebInspector.Layers3DView.ViewportBorderWidt
h * this._scale); | |
604 var vertices = [viewport.width, 0, z, viewport.width, viewport.height, z
, 0, viewport.height, z, 0, 0, z]; | |
605 this._gl.lineWidth(borderWidth); | |
606 this._drawRectangle(vertices, drawChrome ? this._gl.LINE_STRIP : this._g
l.LINE_LOOP, WebInspector.Layers3DView.ViewportBorderColor); | |
607 | |
608 if (!drawChrome) | |
609 return; | |
610 | |
611 var borderAdjustment = WebInspector.Layers3DView.ViewportBorderWidth / 2
; | |
612 var viewportWidth = this._layerTree.viewportSize().width + 2 * borderAdj
ustment; | |
613 var chromeHeight = this._chromeTextures[0].image.naturalHeight; | |
614 var middleFragmentWidth = viewportWidth - this._chromeTextures[0].image.
naturalWidth - this._chromeTextures[2].image.naturalWidth; | |
615 var x = -borderAdjustment; | |
616 var y = -chromeHeight; | |
617 for (var i = 0; i < this._chromeTextures.length; ++i) { | |
618 var width = i === WebInspector.Layers3DView.ChromeTexture.Middle ? m
iddleFragmentWidth : this._chromeTextures[i].image.naturalWidth; | |
619 if (width < 0 || x + width > viewportWidth) | |
620 break; | |
621 vertices = [x, y, z, x + width, y, z, x + width, y + chromeHeight, z
, x, y + chromeHeight, z]; | |
622 this._drawTexture(vertices, /** @type {!WebGLTexture} */ (this._chro
meTextures[i])); | |
623 x += width; | |
624 } | |
625 }, | |
626 | |
627 /** | |
628 * @param {!WebInspector.Layers3DView.Rectangle} rect | |
629 */ | |
630 _drawViewRect: function(rect) | |
631 { | |
632 var vertices = rect.vertices; | |
633 if (rect.texture) | |
634 this._drawTexture(vertices, rect.texture, rect.fillColor || undefine
d); | |
635 else if (rect.fillColor) | |
636 this._drawRectangle(vertices, this._gl.TRIANGLE_FAN, rect.fillColor)
; | |
637 this._gl.lineWidth(rect.lineWidth); | |
638 if (rect.borderColor) | |
639 this._drawRectangle(vertices, this._gl.LINE_LOOP, rect.borderColor); | |
640 }, | |
641 | |
642 _update: function() | |
643 { | |
644 if (!this.isShowing()) { | |
645 this._needsUpdate = true; | |
646 return; | |
647 } | |
648 if (!this._layerTree || !this._layerTree.root()) { | |
649 this._failBanner.show(this.element); | |
650 return; | |
651 } | |
652 var gl = this._initGLIfNecessary(); | |
653 if (!gl) { | |
654 this._failBanner.element.removeChildren(); | |
655 this._failBanner.element.appendChild(this._webglDisabledBanner()); | |
656 this._failBanner.show(this.element); | |
657 return; | |
658 } | |
659 this._failBanner.detach(); | |
660 this._gl.viewportWidth = this._canvasElement.width; | |
661 this._gl.viewportHeight = this._canvasElement.height; | |
662 | |
663 this._calculateDepthsAndVisibility(); | |
664 this._calculateRects(); | |
665 this._updateTransformAndConstraints(); | |
666 | |
667 this._textureManager.setScale(Number.constrain(0.1, 1, this._scale)); | |
668 gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); | |
669 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); | |
670 | |
671 this._rects.forEach(this._drawViewRect.bind(this)); | |
672 this._drawViewportAndChrome(); | |
673 }, | |
674 | |
675 /** | |
676 * @return {!Node} | |
677 */ | |
678 _webglDisabledBanner: function() | |
679 { | |
680 var fragment = this.element.ownerDocument.createDocumentFragment(); | |
681 fragment.createChild("div").textContent = WebInspector.UIString("Can't d
isplay layers,"); | |
682 fragment.createChild("div").textContent = WebInspector.UIString("WebGL s
upport is disabled in your browser."); | |
683 fragment.appendChild(WebInspector.formatLocalized("Check %s for possible
reasons.", [WebInspector.linkifyURLAsNode("about:gpu", undefined, undefined, tr
ue)])); | |
684 return fragment; | |
685 }, | |
686 | |
687 /** | |
688 * @param {!Event} event | |
689 * @return {?WebInspector.LayerView.Selection} | |
690 */ | |
691 _selectionFromEventPoint: function(event) | |
692 { | |
693 if (!this._layerTree) | |
694 return null; | |
695 var closestIntersectionPoint = Infinity; | |
696 var closestObject = null; | |
697 var projectionMatrix = new WebKitCSSMatrix().scale(1, -1, -1).translate(
-1, -1, 0).multiply(this._projectionMatrix); | |
698 var x0 = (event.clientX - this._canvasElement.totalOffsetLeft()) * windo
w.devicePixelRatio; | |
699 var y0 = -(event.clientY - this._canvasElement.totalOffsetTop()) * windo
w.devicePixelRatio; | |
700 | |
701 /** | |
702 * @param {!WebInspector.Layers3DView.Rectangle} rect | |
703 */ | |
704 function checkIntersection(rect) | |
705 { | |
706 if (!rect.relatedObject) | |
707 return; | |
708 var t = rect.intersectWithLine(projectionMatrix, x0, y0); | |
709 if (t < closestIntersectionPoint) { | |
710 closestIntersectionPoint = t; | |
711 closestObject = rect.relatedObject; | |
712 } | |
713 } | |
714 | |
715 this._rects.forEach(checkIntersection); | |
716 return closestObject; | |
717 }, | |
718 | |
719 /** | |
720 * @param {string} caption | |
721 * @param {string} name | |
722 * @param {boolean} value | |
723 * @param {!WebInspector.Toolbar} toolbar | |
724 * @return {!WebInspector.Setting} | |
725 */ | |
726 _createVisibilitySetting: function(caption, name, value, toolbar) | |
727 { | |
728 var checkbox = new WebInspector.ToolbarCheckbox(WebInspector.UIString(ca
ption)); | |
729 toolbar.appendToolbarItem(checkbox); | |
730 var setting = WebInspector.settings.createSetting(name, value); | |
731 WebInspector.SettingsUI.bindCheckbox(checkbox.inputElement, setting); | |
732 setting.addChangeListener(this._update, this); | |
733 return setting; | |
734 }, | |
735 | |
736 _initToolbar: function() | |
737 { | |
738 this._panelToolbar = this._transformController.toolbar(); | |
739 this.element.appendChild(this._panelToolbar.element); | |
740 this._showSlowScrollRectsSetting = this._createVisibilitySetting("Slow s
croll rects", "frameViewerShowSlowScrollRects", true, this._panelToolbar); | |
741 this._showPaintsSetting = this._createVisibilitySetting("Paints", "frame
ViewerShowPaints", true, this._panelToolbar); | |
742 WebInspector.moduleSetting("frameViewerHideChromeWindow").addChangeListe
ner(this._update, this); | |
743 }, | |
744 | |
745 /** | |
746 * @param {!Event} event | |
747 */ | |
748 _onContextMenu: function(event) | |
749 { | |
750 var contextMenu = new WebInspector.ContextMenu(event); | |
751 contextMenu.appendItem(WebInspector.UIString("Reset View"), this._transf
ormController.resetAndNotify.bind(this._transformController), false); | |
752 var selection = this._selectionFromEventPoint(event); | |
753 if (selection && selection.type() === WebInspector.LayerView.Selection.T
ype.Tile) | |
754 contextMenu.appendItem(WebInspector.UIString("Show Paint Profiler"),
this.dispatchEventToListeners.bind(this, WebInspector.Layers3DView.Events.Paint
ProfilerRequested, selection.traceEvent()), false); | |
755 this._layerViewHost.showContextMenu(contextMenu, selection); | |
756 }, | |
757 | |
758 /** | |
759 * @param {!Event} event | |
760 */ | |
761 _onMouseMove: function(event) | |
762 { | |
763 if (event.which) | |
764 return; | |
765 this._layerViewHost.hoverObject(this._selectionFromEventPoint(event)); | |
766 }, | |
767 | |
768 /** | |
769 * @param {!Event} event | |
770 */ | |
771 _onMouseDown: function(event) | |
772 { | |
773 this._mouseDownX = event.clientX; | |
774 this._mouseDownY = event.clientY; | |
775 }, | |
776 | |
777 /** | |
778 * @param {!Event} event | |
779 */ | |
780 _onMouseUp: function(event) | |
781 { | |
782 const maxDistanceInPixels = 6; | |
783 if (this._mouseDownX && Math.abs(event.clientX - this._mouseDownX) < max
DistanceInPixels && Math.abs(event.clientY - this._mouseDownY) < maxDistanceInPi
xels) | |
784 this._layerViewHost.selectObject(this._selectionFromEventPoint(event
)); | |
785 delete this._mouseDownX; | |
786 delete this._mouseDownY; | |
787 }, | |
788 | |
789 /** | |
790 * @param {!Event} event | |
791 */ | |
792 _onDoubleClick: function(event) | |
793 { | |
794 var selection = this._selectionFromEventPoint(event); | |
795 if (selection) { | |
796 if (selection.type() === WebInspector.LayerView.Selection.Type.Tile) | |
797 this.dispatchEventToListeners(WebInspector.Layers3DView.Events.P
aintProfilerRequested, selection.traceEvent()); | |
798 else if (selection.layer()) | |
799 this.dispatchEventToListeners(WebInspector.Layers3DView.Events.L
ayerSnapshotRequested, selection.layer()); | |
800 } | |
801 event.stopPropagation(); | |
802 }, | |
803 | |
804 __proto__: WebInspector.VBox.prototype | |
805 } | |
806 | |
807 /** | |
808 * @constructor | |
809 * @extends {WebInspector.Object} | |
810 */ | |
811 WebInspector.LayerTextureManager = function() | |
812 { | |
813 WebInspector.Object.call(this); | |
814 this.reset(); | |
815 } | |
816 | |
817 /** @enum {symbol} */ | |
818 WebInspector.LayerTextureManager.Events = { | |
819 TextureUpdated: Symbol("TextureUpated") | |
820 } | |
821 | |
822 WebInspector.LayerTextureManager.prototype = { | |
823 reset: function() | |
824 { | |
825 /** @type {!Object.<string, !Array.<!WebInspector.LayerTextureManager.Ti
le>>} */ | |
826 this._tilesByLayerId = {}; | |
827 this._scale = 0; | |
828 }, | |
829 | |
830 /** | |
831 * @param {!WebGLRenderingContext} glContext | |
832 */ | |
833 setContext: function(glContext) | |
834 { | |
835 this._gl = glContext; | |
836 if (this._scale) | |
837 this._updateTextures(); | |
838 }, | |
839 | |
840 /** | |
841 * @param {?Array.<!WebInspector.Layers3DView.PaintTile>} paintTiles | |
842 */ | |
843 setTiles: function(paintTiles) | |
844 { | |
845 this._tilesByLayerId = {}; | |
846 if (!paintTiles) | |
847 return; | |
848 for (var i = 0; i < paintTiles.length; ++i) { | |
849 var layerId = paintTiles[i].layerId; | |
850 var tilesForLayer = this._tilesByLayerId[layerId]; | |
851 if (!tilesForLayer) { | |
852 tilesForLayer = []; | |
853 this._tilesByLayerId[layerId] = tilesForLayer; | |
854 } | |
855 var tile = new WebInspector.LayerTextureManager.Tile(paintTiles[i].s
napshot, paintTiles[i].rect, paintTiles[i].traceEvent); | |
856 tilesForLayer.push(tile); | |
857 if (this._scale && this._gl) | |
858 this._updateTile(tile); | |
859 } | |
860 }, | |
861 | |
862 /** | |
863 * @param {number} scale | |
864 */ | |
865 setScale: function(scale) | |
866 { | |
867 if (this._scale && this._scale >= scale) | |
868 return; | |
869 this._scale = scale; | |
870 this._updateTextures(); | |
871 }, | |
872 | |
873 /** | |
874 * @param {string} layerId | |
875 * @return {!Array.<!WebInspector.LayerTextureManager.Tile>} | |
876 */ | |
877 tilesForLayer: function(layerId) | |
878 { | |
879 return this._tilesByLayerId[layerId] || []; | |
880 }, | |
881 | |
882 _updateTextures: function() | |
883 { | |
884 if (!this._gl) | |
885 return; | |
886 if (!this._scale) | |
887 return; | |
888 | |
889 for (var layerId in this._tilesByLayerId) { | |
890 for (var i = 0; i < this._tilesByLayerId[layerId].length; ++i) { | |
891 var tile = this._tilesByLayerId[layerId][i]; | |
892 if (!tile.scale || tile.scale < this._scale) | |
893 this._updateTile(tile); | |
894 } | |
895 } | |
896 }, | |
897 | |
898 /** | |
899 * @param {!WebInspector.LayerTextureManager.Tile} tile | |
900 */ | |
901 _updateTile: function(tile) | |
902 { | |
903 console.assert(this._scale && this._gl); | |
904 tile.scale = this._scale; | |
905 tile.snapshot.requestImage(null, null, tile.scale, onGotImage.bind(this)
); | |
906 | |
907 /** | |
908 * @this {WebInspector.LayerTextureManager} | |
909 * @param {string=} imageURL | |
910 */ | |
911 function onGotImage(imageURL) | |
912 { | |
913 if (imageURL) | |
914 this.createTexture(onTextureCreated.bind(this), imageURL); | |
915 } | |
916 | |
917 /** | |
918 * @this {WebInspector.LayerTextureManager} | |
919 * @param {?WebGLTexture} texture | |
920 */ | |
921 function onTextureCreated(texture) | |
922 { | |
923 tile.texture = texture; | |
924 this.dispatchEventToListeners(WebInspector.LayerTextureManager.Event
s.TextureUpdated); | |
925 } | |
926 }, | |
927 | |
928 /** | |
929 * @param {function(?WebGLTexture)} textureCreatedCallback | |
930 * @param {string} imageURL | |
931 */ | |
932 createTexture: function(textureCreatedCallback, imageURL) | |
933 { | |
934 var image = new Image(); | |
935 image.addEventListener("load", onImageLoaded.bind(this), false); | |
936 image.addEventListener("error", onImageError, false); | |
937 image.src = imageURL; | |
938 | |
939 /** | |
940 * @this {WebInspector.LayerTextureManager} | |
941 */ | |
942 function onImageLoaded() | |
943 { | |
944 textureCreatedCallback(this._createTextureForImage(image)); | |
945 } | |
946 | |
947 function onImageError() | |
948 { | |
949 textureCreatedCallback(null); | |
950 } | |
951 }, | |
952 | |
953 /** | |
954 * @param {!Image} image | |
955 * @return {!WebGLTexture} texture | |
956 */ | |
957 _createTextureForImage: function(image) | |
958 { | |
959 var texture = this._gl.createTexture(); | |
960 texture.image = image; | |
961 this._gl.bindTexture(this._gl.TEXTURE_2D, texture); | |
962 this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, true); | |
963 this._gl.texImage2D(this._gl.TEXTURE_2D, 0, this._gl.RGBA, this._gl.RGBA
, this._gl.UNSIGNED_BYTE, texture.image); | |
964 this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER,
this._gl.LINEAR); | |
965 this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER,
this._gl.LINEAR); | |
966 this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_S, thi
s._gl.CLAMP_TO_EDGE); | |
967 this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_T, thi
s._gl.CLAMP_TO_EDGE); | |
968 this._gl.bindTexture(this._gl.TEXTURE_2D, null); | |
969 return texture; | |
970 }, | |
971 | |
972 __proto__: WebInspector.Object.prototype | |
973 } | |
974 | |
975 /** | |
976 * @constructor | |
977 * @param {?WebInspector.LayerView.Selection} relatedObject | |
978 */ | |
979 WebInspector.Layers3DView.Rectangle = function(relatedObject) | |
980 { | |
981 this.relatedObject = relatedObject; | |
982 /** @type {number} */ | |
983 this.lineWidth = 1; | |
984 /** @type {?Array.<number>} */ | |
985 this.borderColor = null; | |
986 /** @type {?Array.<number>} */ | |
987 this.fillColor = null; | |
988 /** @type {?WebGLTexture} */ | |
989 this.texture = null; | |
990 } | |
991 | |
992 WebInspector.Layers3DView.Rectangle.prototype = { | |
993 /** | |
994 * @param {!Array.<number>} quad | |
995 * @param {number} z | |
996 */ | |
997 setVertices: function(quad, z) | |
998 { | |
999 this.vertices = [quad[0], quad[1], z, quad[2], quad[3], z, quad[4], quad
[5], z, quad[6], quad[7], z]; | |
1000 }, | |
1001 | |
1002 /** | |
1003 * Finds coordinates of point on layer quad, having offsets (ratioX * width)
and (ratioY * height) | |
1004 * from the left corner of the initial layer rect, where width and heigth ar
e layer bounds. | |
1005 * @param {!Array.<number>} quad | |
1006 * @param {number} ratioX | |
1007 * @param {number} ratioY | |
1008 * @return {!Array.<number>} | |
1009 */ | |
1010 _calculatePointOnQuad: function(quad, ratioX, ratioY) | |
1011 { | |
1012 var x0 = quad[0]; | |
1013 var y0 = quad[1]; | |
1014 var x1 = quad[2]; | |
1015 var y1 = quad[3]; | |
1016 var x2 = quad[4]; | |
1017 var y2 = quad[5]; | |
1018 var x3 = quad[6]; | |
1019 var y3 = quad[7]; | |
1020 // Point on the first quad side clockwise | |
1021 var firstSidePointX = x0 + ratioX * (x1 - x0); | |
1022 var firstSidePointY = y0 + ratioX * (y1 - y0); | |
1023 // Point on the third quad side clockwise | |
1024 var thirdSidePointX = x3 + ratioX * (x2 - x3); | |
1025 var thirdSidePointY = y3 + ratioX * (y2 - y3); | |
1026 var x = firstSidePointX + ratioY * (thirdSidePointX - firstSidePointX); | |
1027 var y = firstSidePointY + ratioY * (thirdSidePointY - firstSidePointY); | |
1028 return [x, y]; | |
1029 }, | |
1030 | |
1031 /** | |
1032 * @param {!WebInspector.Layer} layer | |
1033 * @param {!DOMAgent.Rect} rect | |
1034 * @param {number} z | |
1035 */ | |
1036 calculateVerticesFromRect: function(layer, rect, z) | |
1037 { | |
1038 var quad = layer.quad(); | |
1039 var rx1 = rect.x / layer.width(); | |
1040 var rx2 = (rect.x + rect.width) / layer.width(); | |
1041 var ry1 = rect.y / layer.height(); | |
1042 var ry2 = (rect.y + rect.height) / layer.height(); | |
1043 var rectQuad = this._calculatePointOnQuad(quad, rx1, ry1).concat(this._c
alculatePointOnQuad(quad, rx2, ry1)) | |
1044 .concat(this._calculatePointOnQuad(quad, rx2, ry2)).concat(this._cal
culatePointOnQuad(quad, rx1, ry2)); | |
1045 this.setVertices(rectQuad, z); | |
1046 }, | |
1047 | |
1048 /** | |
1049 * Intersects quad with given transform matrix and line l(t) = (x0, y0, t) | |
1050 * @param {!CSSMatrix} matrix | |
1051 * @param {number} x0 | |
1052 * @param {number} y0 | |
1053 * @return {(number|undefined)} | |
1054 */ | |
1055 intersectWithLine: function(matrix, x0, y0) | |
1056 { | |
1057 var i; | |
1058 // Vertices of the quad with transform matrix applied | |
1059 var points = []; | |
1060 for (i = 0; i < 4; ++i) | |
1061 points[i] = WebInspector.Geometry.multiplyVectorByMatrixAndNormalize
(new WebInspector.Geometry.Vector(this.vertices[i * 3], this.vertices[i * 3 + 1]
, this.vertices[i * 3 + 2]), matrix); | |
1062 // Calculating quad plane normal | |
1063 var normal = WebInspector.Geometry.crossProduct(WebInspector.Geometry.su
btract(points[1], points[0]), WebInspector.Geometry.subtract(points[2], points[1
])); | |
1064 // General form of the equation of the quad plane: A * x + B * y + C * z
+ D = 0 | |
1065 var A = normal.x; | |
1066 var B = normal.y; | |
1067 var C = normal.z; | |
1068 var D = -(A * points[0].x + B * points[0].y + C * points[0].z); | |
1069 // Finding t from the equation | |
1070 var t = -(D + A * x0 + B * y0) / C; | |
1071 // Point of the intersection | |
1072 var pt = new WebInspector.Geometry.Vector(x0, y0, t); | |
1073 // Vectors from the intersection point to vertices of the quad | |
1074 var tVects = points.map(WebInspector.Geometry.subtract.bind(null, pt)); | |
1075 // Intersection point lies inside of the polygon if scalar products of n
ormal of the plane and | |
1076 // cross products of successive tVects are all nonstrictly above or all
nonstrictly below zero | |
1077 for (i = 0; i < tVects.length; ++i) { | |
1078 var product = WebInspector.Geometry.scalarProduct(normal, WebInspect
or.Geometry.crossProduct(tVects[i], tVects[(i + 1) % tVects.length])); | |
1079 if (product < 0) | |
1080 return undefined; | |
1081 } | |
1082 return t; | |
1083 } | |
1084 } | |
1085 | |
1086 /** | |
1087 * @constructor | |
1088 * @param {!WebInspector.PaintProfilerSnapshot} snapshot | |
1089 * @param {!Array.<number>} rect | |
1090 * @param {!WebInspector.TracingModel.Event} traceEvent | |
1091 */ | |
1092 WebInspector.LayerTextureManager.Tile = function(snapshot, rect, traceEvent) | |
1093 { | |
1094 this.snapshot = snapshot; | |
1095 this.rect = rect; | |
1096 this.traceEvent = traceEvent; | |
1097 this.scale = 0; | |
1098 /** @type {?WebGLTexture} */ | |
1099 this.texture = null; | |
1100 } | |
OLD | NEW |