OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @constructor | 6 * @constructor |
7 * @extends {WebInspector.TimelineUIUtils} | 7 * @extends {WebInspector.TimelineUIUtils} |
8 */ | 8 */ |
9 WebInspector.TimelineUIUtilsImpl = function() | 9 WebInspector.TimelineUIUtilsImpl = function() |
10 { | 10 { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 switch(record.type()) { | 56 switch(record.type()) { |
57 case recordTypes.Layout: | 57 case recordTypes.Layout: |
58 return record.data().root; | 58 return record.data().root; |
59 case recordTypes.Paint: | 59 case recordTypes.Paint: |
60 return record.data().clip; | 60 return record.data().clip; |
61 default: | 61 default: |
62 return null; | 62 return null; |
63 } | 63 } |
64 }, | 64 }, |
65 | 65 |
| 66 /** |
| 67 * @param {!WebInspector.TimelineModel.Record} record |
| 68 * @param {!WebInspector.Linkifier} linkifier |
| 69 * @param {boolean} loadedFromFile |
| 70 * @return {?Node} |
| 71 */ |
| 72 buildDetailsNode: function(record, linkifier, loadedFromFile) |
| 73 { |
| 74 return WebInspector.TimelineUIUtilsImpl.buildDetailsNode(record, linkifi
er, loadedFromFile); |
| 75 }, |
| 76 |
| 77 /** |
| 78 * @param {!WebInspector.TimelineModel.Record} record |
| 79 * @param {!WebInspector.TimelineModel} model |
| 80 * @param {!WebInspector.Linkifier} linkifier |
| 81 * @param {function(!DocumentFragment)} callback |
| 82 * @param {boolean} loadedFromFile |
| 83 */ |
| 84 generateDetailsContent: function(record, model, linkifier, callback, loadedF
romFile) |
| 85 { |
| 86 WebInspector.TimelineUIUtilsImpl.generateDetailsContent(record, model, l
inkifier, callback, loadedFromFile); |
| 87 }, |
| 88 |
66 __proto__: WebInspector.TimelineUIUtils.prototype | 89 __proto__: WebInspector.TimelineUIUtils.prototype |
67 } | 90 } |
68 | 91 |
69 | 92 |
70 WebInspector.TimelineUIUtilsImpl._coalescableRecordTypes = {}; | 93 WebInspector.TimelineUIUtilsImpl._coalescableRecordTypes = {}; |
71 WebInspector.TimelineUIUtilsImpl._coalescableRecordTypes[WebInspector.TimelineMo
del.RecordType.Layout] = 1; | 94 WebInspector.TimelineUIUtilsImpl._coalescableRecordTypes[WebInspector.TimelineMo
del.RecordType.Layout] = 1; |
72 WebInspector.TimelineUIUtilsImpl._coalescableRecordTypes[WebInspector.TimelineMo
del.RecordType.Paint] = 1; | 95 WebInspector.TimelineUIUtilsImpl._coalescableRecordTypes[WebInspector.TimelineMo
del.RecordType.Paint] = 1; |
73 WebInspector.TimelineUIUtilsImpl._coalescableRecordTypes[WebInspector.TimelineMo
del.RecordType.Rasterize] = 1; | 96 WebInspector.TimelineUIUtilsImpl._coalescableRecordTypes[WebInspector.TimelineMo
del.RecordType.Rasterize] = 1; |
74 WebInspector.TimelineUIUtilsImpl._coalescableRecordTypes[WebInspector.TimelineMo
del.RecordType.DecodeImage] = 1; | 97 WebInspector.TimelineUIUtilsImpl._coalescableRecordTypes[WebInspector.TimelineMo
del.RecordType.DecodeImage] = 1; |
75 WebInspector.TimelineUIUtilsImpl._coalescableRecordTypes[WebInspector.TimelineMo
del.RecordType.ResizeImage] = 1; | 98 WebInspector.TimelineUIUtilsImpl._coalescableRecordTypes[WebInspector.TimelineMo
del.RecordType.ResizeImage] = 1; |
| 99 |
| 100 |
| 101 /** |
| 102 * @param {!WebInspector.TimelineModel.Record} record |
| 103 * @param {!WebInspector.Linkifier} linkifier |
| 104 * @param {boolean} loadedFromFile |
| 105 * @return {?Node} |
| 106 */ |
| 107 WebInspector.TimelineUIUtilsImpl.buildDetailsNode = function(record, linkifier,
loadedFromFile) |
| 108 { |
| 109 var details; |
| 110 var detailsText; |
| 111 var recordData = record.data(); |
| 112 switch (record.type()) { |
| 113 case WebInspector.TimelineModel.RecordType.GCEvent: |
| 114 detailsText = WebInspector.UIString("%s collected", Number.bytesToString
(recordData["usedHeapSizeDelta"])); |
| 115 break; |
| 116 case WebInspector.TimelineModel.RecordType.TimerFire: |
| 117 detailsText = recordData["timerId"]; |
| 118 break; |
| 119 case WebInspector.TimelineModel.RecordType.FunctionCall: |
| 120 details = linkifyLocation(recordData["scriptId"], recordData["scriptName
"], recordData["scriptLine"], 0); |
| 121 break; |
| 122 case WebInspector.TimelineModel.RecordType.FireAnimationFrame: |
| 123 detailsText = recordData["id"]; |
| 124 break; |
| 125 case WebInspector.TimelineModel.RecordType.EventDispatch: |
| 126 detailsText = recordData ? recordData["type"] : null; |
| 127 break; |
| 128 case WebInspector.TimelineModel.RecordType.Paint: |
| 129 var width = WebInspector.TimelineUIUtils._quadWidth(recordData.clip); |
| 130 var height = WebInspector.TimelineUIUtils._quadHeight(recordData.clip); |
| 131 if (width && height) |
| 132 detailsText = WebInspector.UIString("%d\u2009\u00d7\u2009%d", width,
height); |
| 133 break; |
| 134 case WebInspector.TimelineModel.RecordType.TimerInstall: |
| 135 case WebInspector.TimelineModel.RecordType.TimerRemove: |
| 136 details = linkifyTopCallFrame(); |
| 137 detailsText = recordData["timerId"]; |
| 138 break; |
| 139 case WebInspector.TimelineModel.RecordType.RequestAnimationFrame: |
| 140 case WebInspector.TimelineModel.RecordType.CancelAnimationFrame: |
| 141 details = linkifyTopCallFrame(); |
| 142 detailsText = recordData["id"]; |
| 143 break; |
| 144 case WebInspector.TimelineModel.RecordType.ParseHTML: |
| 145 case WebInspector.TimelineModel.RecordType.RecalculateStyles: |
| 146 details = linkifyTopCallFrame(); |
| 147 break; |
| 148 case WebInspector.TimelineModel.RecordType.EvaluateScript: |
| 149 var url = recordData["url"]; |
| 150 if (url) |
| 151 details = linkifyLocation("", url, recordData["lineNumber"], 0); |
| 152 break; |
| 153 case WebInspector.TimelineModel.RecordType.XHRReadyStateChange: |
| 154 case WebInspector.TimelineModel.RecordType.XHRLoad: |
| 155 case WebInspector.TimelineModel.RecordType.ResourceSendRequest: |
| 156 case WebInspector.TimelineModel.RecordType.DecodeImage: |
| 157 case WebInspector.TimelineModel.RecordType.ResizeImage: |
| 158 var url = recordData["url"]; |
| 159 if (url) |
| 160 detailsText = WebInspector.displayNameForURL(url); |
| 161 break; |
| 162 case WebInspector.TimelineModel.RecordType.ResourceReceivedData: |
| 163 case WebInspector.TimelineModel.RecordType.ResourceReceiveResponse: |
| 164 case WebInspector.TimelineModel.RecordType.ResourceFinish: |
| 165 var initiator = record.initiator(); |
| 166 if (initiator) { |
| 167 var url = initiator.data()["url"]; |
| 168 if (url) |
| 169 detailsText = WebInspector.displayNameForURL(url); |
| 170 } |
| 171 break; |
| 172 case WebInspector.TimelineModel.RecordType.ConsoleTime: |
| 173 detailsText = recordData["message"]; |
| 174 break; |
| 175 case WebInspector.TimelineModel.RecordType.EmbedderCallback: |
| 176 detailsText = recordData["callbackName"]; |
| 177 break; |
| 178 default: |
| 179 details = linkifyTopCallFrame(); |
| 180 break; |
| 181 } |
| 182 |
| 183 if (!details && detailsText) |
| 184 details = document.createTextNode(detailsText); |
| 185 return details; |
| 186 |
| 187 /** |
| 188 * @param {string} scriptId |
| 189 * @param {string} url |
| 190 * @param {number} lineNumber |
| 191 * @param {number=} columnNumber |
| 192 */ |
| 193 function linkifyLocation(scriptId, url, lineNumber, columnNumber) |
| 194 { |
| 195 if (!loadedFromFile && scriptId !== "0") { |
| 196 var location = new WebInspector.DebuggerModel.Location( |
| 197 record.target(), |
| 198 scriptId, |
| 199 lineNumber - 1, |
| 200 (columnNumber || 1) - 1); |
| 201 return linkifier.linkifyRawLocation(location, "timeline-details"); |
| 202 } |
| 203 |
| 204 if (!url) |
| 205 return null; |
| 206 |
| 207 // FIXME(62725): stack trace line/column numbers are one-based. |
| 208 columnNumber = columnNumber ? columnNumber - 1 : 0; |
| 209 return linkifier.linkifyLocation(record.target(), url, lineNumber - 1, c
olumnNumber, "timeline-details"); |
| 210 } |
| 211 |
| 212 /** |
| 213 * @param {!ConsoleAgent.CallFrame} callFrame |
| 214 */ |
| 215 function linkifyCallFrame(callFrame) |
| 216 { |
| 217 return linkifyLocation(callFrame.scriptId, callFrame.url, callFrame.line
Number, callFrame.columnNumber); |
| 218 } |
| 219 |
| 220 /** |
| 221 * @return {?Element} |
| 222 */ |
| 223 function linkifyTopCallFrame() |
| 224 { |
| 225 if (record.stackTrace()) |
| 226 return linkifyCallFrame(record.stackTrace()[0]); |
| 227 if (record.callSiteStackTrace()) |
| 228 return linkifyCallFrame(record.callSiteStackTrace()[0]); |
| 229 return null; |
| 230 } |
| 231 } |
| 232 |
| 233 /** |
| 234 * @param {!WebInspector.TimelineModel.Record} record |
| 235 * @param {!WebInspector.TimelineModel} model |
| 236 * @param {!WebInspector.Linkifier} linkifier |
| 237 * @param {function(!DocumentFragment)} callback |
| 238 * @param {boolean} loadedFromFile |
| 239 */ |
| 240 WebInspector.TimelineUIUtilsImpl.generateDetailsContent = function(record, model
, linkifier, callback, loadedFromFile) |
| 241 { |
| 242 var imageElement = /** @type {?Element} */ (record.getUserObject("TimelineUI
Utils::preview-element") || null); |
| 243 var relatedNode = null; |
| 244 var recordData = record.data(); |
| 245 var barrier = new CallbackBarrier(); |
| 246 if (!imageElement && WebInspector.TimelineUIUtils.needsPreviewElement(record
.type())) |
| 247 WebInspector.DOMPresentationUtils.buildImagePreviewContents(record.targe
t(), recordData["url"], false, barrier.createCallback(saveImage)); |
| 248 if (recordData["backendNodeId"]) |
| 249 record.target().domModel.pushNodesByBackendIdsToFrontend([recordData["ba
ckendNodeId"]], barrier.createCallback(setRelatedNode)); |
| 250 barrier.callWhenDone(callbackWrapper); |
| 251 |
| 252 /** |
| 253 * @param {!Element=} element |
| 254 */ |
| 255 function saveImage(element) |
| 256 { |
| 257 imageElement = element || null; |
| 258 record.setUserObject("TimelineUIUtils::preview-element", element); |
| 259 } |
| 260 |
| 261 /** |
| 262 * @param {?Array.<!DOMAgent.NodeId>} nodeIds |
| 263 */ |
| 264 function setRelatedNode(nodeIds) |
| 265 { |
| 266 if (nodeIds) |
| 267 relatedNode = record.target().domModel.nodeForId(nodeIds[0]); |
| 268 } |
| 269 |
| 270 function callbackWrapper() |
| 271 { |
| 272 callback(WebInspector.TimelineUIUtilsImpl._generateDetailsContentSynchro
nously(record, model, linkifier, imageElement, relatedNode, loadedFromFile)); |
| 273 } |
| 274 } |
| 275 |
| 276 /** |
| 277 * @param {!WebInspector.TimelineModel.Record} record |
| 278 * @param {!WebInspector.TimelineModel} model |
| 279 * @param {!WebInspector.Linkifier} linkifier |
| 280 * @param {?Element} imagePreviewElement |
| 281 * @param {?WebInspector.DOMNode} relatedNode |
| 282 * @param {boolean} loadedFromFile |
| 283 * @return {!DocumentFragment} |
| 284 */ |
| 285 WebInspector.TimelineUIUtilsImpl._generateDetailsContentSynchronously = function
(record, model, linkifier, imagePreviewElement, relatedNode, loadedFromFile) |
| 286 { |
| 287 var fragment = document.createDocumentFragment(); |
| 288 if (record.children().length) |
| 289 fragment.appendChild(WebInspector.TimelineUIUtils.generatePieChart(recor
d.aggregatedStats(), record.category(), record.selfTime())); |
| 290 else |
| 291 fragment.appendChild(WebInspector.TimelineUIUtils.generatePieChart(recor
d.aggregatedStats())); |
| 292 |
| 293 const recordTypes = WebInspector.TimelineModel.RecordType; |
| 294 |
| 295 // The messages may vary per record.type(); |
| 296 var callSiteStackTraceLabel; |
| 297 var callStackLabel; |
| 298 var relatedNodeLabel; |
| 299 |
| 300 var contentHelper = new WebInspector.TimelineDetailsContentHelper(record.tar
get(), linkifier, true); |
| 301 contentHelper.appendTextRow(WebInspector.UIString("Self Time"), Number.milli
sToString(record.selfTime(), true)); |
| 302 contentHelper.appendTextRow(WebInspector.UIString("Start Time"), Number.mill
isToString(record.startTime() - model.minimumRecordTime())); |
| 303 var recordData = record.data(); |
| 304 |
| 305 switch (record.type()) { |
| 306 case recordTypes.GCEvent: |
| 307 contentHelper.appendTextRow(WebInspector.UIString("Collected"), Numb
er.bytesToString(recordData["usedHeapSizeDelta"])); |
| 308 break; |
| 309 case recordTypes.TimerFire: |
| 310 callSiteStackTraceLabel = WebInspector.UIString("Timer installed"); |
| 311 // Fall-through intended. |
| 312 |
| 313 case recordTypes.TimerInstall: |
| 314 case recordTypes.TimerRemove: |
| 315 contentHelper.appendTextRow(WebInspector.UIString("Timer ID"), recor
dData["timerId"]); |
| 316 if (record.type() === recordTypes.TimerInstall) { |
| 317 contentHelper.appendTextRow(WebInspector.UIString("Timeout"), Nu
mber.millisToString(recordData["timeout"])); |
| 318 contentHelper.appendTextRow(WebInspector.UIString("Repeats"), !r
ecordData["singleShot"]); |
| 319 } |
| 320 break; |
| 321 case recordTypes.FireAnimationFrame: |
| 322 callSiteStackTraceLabel = WebInspector.UIString("Animation frame req
uested"); |
| 323 contentHelper.appendTextRow(WebInspector.UIString("Callback ID"), re
cordData["id"]); |
| 324 break; |
| 325 case recordTypes.FunctionCall: |
| 326 if (recordData["scriptName"]) |
| 327 contentHelper.appendLocationRow(WebInspector.UIString("Location"
), recordData["scriptName"], recordData["scriptLine"]); |
| 328 break; |
| 329 case recordTypes.ResourceSendRequest: |
| 330 case recordTypes.ResourceReceiveResponse: |
| 331 case recordTypes.ResourceReceivedData: |
| 332 case recordTypes.ResourceFinish: |
| 333 var url; |
| 334 if (record.type() === recordTypes.ResourceSendRequest) |
| 335 url = recordData["url"]; |
| 336 else if (record.initiator()) |
| 337 url = record.initiator().data()["url"]; |
| 338 if (url) |
| 339 contentHelper.appendElementRow(WebInspector.UIString("Resource")
, WebInspector.linkifyResourceAsNode(url)); |
| 340 if (imagePreviewElement) |
| 341 contentHelper.appendElementRow(WebInspector.UIString("Preview"),
imagePreviewElement); |
| 342 if (recordData["requestMethod"]) |
| 343 contentHelper.appendTextRow(WebInspector.UIString("Request Metho
d"), recordData["requestMethod"]); |
| 344 if (typeof recordData["statusCode"] === "number") |
| 345 contentHelper.appendTextRow(WebInspector.UIString("Status Code")
, recordData["statusCode"]); |
| 346 if (recordData["mimeType"]) |
| 347 contentHelper.appendTextRow(WebInspector.UIString("MIME Type"),
recordData["mimeType"]); |
| 348 if (recordData["encodedDataLength"]) |
| 349 contentHelper.appendTextRow(WebInspector.UIString("Encoded Data
Length"), WebInspector.UIString("%d Bytes", recordData["encodedDataLength"])); |
| 350 break; |
| 351 case recordTypes.EvaluateScript: |
| 352 var url = recordData["url"]; |
| 353 if (url) |
| 354 contentHelper.appendLocationRow(WebInspector.UIString("Script"),
url, recordData["lineNumber"]); |
| 355 break; |
| 356 case recordTypes.Paint: |
| 357 var clip = recordData["clip"]; |
| 358 contentHelper.appendTextRow(WebInspector.UIString("Location"), WebIn
spector.UIString("(%d, %d)", clip[0], clip[1])); |
| 359 var clipWidth = WebInspector.TimelineUIUtils._quadWidth(clip); |
| 360 var clipHeight = WebInspector.TimelineUIUtils._quadHeight(clip); |
| 361 contentHelper.appendTextRow(WebInspector.UIString("Dimensions"), Web
Inspector.UIString("%d × %d", clipWidth, clipHeight)); |
| 362 // Fall-through intended. |
| 363 |
| 364 case recordTypes.PaintSetup: |
| 365 case recordTypes.Rasterize: |
| 366 case recordTypes.ScrollLayer: |
| 367 relatedNodeLabel = WebInspector.UIString("Layer root"); |
| 368 break; |
| 369 case recordTypes.DecodeImage: |
| 370 case recordTypes.ResizeImage: |
| 371 relatedNodeLabel = WebInspector.UIString("Image element"); |
| 372 var url = recordData["url"]; |
| 373 if (url) |
| 374 contentHelper.appendElementRow(WebInspector.UIString("Image URL"
), WebInspector.linkifyResourceAsNode(url)); |
| 375 break; |
| 376 case recordTypes.RecalculateStyles: // We don't want to see default deta
ils. |
| 377 if (recordData["elementCount"]) |
| 378 contentHelper.appendTextRow(WebInspector.UIString("Elements affe
cted"), recordData["elementCount"]); |
| 379 callStackLabel = WebInspector.UIString("Styles recalculation forced"
); |
| 380 break; |
| 381 case recordTypes.Layout: |
| 382 if (recordData["dirtyObjects"]) |
| 383 contentHelper.appendTextRow(WebInspector.UIString("Nodes that ne
ed layout"), recordData["dirtyObjects"]); |
| 384 if (recordData["totalObjects"]) |
| 385 contentHelper.appendTextRow(WebInspector.UIString("Layout tree s
ize"), recordData["totalObjects"]); |
| 386 if (typeof recordData["partialLayout"] === "boolean") { |
| 387 contentHelper.appendTextRow(WebInspector.UIString("Layout scope"
), |
| 388 recordData["partialLayout"] ? WebInspector.UIString("Partial"
) : WebInspector.UIString("Whole document")); |
| 389 } |
| 390 callSiteStackTraceLabel = WebInspector.UIString("Layout invalidated"
); |
| 391 callStackLabel = WebInspector.UIString("Layout forced"); |
| 392 relatedNodeLabel = WebInspector.UIString("Layout root"); |
| 393 break; |
| 394 case recordTypes.ConsoleTime: |
| 395 contentHelper.appendTextRow(WebInspector.UIString("Message"), record
Data["message"]); |
| 396 break; |
| 397 case recordTypes.WebSocketCreate: |
| 398 case recordTypes.WebSocketSendHandshakeRequest: |
| 399 case recordTypes.WebSocketReceiveHandshakeResponse: |
| 400 case recordTypes.WebSocketDestroy: |
| 401 var initiatorData = record.initiator() ? record.initiator().data() :
recordData; |
| 402 if (typeof initiatorData["webSocketURL"] !== "undefined") |
| 403 contentHelper.appendTextRow(WebInspector.UIString("URL"), initia
torData["webSocketURL"]); |
| 404 if (typeof initiatorData["webSocketProtocol"] !== "undefined") |
| 405 contentHelper.appendTextRow(WebInspector.UIString("WebSocket Pro
tocol"), initiatorData["webSocketProtocol"]); |
| 406 if (typeof recordData["message"] !== "undefined") |
| 407 contentHelper.appendTextRow(WebInspector.UIString("Message"), re
cordData["message"]); |
| 408 break; |
| 409 case recordTypes.EmbedderCallback: |
| 410 contentHelper.appendTextRow(WebInspector.UIString("Callback Function
"), recordData["callbackName"]); |
| 411 break; |
| 412 default: |
| 413 var detailsNode = WebInspector.TimelineUIUtilsImpl.buildDetailsNode(
record, linkifier, loadedFromFile); |
| 414 if (detailsNode) |
| 415 contentHelper.appendElementRow(WebInspector.UIString("Details"),
detailsNode); |
| 416 break; |
| 417 } |
| 418 |
| 419 if (relatedNode) |
| 420 contentHelper.appendElementRow(relatedNodeLabel || WebInspector.UIString
("Related node"), WebInspector.DOMPresentationUtils.linkifyNodeReference(related
Node)); |
| 421 |
| 422 if (recordData["scriptName"] && record.type() !== recordTypes.FunctionCall) |
| 423 contentHelper.appendLocationRow(WebInspector.UIString("Function Call"),
recordData["scriptName"], recordData["scriptLine"]); |
| 424 var callSiteStackTrace = record.callSiteStackTrace(); |
| 425 if (callSiteStackTrace) |
| 426 contentHelper.appendStackTrace(callSiteStackTraceLabel || WebInspector.U
IString("Call Site stack"), callSiteStackTrace); |
| 427 var recordStackTrace = record.stackTrace(); |
| 428 if (recordStackTrace) |
| 429 contentHelper.appendStackTrace(callStackLabel || WebInspector.UIString("
Call Stack"), recordStackTrace); |
| 430 |
| 431 if (record.warnings()) { |
| 432 var ul = document.createElement("ul"); |
| 433 for (var i = 0; i < record.warnings().length; ++i) |
| 434 ul.createChild("li").textContent = record.warnings()[i]; |
| 435 contentHelper.appendElementRow(WebInspector.UIString("Warning"), ul); |
| 436 } |
| 437 fragment.appendChild(contentHelper.element); |
| 438 return fragment; |
| 439 } |
OLD | NEW |