blob: da5e06bbcd6bca7a7d77dcaf2a7b2dd7cd776e2c [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
Timeline.TimelinePaintProfilerView = class extends UI.SplitWidget {
/**
* @param {!TimelineModel.TimelineFrameModel} frameModel
*/
constructor(frameModel) {
super(false, false);
this.element.classList.add('timeline-paint-profiler-view');
this.setSidebarSize(60);
this.setResizable(false);
this._frameModel = frameModel;
this._logAndImageSplitWidget = new UI.SplitWidget(true, false);
this._logAndImageSplitWidget.element.classList.add('timeline-paint-profiler-log-split');
this.setMainWidget(this._logAndImageSplitWidget);
this._imageView = new Timeline.TimelinePaintImageView();
this._logAndImageSplitWidget.setMainWidget(this._imageView);
this._paintProfilerView = new LayerViewer.PaintProfilerView(this._imageView.showImage.bind(this._imageView));
this._paintProfilerView.addEventListener(
LayerViewer.PaintProfilerView.Events.WindowChanged, this._onWindowChanged, this);
this.setSidebarWidget(this._paintProfilerView);
this._logTreeView = new LayerViewer.PaintProfilerCommandLogView();
this._logAndImageSplitWidget.setSidebarWidget(this._logTreeView);
this._needsUpdateWhenVisible = false;
/** @type {?SDK.PaintProfilerSnapshot} */
this._pendingSnapshot = null;
/** @type {?SDK.TracingModel.Event} */
this._event = null;
/** @type {?SDK.PaintProfilerModel} */
this._paintProfilerModel = null;
/** @type {?SDK.PaintProfilerSnapshot} */
this._lastLoadedSnapshot = null;
}
/**
* @override
*/
wasShown() {
if (this._needsUpdateWhenVisible) {
this._needsUpdateWhenVisible = false;
this._update();
}
}
/**
* @param {!SDK.PaintProfilerSnapshot} snapshot
*/
setSnapshot(snapshot) {
this._releaseSnapshot();
this._pendingSnapshot = snapshot;
this._event = null;
this._updateWhenVisible();
}
/**
* @param {!SDK.PaintProfilerModel} paintProfilerModel
* @param {!SDK.TracingModel.Event} event
* @return {boolean}
*/
setEvent(paintProfilerModel, event) {
this._releaseSnapshot();
this._paintProfilerModel = paintProfilerModel;
this._pendingSnapshot = null;
this._event = event;
this._updateWhenVisible();
if (this._event.name === TimelineModel.TimelineModel.RecordType.Paint) {
return !!TimelineModel.TimelineData.forEvent(event).picture;
}
if (this._event.name === TimelineModel.TimelineModel.RecordType.RasterTask) {
return this._frameModel.hasRasterTile(this._event);
}
return false;
}
_updateWhenVisible() {
if (this.isShowing()) {
this._update();
} else {
this._needsUpdateWhenVisible = true;
}
}
_update() {
this._logTreeView.setCommandLog([]);
this._paintProfilerView.setSnapshotAndLog(null, [], null);
let snapshotPromise;
if (this._pendingSnapshot) {
snapshotPromise = Promise.resolve({rect: null, snapshot: this._pendingSnapshot});
} else if (this._event.name === TimelineModel.TimelineModel.RecordType.Paint) {
const picture = TimelineModel.TimelineData.forEvent(this._event).picture;
snapshotPromise = picture.objectPromise()
.then(data => this._paintProfilerModel.loadSnapshot(data['skp64']))
.then(snapshot => snapshot && {rect: null, snapshot: snapshot});
} else if (this._event.name === TimelineModel.TimelineModel.RecordType.RasterTask) {
snapshotPromise = this._frameModel.rasterTilePromise(this._event);
} else {
console.assert(false, 'Unexpected event type or no snapshot');
return;
}
snapshotPromise.then(snapshotWithRect => {
this._releaseSnapshot();
if (!snapshotWithRect) {
this._imageView.showImage();
return;
}
const snapshot = snapshotWithRect.snapshot;
this._lastLoadedSnapshot = snapshot;
this._imageView.setMask(snapshotWithRect.rect);
snapshot.commandLog().then(log => onCommandLogDone.call(this, snapshot, snapshotWithRect.rect, log));
});
/**
* @param {!SDK.PaintProfilerSnapshot} snapshot
* @param {?Protocol.DOM.Rect} clipRect
* @param {!Array.<!SDK.PaintProfilerLogItem>=} log
* @this {Timeline.TimelinePaintProfilerView}
*/
function onCommandLogDone(snapshot, clipRect, log) {
this._logTreeView.setCommandLog(log || []);
this._paintProfilerView.setSnapshotAndLog(snapshot, log || [], clipRect);
}
}
_releaseSnapshot() {
if (!this._lastLoadedSnapshot) {
return;
}
this._lastLoadedSnapshot.release();
this._lastLoadedSnapshot = null;
}
_onWindowChanged() {
this._logTreeView.updateWindow(this._paintProfilerView.selectionWindow());
}
};
/**
* @unrestricted
*/
Timeline.TimelinePaintImageView = class extends UI.Widget {
constructor() {
super(true);
this.registerRequiredCSS('timeline/timelinePaintProfiler.css');
this.contentElement.classList.add('fill', 'paint-profiler-image-view');
this._imageContainer = this.contentElement.createChild('div', 'paint-profiler-image-container');
this._imageElement = this._imageContainer.createChild('img');
this._maskElement = this._imageContainer.createChild('div');
this._imageElement.addEventListener('load', this._updateImagePosition.bind(this), false);
this._transformController = new LayerViewer.TransformController(this.contentElement, true);
this._transformController.addEventListener(
LayerViewer.TransformController.Events.TransformChanged, this._updateImagePosition, this);
}
/**
* @override
*/
onResize() {
if (this._imageElement.src) {
this._updateImagePosition();
}
}
_updateImagePosition() {
const width = this._imageElement.naturalWidth;
const height = this._imageElement.naturalHeight;
const clientWidth = this.contentElement.clientWidth;
const clientHeight = this.contentElement.clientHeight;
const paddingFraction = 0.1;
const paddingX = clientWidth * paddingFraction;
const paddingY = clientHeight * paddingFraction;
const scaleX = (clientWidth - paddingX) / width;
const scaleY = (clientHeight - paddingY) / height;
const scale = Math.min(scaleX, scaleY);
if (this._maskRectangle) {
const style = this._maskElement.style;
style.width = width + 'px';
style.height = height + 'px';
style.borderLeftWidth = this._maskRectangle.x + 'px';
style.borderTopWidth = this._maskRectangle.y + 'px';
style.borderRightWidth = (width - this._maskRectangle.x - this._maskRectangle.width) + 'px';
style.borderBottomWidth = (height - this._maskRectangle.y - this._maskRectangle.height) + 'px';
}
this._transformController.setScaleConstraints(0.5, 10 / scale);
let matrix = new WebKitCSSMatrix()
.scale(this._transformController.scale(), this._transformController.scale())
.translate(clientWidth / 2, clientHeight / 2)
.scale(scale, scale)
.translate(-width / 2, -height / 2);
const bounds = UI.Geometry.boundsForTransformedPoints(matrix, [0, 0, 0, width, height, 0]);
this._transformController.clampOffsets(
paddingX - bounds.maxX, clientWidth - paddingX - bounds.minX, paddingY - bounds.maxY,
clientHeight - paddingY - bounds.minY);
matrix = new WebKitCSSMatrix()
.translate(this._transformController.offsetX(), this._transformController.offsetY())
.multiply(matrix);
this._imageContainer.style.webkitTransform = matrix.toString();
}
/**
* @param {string=} imageURL
*/
showImage(imageURL) {
this._imageContainer.classList.toggle('hidden', !imageURL);
if (imageURL) {
this._imageElement.src = imageURL;
}
}
/**
* @param {?Protocol.DOM.Rect} maskRectangle
*/
setMask(maskRectangle) {
this._maskRectangle = maskRectangle;
this._maskElement.classList.toggle('hidden', !maskRectangle);
}
};