OLD | NEW |
(Empty) | |
| 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 */ |
| 7 WebInspector.TracingTimelineUIUtils = function() { } |
| 8 |
| 9 /** |
| 10 * @param {!WebInspector.TracingModel.Event} event |
| 11 * @param {!WebInspector.Linkifier} linkifier |
| 12 * @param {boolean} loadedFromFile |
| 13 * @param {!WebInspector.Target} target |
| 14 * @return {?Node} |
| 15 */ |
| 16 WebInspector.TracingTimelineUIUtils.buildDetailsNodeForTraceEvent = function(eve
nt, linkifier, loadedFromFile, target) |
| 17 { |
| 18 var recordType = WebInspector.TracingTimelineModel.RecordType; |
| 19 |
| 20 var details; |
| 21 var detailsText; |
| 22 var eventData = event.args.data; |
| 23 switch (event.name) { |
| 24 case recordType.GCEvent: |
| 25 var delta = event.args["usedHeapSizeBefore"] - event.args["usedHeapSizeA
fter"]; |
| 26 detailsText = WebInspector.UIString("%s collected", Number.bytesToString
(delta)); |
| 27 break; |
| 28 case recordType.TimerFire: |
| 29 detailsText = eventData["timerId"]; |
| 30 break; |
| 31 case recordType.FunctionCall: |
| 32 details = linkifyLocation(eventData["scriptId"], eventData["scriptName"]
, eventData["scriptLine"], 0); |
| 33 break; |
| 34 case recordType.FireAnimationFrame: |
| 35 detailsText = eventData["id"]; |
| 36 break; |
| 37 case recordType.EventDispatch: |
| 38 detailsText = eventData ? eventData["type"] : null; |
| 39 break; |
| 40 case recordType.Paint: |
| 41 var width = WebInspector.TimelineUIUtils._quadWidth(eventData.clip); |
| 42 var height = WebInspector.TimelineUIUtils._quadHeight(eventData.clip); |
| 43 if (width && height) |
| 44 detailsText = WebInspector.UIString("%d\u2009\u00d7\u2009%d", width,
height); |
| 45 break; |
| 46 case recordType.TimerInstall: |
| 47 case recordType.TimerRemove: |
| 48 details = linkifyTopCallFrame(); |
| 49 detailsText = eventData["timerId"]; |
| 50 break; |
| 51 case recordType.RequestAnimationFrame: |
| 52 case recordType.CancelAnimationFrame: |
| 53 details = linkifyTopCallFrame(); |
| 54 detailsText = eventData["id"]; |
| 55 break; |
| 56 case recordType.ParseHTML: |
| 57 case recordType.RecalculateStyles: |
| 58 details = linkifyTopCallFrame(); |
| 59 break; |
| 60 case recordType.EvaluateScript: |
| 61 var url = eventData["url"]; |
| 62 if (url) |
| 63 details = linkifyLocation("", url, eventData["lineNumber"], 0); |
| 64 break; |
| 65 case recordType.XHRReadyStateChange: |
| 66 case recordType.XHRLoad: |
| 67 case recordType.ResourceSendRequest: |
| 68 case recordType.DecodeImage: |
| 69 case recordType.ResizeImage: |
| 70 var url = eventData["url"]; |
| 71 if (url) |
| 72 detailsText = WebInspector.displayNameForURL(url); |
| 73 break; |
| 74 case recordType.ResourceReceivedData: |
| 75 case recordType.ResourceReceiveResponse: |
| 76 case recordType.ResourceFinish: |
| 77 var initiator = event.initiator; |
| 78 if (initiator) { |
| 79 var url = initiator.args.data["url"]; |
| 80 if (url) |
| 81 detailsText = WebInspector.displayNameForURL(url); |
| 82 } |
| 83 break; |
| 84 case recordType.ConsoleTime: |
| 85 detailsText = eventData["message"]; |
| 86 break; |
| 87 case recordType.EmbedderCallback: |
| 88 detailsText = eventData["callbackName"]; |
| 89 break; |
| 90 |
| 91 case recordType.PaintImage: |
| 92 case recordType.DecodeImage: |
| 93 case recordType.ResizeImage: |
| 94 case recordType.DecodeLazyPixelRef: |
| 95 var url = event.imageURL; |
| 96 if (url) |
| 97 detailsText = WebInspector.displayNameForURL(url); |
| 98 break; |
| 99 |
| 100 default: |
| 101 details = linkifyTopCallFrame(); |
| 102 break; |
| 103 } |
| 104 |
| 105 if (!details && detailsText) |
| 106 details = document.createTextNode(detailsText); |
| 107 return details; |
| 108 |
| 109 /** |
| 110 * @param {string} scriptId |
| 111 * @param {string} url |
| 112 * @param {number} lineNumber |
| 113 * @param {number=} columnNumber |
| 114 */ |
| 115 function linkifyLocation(scriptId, url, lineNumber, columnNumber) |
| 116 { |
| 117 if (!loadedFromFile && scriptId !== "0") { |
| 118 var location = new WebInspector.DebuggerModel.Location( |
| 119 target, |
| 120 scriptId, |
| 121 lineNumber - 1, |
| 122 (columnNumber || 1) - 1); |
| 123 return linkifier.linkifyRawLocation(location, "timeline-details"); |
| 124 } |
| 125 |
| 126 if (!url) |
| 127 return null; |
| 128 |
| 129 // FIXME(62725): stack trace line/column numbers are one-based. |
| 130 columnNumber = columnNumber ? columnNumber - 1 : 0; |
| 131 return linkifier.linkifyLocation(target, url, lineNumber - 1, columnNumb
er, "timeline-details"); |
| 132 } |
| 133 |
| 134 /** |
| 135 * @param {!ConsoleAgent.CallFrame} callFrame |
| 136 */ |
| 137 function linkifyCallFrame(callFrame) |
| 138 { |
| 139 return linkifyLocation(callFrame.scriptId, callFrame.url, callFrame.line
Number, callFrame.columnNumber); |
| 140 } |
| 141 |
| 142 /** |
| 143 * @return {?Element} |
| 144 */ |
| 145 function linkifyTopCallFrame() |
| 146 { |
| 147 var stackTrace = event.stackTrace; |
| 148 if (!stackTrace) { |
| 149 var initiator = event.initiator; |
| 150 if (initiator) |
| 151 stackTrace = initiator.stackTrace; |
| 152 } |
| 153 if (!stackTrace || !stackTrace.length) |
| 154 return null; |
| 155 return linkifyCallFrame(stackTrace[0]); |
| 156 } |
| 157 } |
| 158 |
| 159 /** |
| 160 * @param {!WebInspector.TracingModel.Event} event |
| 161 * @param {!WebInspector.TracingTimelineModel} model |
| 162 * @param {!WebInspector.Linkifier} linkifier |
| 163 * @param {function(!DocumentFragment)} callback |
| 164 * @param {boolean} loadedFromFile |
| 165 * @param {!WebInspector.Target} target |
| 166 */ |
| 167 WebInspector.TracingTimelineUIUtils.buildTraceEventDetails = function(event, mod
el, linkifier, callback, loadedFromFile, target) |
| 168 { |
| 169 var relatedNode = null; |
| 170 var barrier = new CallbackBarrier(); |
| 171 if (event.imageURL && !event.previewElement) |
| 172 WebInspector.DOMPresentationUtils.buildImagePreviewContents(target, even
t.imageURL, false, barrier.createCallback(saveImage)); |
| 173 if (event.backendNodeId) |
| 174 target.domModel.pushNodesByBackendIdsToFrontend([event.backendNodeId], b
arrier.createCallback(setRelatedNode)); |
| 175 barrier.callWhenDone(callbackWrapper); |
| 176 |
| 177 /** |
| 178 * @param {!Element=} element |
| 179 */ |
| 180 function saveImage(element) |
| 181 { |
| 182 event.previewElement = element || null; |
| 183 } |
| 184 |
| 185 /** |
| 186 * @param {?Array.<!DOMAgent.NodeId>} nodeIds |
| 187 */ |
| 188 function setRelatedNode(nodeIds) |
| 189 { |
| 190 if (nodeIds) |
| 191 relatedNode = target.domModel.nodeForId(nodeIds[0]); |
| 192 } |
| 193 |
| 194 function callbackWrapper() |
| 195 { |
| 196 callback(WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSync
hronously(event, model, linkifier, relatedNode, loadedFromFile, target)); |
| 197 } |
| 198 } |
| 199 |
| 200 /** |
| 201 * @param {!WebInspector.TracingModel.Event} event |
| 202 * @param {!WebInspector.TracingTimelineModel} model |
| 203 * @param {!WebInspector.Linkifier} linkifier |
| 204 * @param {?WebInspector.DOMNode} relatedNode |
| 205 * @param {boolean} loadedFromFile |
| 206 * @param {!WebInspector.Target} target |
| 207 * @return {!DocumentFragment} |
| 208 */ |
| 209 WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously = funct
ion(event, model, linkifier, relatedNode, loadedFromFile, target) |
| 210 { |
| 211 var fragment = document.createDocumentFragment(); |
| 212 var stats = WebInspector.TracingTimelineUIUtils._aggregatedStatsForTraceEven
t(model, event); |
| 213 var pieChart = stats.hasChildren ? |
| 214 WebInspector.TimelineUIUtils.generatePieChart(stats.aggregatedStats, Web
Inspector.TimelineUIUtils.styleForTimelineEvent(event.name).category, event.self
Time / 1000) : |
| 215 WebInspector.TimelineUIUtils.generatePieChart(stats.aggregatedStats); |
| 216 fragment.appendChild(pieChart); |
| 217 |
| 218 var recordTypes = WebInspector.TracingTimelineModel.RecordType; |
| 219 |
| 220 // The messages may vary per event.name; |
| 221 var callSiteStackTraceLabel; |
| 222 var callStackLabel; |
| 223 var relatedNodeLabel; |
| 224 |
| 225 var contentHelper = new WebInspector.TimelineDetailsContentHelper(target, li
nkifier, true); |
| 226 contentHelper.appendTextRow(WebInspector.UIString("Self Time"), Number.milli
sToString(event.selfTime / 1000, true)); |
| 227 contentHelper.appendTextRow(WebInspector.UIString("Start Time"), Number.mill
isToString((event.startTime - model.minimumRecordTime()) / 1000)); |
| 228 var eventData = event.args.data; |
| 229 var initiator = event.initiator; |
| 230 |
| 231 switch (event.name) { |
| 232 case recordTypes.GCEvent: |
| 233 var delta = event.args["usedHeapSizeBefore"] - event.args["usedHeapSizeA
fter"]; |
| 234 contentHelper.appendTextRow(WebInspector.UIString("Collected"), Number.b
ytesToString(delta)); |
| 235 break; |
| 236 case recordTypes.TimerFire: |
| 237 callSiteStackTraceLabel = WebInspector.UIString("Timer installed"); |
| 238 // Fall-through intended. |
| 239 |
| 240 case recordTypes.TimerInstall: |
| 241 case recordTypes.TimerRemove: |
| 242 contentHelper.appendTextRow(WebInspector.UIString("Timer ID"), eventData
["timerId"]); |
| 243 if (event.name === recordTypes.TimerInstall) { |
| 244 contentHelper.appendTextRow(WebInspector.UIString("Timeout"), Number
.millisToString(eventData["timeout"])); |
| 245 contentHelper.appendTextRow(WebInspector.UIString("Repeats"), !event
Data["singleShot"]); |
| 246 } |
| 247 break; |
| 248 case recordTypes.FireAnimationFrame: |
| 249 callSiteStackTraceLabel = WebInspector.UIString("Animation frame request
ed"); |
| 250 contentHelper.appendTextRow(WebInspector.UIString("Callback ID"), eventD
ata["id"]); |
| 251 break; |
| 252 case recordTypes.FunctionCall: |
| 253 if (eventData["scriptName"]) |
| 254 contentHelper.appendLocationRow(WebInspector.UIString("Location"), e
ventData["scriptName"], eventData["scriptLine"]); |
| 255 break; |
| 256 case recordTypes.ResourceSendRequest: |
| 257 case recordTypes.ResourceReceiveResponse: |
| 258 case recordTypes.ResourceReceivedData: |
| 259 case recordTypes.ResourceFinish: |
| 260 var url = (event.name === recordTypes.ResourceSendRequest) ? eventData["
url"] : initiator.args.data["url"]; |
| 261 if (url) |
| 262 contentHelper.appendElementRow(WebInspector.UIString("Resource"), We
bInspector.linkifyResourceAsNode(url)); |
| 263 if (event.previewElement) |
| 264 contentHelper.appendElementRow(WebInspector.UIString("Preview"), eve
nt.previewElement); |
| 265 if (eventData["requestMethod"]) |
| 266 contentHelper.appendTextRow(WebInspector.UIString("Request Method"),
eventData["requestMethod"]); |
| 267 if (typeof eventData["statusCode"] === "number") |
| 268 contentHelper.appendTextRow(WebInspector.UIString("Status Code"), ev
entData["statusCode"]); |
| 269 if (eventData["mimeType"]) |
| 270 contentHelper.appendTextRow(WebInspector.UIString("MIME Type"), even
tData["mimeType"]); |
| 271 if (eventData["encodedDataLength"]) |
| 272 contentHelper.appendTextRow(WebInspector.UIString("Encoded Data Leng
th"), WebInspector.UIString("%d Bytes", eventData["encodedDataLength"])); |
| 273 break; |
| 274 case recordTypes.EvaluateScript: |
| 275 var url = eventData["url"]; |
| 276 if (url) |
| 277 contentHelper.appendLocationRow(WebInspector.UIString("Script"), url
, eventData["lineNumber"]); |
| 278 break; |
| 279 case recordTypes.Paint: |
| 280 var clip = eventData["clip"]; |
| 281 contentHelper.appendTextRow(WebInspector.UIString("Location"), WebInspec
tor.UIString("(%d, %d)", clip[0], clip[1])); |
| 282 var clipWidth = WebInspector.TimelineUIUtils._quadWidth(clip); |
| 283 var clipHeight = WebInspector.TimelineUIUtils._quadHeight(clip); |
| 284 contentHelper.appendTextRow(WebInspector.UIString("Dimensions"), WebInsp
ector.UIString("%d × %d", clipWidth, clipHeight)); |
| 285 // Fall-through intended. |
| 286 |
| 287 case recordTypes.PaintSetup: |
| 288 case recordTypes.Rasterize: |
| 289 case recordTypes.ScrollLayer: |
| 290 relatedNodeLabel = WebInspector.UIString("Layer root"); |
| 291 break; |
| 292 case recordTypes.PaintImage: |
| 293 case recordTypes.DecodeLazyPixelRef: |
| 294 case recordTypes.DecodeImage: |
| 295 case recordTypes.ResizeImage: |
| 296 case recordTypes.DrawLazyPixelRef: |
| 297 relatedNodeLabel = WebInspector.UIString("Image element"); |
| 298 if (event.imageURL) |
| 299 contentHelper.appendElementRow(WebInspector.UIString("Image URL"), W
ebInspector.linkifyResourceAsNode(event.imageURL)); |
| 300 if (event.previewElement) |
| 301 contentHelper.appendElementRow(WebInspector.UIString("Preview"), eve
nt.previewElement); |
| 302 break; |
| 303 case recordTypes.RecalculateStyles: // We don't want to see default details. |
| 304 contentHelper.appendTextRow(WebInspector.UIString("Elements affected"),
event.args["elementCount"]); |
| 305 callStackLabel = WebInspector.UIString("Styles recalculation forced"); |
| 306 break; |
| 307 case recordTypes.Layout: |
| 308 var beginData = event.args["beginData"]; |
| 309 contentHelper.appendTextRow(WebInspector.UIString("Nodes that need layou
t"), beginData["dirtyObjects"]); |
| 310 contentHelper.appendTextRow(WebInspector.UIString("Layout tree size"), b
eginData["totalObjects"]); |
| 311 contentHelper.appendTextRow(WebInspector.UIString("Layout scope"), |
| 312 beginData["partialLayout"] ? WebInspector.UI
String("Partial") : WebInspector.UIString("Whole document")); |
| 313 callSiteStackTraceLabel = WebInspector.UIString("Layout invalidated"); |
| 314 callStackLabel = WebInspector.UIString("Layout forced"); |
| 315 relatedNodeLabel = WebInspector.UIString("Layout root"); |
| 316 break; |
| 317 case recordTypes.ConsoleTime: |
| 318 contentHelper.appendTextRow(WebInspector.UIString("Message"), eventData[
"message"]); |
| 319 break; |
| 320 case recordTypes.WebSocketCreate: |
| 321 case recordTypes.WebSocketSendHandshakeRequest: |
| 322 case recordTypes.WebSocketReceiveHandshakeResponse: |
| 323 case recordTypes.WebSocketDestroy: |
| 324 var initiatorData = initiator ? initiator.args.data : eventData; |
| 325 if (typeof initiatorData["webSocketURL"] !== "undefined") |
| 326 contentHelper.appendTextRow(WebInspector.UIString("URL"), initiatorD
ata["webSocketURL"]); |
| 327 if (typeof initiatorData["webSocketProtocol"] !== "undefined") |
| 328 contentHelper.appendTextRow(WebInspector.UIString("WebSocket Protoco
l"), initiatorData["webSocketProtocol"]); |
| 329 if (typeof eventData["message"] !== "undefined") |
| 330 contentHelper.appendTextRow(WebInspector.UIString("Message"), eventD
ata["message"]); |
| 331 break; |
| 332 case recordTypes.EmbedderCallback: |
| 333 contentHelper.appendTextRow(WebInspector.UIString("Callback Function"),
eventData["callbackName"]); |
| 334 break; |
| 335 default: |
| 336 var detailsNode = WebInspector.TracingTimelineUIUtils.buildDetailsNodeFo
rTraceEvent(event, linkifier, loadedFromFile, target); |
| 337 if (detailsNode) |
| 338 contentHelper.appendElementRow(WebInspector.UIString("Details"), det
ailsNode); |
| 339 break; |
| 340 } |
| 341 |
| 342 if (relatedNode) |
| 343 contentHelper.appendElementRow(relatedNodeLabel || WebInspector.UIString
("Related node"), WebInspector.DOMPresentationUtils.linkifyNodeReference(related
Node)); |
| 344 |
| 345 if (eventData && eventData["scriptName"] && event.name !== recordTypes.Funct
ionCall) |
| 346 contentHelper.appendLocationRow(WebInspector.UIString("Function Call"),
eventData["scriptName"], eventData["scriptLine"]); |
| 347 |
| 348 if (initiator) { |
| 349 var callSiteStackTrace = initiator.stackTrace; |
| 350 if (callSiteStackTrace) |
| 351 contentHelper.appendStackTrace(callSiteStackTraceLabel || WebInspect
or.UIString("Call Site stack"), callSiteStackTrace); |
| 352 } |
| 353 var eventStackTrace = event.stackTrace; |
| 354 if (eventStackTrace) |
| 355 contentHelper.appendStackTrace(callStackLabel || WebInspector.UIString("
Call Stack"), eventStackTrace); |
| 356 |
| 357 var warning = event.warning; |
| 358 if (warning) { |
| 359 var div = document.createElement("div"); |
| 360 div.textContent = warning; |
| 361 contentHelper.appendElementRow(WebInspector.UIString("Warning"), div); |
| 362 } |
| 363 fragment.appendChild(contentHelper.element); |
| 364 return fragment; |
| 365 } |
| 366 |
| 367 /** |
| 368 * @param {!WebInspector.TracingTimelineModel} model |
| 369 * @param {!WebInspector.TracingModel.Event} event |
| 370 * @return {!{ aggregatedStats: !Object, hasChildren: boolean }} |
| 371 */ |
| 372 WebInspector.TracingTimelineUIUtils._aggregatedStatsForTraceEvent = function(mod
el, event) |
| 373 { |
| 374 var events = model.inspectedTargetEvents(); |
| 375 /** |
| 376 * @param {number} startTime |
| 377 * @param {!WebInspector.TracingModel.Event} e |
| 378 * @return {number} |
| 379 */ |
| 380 function eventComparator(startTime, e) |
| 381 { |
| 382 return startTime - e.startTime; |
| 383 } |
| 384 var index = events.binaryIndexOf(event.startTime, eventComparator); |
| 385 var hasChildren = false; |
| 386 var aggregatedStats = {}; |
| 387 var endTime = event.endTime; |
| 388 if (endTime) { |
| 389 for (var i = index; i < events.length; i++) { |
| 390 var nextEvent = events[i]; |
| 391 if (nextEvent.startTime >= endTime) |
| 392 break; |
| 393 if (!nextEvent.selfTime) |
| 394 continue; |
| 395 if (i > index) |
| 396 hasChildren = true; |
| 397 var category = WebInspector.TimelineUIUtils.styleForTimelineEvent(ne
xtEvent.name).category.name; |
| 398 aggregatedStats[category] = (aggregatedStats[category] || 0) + nextE
vent.selfTime / 1000; |
| 399 } |
| 400 } |
| 401 return { aggregatedStats: aggregatedStats, hasChildren: hasChildren }; |
| 402 } |
| 403 |
| 404 |
OLD | NEW |