1/* 2 * Copyright (C) 2013 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 * @param {!WebInspector.LayerTreeModel} model 34 * @param {!WebInspector.Layers3DView} layers3DView 35 * @extends {WebInspector.View} 36 */ 37WebInspector.PaintProfilerView = function(model, layers3DView) 38{ 39 WebInspector.View.call(this); 40 this.element.classList.add("fill", "paint-profiler-view"); 41 42 this._model = model; 43 this._layers3DView = layers3DView; 44 45 this._canvas = this.element.createChild("canvas", "fill"); 46 this._context = this._canvas.getContext("2d"); 47 this._selectionWindow = new WebInspector.OverviewGrid.Window(this.element, this.element); 48 this._selectionWindow.addEventListener(WebInspector.OverviewGrid.Events.WindowChanged, this._onWindowChanged, this); 49 50 this._innerBarWidth = 4 * window.devicePixelRatio; 51 this._minBarHeight = 4 * window.devicePixelRatio; 52 this._barPaddingWidth = 2 * window.devicePixelRatio; 53 this._outerBarWidth = this._innerBarWidth + this._barPaddingWidth; 54 55 this._reset(); 56} 57 58WebInspector.PaintProfilerView.prototype = { 59 onResize: function() 60 { 61 this._update(); 62 }, 63 64 _update: function() 65 { 66 this._canvas.width = this.element.clientWidth * window.devicePixelRatio; 67 this._canvas.height = this.element.clientHeight * window.devicePixelRatio; 68 this._samplesPerBar = 0; 69 if (!this._profiles || !this._profiles.length) 70 return; 71 72 var maxBars = Math.floor((this._canvas.width - 2 * this._barPaddingWidth) / this._outerBarWidth); 73 var sampleCount = this._profiles[0].length; 74 this._samplesPerBar = Math.ceil(sampleCount / maxBars); 75 var barCount = Math.floor(sampleCount / this._samplesPerBar); 76 77 var maxBarTime = 0; 78 var barTimes = []; 79 for (var i = 0, lastBarIndex = 0, lastBarTime = 0; i < sampleCount;) { 80 for (var row = 0; row < this._profiles.length; row++) 81 lastBarTime += this._profiles[row][i]; 82 ++i; 83 if (i - lastBarIndex == this._samplesPerBar || i == sampleCount) { 84 // Normalize by total number of samples accumulated. 85 lastBarTime /= this._profiles.length * (i - lastBarIndex); 86 barTimes.push(lastBarTime); 87 if (lastBarTime > maxBarTime) 88 maxBarTime = lastBarTime; 89 lastBarTime = 0; 90 lastBarIndex = i; 91 } 92 } 93 const paddingHeight = 4 * window.devicePixelRatio; 94 var scale = (this._canvas.height - paddingHeight - this._minBarHeight) / maxBarTime; 95 this._context.fillStyle = "rgba(110, 180, 110, 0.7)"; 96 for (var i = 0; i < barTimes.length; ++i) 97 this._renderBar(i, barTimes[i] * scale + this._minBarHeight); 98 }, 99 100 /** 101 * @param {number} index 102 * @param {number} height 103 */ 104 _renderBar: function(index, height) 105 { 106 var x = this._barPaddingWidth + index * this._outerBarWidth; 107 var y = this._canvas.height - height; 108 this._context.fillRect(x, y, this._innerBarWidth, height); 109 }, 110 111 _onWindowChanged: function() 112 { 113 if (this._updateImageTimer) 114 return; 115 this._updateImageTimer = setTimeout(this._updateImage.bind(this), 100); 116 }, 117 118 _updateImage: function() 119 { 120 delete this._updateImageTimer; 121 if (!this._profiles || !this._profiles.length) 122 return; 123 124 var screenLeft = this._selectionWindow.windowLeft * this._canvas.width; 125 var screenRight = this._selectionWindow.windowRight * this._canvas.width; 126 127 var barLeft = Math.floor((screenLeft - this._barPaddingWidth) / this._outerBarWidth); 128 var barRight = Math.floor((screenRight - this._barPaddingWidth + this._innerBarWidth)/ this._outerBarWidth); 129 130 var stepLeft = Math.max(0, barLeft * this._samplesPerBar); 131 var stepRight = Math.min(barRight * this._samplesPerBar, this._profiles[0].length); 132 this._snapshot.requestImage(stepLeft, stepRight, this._layers3DView.showImageForLayer.bind(this._layers3DView, this._layer)); 133 }, 134 135 _reset: function() 136 { 137 this._snapshot = null; 138 this._profiles = null; 139 this._selectionWindow.reset(); 140 }, 141 142 /** 143 * @param {!WebInspector.Layer} layer 144 */ 145 profile: function(layer) 146 { 147 this._reset(); 148 this._layer = layer; 149 this._layer.requestSnapshot(onSnapshotDone.bind(this)); 150 151 /** 152 * @param {!WebInspector.LayerSnapshot=} snapshot 153 * @this {WebInspector.PaintProfilerView} 154 */ 155 function onSnapshotDone(snapshot) 156 { 157 this._snapshot = snapshot; 158 if (!snapshot) { 159 this._profiles = null; 160 this._update(); 161 return; 162 } 163 snapshot.requestImage(null, null, this._layers3DView.showImageForLayer.bind(this._layers3DView, this._layer)); 164 snapshot.profile(onProfileDone.bind(this)); 165 } 166 167 /** 168 * @param {!Array.<!LayerTreeAgent.PaintProfile>=} profiles 169 * @this {WebInspector.PaintProfilerView} 170 */ 171 function onProfileDone(profiles) 172 { 173 this._profiles = profiles; 174 this._update(); 175 } 176 }, 177 178 __proto__: WebInspector.View.prototype 179}; 180