1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 /** 6 * @constructor 7 * @extends {WebInspector.TimelineUIUtils} 8 */ 9 WebInspector.TracingTimelineUIUtils = function() 10 { 11 WebInspector.TimelineUIUtils.call(this); 12 } 13 14 WebInspector.TracingTimelineUIUtils.prototype = { 15 /** 16 * @param {!WebInspector.TimelineModel.Record} record 17 * @return {boolean} 18 */ 19 isBeginFrame: function(record) 20 { 21 return record.type() === WebInspector.TracingTimelineModel.RecordType.BeginFrame; 22 }, 23 24 /** 25 * @param {!WebInspector.TimelineModel.Record} record 26 * @return {boolean} 27 */ 28 isProgram: function(record) 29 { 30 return record.type() === WebInspector.TracingTimelineModel.RecordType.Program; 31 }, 32 33 /** 34 * @param {string} recordType 35 * @return {boolean} 36 */ 37 isCoalescable: function(recordType) 38 { 39 return !!WebInspector.TracingTimelineUIUtils._coalescableRecordTypes[recordType]; 40 }, 41 42 /** 43 * @param {!WebInspector.TimelineModel.Record} record 44 * @return {boolean} 45 */ 46 isEventDivider: function(record) 47 { 48 return WebInspector.TracingTimelineUIUtils.isEventDivider(record); 49 }, 50 51 /** 52 * @param {!WebInspector.TimelineModel.Record} record 53 * @return {?Object} 54 */ 55 countersForRecord: function(record) 56 { 57 return record.type() === WebInspector.TracingTimelineModel.RecordType.UpdateCounters ? record.data() : null; 58 }, 59 60 /** 61 * @param {!WebInspector.TimelineModel.Record} record 62 * @return {?Object} 63 */ 64 highlightQuadForRecord: function(record) 65 { 66 return record.traceEvent().highlightQuad || null; 67 }, 68 69 /** 70 * @param {!WebInspector.TimelineModel.Record} record 71 * @return {string} 72 */ 73 titleForRecord: function(record) 74 { 75 return WebInspector.TracingTimelineUIUtils.styleForTraceEvent(record.traceEvent().name).title; 76 }, 77 78 /** 79 * @param {!WebInspector.TimelineModel.Record} record 80 * @param {!WebInspector.Linkifier} linkifier 81 * @param {boolean} loadedFromFile 82 * @return {?Node} 83 */ 84 buildDetailsNode: function(record, linkifier, loadedFromFile) 85 { 86 return WebInspector.TracingTimelineUIUtils.buildDetailsNodeForTraceEvent(record.traceEvent(), linkifier, loadedFromFile, record.target()); 87 }, 88 89 /** 90 * @param {!WebInspector.TimelineModel.Record} record 91 * @param {!WebInspector.TimelineModel} model 92 * @param {!WebInspector.Linkifier} linkifier 93 * @param {function(!DocumentFragment)} callback 94 * @param {boolean} loadedFromFile 95 */ 96 generateDetailsContent: function(record, model, linkifier, callback, loadedFromFile) 97 { 98 if (!(model instanceof WebInspector.TracingTimelineModel)) 99 throw new Error("Illegal argument."); 100 var tracingTimelineModel = /** @type {!WebInspector.TracingTimelineModel} */ (model); 101 WebInspector.TracingTimelineUIUtils.buildTraceEventDetails(record.traceEvent(), tracingTimelineModel, linkifier, callback, loadedFromFile, record.target()); 102 }, 103 104 /** 105 * @return {!Element} 106 */ 107 createBeginFrameDivider: function() 108 { 109 return this.createEventDivider(WebInspector.TracingTimelineModel.RecordType.BeginFrame); 110 }, 111 112 /** 113 * @param {string} recordType 114 * @param {string=} title 115 * @return {!Element} 116 */ 117 createEventDivider: function(recordType, title) 118 { 119 return WebInspector.TracingTimelineUIUtils._createEventDivider(recordType, title); 120 }, 121 122 /** 123 * @param {!WebInspector.TimelineModel.Record} record 124 * @param {!RegExp} regExp 125 * @return {boolean} 126 */ 127 testContentMatching: function(record, regExp) 128 { 129 var traceEvent = record.traceEvent(); 130 var title = WebInspector.TracingTimelineUIUtils.styleForTraceEvent(traceEvent.name).title; 131 var tokens = [title]; 132 for (var argName in traceEvent.args) { 133 var argValue = traceEvent.args[argName]; 134 for (var key in argValue) 135 tokens.push(argValue[key]); 136 } 137 return regExp.test(tokens.join("|")); 138 }, 139 140 __proto__: WebInspector.TimelineUIUtils.prototype 141 } 142 143 /** 144 * @constructor 145 * @param {string} title 146 * @param {!WebInspector.TimelineCategory} category 147 */ 148 WebInspector.TimelineRecordStyle = function(title, category) 149 { 150 this.title = title; 151 this.category = category; 152 } 153 154 /** 155 * @return {!Object.<string, !WebInspector.TimelineRecordStyle>} 156 */ 157 WebInspector.TracingTimelineUIUtils._initEventStyles = function() 158 { 159 if (WebInspector.TracingTimelineUIUtils._eventStylesMap) 160 return WebInspector.TracingTimelineUIUtils._eventStylesMap; 161 162 var recordTypes = WebInspector.TracingTimelineModel.RecordType; 163 var categories = WebInspector.TimelineUIUtils.categories(); 164 165 var eventStyles = {}; 166 eventStyles[recordTypes.Program] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Other"), categories["other"]); 167 eventStyles[recordTypes.EventDispatch] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Event"), categories["scripting"]); 168 eventStyles[recordTypes.RequestMainThreadFrame] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Request Main Thread Frame"), categories["rendering"]); 169 eventStyles[recordTypes.BeginFrame] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Frame Start"), categories["rendering"]); 170 eventStyles[recordTypes.BeginMainThreadFrame] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Frame Start (main thread)"), categories["rendering"]); 171 eventStyles[recordTypes.DrawFrame] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Draw Frame"), categories["rendering"]); 172 eventStyles[recordTypes.ScheduleStyleRecalculation] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Schedule Style Recalculation"), categories["rendering"]); 173 eventStyles[recordTypes.RecalculateStyles] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Recalculate Style"), categories["rendering"]); 174 eventStyles[recordTypes.InvalidateLayout] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Invalidate Layout"), categories["rendering"]); 175 eventStyles[recordTypes.Layout] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Layout"), categories["rendering"]); 176 eventStyles[recordTypes.PaintSetup] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Paint Setup"), categories["painting"]); 177 eventStyles[recordTypes.UpdateLayer] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Update Layer"), categories["painting"]); 178 eventStyles[recordTypes.Paint] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Paint"), categories["painting"]); 179 eventStyles[recordTypes.Rasterize] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Paint"), categories["painting"]); 180 eventStyles[recordTypes.RasterTask] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Paint"), categories["painting"]); 181 eventStyles[recordTypes.ScrollLayer] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Scroll"), categories["rendering"]); 182 eventStyles[recordTypes.CompositeLayers] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Composite Layers"), categories["painting"]); 183 eventStyles[recordTypes.ParseHTML] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Parse HTML"), categories["loading"]); 184 eventStyles[recordTypes.TimerInstall] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Install Timer"), categories["scripting"]); 185 eventStyles[recordTypes.TimerRemove] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Remove Timer"), categories["scripting"]); 186 eventStyles[recordTypes.TimerFire] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Timer Fired"), categories["scripting"]); 187 eventStyles[recordTypes.XHRReadyStateChange] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("XHR Ready State Change"), categories["scripting"]); 188 eventStyles[recordTypes.XHRLoad] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("XHR Load"), categories["scripting"]); 189 eventStyles[recordTypes.EvaluateScript] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Evaluate Script"), categories["scripting"]); 190 eventStyles[recordTypes.MarkLoad] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Load event"), categories["scripting"]); 191 eventStyles[recordTypes.MarkDOMContent] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("DOMContentLoaded event"), categories["scripting"]); 192 eventStyles[recordTypes.MarkFirstPaint] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("First paint"), categories["painting"]); 193 eventStyles[recordTypes.TimeStamp] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Stamp"), categories["scripting"]); 194 eventStyles[recordTypes.ConsoleTime] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Console Time"), categories["scripting"]); 195 eventStyles[recordTypes.ResourceSendRequest] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Send Request"), categories["loading"]); 196 eventStyles[recordTypes.ResourceReceiveResponse] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Receive Response"), categories["loading"]); 197 eventStyles[recordTypes.ResourceFinish] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Finish Loading"), categories["loading"]); 198 eventStyles[recordTypes.ResourceReceivedData] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Receive Data"), categories["loading"]); 199 eventStyles[recordTypes.FunctionCall] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Function Call"), categories["scripting"]); 200 eventStyles[recordTypes.GCEvent] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("GC Event"), categories["scripting"]); 201 eventStyles[recordTypes.JSFrame] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("JS Frame"), categories["scripting"]); 202 eventStyles[recordTypes.RequestAnimationFrame] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Request Animation Frame"), categories["scripting"]); 203 eventStyles[recordTypes.CancelAnimationFrame] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Cancel Animation Frame"), categories["scripting"]); 204 eventStyles[recordTypes.FireAnimationFrame] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Animation Frame Fired"), categories["scripting"]); 205 eventStyles[recordTypes.WebSocketCreate] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Create WebSocket"), categories["scripting"]); 206 eventStyles[recordTypes.WebSocketSendHandshakeRequest] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Send WebSocket Handshake"), categories["scripting"]); 207 eventStyles[recordTypes.WebSocketReceiveHandshakeResponse] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Receive WebSocket Handshake"), categories["scripting"]); 208 eventStyles[recordTypes.WebSocketDestroy] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Destroy WebSocket"), categories["scripting"]); 209 eventStyles[recordTypes.EmbedderCallback] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Embedder Callback"), categories["scripting"]); 210 eventStyles[recordTypes.DecodeImage] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Image Decode"), categories["painting"]); 211 eventStyles[recordTypes.ResizeImage] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Image Resize"), categories["painting"]); 212 213 WebInspector.TracingTimelineUIUtils._eventStylesMap = eventStyles; 214 return eventStyles; 215 } 216 217 WebInspector.TracingTimelineUIUtils._coalescableRecordTypes = {}; 218 WebInspector.TracingTimelineUIUtils._coalescableRecordTypes[WebInspector.TracingTimelineModel.RecordType.Layout] = 1; 219 WebInspector.TracingTimelineUIUtils._coalescableRecordTypes[WebInspector.TracingTimelineModel.RecordType.Paint] = 1; 220 WebInspector.TracingTimelineUIUtils._coalescableRecordTypes[WebInspector.TracingTimelineModel.RecordType.Rasterize] = 1; 221 WebInspector.TracingTimelineUIUtils._coalescableRecordTypes[WebInspector.TracingTimelineModel.RecordType.DecodeImage] = 1; 222 WebInspector.TracingTimelineUIUtils._coalescableRecordTypes[WebInspector.TracingTimelineModel.RecordType.ResizeImage] = 1; 223 224 /** 225 * @param {!WebInspector.TracingModel.Event} event 226 * @return {!{title: string, category: !WebInspector.TimelineCategory}} 227 */ 228 WebInspector.TracingTimelineUIUtils.eventStyle = function(event) 229 { 230 return WebInspector.TracingTimelineUIUtils.styleForTraceEvent(event.name); 231 } 232 233 /** 234 * @param {string} name 235 * @return {!{title: string, category: !WebInspector.TimelineCategory}} 236 */ 237 WebInspector.TracingTimelineUIUtils.styleForTraceEvent = function(name) 238 { 239 var eventStyles = WebInspector.TracingTimelineUIUtils._initEventStyles(); 240 var result = eventStyles[name]; 241 if (!result) { 242 result = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Unknown: %s", name), WebInspector.TimelineUIUtils.categories()["other"]); 243 eventStyles[name] = result; 244 } 245 return result; 246 } 247 248 /** 249 * @param {!WebInspector.TimelineModel.Record} record 250 * @return {boolean} 251 */ 252 WebInspector.TracingTimelineUIUtils.isEventDivider = function(record) 253 { 254 var recordTypes = WebInspector.TracingTimelineModel.RecordType; 255 if (record.type() === recordTypes.TimeStamp) 256 return true; 257 if (record.type() === recordTypes.MarkFirstPaint) 258 return true; 259 if (record.type() === recordTypes.MarkDOMContent || record.type() === recordTypes.MarkLoad) 260 return record.data()["isMainFrame"]; 261 return false; 262 } 263 264 /** 265 * @param {!WebInspector.TracingModel.Event} event 266 * @param {!WebInspector.Linkifier} linkifier 267 * @param {boolean} loadedFromFile 268 * @param {!WebInspector.Target} target 269 * @return {?Node} 270 */ 271 WebInspector.TracingTimelineUIUtils.buildDetailsNodeForTraceEvent = function(event, linkifier, loadedFromFile, target) 272 { 273 var recordType = WebInspector.TracingTimelineModel.RecordType; 274 275 var details; 276 var detailsText; 277 var eventData = event.args.data; 278 switch (event.name) { 279 case recordType.GCEvent: 280 var delta = event.args["usedHeapSizeBefore"] - event.args["usedHeapSizeAfter"]; 281 detailsText = WebInspector.UIString("%s collected", Number.bytesToString(delta)); 282 break; 283 case recordType.TimerFire: 284 detailsText = eventData["timerId"]; 285 break; 286 case recordType.FunctionCall: 287 details = linkifyLocation(eventData["scriptId"], eventData["scriptName"], eventData["scriptLine"], 0); 288 break; 289 case recordType.FireAnimationFrame: 290 detailsText = eventData["id"]; 291 break; 292 case recordType.EventDispatch: 293 detailsText = eventData ? eventData["type"] : null; 294 break; 295 case recordType.Paint: 296 var width = WebInspector.TimelineUIUtils._quadWidth(eventData.clip); 297 var height = WebInspector.TimelineUIUtils._quadHeight(eventData.clip); 298 if (width && height) 299 detailsText = WebInspector.UIString("%d\u2009\u00d7\u2009%d", width, height); 300 break; 301 case recordType.TimerInstall: 302 case recordType.TimerRemove: 303 details = linkifyTopCallFrame(); 304 detailsText = eventData["timerId"]; 305 break; 306 case recordType.RequestAnimationFrame: 307 case recordType.CancelAnimationFrame: 308 details = linkifyTopCallFrame(); 309 detailsText = eventData["id"]; 310 break; 311 case recordType.ParseHTML: 312 case recordType.RecalculateStyles: 313 details = linkifyTopCallFrame(); 314 break; 315 case recordType.EvaluateScript: 316 var url = eventData["url"]; 317 if (url) 318 details = linkifyLocation("", url, eventData["lineNumber"], 0); 319 break; 320 case recordType.XHRReadyStateChange: 321 case recordType.XHRLoad: 322 case recordType.ResourceSendRequest: 323 var url = eventData["url"]; 324 if (url) 325 detailsText = WebInspector.displayNameForURL(url); 326 break; 327 case recordType.ResourceReceivedData: 328 case recordType.ResourceReceiveResponse: 329 case recordType.ResourceFinish: 330 var initiator = event.initiator; 331 if (initiator) { 332 var url = initiator.args.data["url"]; 333 if (url) 334 detailsText = WebInspector.displayNameForURL(url); 335 } 336 break; 337 case recordType.ConsoleTime: 338 detailsText = eventData["message"]; 339 break; 340 case recordType.EmbedderCallback: 341 detailsText = eventData["callbackName"]; 342 break; 343 344 case recordType.PaintImage: 345 case recordType.DecodeImage: 346 case recordType.ResizeImage: 347 case recordType.DecodeLazyPixelRef: 348 var url = event.imageURL; 349 if (url) 350 detailsText = WebInspector.displayNameForURL(url); 351 break; 352 353 default: 354 details = linkifyTopCallFrame(); 355 break; 356 } 357 358 if (!details && detailsText) 359 details = document.createTextNode(detailsText); 360 return details; 361 362 /** 363 * @param {string} scriptId 364 * @param {string} url 365 * @param {number} lineNumber 366 * @param {number=} columnNumber 367 */ 368 function linkifyLocation(scriptId, url, lineNumber, columnNumber) 369 { 370 if (!loadedFromFile && scriptId !== "0") { 371 var location = new WebInspector.DebuggerModel.Location( 372 target, 373 scriptId, 374 lineNumber - 1, 375 (columnNumber || 1) - 1); 376 return linkifier.linkifyRawLocation(location, "timeline-details"); 377 } 378 379 if (!url) 380 return null; 381 382 // FIXME(62725): stack trace line/column numbers are one-based. 383 columnNumber = columnNumber ? columnNumber - 1 : 0; 384 return linkifier.linkifyLocation(target, url, lineNumber - 1, columnNumber, "timeline-details"); 385 } 386 387 /** 388 * @param {!ConsoleAgent.CallFrame} callFrame 389 */ 390 function linkifyCallFrame(callFrame) 391 { 392 return linkifyLocation(callFrame.scriptId, callFrame.url, callFrame.lineNumber, callFrame.columnNumber); 393 } 394 395 /** 396 * @return {?Element} 397 */ 398 function linkifyTopCallFrame() 399 { 400 var stackTrace = event.stackTrace; 401 if (!stackTrace) { 402 var initiator = event.initiator; 403 if (initiator) 404 stackTrace = initiator.stackTrace; 405 } 406 if (!stackTrace || !stackTrace.length) 407 return null; 408 return linkifyCallFrame(stackTrace[0]); 409 } 410 } 411 412 /** 413 * @param {!WebInspector.TracingModel.Event} event 414 * @param {!WebInspector.TracingTimelineModel} model 415 * @param {!WebInspector.Linkifier} linkifier 416 * @param {function(!DocumentFragment)} callback 417 * @param {boolean} loadedFromFile 418 * @param {!WebInspector.Target} target 419 */ 420 WebInspector.TracingTimelineUIUtils.buildTraceEventDetails = function(event, model, linkifier, callback, loadedFromFile, target) 421 { 422 var relatedNode = null; 423 var barrier = new CallbackBarrier(); 424 if (!event.previewElement) { 425 if (event.imageURL) 426 WebInspector.DOMPresentationUtils.buildImagePreviewContents(target, event.imageURL, false, barrier.createCallback(saveImage)); 427 else if (event.picture) 428 WebInspector.TracingTimelineUIUtils._buildPicturePreviewContent(event.picture, barrier.createCallback(saveImage)); 429 } 430 if (event.backendNodeId) 431 target.domModel.pushNodesByBackendIdsToFrontend([event.backendNodeId], barrier.createCallback(setRelatedNode)); 432 barrier.callWhenDone(callbackWrapper); 433 434 /** 435 * @param {!Element=} element 436 */ 437 function saveImage(element) 438 { 439 event.previewElement = element || null; 440 } 441 442 /** 443 * @param {?Array.<!DOMAgent.NodeId>} nodeIds 444 */ 445 function setRelatedNode(nodeIds) 446 { 447 if (nodeIds) 448 relatedNode = target.domModel.nodeForId(nodeIds[0]); 449 } 450 451 function callbackWrapper() 452 { 453 callback(WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously(event, model, linkifier, relatedNode, loadedFromFile, target)); 454 } 455 } 456 457 /** 458 * @param {!WebInspector.TracingModel.Event} event 459 * @param {!WebInspector.TracingTimelineModel} model 460 * @param {!WebInspector.Linkifier} linkifier 461 * @param {?WebInspector.DOMNode} relatedNode 462 * @param {boolean} loadedFromFile 463 * @param {!WebInspector.Target} target 464 * @return {!DocumentFragment} 465 */ 466 WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously = function(event, model, linkifier, relatedNode, loadedFromFile, target) 467 { 468 var fragment = document.createDocumentFragment(); 469 var stats = WebInspector.TracingTimelineUIUtils._aggregatedStatsForTraceEvent(model, event); 470 var pieChart = stats.hasChildren ? 471 WebInspector.TimelineUIUtils.generatePieChart(stats.aggregatedStats, WebInspector.TracingTimelineUIUtils.styleForTraceEvent(event.name).category, event.selfTime) : 472 WebInspector.TimelineUIUtils.generatePieChart(stats.aggregatedStats); 473 fragment.appendChild(pieChart); 474 475 var recordTypes = WebInspector.TracingTimelineModel.RecordType; 476 477 // The messages may vary per event.name; 478 var callSiteStackTraceLabel; 479 var callStackLabel; 480 var relatedNodeLabel; 481 482 var contentHelper = new WebInspector.TimelineDetailsContentHelper(target, linkifier, true); 483 contentHelper.appendTextRow(WebInspector.UIString("Self Time"), Number.millisToString(event.selfTime, true)); 484 contentHelper.appendTextRow(WebInspector.UIString("Start Time"), Number.millisToString((event.startTime - model.minimumRecordTime()))); 485 var eventData = event.args.data; 486 var initiator = event.initiator; 487 488 switch (event.name) { 489 case recordTypes.GCEvent: 490 var delta = event.args["usedHeapSizeBefore"] - event.args["usedHeapSizeAfter"]; 491 contentHelper.appendTextRow(WebInspector.UIString("Collected"), Number.bytesToString(delta)); 492 break; 493 case recordTypes.TimerFire: 494 callSiteStackTraceLabel = WebInspector.UIString("Timer installed"); 495 // Fall-through intended. 496 497 case recordTypes.TimerInstall: 498 case recordTypes.TimerRemove: 499 contentHelper.appendTextRow(WebInspector.UIString("Timer ID"), eventData["timerId"]); 500 if (event.name === recordTypes.TimerInstall) { 501 contentHelper.appendTextRow(WebInspector.UIString("Timeout"), Number.millisToString(eventData["timeout"])); 502 contentHelper.appendTextRow(WebInspector.UIString("Repeats"), !eventData["singleShot"]); 503 } 504 break; 505 case recordTypes.FireAnimationFrame: 506 callSiteStackTraceLabel = WebInspector.UIString("Animation frame requested"); 507 contentHelper.appendTextRow(WebInspector.UIString("Callback ID"), eventData["id"]); 508 break; 509 case recordTypes.FunctionCall: 510 if (eventData["scriptName"]) 511 contentHelper.appendLocationRow(WebInspector.UIString("Location"), eventData["scriptName"], eventData["scriptLine"]); 512 break; 513 case recordTypes.ResourceSendRequest: 514 case recordTypes.ResourceReceiveResponse: 515 case recordTypes.ResourceReceivedData: 516 case recordTypes.ResourceFinish: 517 var url = (event.name === recordTypes.ResourceSendRequest) ? eventData["url"] : initiator.args.data["url"]; 518 if (url) 519 contentHelper.appendElementRow(WebInspector.UIString("Resource"), WebInspector.linkifyResourceAsNode(url)); 520 if (eventData["requestMethod"]) 521 contentHelper.appendTextRow(WebInspector.UIString("Request Method"), eventData["requestMethod"]); 522 if (typeof eventData["statusCode"] === "number") 523 contentHelper.appendTextRow(WebInspector.UIString("Status Code"), eventData["statusCode"]); 524 if (eventData["mimeType"]) 525 contentHelper.appendTextRow(WebInspector.UIString("MIME Type"), eventData["mimeType"]); 526 if (eventData["encodedDataLength"]) 527 contentHelper.appendTextRow(WebInspector.UIString("Encoded Data Length"), WebInspector.UIString("%d Bytes", eventData["encodedDataLength"])); 528 break; 529 case recordTypes.EvaluateScript: 530 var url = eventData["url"]; 531 if (url) 532 contentHelper.appendLocationRow(WebInspector.UIString("Script"), url, eventData["lineNumber"]); 533 break; 534 case recordTypes.Paint: 535 var clip = eventData["clip"]; 536 contentHelper.appendTextRow(WebInspector.UIString("Location"), WebInspector.UIString("(%d, %d)", clip[0], clip[1])); 537 var clipWidth = WebInspector.TimelineUIUtils._quadWidth(clip); 538 var clipHeight = WebInspector.TimelineUIUtils._quadHeight(clip); 539 contentHelper.appendTextRow(WebInspector.UIString("Dimensions"), WebInspector.UIString("%d %d", clipWidth, clipHeight)); 540 // Fall-through intended. 541 542 case recordTypes.PaintSetup: 543 case recordTypes.Rasterize: 544 case recordTypes.ScrollLayer: 545 relatedNodeLabel = WebInspector.UIString("Layer root"); 546 break; 547 case recordTypes.PaintImage: 548 case recordTypes.DecodeLazyPixelRef: 549 case recordTypes.DecodeImage: 550 case recordTypes.ResizeImage: 551 case recordTypes.DrawLazyPixelRef: 552 relatedNodeLabel = WebInspector.UIString("Image element"); 553 if (event.imageURL) 554 contentHelper.appendElementRow(WebInspector.UIString("Image URL"), WebInspector.linkifyResourceAsNode(event.imageURL)); 555 break; 556 case recordTypes.RecalculateStyles: // We don't want to see default details. 557 contentHelper.appendTextRow(WebInspector.UIString("Elements affected"), event.args["elementCount"]); 558 callStackLabel = WebInspector.UIString("Styles recalculation forced"); 559 break; 560 case recordTypes.Layout: 561 var beginData = event.args["beginData"]; 562 contentHelper.appendTextRow(WebInspector.UIString("Nodes that need layout"), beginData["dirtyObjects"]); 563 contentHelper.appendTextRow(WebInspector.UIString("Layout tree size"), beginData["totalObjects"]); 564 contentHelper.appendTextRow(WebInspector.UIString("Layout scope"), 565 beginData["partialLayout"] ? WebInspector.UIString("Partial") : WebInspector.UIString("Whole document")); 566 callSiteStackTraceLabel = WebInspector.UIString("Layout invalidated"); 567 callStackLabel = WebInspector.UIString("Layout forced"); 568 relatedNodeLabel = WebInspector.UIString("Layout root"); 569 break; 570 case recordTypes.ConsoleTime: 571 contentHelper.appendTextRow(WebInspector.UIString("Message"), eventData["message"]); 572 break; 573 case recordTypes.WebSocketCreate: 574 case recordTypes.WebSocketSendHandshakeRequest: 575 case recordTypes.WebSocketReceiveHandshakeResponse: 576 case recordTypes.WebSocketDestroy: 577 var initiatorData = initiator ? initiator.args.data : eventData; 578 if (typeof initiatorData["webSocketURL"] !== "undefined") 579 contentHelper.appendTextRow(WebInspector.UIString("URL"), initiatorData["webSocketURL"]); 580 if (typeof initiatorData["webSocketProtocol"] !== "undefined") 581 contentHelper.appendTextRow(WebInspector.UIString("WebSocket Protocol"), initiatorData["webSocketProtocol"]); 582 if (typeof eventData["message"] !== "undefined") 583 contentHelper.appendTextRow(WebInspector.UIString("Message"), eventData["message"]); 584 break; 585 case recordTypes.EmbedderCallback: 586 contentHelper.appendTextRow(WebInspector.UIString("Callback Function"), eventData["callbackName"]); 587 break; 588 default: 589 var detailsNode = WebInspector.TracingTimelineUIUtils.buildDetailsNodeForTraceEvent(event, linkifier, loadedFromFile, target); 590 if (detailsNode) 591 contentHelper.appendElementRow(WebInspector.UIString("Details"), detailsNode); 592 break; 593 } 594 595 if (relatedNode) 596 contentHelper.appendElementRow(relatedNodeLabel || WebInspector.UIString("Related node"), WebInspector.DOMPresentationUtils.linkifyNodeReference(relatedNode)); 597 598 if (eventData && eventData["scriptName"] && event.name !== recordTypes.FunctionCall) 599 contentHelper.appendLocationRow(WebInspector.UIString("Function Call"), eventData["scriptName"], eventData["scriptLine"]); 600 601 if (initiator) { 602 var callSiteStackTrace = initiator.stackTrace; 603 if (callSiteStackTrace) 604 contentHelper.appendStackTrace(callSiteStackTraceLabel || WebInspector.UIString("Call Site stack"), callSiteStackTrace); 605 } 606 var eventStackTrace = event.stackTrace; 607 if (eventStackTrace) 608 contentHelper.appendStackTrace(callStackLabel || WebInspector.UIString("Call Stack"), eventStackTrace); 609 610 var warning = event.warning; 611 if (warning) { 612 var div = document.createElement("div"); 613 div.textContent = warning; 614 contentHelper.appendElementRow(WebInspector.UIString("Warning"), div); 615 } 616 if (event.previewElement) 617 contentHelper.appendElementRow(WebInspector.UIString("Preview"), event.previewElement); 618 fragment.appendChild(contentHelper.element); 619 return fragment; 620 } 621 622 /** 623 * @param {!WebInspector.TracingTimelineModel} model 624 * @param {!WebInspector.TracingModel.Event} event 625 * @return {!{ aggregatedStats: !Object, hasChildren: boolean }} 626 */ 627 WebInspector.TracingTimelineUIUtils._aggregatedStatsForTraceEvent = function(model, event) 628 { 629 var events = model.inspectedTargetEvents(); 630 /** 631 * @param {number} startTime 632 * @param {!WebInspector.TracingModel.Event} e 633 * @return {number} 634 */ 635 function eventComparator(startTime, e) 636 { 637 return startTime - e.startTime; 638 } 639 var index = events.binaryIndexOf(event.startTime, eventComparator); 640 var hasChildren = false; 641 var aggregatedStats = {}; 642 var endTime = event.endTime; 643 if (endTime) { 644 for (var i = index; i < events.length; i++) { 645 var nextEvent = events[i]; 646 if (nextEvent.startTime >= endTime) 647 break; 648 if (!nextEvent.selfTime) 649 continue; 650 if (i > index) 651 hasChildren = true; 652 var category = WebInspector.TracingTimelineUIUtils.styleForTraceEvent(nextEvent.name).category.name; 653 aggregatedStats[category] = (aggregatedStats[category] || 0) + nextEvent.selfTime; 654 } 655 } 656 return { aggregatedStats: aggregatedStats, hasChildren: hasChildren }; 657 } 658 659 /** 660 * @param {string} encodedPicture 661 * @param {function(!Element=)} callback 662 */ 663 WebInspector.TracingTimelineUIUtils._buildPicturePreviewContent = function(encodedPicture, callback) 664 { 665 var snapshotId; 666 667 LayerTreeAgent.loadSnapshot(encodedPicture, onSnapshotLoaded); 668 /** 669 * @param {string} error 670 * @param {string} id 671 */ 672 function onSnapshotLoaded(error, id) 673 { 674 if (error) { 675 console.error("LayerTreeAgent.loadSnapshot(): " + error); 676 callback(); 677 return; 678 } 679 snapshotId = id; 680 LayerTreeAgent.replaySnapshot(snapshotId, onSnapshotReplayed); 681 } 682 683 /** 684 * @param {string} error 685 * @param {string} encodedBitmap 686 */ 687 function onSnapshotReplayed(error, encodedBitmap) 688 { 689 LayerTreeAgent.releaseSnapshot(snapshotId); 690 if (error) { 691 console.error("LayerTreeAgent.replaySnapshot(): " + error); 692 callback(); 693 return; 694 } 695 var container = document.createElement("div"); 696 container.className = "image-preview-container"; 697 var img = container.createChild("img"); 698 img.src = encodedBitmap; 699 callback(container); 700 } 701 } 702 703 /** 704 * @param {string} recordType 705 * @param {string=} title 706 * @return {!Element} 707 */ 708 WebInspector.TracingTimelineUIUtils._createEventDivider = function(recordType, title) 709 { 710 var eventDivider = document.createElement("div"); 711 eventDivider.className = "resources-event-divider"; 712 var recordTypes = WebInspector.TracingTimelineModel.RecordType; 713 714 if (recordType === recordTypes.MarkDOMContent) 715 eventDivider.className += " resources-blue-divider"; 716 else if (recordType === recordTypes.MarkLoad) 717 eventDivider.className += " resources-red-divider"; 718 else if (recordType === recordTypes.MarkFirstPaint) 719 eventDivider.className += " resources-green-divider"; 720 else if (recordType === recordTypes.TimeStamp) 721 eventDivider.className += " resources-orange-divider"; 722 else if (recordType === recordTypes.BeginFrame) 723 eventDivider.className += " timeline-frame-divider"; 724 725 if (title) 726 eventDivider.title = title; 727 728 return eventDivider; 729 } 730