blob: 6f41245e16307035a2cf9cd2259068bf6813e08f [file] [log] [blame]
/*
* Copyright (C) 2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
WI.CanvasManager = class CanvasManager extends WI.Object
{
constructor()
{
super();
WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
this._canvasIdentifierMap = new Map;
this._shaderProgramIdentifierMap = new Map;
this._recordingCanvas = null;
this._recordingFrameMap = new Map;
if (window.CanvasAgent)
CanvasAgent.enable();
}
// Public
get canvases()
{
return [...this._canvasIdentifierMap.values()];
}
get shaderPrograms()
{
return [...this._shaderProgramIdentifierMap.values()];
}
get recordingCanvas() { return this._recordingCanvas; }
importRecording()
{
WI.loadDataFromFile((data, filename) => {
if (!data)
return;
let payload = null;
try {
payload = JSON.parse(data);
} catch (e) {
WI.Recording.synthesizeError(e);
return;
}
let recording = WI.Recording.fromPayload(payload);
if (!recording) {
WI.Recording.synthesizeError(WI.UIString("unsupported version."));
return;
}
let extensionStart = filename.lastIndexOf(".");
if (extensionStart !== -1)
filename = filename.substring(0, extensionStart);
recording.createDisplayName(filename);
this.dispatchEventToListeners(WI.CanvasManager.Event.RecordingImported, {recording});
});
}
startRecording(canvas, singleFrame)
{
console.assert(!this._recordingCanvas, "Recording already started.");
if (this._recordingCanvas)
return;
this._recordingCanvas = canvas;
CanvasAgent.startRecording(canvas.identifier, singleFrame, (error) => {
if (error) {
console.error(error);
this._recordingCanvas = null;
return;
}
this.dispatchEventToListeners(WI.CanvasManager.Event.RecordingStarted, {canvas});
});
}
stopRecording()
{
console.assert(this._recordingCanvas, "No recording started.");
if (!this._recordingCanvas)
return;
let canvas = this._recordingCanvas;
CanvasAgent.stopRecording(canvas.identifier, (error) => {
if (!error)
return;
console.error(error);
this._recordingCanvas = null;
this.dispatchEventToListeners(WI.CanvasManager.Event.RecordingStopped, {canvas, recording: null});
});
}
canvasAdded(canvasPayload)
{
// Called from WI.CanvasObserver.
console.assert(!this._canvasIdentifierMap.has(canvasPayload.canvasId), `Canvas already exists with id ${canvasPayload.canvasId}.`);
let canvas = WI.Canvas.fromPayload(canvasPayload);
this._canvasIdentifierMap.set(canvas.identifier, canvas);
this.dispatchEventToListeners(WI.CanvasManager.Event.CanvasAdded, {canvas});
}
canvasRemoved(canvasIdentifier)
{
// Called from WI.CanvasObserver.
let canvas = this._canvasIdentifierMap.take(canvasIdentifier);
console.assert(canvas);
if (!canvas)
return;
this._removeCanvas(canvas);
}
canvasMemoryChanged(canvasIdentifier, memoryCost)
{
// Called from WI.CanvasObserver.
let canvas = this._canvasIdentifierMap.get(canvasIdentifier);
console.assert(canvas);
if (!canvas)
return;
canvas.memoryCost = memoryCost;
}
cssCanvasClientNodesChanged(canvasIdentifier)
{
// Called from WI.CanvasObserver.
let canvas = this._canvasIdentifierMap.get(canvasIdentifier);
console.assert(canvas);
if (!canvas)
return;
canvas.cssCanvasClientNodesChanged();
}
recordingProgress(canvasIdentifier, framesPayload, bufferUsed)
{
// Called from WI.CanvasObserver.
let canvas = this._canvasIdentifierMap.get(canvasIdentifier);
console.assert(canvas);
if (!canvas)
return;
let existingFrames = this._recordingFrameMap.get(canvasIdentifier);
if (!existingFrames) {
existingFrames = [];
this._recordingFrameMap.set(canvasIdentifier, existingFrames);
}
existingFrames.push(...framesPayload.map(WI.RecordingFrame.fromPayload));
this.dispatchEventToListeners(WI.CanvasManager.Event.RecordingProgress, {
canvas,
frameCount: existingFrames.length,
bufferUsed,
});
}
recordingFinished(canvasIdentifier, recordingPayload)
{
// Called from WI.CanvasObserver.
let canvas = this._canvasIdentifierMap.get(canvasIdentifier);
console.assert(canvas);
let fromConsole = canvas !== this._recordingCanvas;
if (!fromConsole)
this._recordingCanvas = null;
if (!canvas)
return;
let frames = this._recordingFrameMap.take(canvasIdentifier);
let recording = recordingPayload ? WI.Recording.fromPayload(recordingPayload, frames) : null;
if (recording) {
recording.source = canvas;
recording.createDisplayName(recordingPayload.name);
canvas.recordingCollection.add(recording);
}
this.dispatchEventToListeners(WI.CanvasManager.Event.RecordingStopped, {canvas, recording, fromConsole});
}
extensionEnabled(canvasIdentifier, extension)
{
// Called from WI.CanvasObserver.
let canvas = this._canvasIdentifierMap.get(canvasIdentifier);
console.assert(canvas);
if (!canvas)
return;
canvas.enableExtension(extension);
}
programCreated(canvasIdentifier, programIdentifier)
{
// Called from WI.CanvasObserver.
let canvas = this._canvasIdentifierMap.get(canvasIdentifier);
console.assert(canvas);
if (!canvas)
return;
console.assert(!this._shaderProgramIdentifierMap.has(programIdentifier), `ShaderProgram already exists with id ${programIdentifier}.`);
let program = new WI.ShaderProgram(programIdentifier, canvas);
this._shaderProgramIdentifierMap.set(program.identifier, program);
canvas.shaderProgramCollection.add(program);
this.dispatchEventToListeners(WI.CanvasManager.Event.ShaderProgramAdded, {program});
}
programDeleted(programIdentifier)
{
// Called from WI.CanvasObserver.
let program = this._shaderProgramIdentifierMap.take(programIdentifier);
console.assert(program);
if (!program)
return;
program.canvas.shaderProgramCollection.remove(program);
this._dispatchShaderProgramRemoved(program);
}
// Private
_removeCanvas(canvas)
{
for (let program of canvas.shaderProgramCollection.items) {
this._shaderProgramIdentifierMap.delete(program.identifier);
this._dispatchShaderProgramRemoved(program);
}
this.dispatchEventToListeners(WI.CanvasManager.Event.CanvasRemoved, {canvas});
}
_mainResourceDidChange(event)
{
console.assert(event.target instanceof WI.Frame);
if (!event.target.isMainFrame())
return;
WI.Canvas.resetUniqueDisplayNameNumbers();
for (let canvas of this._canvasIdentifierMap.values())
this._removeCanvas(canvas);
this._shaderProgramIdentifierMap.clear();
this._canvasIdentifierMap.clear();
}
_dispatchShaderProgramRemoved(program)
{
this.dispatchEventToListeners(WI.CanvasManager.Event.ShaderProgramRemoved, {program});
}
};
WI.CanvasManager.Event = {
CanvasAdded: "canvas-manager-canvas-was-added",
CanvasRemoved: "canvas-manager-canvas-was-removed",
RecordingImported: "canvas-manager-recording-imported",
RecordingStarted: "canvas-manager-recording-started",
RecordingProgress: "canvas-manager-recording-progress",
RecordingStopped: "canvas-manager-recording-stopped",
ShaderProgramAdded: "canvas-manager-shader-program-added",
ShaderProgramRemoved: "canvas-manager-shader-program-removed",
};