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 * @extends {WebInspector.TimelineOverviewBase} 34 * @param {!WebInspector.TimelineModel} model 35 * @param {!WebInspector.TimelineUIUtils} uiUtils 36 */ 37 WebInspector.TimelineEventOverview = function(model, uiUtils) 38 { 39 WebInspector.TimelineOverviewBase.call(this, model); 40 this._uiUtils = uiUtils; 41 this.element.id = "timeline-overview-events"; 42 43 this._fillStyles = {}; 44 var categories = WebInspector.TimelineUIUtils.categories(); 45 for (var category in categories) { 46 this._fillStyles[category] = WebInspector.TimelineUIUtils.createFillStyleForCategory(this._context, 0, WebInspector.TimelineEventOverview._stripGradientHeight, categories[category]); 47 categories[category].addEventListener(WebInspector.TimelineCategory.Events.VisibilityChanged, this._onCategoryVisibilityChanged, this); 48 } 49 50 this._disabledCategoryFillStyle = WebInspector.TimelineUIUtils.createFillStyle(this._context, 0, WebInspector.TimelineEventOverview._stripGradientHeight, 51 "hsl(0, 0%, 85%)", "hsl(0, 0%, 67%)", "hsl(0, 0%, 56%)"); 52 53 this._disabledCategoryBorderStyle = "rgb(143, 143, 143)"; 54 } 55 56 /** @const */ 57 WebInspector.TimelineEventOverview._numberOfStrips = 3; 58 59 /** @const */ 60 WebInspector.TimelineEventOverview._stripGradientHeight = 120; 61 62 WebInspector.TimelineEventOverview.prototype = { 63 dispose: function() 64 { 65 var categories = WebInspector.TimelineUIUtils.categories(); 66 for (var category in categories) 67 categories[category].removeEventListener(WebInspector.TimelineCategory.Events.VisibilityChanged, this._onCategoryVisibilityChanged, this); 68 }, 69 70 update: function() 71 { 72 this.resetCanvas(); 73 74 var stripHeight = Math.round(this._canvas.height / WebInspector.TimelineEventOverview._numberOfStrips); 75 var timeOffset = this._model.minimumRecordTime(); 76 var timeSpan = this._model.maximumRecordTime() - timeOffset; 77 var scale = this._canvas.width / timeSpan; 78 79 var lastBarByGroup = []; 80 81 this._context.fillStyle = "rgba(0, 0, 0, 0.05)"; 82 for (var i = 1; i < WebInspector.TimelineEventOverview._numberOfStrips; i += 2) 83 this._context.fillRect(0.5, i * stripHeight + 0.5, this._canvas.width, stripHeight); 84 85 /** 86 * @param {!WebInspector.TimelineModel.Record} record 87 * @this {WebInspector.TimelineEventOverview} 88 */ 89 function appendRecord(record) 90 { 91 if (this._uiUtils.isBeginFrame(record)) 92 return; 93 var recordStart = Math.floor((record.startTime() - timeOffset) * scale); 94 var recordEnd = Math.ceil((record.endTime() - timeOffset) * scale); 95 var category = record.category(); 96 if (category.overviewStripGroupIndex < 0) 97 return; 98 var bar = lastBarByGroup[category.overviewStripGroupIndex]; 99 // This bar may be merged with previous -- so just adjust the previous bar. 100 if (bar) { 101 // If record fits entirely into previous bar just absorb it ignoring the category match. 102 if (recordEnd <= bar.end) 103 return; 104 if (bar.category === category && recordStart <= bar.end) { 105 bar.end = recordEnd; 106 return; 107 } 108 this._renderBar(bar.start, bar.end, stripHeight, bar.category); 109 } 110 lastBarByGroup[category.overviewStripGroupIndex] = { start: recordStart, end: recordEnd, category: category }; 111 } 112 this._model.forAllRecords(appendRecord.bind(this)); 113 for (var i = 0; i < lastBarByGroup.length; ++i) { 114 if (lastBarByGroup[i]) 115 this._renderBar(lastBarByGroup[i].start, lastBarByGroup[i].end, stripHeight, lastBarByGroup[i].category); 116 } 117 }, 118 119 _onCategoryVisibilityChanged: function() 120 { 121 this.update(); 122 }, 123 124 /** 125 * @param {number} begin 126 * @param {number} end 127 * @param {number} height 128 * @param {!WebInspector.TimelineCategory} category 129 */ 130 _renderBar: function(begin, end, height, category) 131 { 132 const stripPadding = 4 * window.devicePixelRatio; 133 const innerStripHeight = height - 2 * stripPadding; 134 135 var x = begin; 136 var y = category.overviewStripGroupIndex * height + stripPadding + 0.5; 137 var width = Math.max(end - begin, 1); 138 139 this._context.save(); 140 this._context.translate(x, y); 141 this._context.beginPath(); 142 this._context.scale(1, innerStripHeight / WebInspector.TimelineEventOverview._stripGradientHeight); 143 this._context.fillStyle = category.hidden ? this._disabledCategoryFillStyle : this._fillStyles[category.name]; 144 this._context.fillRect(0, 0, width, WebInspector.TimelineEventOverview._stripGradientHeight); 145 this._context.strokeStyle = category.hidden ? this._disabledCategoryBorderStyle : category.borderColor; 146 this._context.moveTo(0, 0); 147 this._context.lineTo(width, 0); 148 this._context.moveTo(0, WebInspector.TimelineEventOverview._stripGradientHeight); 149 this._context.lineTo(width, WebInspector.TimelineEventOverview._stripGradientHeight); 150 this._context.stroke(); 151 this._context.restore(); 152 }, 153 154 __proto__: WebInspector.TimelineOverviewBase.prototype 155 } 156