2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * Copyright (C) 2012 Intel Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 WebInspector.TimelineUIUtils = function() { }
37 WebInspector.TimelineUIUtils.prototype = {
39 * @param {!WebInspector.TimelineModel.Record} record
42 isBeginFrame: function(record)
44 throw new Error("Not implemented.");
47 * @param {!WebInspector.TimelineModel.Record} record
50 isProgram: function(record)
52 throw new Error("Not implemented.");
55 * @param {string} recordType
58 isCoalescable: function(recordType)
60 throw new Error("Not implemented.");
63 * @param {!WebInspector.TimelineModel.Record} record
66 isEventDivider: function(record)
68 throw new Error("Not implemented.");
71 * @param {!WebInspector.TimelineModel.Record} record
74 countersForRecord: function(record)
76 throw new Error("Not implemented.");
79 * @param {!WebInspector.TimelineModel.Record} record
82 highlightQuadForRecord: function(record)
84 throw new Error("Not implemented.");
87 * @param {!WebInspector.TimelineModel.Record} record
90 titleForRecord: function(record)
92 throw new Error("Not implemented.");
95 * @param {!WebInspector.TimelineModel.Record} record
96 * @return {!WebInspector.TimelineCategory}
98 categoryForRecord: function(record)
100 throw new Error("Not implemented.");
103 * @param {!WebInspector.TimelineModel.Record} record
104 * @param {!WebInspector.Linkifier} linkifier
107 buildDetailsNode: function(record, linkifier)
109 throw new Error("Not implemented.");
112 * @param {!WebInspector.TimelineModel.Record} record
113 * @param {!WebInspector.TimelineModel} model
114 * @param {!WebInspector.Linkifier} linkifier
115 * @param {function(!DocumentFragment)} callback
117 generateDetailsContent: function(record, model, linkifier, callback)
119 throw new Error("Not implemented.");
124 createBeginFrameDivider: function()
126 throw new Error("Not implemented.");
129 * @param {string} recordType
130 * @param {string=} title
133 createEventDivider: function(recordType, title)
135 throw new Error("Not implemented.");
138 * @param {!WebInspector.TimelineModel.Record} record
139 * @param {!RegExp} regExp
142 testContentMatching: function(record, regExp)
144 throw new Error("Not implemented.");
147 * @param {!Object} total
148 * @param {!WebInspector.TimelineModel.Record} record
150 aggregateTimeForRecord: function(total, record)
152 throw new Error("Not implemented.");
155 * @return {!WebInspector.TimelineModel.Filter}
157 hiddenRecordsFilter: function()
159 throw new Error("Not implemented.");
162 * @return {?WebInspector.TimelineModel.Filter}
164 hiddenEmptyRecordsFilter: function()
171 * @return {!Object.<string, !WebInspector.TimelineCategory>}
173 WebInspector.TimelineUIUtils.categories = function()
175 if (WebInspector.TimelineUIUtils._categories)
176 return WebInspector.TimelineUIUtils._categories;
177 WebInspector.TimelineUIUtils._categories = {
178 loading: new WebInspector.TimelineCategory("loading", WebInspector.UIString("Loading"), 0, "hsl(214, 53%, 58%)", "hsl(214, 67%, 90%)", "hsl(214, 67%, 74%)", "hsl(214, 67%, 66%)"),
179 scripting: new WebInspector.TimelineCategory("scripting", WebInspector.UIString("Scripting"), 1, "hsl(43, 90%, 45%)", "hsl(43, 83%, 90%)", "hsl(43, 83%, 72%)", "hsl(43, 83%, 64%) "),
180 rendering: new WebInspector.TimelineCategory("rendering", WebInspector.UIString("Rendering"), 2, "hsl(256, 50%, 60%)", "hsl(256, 67%, 90%)", "hsl(256, 67%, 76%)", "hsl(256, 67%, 70%)"),
181 painting: new WebInspector.TimelineCategory("painting", WebInspector.UIString("Painting"), 2, "hsl(109, 33%, 47%)", "hsl(109, 33%, 90%)", "hsl(109, 33%, 64%)", "hsl(109, 33%, 55%)"),
182 other: new WebInspector.TimelineCategory("other", WebInspector.UIString("Other"), -1, "hsl(0, 0%, 73%)", "hsl(0, 0%, 90%)", "hsl(0, 0%, 87%)", "hsl(0, 0%, 79%)"),
183 idle: new WebInspector.TimelineCategory("idle", WebInspector.UIString("Idle"), -1, "hsl(0, 0%, 87%)", "hsl(0, 100%, 100%)", "hsl(0, 100%, 100%)", "hsl(0, 100%, 100%)")
185 return WebInspector.TimelineUIUtils._categories;
189 * @param {!WebInspector.TimelineModel} model
190 * @param {!{name: string, tasks: !Array.<!WebInspector.TimelineModel.Record>, firstTaskIndex: number, lastTaskIndex: number}} info
193 WebInspector.TimelineUIUtils.generateMainThreadBarPopupContent = function(model, info)
195 var firstTaskIndex = info.firstTaskIndex;
196 var lastTaskIndex = info.lastTaskIndex;
197 var tasks = info.tasks;
198 var messageCount = lastTaskIndex - firstTaskIndex + 1;
201 for (var i = firstTaskIndex; i <= lastTaskIndex; ++i) {
203 cpuTime += task.endTime() - task.startTime();
205 var startTime = tasks[firstTaskIndex].startTime();
206 var endTime = tasks[lastTaskIndex].endTime();
207 var duration = endTime - startTime;
209 var contentHelper = new WebInspector.TimelinePopupContentHelper(info.name);
210 var durationText = WebInspector.UIString("%s (at %s)", Number.millisToString(duration, true),
211 Number.millisToString(startTime - model.minimumRecordTime(), true));
212 contentHelper.appendTextRow(WebInspector.UIString("Duration"), durationText);
213 contentHelper.appendTextRow(WebInspector.UIString("CPU time"), Number.millisToString(cpuTime, true));
214 contentHelper.appendTextRow(WebInspector.UIString("Message Count"), messageCount);
215 return contentHelper.contentTable();
219 * @param {!Object} aggregatedStats
221 WebInspector.TimelineUIUtils._generateAggregatedInfo = function(aggregatedStats)
223 var cell = document.createElement("span");
224 cell.className = "timeline-aggregated-info";
225 for (var index in aggregatedStats) {
226 var label = document.createElement("div");
227 label.className = "timeline-aggregated-category timeline-" + index;
228 cell.appendChild(label);
229 var text = document.createElement("span");
230 text.textContent = Number.millisToString(aggregatedStats[index], true);
231 cell.appendChild(text);
237 * @param {!Object} aggregatedStats
238 * @param {!WebInspector.TimelineCategory=} selfCategory
239 * @param {number=} selfTime
242 WebInspector.TimelineUIUtils.generatePieChart = function(aggregatedStats, selfCategory, selfTime)
244 var element = document.createElement("div");
245 element.className = "timeline-aggregated-info";
248 for (var categoryName in aggregatedStats)
249 total += aggregatedStats[categoryName];
251 function formatter(value)
253 return Number.millisToString(value, true);
255 var pieChart = new WebInspector.PieChart(100, formatter);
256 pieChart.setTotal(total);
257 element.appendChild(pieChart.element);
258 var footerElement = element.createChild("div", "timeline-aggregated-info-legend");
260 // In case of self time, first add self, then children of the same category.
261 if (selfCategory && selfTime) {
263 pieChart.addSlice(selfTime, selfCategory.fillColorStop1);
264 var rowElement = footerElement.createChild("div");
265 rowElement.createChild("div", "timeline-aggregated-category timeline-" + selfCategory.name);
266 rowElement.createTextChild(WebInspector.UIString("%s %s (Self)", formatter(selfTime), selfCategory.title));
268 // Children of the same category.
269 var categoryTime = aggregatedStats[selfCategory.name];
270 var value = categoryTime - selfTime;
272 pieChart.addSlice(value, selfCategory.fillColorStop0);
273 rowElement = footerElement.createChild("div");
274 rowElement.createChild("div", "timeline-aggregated-category timeline-" + selfCategory.name);
275 rowElement.createTextChild(WebInspector.UIString("%s %s (Children)", formatter(value), selfCategory.title));
279 // Add other categories.
280 for (var categoryName in WebInspector.TimelineUIUtils.categories()) {
281 var category = WebInspector.TimelineUIUtils.categories()[categoryName];
282 if (category === selfCategory)
284 var value = aggregatedStats[category.name];
287 pieChart.addSlice(value, category.fillColorStop0);
288 var rowElement = footerElement.createChild("div");
289 rowElement.createChild("div", "timeline-aggregated-category timeline-" + category.name);
290 rowElement.createTextChild(WebInspector.UIString("%s %s", formatter(value), category.title));
296 * @param {!WebInspector.TimelineFrameModel} frameModel
297 * @param {!WebInspector.TimelineFrame} frame
300 WebInspector.TimelineUIUtils.generateDetailsContentForFrame = function(frameModel, frame)
302 var contentHelper = new WebInspector.TimelineDetailsContentHelper(null, null, true);
303 var durationInMillis = frame.endTime - frame.startTime;
304 var durationText = WebInspector.UIString("%s (at %s)", Number.millisToString(frame.endTime - frame.startTime, true),
305 Number.millisToString(frame.startTimeOffset, true));
306 contentHelper.appendTextRow(WebInspector.UIString("Duration"), durationText);
307 contentHelper.appendTextRow(WebInspector.UIString("FPS"), Math.floor(1000 / durationInMillis));
308 contentHelper.appendTextRow(WebInspector.UIString("CPU time"), Number.millisToString(frame.cpuTime, true));
309 contentHelper.appendElementRow(WebInspector.UIString("Aggregated Time"),
310 WebInspector.TimelineUIUtils._generateAggregatedInfo(frame.timeByCategory));
311 if (Runtime.experiments.isEnabled("layersPanel") && frame.layerTree) {
312 contentHelper.appendElementRow(WebInspector.UIString("Layer tree"),
313 WebInspector.Linkifier.linkifyUsingRevealer(frame.layerTree, WebInspector.UIString("show")));
315 return contentHelper.element;
319 * @param {!CanvasRenderingContext2D} context
320 * @param {number} width
321 * @param {number} height
322 * @param {string} color0
323 * @param {string} color1
324 * @param {string} color2
325 * @return {!CanvasGradient}
327 WebInspector.TimelineUIUtils.createFillStyle = function(context, width, height, color0, color1, color2)
329 var gradient = context.createLinearGradient(0, 0, width, height);
330 gradient.addColorStop(0, color0);
331 gradient.addColorStop(0.25, color1);
332 gradient.addColorStop(0.75, color1);
333 gradient.addColorStop(1, color2);
338 * @param {!CanvasRenderingContext2D} context
339 * @param {number} width
340 * @param {number} height
341 * @param {!WebInspector.TimelineCategory} category
342 * @return {!CanvasGradient}
344 WebInspector.TimelineUIUtils.createFillStyleForCategory = function(context, width, height, category)
346 return WebInspector.TimelineUIUtils.createFillStyle(context, width, height, category.fillColorStop0, category.fillColorStop1, category.borderColor);
350 * @param {!WebInspector.TimelineCategory} category
353 WebInspector.TimelineUIUtils.createStyleRuleForCategory = function(category)
355 var selector = ".timeline-category-" + category.name + " .timeline-graph-bar, " +
356 ".panel.timeline .timeline-filters-header .filter-checkbox-filter.filter-checkbox-filter-" + category.name + " .checkbox-filter-checkbox, " +
357 ".timeline-details-view .timeline-" + category.name + ", " +
358 ".timeline-category-" + category.name + " .timeline-tree-icon"
360 return selector + " { background-image: linear-gradient(" +
361 category.fillColorStop0 + ", " + category.fillColorStop1 + " 25%, " + category.fillColorStop1 + " 25%, " + category.fillColorStop1 + ");" +
362 " border-color: " + category.borderColor +
367 * @param {!Array.<number>} quad
370 WebInspector.TimelineUIUtils.quadWidth = function(quad)
372 return Math.round(Math.sqrt(Math.pow(quad[0] - quad[2], 2) + Math.pow(quad[1] - quad[3], 2)));
376 * @param {!Array.<number>} quad
379 WebInspector.TimelineUIUtils.quadHeight = function(quad)
381 return Math.round(Math.sqrt(Math.pow(quad[0] - quad[6], 2) + Math.pow(quad[1] - quad[7], 2)));
386 * @extends {WebInspector.Object}
387 * @param {string} name
388 * @param {string} title
389 * @param {number} overviewStripGroupIndex
390 * @param {string} borderColor
391 * @param {string} backgroundColor
392 * @param {string} fillColorStop0
393 * @param {string} fillColorStop1
395 WebInspector.TimelineCategory = function(name, title, overviewStripGroupIndex, borderColor, backgroundColor, fillColorStop0, fillColorStop1)
399 this.overviewStripGroupIndex = overviewStripGroupIndex;
400 this.borderColor = borderColor;
401 this.backgroundColor = backgroundColor;
402 this.fillColorStop0 = fillColorStop0;
403 this.fillColorStop1 = fillColorStop1;
407 WebInspector.TimelineCategory.Events = {
408 VisibilityChanged: "VisibilityChanged"
411 WebInspector.TimelineCategory.prototype = {
422 this._hidden = hidden;
423 this.dispatchEventToListeners(WebInspector.TimelineCategory.Events.VisibilityChanged, this);
426 __proto__: WebInspector.Object.prototype
431 * @param {string} title
433 WebInspector.TimelinePopupContentHelper = function(title)
435 this._contentTable = document.createElement("table");
436 var titleCell = this._createCell(WebInspector.UIString("%s - Details", title), "timeline-details-title");
437 titleCell.colSpan = 2;
438 var titleRow = document.createElement("tr");
439 titleRow.appendChild(titleCell);
440 this._contentTable.appendChild(titleRow);
443 WebInspector.TimelinePopupContentHelper.prototype = {
447 contentTable: function()
449 return this._contentTable;
453 * @param {string|number} content
454 * @param {string=} styleName
456 _createCell: function(content, styleName)
458 var text = document.createElement("label");
459 text.createTextChild(String(content));
460 var cell = document.createElement("td");
461 cell.className = "timeline-details";
463 cell.className += " " + styleName;
464 cell.textContent = content;
469 * @param {string} title
470 * @param {string|number} content
472 appendTextRow: function(title, content)
474 var row = document.createElement("tr");
475 row.appendChild(this._createCell(title, "timeline-details-row-title"));
476 row.appendChild(this._createCell(content, "timeline-details-row-data"));
477 this._contentTable.appendChild(row);
481 * @param {string} title
482 * @param {!Node|string} content
484 appendElementRow: function(title, content)
486 var row = document.createElement("tr");
487 var titleCell = this._createCell(title, "timeline-details-row-title");
488 row.appendChild(titleCell);
489 var cell = document.createElement("td");
490 cell.className = "details";
491 if (content instanceof Node)
492 cell.appendChild(content);
494 cell.createTextChild(content || "");
495 row.appendChild(cell);
496 this._contentTable.appendChild(row);
502 * @param {?WebInspector.Target} target
503 * @param {?WebInspector.Linkifier} linkifier
504 * @param {boolean} monospaceValues
506 WebInspector.TimelineDetailsContentHelper = function(target, linkifier, monospaceValues)
508 this._linkifier = linkifier;
509 this._target = target;
510 this.element = document.createElement("div");
511 this.element.className = "timeline-details-view-block";
512 this._monospaceValues = monospaceValues;
515 WebInspector.TimelineDetailsContentHelper.prototype = {
517 * @param {string} title
518 * @param {string|number|boolean} value
520 appendTextRow: function(title, value)
522 var rowElement = this.element.createChild("div", "timeline-details-view-row");
523 rowElement.createChild("span", "timeline-details-view-row-title").textContent = WebInspector.UIString("%s: ", title);
524 rowElement.createChild("span", "timeline-details-view-row-value" + (this._monospaceValues ? " monospace" : "")).textContent = value;
528 * @param {string} title
529 * @param {!Node|string} content
531 appendElementRow: function(title, content)
533 var rowElement = this.element.createChild("div", "timeline-details-view-row");
534 rowElement.createChild("span", "timeline-details-view-row-title").textContent = WebInspector.UIString("%s: ", title);
535 var valueElement = rowElement.createChild("span", "timeline-details-view-row-details" + (this._monospaceValues ? " monospace" : ""));
536 if (content instanceof Node)
537 valueElement.appendChild(content);
539 valueElement.createTextChild(content || "");
543 * @param {string} title
544 * @param {string} url
545 * @param {number} line
547 appendLocationRow: function(title, url, line)
549 if (!this._linkifier || !this._target)
551 this.appendElementRow(title, this._linkifier.linkifyScriptLocation(this._target, null, url, line - 1) || "");
555 * @param {string} title
556 * @param {!Array.<!ConsoleAgent.CallFrame>} stackTrace
558 appendStackTrace: function(title, stackTrace)
560 if (!this._linkifier || !this._target)
563 var rowElement = this.element.createChild("div", "timeline-details-view-row");
564 rowElement.createChild("span", "timeline-details-view-row-title").textContent = WebInspector.UIString("%s: ", title);
565 var stackTraceElement = rowElement.createChild("div", "timeline-details-view-row-stack-trace monospace");
567 for (var i = 0; i < stackTrace.length; ++i) {
568 var stackFrame = stackTrace[i];
569 var row = stackTraceElement.createChild("div");
570 row.createTextChild(stackFrame.functionName || WebInspector.UIString("(anonymous function)"));
571 row.createTextChild(" @ ");
572 var urlElement = this._linkifier.linkifyScriptLocation(this._target, stackFrame.scriptId, stackFrame.url, stackFrame.lineNumber - 1, stackFrame.columnNumber - 1);
573 row.appendChild(urlElement);