• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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