1 /* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * Copyright (C) 2012 Intel Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 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 14 * distribution. 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. 18 * 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. 30 */ 31 32 /** 33 * @constructor 34 */ 35 WebInspector.TimelineUIUtils = function() { } 36 37 WebInspector.TimelineUIUtils.prototype = { 38 /** 39 * @param {!WebInspector.TimelineModel.Record} record 40 * @return {boolean} 41 */ 42 isBeginFrame: function(record) 43 { 44 throw new Error("Not implemented."); 45 }, 46 /** 47 * @param {!WebInspector.TimelineModel.Record} record 48 * @return {boolean} 49 */ 50 isProgram: function(record) 51 { 52 throw new Error("Not implemented."); 53 }, 54 /** 55 * @param {string} recordType 56 * @return {boolean} 57 */ 58 isCoalescable: function(recordType) 59 { 60 throw new Error("Not implemented."); 61 }, 62 /** 63 * @param {!WebInspector.TimelineModel.Record} record 64 * @return {boolean} 65 */ 66 isEventDivider: function(record) 67 { 68 throw new Error("Not implemented."); 69 }, 70 /** 71 * @param {!WebInspector.TimelineModel.Record} record 72 * @return {?Object} 73 */ 74 countersForRecord: function(record) 75 { 76 throw new Error("Not implemented."); 77 }, 78 /** 79 * @param {!WebInspector.TimelineModel.Record} record 80 * @return {?Object} 81 */ 82 highlightQuadForRecord: function(record) 83 { 84 throw new Error("Not implemented."); 85 }, 86 /** 87 * @param {!WebInspector.TimelineModel.Record} record 88 * @return {string} 89 */ 90 titleForRecord: function(record) 91 { 92 throw new Error("Not implemented."); 93 }, 94 /** 95 * @param {!WebInspector.TimelineModel.Record} record 96 * @param {!WebInspector.Linkifier} linkifier 97 * @param {boolean} loadedFromFile 98 * @return {?Node} 99 */ 100 buildDetailsNode: function(record, linkifier, loadedFromFile) 101 { 102 throw new Error("Not implemented."); 103 }, 104 /** 105 * @param {!WebInspector.TimelineModel.Record} record 106 * @param {!WebInspector.TimelineModel} model 107 * @param {!WebInspector.Linkifier} linkifier 108 * @param {function(!DocumentFragment)} callback 109 * @param {boolean} loadedFromFile 110 */ 111 generateDetailsContent: function(record, model, linkifier, callback, loadedFromFile) 112 { 113 throw new Error("Not implemented."); 114 }, 115 /** 116 * @return {!Element} 117 */ 118 createBeginFrameDivider: function() 119 { 120 throw new Error("Not implemented."); 121 }, 122 /** 123 * @param {string} recordType 124 * @param {string=} title 125 * @return {!Element} 126 */ 127 createEventDivider: function(recordType, title) 128 { 129 throw new Error("Not implemented."); 130 }, 131 /** 132 * @param {!WebInspector.TimelineModel.Record} record 133 * @param {!RegExp} regExp 134 * @return {boolean} 135 */ 136 testContentMatching: function(record, regExp) 137 { 138 throw new Error("Not implemented."); 139 } 140 } 141 142 /** 143 * @return {!Object.<string, !WebInspector.TimelineCategory>} 144 */ 145 WebInspector.TimelineUIUtils.categories = function() 146 { 147 if (WebInspector.TimelineUIUtils._categories) 148 return WebInspector.TimelineUIUtils._categories; 149 WebInspector.TimelineUIUtils._categories = { 150 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%)"), 151 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%) "), 152 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%)"), 153 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%)"), 154 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%)"), 155 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%)") 156 }; 157 return WebInspector.TimelineUIUtils._categories; 158 }; 159 160 /** 161 * @return {!Object.<string, !{title: string, category: !WebInspector.TimelineCategory}>} 162 */ 163 WebInspector.TimelineUIUtils._initRecordStyles = function() 164 { 165 if (WebInspector.TimelineUIUtils._recordStylesMap) 166 return WebInspector.TimelineUIUtils._recordStylesMap; 167 168 var recordTypes = WebInspector.TimelineModel.RecordType; 169 var categories = WebInspector.TimelineUIUtils.categories(); 170 171 var recordStyles = {}; 172 recordStyles[recordTypes.Root] = { title: "#root", category: categories["loading"] }; 173 recordStyles[recordTypes.Program] = { title: WebInspector.UIString("Other"), category: categories["other"] }; 174 recordStyles[recordTypes.EventDispatch] = { title: WebInspector.UIString("Event"), category: categories["scripting"] }; 175 recordStyles[recordTypes.BeginFrame] = { title: WebInspector.UIString("Frame Start"), category: categories["rendering"] }; 176 recordStyles[recordTypes.ScheduleStyleRecalculation] = { title: WebInspector.UIString("Schedule Style Recalculation"), category: categories["rendering"] }; 177 recordStyles[recordTypes.RecalculateStyles] = { title: WebInspector.UIString("Recalculate Style"), category: categories["rendering"] }; 178 recordStyles[recordTypes.InvalidateLayout] = { title: WebInspector.UIString("Invalidate Layout"), category: categories["rendering"] }; 179 recordStyles[recordTypes.Layout] = { title: WebInspector.UIString("Layout"), category: categories["rendering"] }; 180 recordStyles[recordTypes.UpdateLayerTree] = { title: WebInspector.UIString("Update layer tree"), category: categories["rendering"] }; 181 recordStyles[recordTypes.PaintSetup] = { title: WebInspector.UIString("Paint Setup"), category: categories["painting"] }; 182 recordStyles[recordTypes.Paint] = { title: WebInspector.UIString("Paint"), category: categories["painting"] }; 183 recordStyles[recordTypes.Rasterize] = { title: WebInspector.UIString("Paint"), category: categories["painting"] }; 184 recordStyles[recordTypes.ScrollLayer] = { title: WebInspector.UIString("Scroll"), category: categories["rendering"] }; 185 recordStyles[recordTypes.DecodeImage] = { title: WebInspector.UIString("Image Decode"), category: categories["painting"] }; 186 recordStyles[recordTypes.ResizeImage] = { title: WebInspector.UIString("Image Resize"), category: categories["painting"] }; 187 recordStyles[recordTypes.CompositeLayers] = { title: WebInspector.UIString("Composite Layers"), category: categories["painting"] }; 188 recordStyles[recordTypes.ParseHTML] = { title: WebInspector.UIString("Parse HTML"), category: categories["loading"] }; 189 recordStyles[recordTypes.TimerInstall] = { title: WebInspector.UIString("Install Timer"), category: categories["scripting"] }; 190 recordStyles[recordTypes.TimerRemove] = { title: WebInspector.UIString("Remove Timer"), category: categories["scripting"] }; 191 recordStyles[recordTypes.TimerFire] = { title: WebInspector.UIString("Timer Fired"), category: categories["scripting"] }; 192 recordStyles[recordTypes.XHRReadyStateChange] = { title: WebInspector.UIString("XHR Ready State Change"), category: categories["scripting"] }; 193 recordStyles[recordTypes.XHRLoad] = { title: WebInspector.UIString("XHR Load"), category: categories["scripting"] }; 194 recordStyles[recordTypes.EvaluateScript] = { title: WebInspector.UIString("Evaluate Script"), category: categories["scripting"] }; 195 recordStyles[recordTypes.ResourceSendRequest] = { title: WebInspector.UIString("Send Request"), category: categories["loading"] }; 196 recordStyles[recordTypes.ResourceReceiveResponse] = { title: WebInspector.UIString("Receive Response"), category: categories["loading"] }; 197 recordStyles[recordTypes.ResourceFinish] = { title: WebInspector.UIString("Finish Loading"), category: categories["loading"] }; 198 recordStyles[recordTypes.FunctionCall] = { title: WebInspector.UIString("Function Call"), category: categories["scripting"] }; 199 recordStyles[recordTypes.ResourceReceivedData] = { title: WebInspector.UIString("Receive Data"), category: categories["loading"] }; 200 recordStyles[recordTypes.GCEvent] = { title: WebInspector.UIString("GC Event"), category: categories["scripting"] }; 201 recordStyles[recordTypes.JSFrame] = { title: WebInspector.UIString("JS Frame"), category: categories["scripting"] }; 202 recordStyles[recordTypes.MarkDOMContent] = { title: WebInspector.UIString("DOMContentLoaded event"), category: categories["scripting"] }; 203 recordStyles[recordTypes.MarkLoad] = { title: WebInspector.UIString("Load event"), category: categories["scripting"] }; 204 recordStyles[recordTypes.MarkFirstPaint] = { title: WebInspector.UIString("First paint"), category: categories["painting"] }; 205 recordStyles[recordTypes.TimeStamp] = { title: WebInspector.UIString("Stamp"), category: categories["scripting"] }; 206 recordStyles[recordTypes.ConsoleTime] = { title: WebInspector.UIString("Console Time"), category: categories["scripting"] }; 207 recordStyles[recordTypes.RequestAnimationFrame] = { title: WebInspector.UIString("Request Animation Frame"), category: categories["scripting"] }; 208 recordStyles[recordTypes.CancelAnimationFrame] = { title: WebInspector.UIString("Cancel Animation Frame"), category: categories["scripting"] }; 209 recordStyles[recordTypes.FireAnimationFrame] = { title: WebInspector.UIString("Animation Frame Fired"), category: categories["scripting"] }; 210 recordStyles[recordTypes.WebSocketCreate] = { title: WebInspector.UIString("Create WebSocket"), category: categories["scripting"] }; 211 recordStyles[recordTypes.WebSocketSendHandshakeRequest] = { title: WebInspector.UIString("Send WebSocket Handshake"), category: categories["scripting"] }; 212 recordStyles[recordTypes.WebSocketReceiveHandshakeResponse] = { title: WebInspector.UIString("Receive WebSocket Handshake"), category: categories["scripting"] }; 213 recordStyles[recordTypes.WebSocketDestroy] = { title: WebInspector.UIString("Destroy WebSocket"), category: categories["scripting"] }; 214 recordStyles[recordTypes.EmbedderCallback] = { title: WebInspector.UIString("Embedder Callback"), category: categories["scripting"] }; 215 216 WebInspector.TimelineUIUtils._recordStylesMap = recordStyles; 217 return recordStyles; 218 } 219 220 /** 221 * @param {!WebInspector.TimelineModel.Record} record 222 * @return {!{title: string, category: !WebInspector.TimelineCategory}} 223 */ 224 WebInspector.TimelineUIUtils.recordStyle = function(record) 225 { 226 var type = record.type(); 227 var recordStyles = WebInspector.TimelineUIUtils._initRecordStyles(); 228 var result = recordStyles[type]; 229 if (!result) { 230 result = { 231 title: WebInspector.UIString("Unknown: %s", type), 232 category: WebInspector.TimelineUIUtils.categories()["other"] 233 }; 234 recordStyles[type] = result; 235 } 236 return result; 237 } 238 239 /** 240 * @param {!WebInspector.TimelineModel} model 241 * @param {!{name: string, tasks: !Array.<!{startTime: number, endTime: number}>, firstTaskIndex: number, lastTaskIndex: number}} info 242 * @return {!Element} 243 */ 244 WebInspector.TimelineUIUtils.generateMainThreadBarPopupContent = function(model, info) 245 { 246 var firstTaskIndex = info.firstTaskIndex; 247 var lastTaskIndex = info.lastTaskIndex; 248 var tasks = info.tasks; 249 var messageCount = lastTaskIndex - firstTaskIndex + 1; 250 var cpuTime = 0; 251 252 for (var i = firstTaskIndex; i <= lastTaskIndex; ++i) { 253 var task = tasks[i]; 254 cpuTime += task.endTime - task.startTime; 255 } 256 var startTime = tasks[firstTaskIndex].startTime; 257 var endTime = tasks[lastTaskIndex].endTime; 258 var duration = endTime - startTime; 259 260 var contentHelper = new WebInspector.TimelinePopupContentHelper(info.name); 261 var durationText = WebInspector.UIString("%s (at %s)", Number.millisToString(duration, true), 262 Number.millisToString(startTime - model.minimumRecordTime(), true)); 263 contentHelper.appendTextRow(WebInspector.UIString("Duration"), durationText); 264 contentHelper.appendTextRow(WebInspector.UIString("CPU time"), Number.millisToString(cpuTime, true)); 265 contentHelper.appendTextRow(WebInspector.UIString("Message Count"), messageCount); 266 return contentHelper.contentTable(); 267 } 268 269 /** 270 * @param {!Object} total 271 * @param {!Object} addend 272 */ 273 WebInspector.TimelineUIUtils.aggregateTimeByCategory = function(total, addend) 274 { 275 for (var category in addend) 276 total[category] = (total[category] || 0) + addend[category]; 277 } 278 279 /** 280 * @param {!Object} total 281 * @param {!WebInspector.TimelineModel.Record} record 282 */ 283 WebInspector.TimelineUIUtils.aggregateTimeForRecord = function(total, record) 284 { 285 var childrenTime = 0; 286 var children = record.children(); 287 for (var i = 0; i < children.length; ++i) { 288 WebInspector.TimelineUIUtils.aggregateTimeForRecord(total, children[i]); 289 childrenTime += children[i].endTime() - children[i].startTime(); 290 } 291 var categoryName = WebInspector.TimelineUIUtils.recordStyle(record).category.name; 292 var ownTime = record.endTime() - record.startTime() - childrenTime; 293 total[categoryName] = (total[categoryName] || 0) + ownTime; 294 } 295 296 /** 297 * @param {!Object} aggregatedStats 298 */ 299 WebInspector.TimelineUIUtils._generateAggregatedInfo = function(aggregatedStats) 300 { 301 var cell = document.createElement("span"); 302 cell.className = "timeline-aggregated-info"; 303 for (var index in aggregatedStats) { 304 var label = document.createElement("div"); 305 label.className = "timeline-aggregated-category timeline-" + index; 306 cell.appendChild(label); 307 var text = document.createElement("span"); 308 text.textContent = Number.millisToString(aggregatedStats[index], true); 309 cell.appendChild(text); 310 } 311 return cell; 312 } 313 314 /** 315 * @param {!Object} aggregatedStats 316 * @param {!WebInspector.TimelineCategory=} selfCategory 317 * @param {number=} selfTime 318 * @return {!Element} 319 */ 320 WebInspector.TimelineUIUtils.generatePieChart = function(aggregatedStats, selfCategory, selfTime) 321 { 322 var element = document.createElement("div"); 323 element.className = "timeline-aggregated-info"; 324 325 var total = 0; 326 for (var categoryName in aggregatedStats) 327 total += aggregatedStats[categoryName]; 328 329 function formatter(value) 330 { 331 return Number.millisToString(value, true); 332 } 333 var pieChart = new WebInspector.PieChart(total, formatter); 334 element.appendChild(pieChart.element); 335 var footerElement = element.createChild("div", "timeline-aggregated-info-legend"); 336 337 // In case of self time, first add self, then children of the same category. 338 if (selfCategory && selfTime) { 339 // Self. 340 pieChart.addSlice(selfTime, selfCategory.fillColorStop1); 341 var rowElement = footerElement.createChild("div"); 342 rowElement.createChild("div", "timeline-aggregated-category timeline-" + selfCategory.name); 343 rowElement.createTextChild(WebInspector.UIString("%s %s (Self)", formatter(selfTime), selfCategory.title)); 344 345 // Children of the same category. 346 var categoryTime = aggregatedStats[selfCategory.name]; 347 var value = categoryTime - selfTime; 348 if (value > 0) { 349 pieChart.addSlice(value, selfCategory.fillColorStop0); 350 rowElement = footerElement.createChild("div"); 351 rowElement.createChild("div", "timeline-aggregated-category timeline-" + selfCategory.name); 352 rowElement.createTextChild(WebInspector.UIString("%s %s (Children)", formatter(value), selfCategory.title)); 353 } 354 } 355 356 // Add other categories. 357 for (var categoryName in WebInspector.TimelineUIUtils.categories()) { 358 var category = WebInspector.TimelineUIUtils.categories()[categoryName]; 359 if (category === selfCategory) 360 continue; 361 var value = aggregatedStats[category.name]; 362 if (!value) 363 continue; 364 pieChart.addSlice(value, category.fillColorStop0); 365 var rowElement = footerElement.createChild("div"); 366 rowElement.createChild("div", "timeline-aggregated-category timeline-" + category.name); 367 rowElement.createTextChild(WebInspector.UIString("%s %s", formatter(value), category.title)); 368 } 369 return element; 370 } 371 372 /** 373 * @param {!WebInspector.TimelineFrameModel} frameModel 374 * @param {!WebInspector.TimelineFrame} frame 375 * @return {!Element} 376 */ 377 WebInspector.TimelineUIUtils.generateDetailsContentForFrame = function(frameModel, frame) 378 { 379 var contentHelper = new WebInspector.TimelineDetailsContentHelper(null, null, true); 380 var durationInMillis = frame.endTime - frame.startTime; 381 var durationText = WebInspector.UIString("%s (at %s)", Number.millisToString(frame.endTime - frame.startTime, true), 382 Number.millisToString(frame.startTimeOffset, true)); 383 contentHelper.appendTextRow(WebInspector.UIString("Duration"), durationText); 384 contentHelper.appendTextRow(WebInspector.UIString("FPS"), Math.floor(1000 / durationInMillis)); 385 contentHelper.appendTextRow(WebInspector.UIString("CPU time"), Number.millisToString(frame.cpuTime, true)); 386 contentHelper.appendElementRow(WebInspector.UIString("Aggregated Time"), 387 WebInspector.TimelineUIUtils._generateAggregatedInfo(frame.timeByCategory)); 388 if (WebInspector.experimentsSettings.layersPanel.isEnabled() && frame.layerTree) { 389 contentHelper.appendElementRow(WebInspector.UIString("Layer tree"), 390 WebInspector.Linkifier.linkifyUsingRevealer(frame.layerTree, WebInspector.UIString("show"))); 391 } 392 return contentHelper.element; 393 } 394 395 /** 396 * @param {!CanvasRenderingContext2D} context 397 * @param {number} width 398 * @param {number} height 399 * @param {string} color0 400 * @param {string} color1 401 * @param {string} color2 402 * @return {!CanvasGradient} 403 */ 404 WebInspector.TimelineUIUtils.createFillStyle = function(context, width, height, color0, color1, color2) 405 { 406 var gradient = context.createLinearGradient(0, 0, width, height); 407 gradient.addColorStop(0, color0); 408 gradient.addColorStop(0.25, color1); 409 gradient.addColorStop(0.75, color1); 410 gradient.addColorStop(1, color2); 411 return gradient; 412 } 413 414 /** 415 * @param {!CanvasRenderingContext2D} context 416 * @param {number} width 417 * @param {number} height 418 * @param {!WebInspector.TimelineCategory} category 419 * @return {!CanvasGradient} 420 */ 421 WebInspector.TimelineUIUtils.createFillStyleForCategory = function(context, width, height, category) 422 { 423 return WebInspector.TimelineUIUtils.createFillStyle(context, width, height, category.fillColorStop0, category.fillColorStop1, category.borderColor); 424 } 425 426 /** 427 * @param {!WebInspector.TimelineCategory} category 428 * @return {string} 429 */ 430 WebInspector.TimelineUIUtils.createStyleRuleForCategory = function(category) 431 { 432 var selector = ".timeline-category-" + category.name + " .timeline-graph-bar, " + 433 ".panel.timeline .timeline-filters-header .filter-checkbox-filter.filter-checkbox-filter-" + category.name + " .checkbox-filter-checkbox, " + 434 ".popover .timeline-" + category.name + ", " + 435 ".timeline-details-view .timeline-" + category.name + ", " + 436 ".timeline-category-" + category.name + " .timeline-tree-icon" 437 438 return selector + " { background-image: linear-gradient(" + 439 category.fillColorStop0 + ", " + category.fillColorStop1 + " 25%, " + category.fillColorStop1 + " 25%, " + category.fillColorStop1 + ");" + 440 " border-color: " + category.borderColor + 441 "}"; 442 } 443 444 /** 445 * @param {!Array.<number>} quad 446 * @return {number} 447 */ 448 WebInspector.TimelineUIUtils._quadWidth = function(quad) 449 { 450 return Math.round(Math.sqrt(Math.pow(quad[0] - quad[2], 2) + Math.pow(quad[1] - quad[3], 2))); 451 } 452 453 /** 454 * @param {!Array.<number>} quad 455 * @return {number} 456 */ 457 WebInspector.TimelineUIUtils._quadHeight = function(quad) 458 { 459 return Math.round(Math.sqrt(Math.pow(quad[0] - quad[6], 2) + Math.pow(quad[1] - quad[7], 2))); 460 } 461 462 /** 463 * @constructor 464 * @extends {WebInspector.Object} 465 * @param {string} name 466 * @param {string} title 467 * @param {number} overviewStripGroupIndex 468 * @param {string} borderColor 469 * @param {string} backgroundColor 470 * @param {string} fillColorStop0 471 * @param {string} fillColorStop1 472 */ 473 WebInspector.TimelineCategory = function(name, title, overviewStripGroupIndex, borderColor, backgroundColor, fillColorStop0, fillColorStop1) 474 { 475 this.name = name; 476 this.title = title; 477 this.overviewStripGroupIndex = overviewStripGroupIndex; 478 this.borderColor = borderColor; 479 this.backgroundColor = backgroundColor; 480 this.fillColorStop0 = fillColorStop0; 481 this.fillColorStop1 = fillColorStop1; 482 this.hidden = false; 483 } 484 485 WebInspector.TimelineCategory.Events = { 486 VisibilityChanged: "VisibilityChanged" 487 }; 488 489 WebInspector.TimelineCategory.prototype = { 490 /** 491 * @return {boolean} 492 */ 493 get hidden() 494 { 495 return this._hidden; 496 }, 497 498 set hidden(hidden) 499 { 500 this._hidden = hidden; 501 this.dispatchEventToListeners(WebInspector.TimelineCategory.Events.VisibilityChanged, this); 502 }, 503 504 __proto__: WebInspector.Object.prototype 505 } 506 507 /** 508 * @constructor 509 * @param {string} title 510 */ 511 WebInspector.TimelinePopupContentHelper = function(title) 512 { 513 this._contentTable = document.createElement("table"); 514 var titleCell = this._createCell(WebInspector.UIString("%s - Details", title), "timeline-details-title"); 515 titleCell.colSpan = 2; 516 var titleRow = document.createElement("tr"); 517 titleRow.appendChild(titleCell); 518 this._contentTable.appendChild(titleRow); 519 } 520 521 WebInspector.TimelinePopupContentHelper.prototype = { 522 /** 523 * @return {!Element} 524 */ 525 contentTable: function() 526 { 527 return this._contentTable; 528 }, 529 530 /** 531 * @param {string|number} content 532 * @param {string=} styleName 533 */ 534 _createCell: function(content, styleName) 535 { 536 var text = document.createElement("label"); 537 text.appendChild(document.createTextNode(content)); 538 var cell = document.createElement("td"); 539 cell.className = "timeline-details"; 540 if (styleName) 541 cell.className += " " + styleName; 542 cell.textContent = content; 543 return cell; 544 }, 545 546 /** 547 * @param {string} title 548 * @param {string|number} content 549 */ 550 appendTextRow: function(title, content) 551 { 552 var row = document.createElement("tr"); 553 row.appendChild(this._createCell(title, "timeline-details-row-title")); 554 row.appendChild(this._createCell(content, "timeline-details-row-data")); 555 this._contentTable.appendChild(row); 556 }, 557 558 /** 559 * @param {string} title 560 * @param {!Node|string} content 561 */ 562 appendElementRow: function(title, content) 563 { 564 var row = document.createElement("tr"); 565 var titleCell = this._createCell(title, "timeline-details-row-title"); 566 row.appendChild(titleCell); 567 var cell = document.createElement("td"); 568 cell.className = "details"; 569 if (content instanceof Node) 570 cell.appendChild(content); 571 else 572 cell.createTextChild(content || ""); 573 row.appendChild(cell); 574 this._contentTable.appendChild(row); 575 } 576 } 577 578 /** 579 * @constructor 580 * @param {?WebInspector.Target} target 581 * @param {?WebInspector.Linkifier} linkifier 582 * @param {boolean} monospaceValues 583 */ 584 WebInspector.TimelineDetailsContentHelper = function(target, linkifier, monospaceValues) 585 { 586 this._linkifier = linkifier; 587 this._target = target; 588 this.element = document.createElement("div"); 589 this.element.className = "timeline-details-view-block"; 590 this._monospaceValues = monospaceValues; 591 } 592 593 WebInspector.TimelineDetailsContentHelper.prototype = { 594 /** 595 * @param {string} title 596 * @param {string|number|boolean} value 597 */ 598 appendTextRow: function(title, value) 599 { 600 var rowElement = this.element.createChild("div", "timeline-details-view-row"); 601 rowElement.createChild("span", "timeline-details-view-row-title").textContent = WebInspector.UIString("%s: ", title); 602 rowElement.createChild("span", "timeline-details-view-row-value" + (this._monospaceValues ? " monospace" : "")).textContent = value; 603 }, 604 605 /** 606 * @param {string} title 607 * @param {!Node|string} content 608 */ 609 appendElementRow: function(title, content) 610 { 611 var rowElement = this.element.createChild("div", "timeline-details-view-row"); 612 rowElement.createChild("span", "timeline-details-view-row-title").textContent = WebInspector.UIString("%s: ", title); 613 var valueElement = rowElement.createChild("span", "timeline-details-view-row-details" + (this._monospaceValues ? " monospace" : "")); 614 if (content instanceof Node) 615 valueElement.appendChild(content); 616 else 617 valueElement.createTextChild(content || ""); 618 }, 619 620 /** 621 * @param {string} title 622 * @param {string} url 623 * @param {number} line 624 */ 625 appendLocationRow: function(title, url, line) 626 { 627 if (!this._linkifier || !this._target) 628 return; 629 this.appendElementRow(title, this._linkifier.linkifyLocation(this._target, url, line - 1) || ""); 630 }, 631 632 /** 633 * @param {string} title 634 * @param {!Array.<!ConsoleAgent.CallFrame>} stackTrace 635 */ 636 appendStackTrace: function(title, stackTrace) 637 { 638 if (!this._linkifier || !this._target) 639 return; 640 641 var rowElement = this.element.createChild("div", "timeline-details-view-row"); 642 rowElement.createChild("span", "timeline-details-view-row-title").textContent = WebInspector.UIString("%s: ", title); 643 var stackTraceElement = rowElement.createChild("div", "timeline-details-view-row-stack-trace monospace"); 644 645 for (var i = 0; i < stackTrace.length; ++i) { 646 var stackFrame = stackTrace[i]; 647 var row = stackTraceElement.createChild("div"); 648 row.createTextChild(stackFrame.functionName || WebInspector.UIString("(anonymous function)")); 649 row.createTextChild(" @ "); 650 var urlElement = this._linkifier.linkifyLocation(this._target, stackFrame.url, stackFrame.lineNumber - 1); 651 row.appendChild(urlElement); 652 } 653 } 654 } 655