712 lines
24 KiB
JavaScript
712 lines
24 KiB
JavaScript
/*
|
|
* 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.RecordingAction = class RecordingAction extends WI.Object
|
|
{
|
|
constructor(name, parameters, swizzleTypes, trace, snapshot)
|
|
{
|
|
super();
|
|
|
|
this._payloadName = name;
|
|
this._payloadParameters = parameters;
|
|
this._payloadSwizzleTypes = swizzleTypes;
|
|
this._payloadTrace = trace;
|
|
this._payloadSnapshot = snapshot ?? -1;
|
|
|
|
this._name = "";
|
|
this._parameters = [];
|
|
this._trace = [];
|
|
this._snapshot = "";
|
|
|
|
this._valid = true;
|
|
this._isFunction = false;
|
|
this._isGetter = false;
|
|
this._isVisual = false;
|
|
|
|
this._contextReplacer = null;
|
|
|
|
this._states = [];
|
|
this._stateModifiers = new Set;
|
|
|
|
this._warning = null;
|
|
this._swizzled = false;
|
|
this._processed = false;
|
|
}
|
|
|
|
// Static
|
|
|
|
// Payload format: (name, parameters, swizzleTypes, [trace, [snapshot]])
|
|
static fromPayload(payload)
|
|
{
|
|
if (!Array.isArray(payload))
|
|
payload = [];
|
|
|
|
if (typeof payload[0] !== "number") {
|
|
if (payload.length > 0)
|
|
WI.Recording.synthesizeWarning(WI.UIString("non-number %s").format(WI.unlocalizedString("name")));
|
|
|
|
payload[0] = -1;
|
|
}
|
|
|
|
if (!Array.isArray(payload[1])) {
|
|
if (payload.length > 1)
|
|
WI.Recording.synthesizeWarning(WI.UIString("non-array %s").format(WI.unlocalizedString("parameters")));
|
|
|
|
payload[1] = [];
|
|
}
|
|
|
|
if (!Array.isArray(payload[2])) {
|
|
if (payload.length > 2)
|
|
WI.Recording.synthesizeWarning(WI.UIString("non-array %s").format(WI.unlocalizedString("swizzleTypes")));
|
|
|
|
payload[2] = [];
|
|
}
|
|
|
|
if (typeof payload[3] !== "number" || isNaN(payload[3]) || (!payload[3] && payload[3] !== 0)) {
|
|
// COMPATIBILITY (iOS 12.1): "trace" was sent as an array of call frames instead of a single call stack
|
|
if (!Array.isArray(payload[3])) {
|
|
if (payload.length > 3)
|
|
WI.Recording.synthesizeWarning(WI.UIString("non-number %s").format(WI.unlocalizedString("trace")));
|
|
|
|
payload[3] = [];
|
|
}
|
|
}
|
|
|
|
if (typeof payload[4] !== "number" || isNaN(payload[4])) {
|
|
if (payload.length > 4)
|
|
WI.Recording.synthesizeWarning(WI.UIString("non-number %s").format(WI.unlocalizedString("snapshot")));
|
|
|
|
payload[4] = -1;
|
|
}
|
|
|
|
return new WI.RecordingAction(...payload);
|
|
}
|
|
|
|
static isFunctionForType(type, name)
|
|
{
|
|
let prototype = WI.RecordingAction._prototypeForType(type);
|
|
if (!prototype)
|
|
return false;
|
|
let propertyDescriptor = Object.getOwnPropertyDescriptor(prototype, name);
|
|
if (!propertyDescriptor)
|
|
return false;
|
|
return typeof propertyDescriptor.value === "function";
|
|
}
|
|
|
|
static constantNameForParameter(type, name, value, index, count)
|
|
{
|
|
let indexesForType = WI.RecordingAction._constantIndexes[type];
|
|
if (!indexesForType)
|
|
return null;
|
|
|
|
let indexesForAction = indexesForType[name];
|
|
if (!indexesForAction)
|
|
return null;
|
|
|
|
if (Array.isArray(indexesForAction) && !indexesForAction.includes(index))
|
|
return null;
|
|
|
|
if (typeof indexesForAction === "object") {
|
|
let indexesForActionVariant = indexesForAction[count];
|
|
if (!indexesForActionVariant)
|
|
return null;
|
|
|
|
if (Array.isArray(indexesForActionVariant) && !indexesForActionVariant.includes(index))
|
|
return null;
|
|
}
|
|
|
|
if (value === 0 && (type === WI.Recording.Type.CanvasWebGL || type === WI.Recording.Type.CanvasWebGL2)) {
|
|
if (name === "blendFunc" || name === "blendFuncSeparate")
|
|
return "ZERO";
|
|
if (index === 0) {
|
|
if (name === "drawArrays" || name === "drawElements")
|
|
return "POINTS";
|
|
if (name === "pixelStorei")
|
|
return "NONE";
|
|
}
|
|
}
|
|
|
|
let prototype = WI.RecordingAction._prototypeForType(type);
|
|
if (prototype) {
|
|
for (let key in prototype) {
|
|
let descriptor = Object.getOwnPropertyDescriptor(prototype, key);
|
|
if (descriptor && descriptor.value === value)
|
|
return key;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
static _prototypeForType(type)
|
|
{
|
|
switch (type) {
|
|
case WI.Recording.Type.Canvas2D:
|
|
return CanvasRenderingContext2D.prototype;
|
|
case WI.Recording.Type.CanvasBitmapRenderer:
|
|
if (window.ImageBitmapRenderingContext)
|
|
return ImageBitmapRenderingContext.prototype;
|
|
break;
|
|
case WI.Recording.Type.CanvasWebGL:
|
|
if (window.WebGLRenderingContext)
|
|
return WebGLRenderingContext.prototype;
|
|
break;
|
|
case WI.Recording.Type.CanvasWebGL2:
|
|
if (window.WebGL2RenderingContext)
|
|
return WebGL2RenderingContext.prototype;
|
|
break;
|
|
}
|
|
|
|
WI.reportInternalError("Unknown recording type: " + type);
|
|
return null;
|
|
}
|
|
|
|
// Public
|
|
|
|
get name() { return this._name; }
|
|
get parameters() { return this._parameters; }
|
|
get swizzleTypes() { return this._payloadSwizzleTypes; }
|
|
get trace() { return this._trace; }
|
|
get snapshot() { return this._snapshot; }
|
|
get valid() { return this._valid; }
|
|
get isFunction() { return this._isFunction; }
|
|
get isGetter() { return this._isGetter; }
|
|
get isVisual() { return this._isVisual; }
|
|
get contextReplacer() { return this._contextReplacer; }
|
|
get states() { return this._states; }
|
|
get stateModifiers() { return this._stateModifiers; }
|
|
get warning() { return this._warning; }
|
|
|
|
get ready()
|
|
{
|
|
return this._swizzled && this._processed;
|
|
}
|
|
|
|
process(recording, context, states, {lastAction} = {})
|
|
{
|
|
console.assert(this._swizzled, "You must swizzle() before you can process().");
|
|
console.assert(!this._processed, "You should only process() once.");
|
|
|
|
this._processed = true;
|
|
|
|
if (recording.type === WI.Recording.Type.CanvasWebGL || recording.type === WI.Recording.Type.CanvasWebGL2) {
|
|
// We add each RecordingAction to the list of visualActionIndexes after it is processed.
|
|
if (this._valid && this._isVisual) {
|
|
let contentBefore = recording.visualActionIndexes.length ? recording.actions[recording.visualActionIndexes.lastValue].snapshot : recording.initialState.content;
|
|
if (this._snapshot === contentBefore)
|
|
this._warning = WI.UIString("This action causes no visual change");
|
|
}
|
|
return;
|
|
}
|
|
|
|
function getContent() {
|
|
if (context instanceof CanvasRenderingContext2D)
|
|
return context.getImageData(0, 0, context.canvas.width, context.canvas.height).data;
|
|
|
|
if ((window.WebGLRenderingContext && context instanceof WebGLRenderingContext) || (window.WebGL2RenderingContext && context instanceof WebGL2RenderingContext)) {
|
|
let pixels = new Uint8Array(context.drawingBufferWidth * context.drawingBufferHeight * 4);
|
|
context.readPixels(0, 0, context.canvas.width, context.canvas.height, context.RGBA, context.UNSIGNED_BYTE, pixels);
|
|
return pixels;
|
|
}
|
|
|
|
if (context.canvas instanceof HTMLCanvasElement)
|
|
return [context.canvas.toDataURL()];
|
|
|
|
console.assert("Unknown context type", context);
|
|
return [];
|
|
}
|
|
|
|
let contentBefore = null;
|
|
let shouldCheckHasVisualEffect = this._valid && this._isVisual;
|
|
if (shouldCheckHasVisualEffect)
|
|
contentBefore = getContent();
|
|
|
|
this.apply(context);
|
|
|
|
if (shouldCheckHasVisualEffect) {
|
|
let contentAfter = getContent();
|
|
if (Array.shallowEqual(contentBefore, contentAfter))
|
|
this._warning = WI.UIString("This action causes no visual change");
|
|
}
|
|
|
|
if (recording.type === WI.Recording.Type.Canvas2D) {
|
|
let currentState = WI.RecordingState.fromContext(recording.type, context, {source: this});
|
|
console.assert(currentState);
|
|
|
|
if (this.name === "save")
|
|
states.push(currentState);
|
|
else if (this.name === "restore")
|
|
states.pop();
|
|
|
|
this._states = states.slice();
|
|
this._states.push(currentState);
|
|
|
|
let lastState = null;
|
|
if (lastAction) {
|
|
lastState = lastAction.states.lastValue;
|
|
for (let [name, value] of currentState) {
|
|
let previousValue = lastState.get(name);
|
|
if (value !== previousValue && !Object.shallowEqual(value, previousValue))
|
|
this._stateModifiers.add(name);
|
|
}
|
|
}
|
|
|
|
if (WI.ImageUtilities.supportsCanvasPathDebugging()) {
|
|
let currentX = currentState.get("currentX");
|
|
let invalidX = (currentX < 0 || currentX >= context.canvas.width) && (!lastState || currentX !== lastState.get("currentX"));
|
|
|
|
let currentY = currentState.get("currentY");
|
|
let invalidY = (currentY < 0 || currentY >= context.canvas.height) && (!lastState || currentY !== lastState.get("currentY"));
|
|
|
|
if (invalidX || invalidY)
|
|
this._warning = WI.UIString("This action moves the path outside the visible area");
|
|
}
|
|
}
|
|
}
|
|
|
|
async swizzle(recording, lastAction)
|
|
{
|
|
console.assert(!this._swizzled, "You should only swizzle() once.");
|
|
|
|
if (!this._valid) {
|
|
this._swizzled = true;
|
|
return;
|
|
}
|
|
|
|
let swizzleParameter = (item, index) => {
|
|
return recording.swizzle(item, this._payloadSwizzleTypes[index]);
|
|
};
|
|
|
|
let swizzlePromises = [
|
|
recording.swizzle(this._payloadName, WI.Recording.Swizzle.String),
|
|
Promise.all(this._payloadParameters.map(swizzleParameter)),
|
|
];
|
|
|
|
if (!isNaN(this._payloadTrace))
|
|
swizzlePromises.push(recording.swizzle(this._payloadTrace, WI.Recording.Swizzle.CallStack))
|
|
else {
|
|
// COMPATIBILITY (iOS 12.1): "trace" was sent as an array of call frames instead of a single call stack
|
|
swizzlePromises.push(Promise.all(this._payloadTrace.map((item) => recording.swizzle(item, WI.Recording.Swizzle.CallFrame))));
|
|
}
|
|
|
|
if (this._payloadSnapshot >= 0)
|
|
swizzlePromises.push(recording.swizzle(this._payloadSnapshot, WI.Recording.Swizzle.String));
|
|
|
|
let [name, parameters, callFrames, snapshot] = await Promise.all(swizzlePromises);
|
|
this._name = name;
|
|
this._parameters = parameters;
|
|
this._trace = callFrames;
|
|
if (this._payloadSnapshot >= 0)
|
|
this._snapshot = snapshot;
|
|
|
|
if (recording.type === WI.Recording.Type.Canvas2D || recording.type === WI.Recording.Type.CanvasBitmapRenderer || recording.type === WI.Recording.Type.CanvasWebGL || recording.type === WI.Recording.Type.CanvasWebGL2) {
|
|
if (this._name === "width" || this._name === "height") {
|
|
this._contextReplacer = "canvas";
|
|
this._isFunction = false;
|
|
this._isGetter = !this._parameters.length;
|
|
this._isVisual = !this._isGetter;
|
|
}
|
|
|
|
// FIXME: <https://webkit.org/b/180833>
|
|
}
|
|
|
|
if (!this._contextReplacer) {
|
|
this._isFunction = WI.RecordingAction.isFunctionForType(recording.type, this._name);
|
|
this._isGetter = !this._isFunction && !this._parameters.length;
|
|
|
|
if (this._snapshot)
|
|
this._isVisual = true;
|
|
else {
|
|
let visualNames = WI.RecordingAction._visualNames[recording.type];
|
|
this._isVisual = visualNames ? visualNames.has(this._name) : false;
|
|
}
|
|
|
|
if (this._valid) {
|
|
let prototype = WI.RecordingAction._prototypeForType(recording.type);
|
|
if (prototype && !(name in prototype)) {
|
|
this.markInvalid();
|
|
|
|
WI.Recording.synthesizeWarning(WI.UIString("\u0022%s\u0022 is not valid for %s").format(name, prototype.constructor.name));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this._valid) {
|
|
let parametersSpecified = this._parameters.every((parameter) => parameter !== undefined);
|
|
let parametersCanBeSwizzled = this._payloadSwizzleTypes.every((swizzleType) => swizzleType !== WI.Recording.Swizzle.None);
|
|
if (!parametersSpecified || !parametersCanBeSwizzled)
|
|
this.markInvalid();
|
|
}
|
|
|
|
if (this._valid) {
|
|
let stateModifiers = WI.RecordingAction._stateModifiers[recording.type];
|
|
if (stateModifiers) {
|
|
this._stateModifiers.add(this._name);
|
|
let modifiedByAction = stateModifiers[this._name] || [];
|
|
for (let item of modifiedByAction)
|
|
this._stateModifiers.add(item);
|
|
}
|
|
}
|
|
|
|
this._swizzled = true;
|
|
}
|
|
|
|
apply(context, options = {})
|
|
{
|
|
console.assert(this._swizzled, "You must swizzle() before you can apply().");
|
|
console.assert(this._processed, "You must process() before you can apply().");
|
|
|
|
if (!this.valid)
|
|
return;
|
|
|
|
try {
|
|
let name = options.nameOverride || this._name;
|
|
|
|
if (this._contextReplacer)
|
|
context = context[this._contextReplacer];
|
|
|
|
if (this.isFunction)
|
|
context[name](...this._parameters);
|
|
else {
|
|
if (this.isGetter)
|
|
context[name];
|
|
else
|
|
context[name] = this._parameters[0];
|
|
}
|
|
} catch {
|
|
this.markInvalid();
|
|
|
|
WI.Recording.synthesizeWarning(WI.UIString("\u0022%s\u0022 threw an error").format(this._name));
|
|
}
|
|
}
|
|
|
|
markInvalid()
|
|
{
|
|
if (!this._valid)
|
|
return;
|
|
|
|
this._valid = false;
|
|
|
|
this.dispatchEventToListeners(WI.RecordingAction.Event.ValidityChanged);
|
|
}
|
|
|
|
getColorParameters()
|
|
{
|
|
switch (this._name) {
|
|
// 2D
|
|
case "fillStyle":
|
|
case "strokeStyle":
|
|
case "shadowColor":
|
|
// 2D (non-standard, legacy)
|
|
case "setFillColor":
|
|
case "setStrokeColor":
|
|
// WebGL
|
|
case "blendColor":
|
|
case "clearColor":
|
|
case "colorMask":
|
|
return this._parameters;
|
|
|
|
// 2D (non-standard, legacy)
|
|
case "setShadow":
|
|
return this._parameters.slice(3);
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
getImageParameters()
|
|
{
|
|
switch (this._name) {
|
|
// 2D
|
|
case "createImageData":
|
|
case "createPattern":
|
|
case "drawImage":
|
|
case "fillStyle":
|
|
case "putImageData":
|
|
case "strokeStyle":
|
|
// 2D (non-standard)
|
|
case "drawImageFromRect":
|
|
// BitmapRenderer
|
|
case "transferFromImageBitmap":
|
|
return this._parameters.slice(0, 1);
|
|
|
|
// WebGL
|
|
case "texImage2D":
|
|
case "texSubImage2D":
|
|
case "compressedTexImage2D":
|
|
return [this._parameters.lastValue];
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
toJSON()
|
|
{
|
|
let json = [this._payloadName, this._payloadParameters, this._payloadSwizzleTypes, this._payloadTrace];
|
|
if (this._payloadSnapshot >= 0)
|
|
json.push(this._payloadSnapshot);
|
|
return json;
|
|
}
|
|
};
|
|
|
|
WI.RecordingAction.Event = {
|
|
ValidityChanged: "recording-action-marked-invalid",
|
|
};
|
|
|
|
WI.RecordingAction._constantIndexes = {
|
|
[WI.Recording.Type.CanvasWebGL]: {
|
|
"activeTexture": true,
|
|
"bindBuffer": true,
|
|
"bindFramebuffer": true,
|
|
"bindRenderbuffer": true,
|
|
"bindTexture": true,
|
|
"blendEquation": true,
|
|
"blendEquationSeparate": true,
|
|
"blendFunc": true,
|
|
"blendFuncSeparate": true,
|
|
"bufferData": [0, 2],
|
|
"bufferSubData": [0],
|
|
"checkFramebufferStatus": true,
|
|
"compressedTexImage2D": [0, 2],
|
|
"compressedTexSubImage2D": [0],
|
|
"copyTexImage2D": [0, 2],
|
|
"copyTexSubImage2D": [0],
|
|
"createShader": true,
|
|
"cullFace": true,
|
|
"depthFunc": true,
|
|
"disable": true,
|
|
"drawArrays": [0],
|
|
"drawElements": [0, 2],
|
|
"enable": true,
|
|
"framebufferRenderbuffer": true,
|
|
"framebufferTexture2D": [0, 1, 2],
|
|
"frontFace": true,
|
|
"generateMipmap": true,
|
|
"getBufferParameter": true,
|
|
"getFramebufferAttachmentParameter": true,
|
|
"getParameter": true,
|
|
"getProgramParameter": true,
|
|
"getRenderbufferParameter": true,
|
|
"getShaderParameter": true,
|
|
"getShaderPrecisionFormat": true,
|
|
"getTexParameter": true,
|
|
"getVertexAttrib": [1],
|
|
"getVertexAttribOffset": [1],
|
|
"hint": true,
|
|
"isEnabled": true,
|
|
"pixelStorei": [0],
|
|
"readPixels": [4, 5],
|
|
"renderbufferStorage": [0, 1],
|
|
"stencilFunc": [0],
|
|
"stencilFuncSeparate": [0, 1],
|
|
"stencilMaskSeparate": [0],
|
|
"stencilOp": true,
|
|
"stencilOpSeparate": true,
|
|
"texImage2D": {
|
|
5: [0, 2, 3, 4],
|
|
6: [0, 2, 3, 4],
|
|
8: [0, 2, 6, 7],
|
|
9: [0, 2, 6, 7],
|
|
},
|
|
"texParameterf": [0, 1],
|
|
"texParameteri": [0, 1],
|
|
"texSubImage2D": {
|
|
6: [0, 4, 5],
|
|
7: [0, 4, 5],
|
|
8: [0, 6, 7],
|
|
9: [0, 6, 7],
|
|
},
|
|
"vertexAttribPointer": [2],
|
|
},
|
|
[WI.Recording.Type.CanvasWebGL2]: {
|
|
"activeTexture": true,
|
|
"beginQuery": [0],
|
|
"beginTransformFeedback": true,
|
|
"bindBuffer": true,
|
|
"bindBufferBase": [0],
|
|
"bindBufferRange": [0],
|
|
"bindFramebuffer": true,
|
|
"bindRenderbuffer": true,
|
|
"bindTexture": true,
|
|
"bindTransformFeedback": [0],
|
|
"blendEquation": true,
|
|
"blendEquationSeparate": true,
|
|
"blendFunc": true,
|
|
"blendFuncSeparate": true,
|
|
"blitFramebuffer": [10],
|
|
"bufferData": [0, 2],
|
|
"bufferSubData": [0],
|
|
"checkFramebufferStatus": true,
|
|
"clearBufferfi": [0],
|
|
"clearBufferfv": [0],
|
|
"clearBufferiv": [0],
|
|
"clearBufferuiv": [0],
|
|
"compressedTexImage2D": [0, 2],
|
|
"compressedTexSubImage2D": [0],
|
|
"compressedTexSubImage3D": [0],
|
|
"copyBufferSubData": [0, 1],
|
|
"copyTexImage2D": [0, 2],
|
|
"copyTexSubImage2D": [0],
|
|
"copyTexSubImage3D": [0],
|
|
"createShader": true,
|
|
"cullFace": true,
|
|
"depthFunc": true,
|
|
"disable": true,
|
|
"drawArrays": [0],
|
|
"drawArraysInstanced": [0],
|
|
"drawBuffers": true,
|
|
"drawElements": [0, 2],
|
|
"drawElementsInstanced": [0, 2],
|
|
"drawRangeElements": [0, 4],
|
|
"enable": true,
|
|
"endQuery": true,
|
|
"fenceSync": [0],
|
|
"framebufferRenderbuffer": true,
|
|
"framebufferTexture2D": [0, 1, 2],
|
|
"framebufferTextureLayer": [0, 1],
|
|
"frontFace": true,
|
|
"generateMipmap": true,
|
|
"getActiveUniformBlockParameter": [2],
|
|
"getActiveUniforms": [2],
|
|
"getBufferParameter": true,
|
|
"getBufferSubData": [0],
|
|
"getFramebufferAttachmentParameter": true,
|
|
"getIndexedParameter": [0],
|
|
"getInternalformatParameter": true,
|
|
"getParameter": true,
|
|
"getProgramParameter": true,
|
|
"getQuery": true,
|
|
"getQueryParameter": [1],
|
|
"getRenderbufferParameter": true,
|
|
"getSamplerParameter": [1],
|
|
"getShaderParameter": true,
|
|
"getShaderPrecisionFormat": true,
|
|
"getSyncParameter": [1],
|
|
"getTexParameter": true,
|
|
"getVertexAttrib": [1],
|
|
"getVertexAttribOffset": [1],
|
|
"hint": true,
|
|
"invalidateFramebuffer": [0, 1],
|
|
"invalidateSubFramebuffer": [0, 1],
|
|
"isEnabled": true,
|
|
"pixelStorei": [0],
|
|
"readBuffer": true,
|
|
"readPixels": [4, 5],
|
|
"renderbufferStorage": [0, 1],
|
|
"renderbufferStorageMultisample": [0, 2],
|
|
"samplerParameterf": [1],
|
|
"samplerParameteri": [1],
|
|
"stencilFunc": [0],
|
|
"stencilFuncSeparate": [0, 1],
|
|
"stencilMaskSeparate": [0],
|
|
"stencilOp": true,
|
|
"stencilOpSeparate": true,
|
|
"texImage2D": {
|
|
5: [0, 2, 3, 4],
|
|
6: [0, 2, 3, 4],
|
|
8: [0, 2, 6, 7],
|
|
9: [0, 2, 6, 7],
|
|
10: [0, 2, 6, 7],
|
|
11: [0, 2, 7, 8],
|
|
},
|
|
"texParameterf": [0, 1],
|
|
"texParameteri": [0, 1],
|
|
"texStorage2D":[0, 2],
|
|
"texSubImage2D": {
|
|
6: [0, 4, 5],
|
|
7: [0, 4, 5],
|
|
8: [0, 6, 7],
|
|
9: [0, 6, 7],
|
|
10: [0, 6, 7],
|
|
11: [0, 8, 9],
|
|
12: [0, 8, 9],
|
|
},
|
|
"transformFeedbackVaryings": [2],
|
|
"vertexAttribIPointer": [2],
|
|
"vertexAttribPointer": [2],
|
|
},
|
|
};
|
|
|
|
WI.RecordingAction._visualNames = {
|
|
[WI.Recording.Type.Canvas2D]: new Set([
|
|
"clearRect",
|
|
"drawFocusIfNeeded",
|
|
"drawImage",
|
|
"drawImageFromRect",
|
|
"fill",
|
|
"fillRect",
|
|
"fillText",
|
|
"putImageData",
|
|
"stroke",
|
|
"strokeRect",
|
|
"strokeText",
|
|
]),
|
|
[WI.Recording.Type.CanvasBitmapRenderer]: new Set([
|
|
"transferFromImageBitmap",
|
|
]),
|
|
[WI.Recording.Type.CanvasWebGL]: new Set([
|
|
"clear",
|
|
"drawArrays",
|
|
"drawElements",
|
|
]),
|
|
[WI.Recording.Type.CanvasWebGL2]: new Set([
|
|
"clear",
|
|
"drawArrays",
|
|
"drawArraysInstanced",
|
|
"drawElements",
|
|
"drawElementsInstanced",
|
|
]),
|
|
};
|
|
|
|
WI.RecordingAction._stateModifiers = {
|
|
[WI.Recording.Type.Canvas2D]: {
|
|
arc: ["currentX", "currentY"],
|
|
arcTo: ["currentX", "currentY"],
|
|
beginPath: ["currentX", "currentY"],
|
|
bezierCurveTo: ["currentX", "currentY"],
|
|
clearShadow: ["shadowOffsetX", "shadowOffsetY", "shadowBlur", "shadowColor"],
|
|
closePath: ["currentX", "currentY"],
|
|
ellipse: ["currentX", "currentY"],
|
|
lineTo: ["currentX", "currentY"],
|
|
moveTo: ["currentX", "currentY"],
|
|
quadraticCurveTo: ["currentX", "currentY"],
|
|
rect: ["currentX", "currentY"],
|
|
resetTransform: ["transform"],
|
|
rotate: ["transform"],
|
|
scale: ["transform"],
|
|
setAlpha: ["globalAlpha"],
|
|
setCompositeOperation: ["globalCompositeOperation"],
|
|
setFillColor: ["fillStyle"],
|
|
setLineCap: ["lineCap"],
|
|
setLineJoin: ["lineJoin"],
|
|
setLineWidth: ["lineWidth"],
|
|
setMiterLimit: ["miterLimit"],
|
|
setShadow: ["shadowOffsetX", "shadowOffsetY", "shadowBlur", "shadowColor"],
|
|
setStrokeColor: ["strokeStyle"],
|
|
setTransform: ["transform"],
|
|
translate: ["transform"],
|
|
},
|
|
};
|