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 10c2d302e40e8f4a960ef1fdcec6bf741eb88015..acc5d9ec9b22e716d65186d554f005e98cea9023 100644 |
--- a/Source/devtools/front_end/timeline/TracingTimelineUIUtils.js |
+++ b/Source/devtools/front_end/timeline/TracingTimelineUIUtils.js |
@@ -485,6 +485,8 @@ WebInspector.TracingTimelineUIUtils.buildTraceEventDetails = function(event, mod |
{ |
var target = event.thread.target(); |
var relatedNode = null; |
+ var invalidationBackendNodeIds = []; |
+ var invalidationEvent = event; |
var barrier = new CallbackBarrier(); |
if (!event.previewElement && target) { |
if (event.imageURL) |
@@ -492,8 +494,34 @@ WebInspector.TracingTimelineUIUtils.buildTraceEventDetails = function(event, mod |
else if (event.picture) |
WebInspector.TracingTimelineUIUtils.buildPicturePreviewContent(target, event.picture, barrier.createCallback(saveImage)); |
} |
+ |
+ if (target) { |
+ var invalidationNodeIdMap = {}; |
+ |
+ if (event.nodeId) |
+ invalidationNodeIdMap[event.nodeId] = true; |
+ if (event.styleInvalidationTrackingEvents && event.styleInvalidationTrackingEvents.length) { |
+ event.styleInvalidationTrackingEvents.forEach(function(invalidationEvent) { |
+ if (invalidationEvent.nodeId) |
+ invalidationNodeIdMap[invalidationEvent.nodeId] = true; |
+ }); |
+ } |
+ if (event.layoutInvalidationTrackingEvents && event.layoutInvalidationTrackingEvents.length) { |
+ event.layoutInvalidationTrackingEvents.forEach(function(invalidationEvent) { |
+ if (invalidationEvent.nodeId) |
+ invalidationNodeIdMap[invalidationEvent.nodeId] = true; |
+ }); |
+ } |
+ |
+ var keys = Object.keys(invalidationNodeIdMap); |
+ for (var i = 0; i < keys.length; i++) |
+ invalidationBackendNodeIds.push(parseInt(keys[i])); |
+ target.domModel.pushNodesByBackendIdsToFrontend(invalidationBackendNodeIds, barrier.createCallback(updateInvalidationNodeIds)); |
+ } |
+ |
if (event.backendNodeId && target) |
target.domModel.pushNodesByBackendIdsToFrontend([event.backendNodeId], barrier.createCallback(setRelatedNode)); |
+ |
barrier.callWhenDone(callbackWrapper); |
/** |
@@ -513,6 +541,34 @@ WebInspector.TracingTimelineUIUtils.buildTraceEventDetails = function(event, mod |
relatedNode = target.domModel.nodeForId(nodeIds[0]); |
} |
+ function updateInvalidationNodeIds(frontendNodeIds) |
+ { |
+ if (!frontendNodeIds) |
+ return; |
+ if (frontendNodeIds.length != invalidationBackendNodeIds.length) { |
+ console.error('Did not resolve the correct number of frontend node ids.'); |
+ return; |
+ } |
+ |
+ // FIXME: Use a map here instead of an O(n^2) loop. |
+ invalidationBackendNodeIds.forEach(function(backendNodeId, index) { |
+ if (invalidationEvent.nodeId == backendNodeId) |
+ invalidationEvent.frontendNodeId = frontendNodeIds[index]; |
+ if (invalidationEvent.styleInvalidationTrackingEvents && invalidationEvent.styleInvalidationTrackingEvents.length) { |
+ invalidationEvent.styleInvalidationTrackingEvents.forEach(function(invalidationEvent) { |
+ if (invalidationEvent.nodeId == backendNodeId) |
+ invalidationEvent.frontendNodeId = frontendNodeIds[index]; |
+ }); |
+ } |
+ if (invalidationEvent.layoutInvalidationTrackingEvents && invalidationEvent.layoutInvalidationTrackingEvents.length) { |
+ invalidationEvent.layoutInvalidationTrackingEvents.forEach(function(invalidationEvent) { |
+ if (invalidationEvent.nodeId == backendNodeId) |
+ invalidationEvent.frontendNodeId = frontendNodeIds[index]; |
+ }); |
+ } |
+ }); |
+ } |
+ |
function callbackWrapper() |
{ |
callback(WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously(event, model, linkifier, relatedNode)); |
@@ -620,6 +676,7 @@ WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously = funct |
case recordTypes.RecalculateStyles: // We don't want to see default details. |
contentHelper.appendTextRow(WebInspector.UIString("Elements affected"), event.args["elementCount"]); |
callStackLabel = WebInspector.UIString("Styles recalculation forced"); |
+ // FIXME: Show invalidation tracking for updating style. |
break; |
case recordTypes.Layout: |
var beginData = event.args["beginData"]; |
@@ -630,6 +687,10 @@ WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously = funct |
callSiteStackTraceLabel = WebInspector.UIString("Layout invalidated"); |
callStackLabel = WebInspector.UIString("Layout forced"); |
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); |
@@ -679,6 +740,19 @@ WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously = funct |
} |
if (event.previewElement) |
contentHelper.appendElementRow(WebInspector.UIString("Preview"), event.previewElement); |
+ |
+ // Show invalidation tracking. |
+ if (event.styleInvalidationTrackingEvents && event.styleInvalidationTrackingEvents.length) { |
+ contentHelper.element.appendChild( |
+ this._buildInvalidationDetailsNode(WebInspector.UIString("Style invalidations"), |
+ linkifier, event, event.styleInvalidationTrackingEvents)); |
+ } |
+ if (event.layoutInvalidationTrackingEvents && event.layoutInvalidationTrackingEvents.length) { |
+ contentHelper.element.appendChild( |
+ this._buildInvalidationDetailsNode(WebInspector.UIString("Layout invalidations"), |
+ linkifier, event, event.layoutInvalidationTrackingEvents)); |
+ } |
+ |
fragment.appendChild(contentHelper.element); |
return fragment; |
} |
@@ -791,6 +865,53 @@ WebInspector.TracingTimelineUIUtils._createEventDivider = function(recordType, t |
} |
/** |
+ * TODO: write me |
+ */ |
+WebInspector.TracingTimelineUIUtils._buildInvalidationDetailsNode = function(title, linkifier, event, 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(invalidationEvent, idx) { |
+ var row = document.createElement("li"); |
+ eventsList.appendChild(row); |
+ |
+ var nodeRow = document.createElement("div"); |
+ row.appendChild(nodeRow); |
+ var target = event.thread.target(); |
+ var node = target.domModel.nodeForId(invalidationEvent.frontendNodeId); |
+ if (node) |
+ nodeRow.appendChild(WebInspector.DOMPresentationUtils.linkifyNodeReference(node)); |
+ else if (invalidationEvent.nodeName) |
+ nodeRow.textContent = '[' + invalidationEvent.nodeName + ']'; |
+ else |
+ nodeRow.textContent = '[ unknown node ]'; |
+ |
+ var callstack = invalidationEvent.callstack ? JSON.parse(invalidationEvent.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; |
+} |
+ |
+/** |
* @return {!Array.<string>} |
*/ |
WebInspector.TracingTimelineUIUtils._visibleTypes = function() |