Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(215)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/timeline/Layers3DView.js

Issue 2358253002: DevTools: extract a component for layer viewer (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698