Commit e4f43999 authored by caseq@chromium.org's avatar caseq@chromium.org

Timeline: add preview of painted picture for Paint event

- enable "Capture picture" check-box in Timeline capture filter when
    Timeline on trace events experiment is enabled;
- add disabled-by-default-devtools.timeline.{picture,layers} categories
    to trace filter when the above is checked;
- associate recorded SkPicture with the last paint event of the layer
    with matching id;
- display pictures preview in Timeline's details view, when these are
    available.

BUG=

Review URL: https://codereview.chromium.org/328143003

git-svn-id: svn://svn.chromium.org/blink/trunk@176196 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 31e41790
...@@ -142,6 +142,19 @@ WebInspector.TimelineModel.forAllRecords = function(recordsArray, preOrderCallba ...@@ -142,6 +142,19 @@ WebInspector.TimelineModel.forAllRecords = function(recordsArray, preOrderCallba
} }
WebInspector.TimelineModel.prototype = { WebInspector.TimelineModel.prototype = {
/**
* @param {boolean} captureStacks
* @param {boolean} captureMemory
* @param {boolean} capturePictures
*/
startRecording: function(captureStacks, captureMemory, capturePictures)
{
},
stopRecording: function()
{
},
/** /**
* @return {boolean} * @return {boolean}
*/ */
......
...@@ -36,9 +36,11 @@ WebInspector.TimelineModelImpl.prototype = { ...@@ -36,9 +36,11 @@ WebInspector.TimelineModelImpl.prototype = {
/** /**
* @param {boolean} captureStacks * @param {boolean} captureStacks
* @param {boolean} captureMemory * @param {boolean} captureMemory
* @param {boolean} capturePictures
*/ */
startRecording: function(captureStacks, captureMemory) startRecording: function(captureStacks, captureMemory, capturePictures)
{ {
console.assert(!capturePictures, "Legacy timeline does not support capturing pictures");
this._clientInitiatedRecording = true; this._clientInitiatedRecording = true;
this.reset(); this.reset();
var maxStackFrames = captureStacks ? 30 : 0; var maxStackFrames = captureStacks ? 30 : 0;
......
...@@ -341,6 +341,11 @@ WebInspector.TimelinePanel.prototype = { ...@@ -341,6 +341,11 @@ WebInspector.TimelinePanel.prototype = {
this._captureTracingSetting, true, undefined, this._captureTracingSetting, true, undefined,
WebInspector.UIString("Capture tracing information"))); WebInspector.UIString("Capture tracing information")));
this._captureTracingSetting.addChangeListener(this._onModeChanged, this); this._captureTracingSetting.addChangeListener(this._onModeChanged, this);
} else if (WebInspector.experimentsSettings.timelineOnTraceEvents.isEnabled()) {
this._captureLayersAndPicturesSetting = WebInspector.settings.createSetting("timelineCaptureLayersAndPictures", false);
topPaneSidebarElement.appendChild(WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Capture pictures"),
this._captureLayersAndPicturesSetting, true, undefined,
WebInspector.UIString("Capture graphics layer positions and painted pictures")));
} }
}, },
...@@ -652,7 +657,7 @@ WebInspector.TimelinePanel.prototype = { ...@@ -652,7 +657,7 @@ WebInspector.TimelinePanel.prototype = {
_startRecording: function(userInitiated) _startRecording: function(userInitiated)
{ {
this._userInitiatedRecording = userInitiated; this._userInitiatedRecording = userInitiated;
this._model.startRecording(this._captureStacksSetting.get(), this._captureMemorySetting.get()); this._model.startRecording(this._captureStacksSetting.get(), this._captureMemorySetting.get(), this._captureLayersAndPicturesSetting && this._captureLayersAndPicturesSetting.get());
if (WebInspector.experimentsSettings.timelineNoLiveUpdate.isEnabled() && this._lazyFrameModel) if (WebInspector.experimentsSettings.timelineNoLiveUpdate.isEnabled() && this._lazyFrameModel)
this._lazyFrameModel.setMergeRecords(false); this._lazyFrameModel.setMergeRecords(false);
......
...@@ -124,20 +124,31 @@ WebInspector.TimelineTracingView.prototype = { ...@@ -124,20 +124,31 @@ WebInspector.TimelineTracingView.prototype = {
{ {
WebInspector.Revealer.reveal(new WebInspector.DeferredTracingLayerTree(this._tracingModel.target(), record.args["snapshot"]["active_tree"]["root_layer"])); WebInspector.Revealer.reveal(new WebInspector.DeferredTracingLayerTree(this._tracingModel.target(), record.args["snapshot"]["active_tree"]["root_layer"]));
} }
if (record.name === "cc::LayerTreeHostImpl") { /**
* @param {!Node=} node
* @this {WebInspector.TimelineTracingView}
*/
function appendPreviewAndshowDetails(node)
{
if (node)
contentHelper.appendElementRow("Preview", node);
this._delegate.showInDetails(WebInspector.UIString("Selected Event"), contentHelper.element);
}
var recordTypes = WebInspector.TracingTimelineModel.RecordType;
switch (record.name) {
case recordTypes.PictureSnapshot:
WebInspector.TracingTimelineUIUtils._buildPicturePreviewContent(record.args["snapshot"]["skp64"], appendPreviewAndshowDetails.bind(this));
break;
case recordTypes.LayerTreeHostImplSnapshot:
var link = document.createElement("span"); var link = document.createElement("span");
link.classList.add("revealable-link"); link.classList.add("revealable-link");
link.textContent = "show"; link.textContent = "show";
link.addEventListener("click", reveal.bind(this), false); link.addEventListener("click", reveal.bind(this), false);
contentHelper.appendElementRow(WebInspector.UIString("Layer tree"), link); contentHelper.appendElementRow(WebInspector.UIString("Layer tree"), link);
} else if (record.name === "cc::Picture") { // Fall-through intended.
var div = document.createElement("div"); default:
div.className = "image-preview-container";
var img = div.createChild("img");
contentHelper.appendElementRow("Preview", div);
this._requestThumbnail(img, record.args["snapshot"]["skp64"]);
}
this._delegate.showInDetails(WebInspector.UIString("Selected Event"), contentHelper.element); this._delegate.showInDetails(WebInspector.UIString("Selected Event"), contentHelper.element);
}
}, },
/** /**
...@@ -163,43 +174,6 @@ WebInspector.TimelineTracingView.prototype = { ...@@ -163,43 +174,6 @@ WebInspector.TimelineTracingView.prototype = {
return table; return table;
}, },
/**
* @param {!Element} img
* @param {string} encodedPicture
*/
_requestThumbnail: function(img, encodedPicture)
{
var snapshotId;
LayerTreeAgent.loadSnapshot(encodedPicture, onSnapshotLoaded);
/**
* @param {string} error
* @param {string} id
*/
function onSnapshotLoaded(error, id)
{
if (error) {
console.error("LayerTreeAgent.loadSnapshot(): " + error);
return;
}
snapshotId = id;
LayerTreeAgent.replaySnapshot(snapshotId, onSnapshotReplayed);
}
/**
* @param {string} error
* @param {string} encodedBitmap
*/
function onSnapshotReplayed(error, encodedBitmap)
{
LayerTreeAgent.releaseSnapshot(snapshotId);
if (error) {
console.error("LayerTreeAgent.replaySnapshot(): " + error);
return;
}
img.src = encodedBitmap;
}
},
__proto__: WebInspector.VBox.prototype __proto__: WebInspector.VBox.prototype
}; };
......
...@@ -32,6 +32,7 @@ WebInspector.TracingTimelineModel.RecordType = { ...@@ -32,6 +32,7 @@ WebInspector.TracingTimelineModel.RecordType = {
RecalculateStyles: "RecalculateStyles", RecalculateStyles: "RecalculateStyles",
InvalidateLayout: "InvalidateLayout", InvalidateLayout: "InvalidateLayout",
Layout: "Layout", Layout: "Layout",
UpdateLayer: "UpdateLayer",
PaintSetup: "PaintSetup", PaintSetup: "PaintSetup",
Paint: "Paint", Paint: "Paint",
PaintImage: "PaintImage", PaintImage: "PaintImage",
...@@ -89,7 +90,8 @@ WebInspector.TracingTimelineModel.RecordType = { ...@@ -89,7 +90,8 @@ WebInspector.TracingTimelineModel.RecordType = {
DecodeLazyPixelRef: "Decode LazyPixelRef", DecodeLazyPixelRef: "Decode LazyPixelRef",
LazyPixelRef: "LazyPixelRef", LazyPixelRef: "LazyPixelRef",
LayerTreeHostImplSnapshot: "cc::LayerTreeHostImpl" LayerTreeHostImplSnapshot: "cc::LayerTreeHostImpl",
PictureSnapshot: "cc::Picture"
}; };
WebInspector.TracingTimelineModel.defaultTracingCategoryFilter = "*,disabled-by-default-cc.debug,disabled-by-default-devtools.timeline,disabled-by-default-devtools.timeline.frame"; WebInspector.TracingTimelineModel.defaultTracingCategoryFilter = "*,disabled-by-default-cc.debug,disabled-by-default-devtools.timeline,disabled-by-default-devtools.timeline.frame";
...@@ -98,8 +100,9 @@ WebInspector.TracingTimelineModel.prototype = { ...@@ -98,8 +100,9 @@ WebInspector.TracingTimelineModel.prototype = {
/** /**
* @param {boolean} captureStacks * @param {boolean} captureStacks
* @param {boolean} captureMemory * @param {boolean} captureMemory
* @param {boolean} capturePictures
*/ */
startRecording: function(captureStacks, captureMemory) startRecording: function(captureStacks, captureMemory, capturePictures)
{ {
var categories; var categories;
if (WebInspector.experimentsSettings.timelineTracingMode.isEnabled()) { if (WebInspector.experimentsSettings.timelineTracingMode.isEnabled()) {
...@@ -108,6 +111,8 @@ WebInspector.TracingTimelineModel.prototype = { ...@@ -108,6 +111,8 @@ WebInspector.TracingTimelineModel.prototype = {
var categoriesArray = ["disabled-by-default-devtools.timeline", "disabled-by-default-devtools.timeline.frame", "devtools"]; var categoriesArray = ["disabled-by-default-devtools.timeline", "disabled-by-default-devtools.timeline.frame", "devtools"];
if (captureStacks) if (captureStacks)
categoriesArray.push("disabled-by-default-devtools.timeline.stack"); categoriesArray.push("disabled-by-default-devtools.timeline.stack");
if (capturePictures)
categoriesArray.push("disabled-by-default-devtools.timeline.layers", "disabled-by-default-devtools.timeline.picture");
categories = categoriesArray.join(","); categories = categoriesArray.join(",");
} }
this._startRecordingWithCategories(categories); this._startRecordingWithCategories(categories);
...@@ -254,7 +259,7 @@ WebInspector.TracingTimelineModel.prototype = { ...@@ -254,7 +259,7 @@ WebInspector.TracingTimelineModel.prototype = {
this._lastScheduleStyleRecalculation = {}; this._lastScheduleStyleRecalculation = {};
this._webSocketCreateEvents = {}; this._webSocketCreateEvents = {};
this._paintImageEventByPixelRefId = {}; this._paintImageEventByPixelRefId = {};
this._lastPaintForLayer = {};
this._lastRecalculateStylesEvent = null; this._lastRecalculateStylesEvent = null;
this._currentScriptEvent = null; this._currentScriptEvent = null;
this._eventStack = []; this._eventStack = [];
...@@ -394,7 +399,23 @@ WebInspector.TracingTimelineModel.prototype = { ...@@ -394,7 +399,23 @@ WebInspector.TracingTimelineModel.prototype = {
case recordTypes.Paint: case recordTypes.Paint:
event.highlightQuad = event.args["data"]["clip"]; event.highlightQuad = event.args["data"]["clip"];
// Initionally fall through. event.backendNodeId = event.args["data"]["nodeId"];
var layerUpdateEvent = this._findAncestorEvent(recordTypes.UpdateLayer);
if (!layerUpdateEvent || layerUpdateEvent.args["layerTreeId"] !== this._inspectedTargetLayerTreeId)
break;
this._lastPaintForLayer[layerUpdateEvent.args["layerId"]] = event;
break;
case recordTypes.PictureSnapshot:
var layerUpdateEvent = this._findAncestorEvent(recordTypes.UpdateLayer);
if (!layerUpdateEvent || layerUpdateEvent.args["layerTreeId"] !== this._inspectedTargetLayerTreeId)
break;
var paintEvent = this._lastPaintForLayer[layerUpdateEvent.args["layerId"]];
if (!paintEvent)
break;
paintEvent.picture = event.args["snapshot"]["skp64"];
break;
case recordTypes.ScrollLayer: case recordTypes.ScrollLayer:
event.backendNodeId = event.args["data"]["nodeId"]; event.backendNodeId = event.args["data"]["nodeId"];
break; break;
......
...@@ -40,6 +40,7 @@ WebInspector.TracingTimelineUIUtils._initEventStyles = function() ...@@ -40,6 +40,7 @@ WebInspector.TracingTimelineUIUtils._initEventStyles = function()
eventStyles[recordTypes.InvalidateLayout] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Invalidate Layout"), categories["rendering"]); eventStyles[recordTypes.InvalidateLayout] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Invalidate Layout"), categories["rendering"]);
eventStyles[recordTypes.Layout] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Layout"), categories["rendering"]); eventStyles[recordTypes.Layout] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Layout"), categories["rendering"]);
eventStyles[recordTypes.PaintSetup] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Paint Setup"), categories["painting"]); eventStyles[recordTypes.PaintSetup] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Paint Setup"), categories["painting"]);
eventStyles[recordTypes.UpdateLayer] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Update Layer"), categories["painting"]);
eventStyles[recordTypes.Paint] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Paint"), categories["painting"]); eventStyles[recordTypes.Paint] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Paint"), categories["painting"]);
eventStyles[recordTypes.Rasterize] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Paint"), categories["painting"]); eventStyles[recordTypes.Rasterize] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Paint"), categories["painting"]);
eventStyles[recordTypes.RasterTask] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Paint"), categories["painting"]); eventStyles[recordTypes.RasterTask] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Paint"), categories["painting"]);
...@@ -265,8 +266,12 @@ WebInspector.TracingTimelineUIUtils.buildTraceEventDetails = function(event, mod ...@@ -265,8 +266,12 @@ WebInspector.TracingTimelineUIUtils.buildTraceEventDetails = function(event, mod
{ {
var relatedNode = null; var relatedNode = null;
var barrier = new CallbackBarrier(); var barrier = new CallbackBarrier();
if (event.imageURL && !event.previewElement) if (!event.previewElement) {
if (event.imageURL)
WebInspector.DOMPresentationUtils.buildImagePreviewContents(target, event.imageURL, false, barrier.createCallback(saveImage)); WebInspector.DOMPresentationUtils.buildImagePreviewContents(target, event.imageURL, false, barrier.createCallback(saveImage));
else if (event.picture)
WebInspector.TracingTimelineUIUtils._buildPicturePreviewContent(event.picture, barrier.createCallback(saveImage));
}
if (event.backendNodeId) if (event.backendNodeId)
target.domModel.pushNodesByBackendIdsToFrontend([event.backendNodeId], barrier.createCallback(setRelatedNode)); target.domModel.pushNodesByBackendIdsToFrontend([event.backendNodeId], barrier.createCallback(setRelatedNode));
barrier.callWhenDone(callbackWrapper); barrier.callWhenDone(callbackWrapper);
...@@ -357,8 +362,6 @@ WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously = funct ...@@ -357,8 +362,6 @@ WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously = funct
var url = (event.name === recordTypes.ResourceSendRequest) ? eventData["url"] : initiator.args.data["url"]; var url = (event.name === recordTypes.ResourceSendRequest) ? eventData["url"] : initiator.args.data["url"];
if (url) if (url)
contentHelper.appendElementRow(WebInspector.UIString("Resource"), WebInspector.linkifyResourceAsNode(url)); contentHelper.appendElementRow(WebInspector.UIString("Resource"), WebInspector.linkifyResourceAsNode(url));
if (event.previewElement)
contentHelper.appendElementRow(WebInspector.UIString("Preview"), event.previewElement);
if (eventData["requestMethod"]) if (eventData["requestMethod"])
contentHelper.appendTextRow(WebInspector.UIString("Request Method"), eventData["requestMethod"]); contentHelper.appendTextRow(WebInspector.UIString("Request Method"), eventData["requestMethod"]);
if (typeof eventData["statusCode"] === "number") if (typeof eventData["statusCode"] === "number")
...@@ -394,8 +397,6 @@ WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously = funct ...@@ -394,8 +397,6 @@ WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously = funct
relatedNodeLabel = WebInspector.UIString("Image element"); relatedNodeLabel = WebInspector.UIString("Image element");
if (event.imageURL) if (event.imageURL)
contentHelper.appendElementRow(WebInspector.UIString("Image URL"), WebInspector.linkifyResourceAsNode(event.imageURL)); contentHelper.appendElementRow(WebInspector.UIString("Image URL"), WebInspector.linkifyResourceAsNode(event.imageURL));
if (event.previewElement)
contentHelper.appendElementRow(WebInspector.UIString("Preview"), event.previewElement);
break; break;
case recordTypes.RecalculateStyles: // We don't want to see default details. case recordTypes.RecalculateStyles: // We don't want to see default details.
contentHelper.appendTextRow(WebInspector.UIString("Elements affected"), event.args["elementCount"]); contentHelper.appendTextRow(WebInspector.UIString("Elements affected"), event.args["elementCount"]);
...@@ -457,6 +458,8 @@ WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously = funct ...@@ -457,6 +458,8 @@ WebInspector.TracingTimelineUIUtils._buildTraceEventDetailsSynchronously = funct
div.textContent = warning; div.textContent = warning;
contentHelper.appendElementRow(WebInspector.UIString("Warning"), div); contentHelper.appendElementRow(WebInspector.UIString("Warning"), div);
} }
if (event.previewElement)
contentHelper.appendElementRow(WebInspector.UIString("Preview"), event.previewElement);
fragment.appendChild(contentHelper.element); fragment.appendChild(contentHelper.element);
return fragment; return fragment;
} }
...@@ -497,3 +500,47 @@ WebInspector.TracingTimelineUIUtils._aggregatedStatsForTraceEvent = function(mod ...@@ -497,3 +500,47 @@ WebInspector.TracingTimelineUIUtils._aggregatedStatsForTraceEvent = function(mod
} }
return { aggregatedStats: aggregatedStats, hasChildren: hasChildren }; return { aggregatedStats: aggregatedStats, hasChildren: hasChildren };
} }
/**
* @param {string} encodedPicture
* @param {function(!Element=)} callback
*/
WebInspector.TracingTimelineUIUtils._buildPicturePreviewContent = function(encodedPicture, callback)
{
var snapshotId;
LayerTreeAgent.loadSnapshot(encodedPicture, onSnapshotLoaded);
/**
* @param {string} error
* @param {string} id
*/
function onSnapshotLoaded(error, id)
{
if (error) {
console.error("LayerTreeAgent.loadSnapshot(): " + error);
callback();
return;
}
snapshotId = id;
LayerTreeAgent.replaySnapshot(snapshotId, onSnapshotReplayed);
}
/**
* @param {string} error
* @param {string} encodedBitmap
*/
function onSnapshotReplayed(error, encodedBitmap)
{
LayerTreeAgent.releaseSnapshot(snapshotId);
if (error) {
console.error("LayerTreeAgent.replaySnapshot(): " + error);
callback();
return;
}
var container = document.createElement("div");
container.className = "image-preview-container";
var img = container.createChild("img");
img.src = encodedBitmap;
callback(container);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment