Chromium Code Reviews| Index: Source/devtools/front_end/timeline/TracingTimelineUIUtils.js |
| diff --git a/Source/devtools/front_end/timeline/TracingTimelineUIUtils.js b/Source/devtools/front_end/timeline/TracingTimelineUIUtils.js |
| index 4e853e8528979a5c59fa52829d7b5c68656a904d..ec61010f8faee18714d0d8209725cc66ab2a83d9 100644 |
| --- a/Source/devtools/front_end/timeline/TracingTimelineUIUtils.js |
| +++ b/Source/devtools/front_end/timeline/TracingTimelineUIUtils.js |
| @@ -494,6 +494,8 @@ WebInspector.TracingTimelineUIUtils.buildTraceEventDetails = function(event, mod |
| } |
| if (event.backendNodeId && target) |
| target.domModel.pushNodesByBackendIdsToFrontend([event.backendNodeId], barrier.createCallback(setRelatedNode)); |
| + if (target && event.invalidationTrackingEvents) |
|
caseq
2014/10/15 16:24:54
Please drop test for target (the one above is like
pdr.
2014/10/16 07:46:48
Fixed, and removed the two above.
|
| + WebInspector.TracingTimelineUIUtils._resolveInvalidationTrackingNodeIds(event, barrier); |
| barrier.callWhenDone(callbackWrapper); |
| /** |
| @@ -612,6 +614,7 @@ WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously = funct |
| contentHelper.appendElementRow(WebInspector.UIString("Image URL"), WebInspector.linkifyResourceAsNode(event.imageURL)); |
| break; |
| case recordTypes.RecalculateStyles: // We don't want to see default details. |
| + // FIXME: Show invalidation tracking for updating style. |
| contentHelper.appendTextRow(WebInspector.UIString("Elements affected"), event.args["elementCount"]); |
| break; |
| case recordTypes.Layout: |
| @@ -621,6 +624,10 @@ WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously = funct |
| contentHelper.appendTextRow(WebInspector.UIString("Layout scope"), |
| beginData["partialLayout"] ? WebInspector.UIString("Partial") : WebInspector.UIString("Whole document")); |
| relatedNodeLabel = WebInspector.UIString("Layout root"); |
| + // FIXME: Show invalidation tracking for updating layout. |
| + break; |
| + case recordTypes.UpdateLayerTree: |
| + // FIXME: Show invalidation tracking for updating the layer tree. |
| break; |
| case recordTypes.ConsoleTime: |
| contentHelper.appendTextRow(WebInspector.UIString("Message"), event.name); |
| @@ -662,8 +669,8 @@ WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously = funct |
| if (event.previewElement) |
| contentHelper.appendElementRow(WebInspector.UIString("Preview"), event.previewElement); |
| - if (event.stackTrace || (event.initiator && event.initiator.stackTrace)) |
| - WebInspector.TracingTimelineUIUtils._generateCauses(event, contentHelper); |
| + if (event.stackTrace || (event.initiator && event.initiator.stackTrace) || event.invalidationTrackingEvents) |
| + WebInspector.TracingTimelineUIUtils._generateCauses(event, linkifier, contentHelper); |
| fragment.appendChild(contentHelper.element); |
| return fragment; |
| @@ -671,14 +678,16 @@ WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously = funct |
| /** |
| * @param {!WebInspector.TracingModel.Event} event |
| + * @param {!WebInspector.Linkifier} linkifier |
| * @param {!WebInspector.TimelineDetailsContentHelper} contentHelper |
| */ |
| -WebInspector.TracingTimelineUIUtils._generateCauses = function(event, contentHelper) |
| +WebInspector.TracingTimelineUIUtils._generateCauses = function(event, linkifier, contentHelper) |
| { |
| var recordTypes = WebInspector.TracingTimelineModel.RecordType; |
| var callSiteStackLabel; |
| var stackLabel; |
| + var initiator = event.initiator; |
| switch (event.name) { |
| case recordTypes.TimerFire: |
| @@ -700,10 +709,153 @@ WebInspector.TracingTimelineUIUtils._generateCauses = function(event, contentHel |
| if (event.stackTrace) |
| contentHelper.appendStackTrace(stackLabel || WebInspector.UIString("Stack when this event occurred"), event.stackTrace); |
| - // Indirect cause / invalidation. |
| - var initiator = event.initiator; |
| - if (initiator && initiator.stackTrace) |
| + // Indirect causes. |
| + if (event.invalidationTrackingEvents) { // Full invalidation tracking (experimental). |
| + WebInspector.TracingTimelineUIUtils._generateInvalidations(event, linkifier, contentHelper); |
| + } else if (initiator && initiator.stackTrace) { // Partial invalidation tracking. |
| contentHelper.appendStackTrace(callSiteStackLabel || WebInspector.UIString("Stack when first invalidated"), initiator.stackTrace); |
| + } |
| +} |
| + |
| +/** |
| + * @param {!WebInspector.TracingModel.Event} event |
| + * @param {!WebInspector.Linkifier} linkifier |
| + * @param {!WebInspector.TimelineDetailsContentHelper} contentHelper |
| + */ |
| +WebInspector.TracingTimelineUIUtils._generateInvalidations = function(event, linkifier, contentHelper) |
| +{ |
| + if (!event.invalidationTrackingEvents) |
| + return; |
| + |
| + var target = event.thread.target(); |
| + var styleInvalidations = []; |
|
kouhei (in TOK)
2014/10/15 05:34:00
We might want to use a map of arrays here, as we e
caseq
2014/10/15 16:24:53
+1
pdr.
2014/10/16 07:46:48
Excellent point. Refactored!
|
| + var layoutInvalidations = []; |
| + var layerInvalidations = []; |
| + event.invalidationTrackingEvents.forEach(function(invalidation) { |
| + switch (invalidation.type) { |
| + case WebInspector.TracingTimelineModel.RecordType.StyleRecalcInvalidationTracking: |
| + styleInvalidations.push(invalidation); |
| + break; |
| + case WebInspector.TracingTimelineModel.RecordType.LayoutInvalidationTracking: |
| + layoutInvalidations.push(invalidation); |
| + break; |
| + case WebInspector.TracingTimelineModel.RecordType.LayerInvalidationTracking: |
| + layerInvalidations.push(invalidation); |
| + break; |
| + default: |
| + console.error("Unknown invalidation tracking event."); |
| + console.error(invalidation); |
| + } |
| + }); |
| + if (styleInvalidations.length) |
|
caseq
2014/10/15 16:24:54
style: here and below, please use {} for multi-lin
pdr.
2014/10/16 07:46:48
Refactored this to be much cleaner. I'm not sure w
|
| + contentHelper.element.appendChild( |
| + WebInspector.TracingTimelineUIUtils._buildInvalidationDetailsNode(WebInspector.UIString("Style invalidations"), linkifier, target, styleInvalidations)); |
| + if (layoutInvalidations.length) |
| + contentHelper.element.appendChild( |
| + WebInspector.TracingTimelineUIUtils._buildInvalidationDetailsNode(WebInspector.UIString("Layout invalidations"), linkifier, target, layoutInvalidations)); |
| + if (layerInvalidations.length) |
| + contentHelper.element.appendChild( |
| + WebInspector.TracingTimelineUIUtils._buildInvalidationDetailsNode(WebInspector.UIString("Layer invalidations"), linkifier, target, layerInvalidations)); |
| +} |
| + |
| +/** |
| + * @param {string} title |
| + * @param {!WebInspector.Linkifier} linkifier |
| + * @param {?WebInspector.Target} target |
| + * @param {!WebInspector.TimelineDetailsContentHelper} contentHelper |
| + */ |
| +WebInspector.TracingTimelineUIUtils._buildInvalidationDetailsNode = function(title, linkifier, target, invalidationEvents) |
| +{ |
| + var detailsNode = document.createElement("div"); |
| + detailsNode.className = "timeline-details-view-row"; |
| + var titleElement = document.createElement("span"); |
| + titleElement.className = "timeline-details-view-row-title"; |
| + titleElement.textContent = WebInspector.UIString("%s: ", title); |
| + detailsNode.appendChild(titleElement); |
|
caseq
2014/10/15 16:24:54
nit: var titleElement = detailsNode.createChild("s
|
| + var eventsList = document.createElement("ol"); |
| + detailsNode.appendChild(eventsList); |
|
caseq
2014/10/15 16:24:53
ditto
|
| + |
| + invalidationEvents.forEach(function(invalidation, idx) { |
| + var row = document.createElement("li"); |
| + eventsList.appendChild(row); |
|
caseq
2014/10/15 16:24:54
ditto
|
| + |
| + var nodeRow = document.createElement("div"); |
| + row.appendChild(nodeRow); |
|
caseq
2014/10/15 16:24:53
ditto
|
| + var node = target.domModel.nodeForId(invalidation.frontendNodeId); |
| + if (node) |
| + nodeRow.appendChild(WebInspector.DOMPresentationUtils.linkifyNodeReference(node)); |
| + else if (invalidation.nodeName) |
| + nodeRow.textContent = '[' + invalidation.nodeName + ']'; |
|
caseq
2014/10/15 16:24:53
WebInspector.UIString("[ %s ]", invalidation.nodeN
|
| + else |
| + nodeRow.textContent = '[ unknown node ]'; |
|
caseq
2014/10/15 16:24:53
WebInspector.UISreing("[ unknown node ]")
|
| + |
| + if (invalidation.reason) { |
| + var reasonRow = document.createElement("div"); |
| + reasonRow.textContent = 'Reason: ' + invalidation.reason + (invalidation.reason.endsWith('.') ? '' : '.'); |
|
caseq
2014/10/15 16:24:53
ditto
|
| + row.appendChild(reasonRow); |
| + } |
| + |
| + var callstack = invalidation.callstack ? JSON.parse(invalidation.callstack) : []; |
|
caseq
2014/10/15 16:24:53
I think we need to capture callstacks the usual wa
pdr.
2014/10/16 07:46:48
I wasn't able to find the benefit of this, but I m
|
| + if (callstack.length > 0) { |
|
caseq
2014/10/15 16:24:53
if (callstack.length)
|
| + var callstackRow = document.createElement("div"); |
| + row.appendChild(callstackRow); |
| + callstack.forEach(function(stackFrame) { |
| + var frameRow = document.createElement("div"); |
| + frameRow.className = "timeline-details-view-row monospace"; |
| + callstackRow.appendChild(frameRow); |
| + frameRow.textContent = stackFrame.functionName || WebInspector.UIString("(anonymous function)"); |
| + frameRow.textContent += " @ "; |
| + var urlElement = linkifier.linkifyScriptLocation(target, stackFrame.scriptId, stackFrame.url, stackFrame.lineNumber - 1, stackFrame.columnNumber - 1); |
|
kouhei (in TOK)
2014/10/15 05:34:00
This part looks similar to WebInspector.TimelineDe
pdr.
2014/10/16 07:46:48
Factored this out into the content helper itself.
|
| + frameRow.appendChild(urlElement); |
| + }); |
| + } |
| + }); |
| + |
| + return detailsNode; |
| +} |
| + |
| +/** |
| + * @param {!WebInspector.TracingModel.Event} event |
| + * @param {!CallbackBarrier} barrier |
| + */ |
| +WebInspector.TracingTimelineUIUtils._resolveInvalidationTrackingNodeIds = function(event, barrier) |
| +{ |
| + var backendNodeIdSet = {}; |
| + if (event.nodeId) |
| + backendNodeIdSet[event.nodeId] = true; |
| + event.invalidationTrackingEvents.forEach(function(invalidation) { |
| + if (invalidation.nodeId) |
| + backendNodeIdSet[invalidation.nodeId] = true; |
| + }); |
|
kouhei (in TOK)
2014/10/15 05:34:00
This looks a bit complicated. If Object.keys(backe
pdr.
2014/10/16 07:46:48
This is the simplest way I know how to create a se
|
| + |
| + var backendNodeIds = []; |
| + Object.keys(backendNodeIdSet).forEach(function(backendNodeId) { |
| + backendNodeIds.push(parseInt(backendNodeId)); |
|
kouhei (in TOK)
2014/10/15 05:34:00
in other words, can we only use backendNodeIds?
pdr.
2014/10/16 07:46:48
It's the opposite--we can only use frontendNodeIds
|
| + }); |
| + event.thread.target().domModel.pushNodesByBackendIdsToFrontend( |
| + backendNodeIds, barrier.createCallback(updateInvalidationNodeIds)); |
|
caseq
2014/10/15 16:24:53
You're calling barrier.createCallback() exactly on
pdr.
2014/10/16 07:46:48
I think we need to use the barrier as it increment
|
| + |
| + function updateInvalidationNodeIds(frontendNodeIds) |
| + { |
| + if (!frontendNodeIds) |
| + return; |
| + if (frontendNodeIds.length != backendNodeIds.length) { |
| + console.error('Did not resolve the correct number of frontend node ids.'); |
| + return; |
| + } |
| + |
| + var backendToFrontendNodeIdMap = {}; |
| + backendNodeIds.forEach(function(backendNodeId, index) { |
| + backendToFrontendNodeIdMap[backendNodeId] = frontendNodeIds[index]; |
| + }); |
| + |
| + if (event.nodeId) |
| + event.frontendNodeId = backendToFrontendNodeIdMap[event.nodeId]; |
| + event.invalidationTrackingEvents.forEach(function(invalidation) { |
| + if (invalidation.nodeId) |
| + invalidation.frontendNodeId = backendToFrontendNodeIdMap[invalidation.nodeId]; |
| + }); |
| + } |
| } |
| /** |