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) |
+ 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 = []; |
+ 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) |
+ 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); |
+ var eventsList = document.createElement("ol"); |
+ detailsNode.appendChild(eventsList); |
+ |
+ invalidationEvents.forEach(function(invalidation, idx) { |
+ var row = document.createElement("li"); |
+ eventsList.appendChild(row); |
+ |
+ var nodeRow = document.createElement("div"); |
+ row.appendChild(nodeRow); |
+ var node = target.domModel.nodeForId(invalidation.frontendNodeId); |
+ if (node) |
+ nodeRow.appendChild(WebInspector.DOMPresentationUtils.linkifyNodeReference(node)); |
+ else if (invalidation.nodeName) |
+ nodeRow.textContent = '[' + invalidation.nodeName + ']'; |
+ else |
+ nodeRow.textContent = '[ unknown node ]'; |
+ |
+ if (invalidation.reason) { |
+ var reasonRow = document.createElement("div"); |
+ reasonRow.textContent = 'Reason: ' + invalidation.reason + (invalidation.reason.endsWith('.') ? '' : '.'); |
+ row.appendChild(reasonRow); |
+ } |
+ |
+ var callstack = invalidation.callstack ? JSON.parse(invalidation.callstack) : []; |
+ if (callstack.length > 0) { |
+ 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); |
+ 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; |
+ }); |
+ |
+ var backendNodeIds = []; |
+ Object.keys(backendNodeIdSet).forEach(function(backendNodeId) { |
+ backendNodeIds.push(parseInt(backendNodeId)); |
+ }); |
+ event.thread.target().domModel.pushNodesByBackendIdsToFrontend( |
+ backendNodeIds, barrier.createCallback(updateInvalidationNodeIds)); |
+ |
+ 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]; |
+ }); |
+ } |
} |
/** |