blob: dd3dce77fc975fab934bd2a3721a4acb1129244e [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.
*/
WebInspector.RecordingAction = class RecordingAction
{
constructor(name, parameters)
{
this._payloadName = name;
this._payloadParameters = parameters;
this._name = "";
this._parameters = [];
this._valid = true;
this._isFunction = false;
this._isGetter = false;
this._isVisual = false;
this._stateModifiers = [];
}
// Static
// Payload format: [name, parameters]
static fromPayload(payload)
{
if (!Array.isArray(payload))
payload = [];
if (isNaN(payload[0]))
payload[0] = -1;
if (!Array.isArray(payload[1]))
payload[1] = [];
return new WebInspector.RecordingAction(...payload);
}
static isFunctionForType(type, name)
{
let functionNames = WebInspector.RecordingAction._functionNames[type];
if (!functionNames)
return false;
return functionNames.includes(name);
}
// Public
get name() { return this._name; }
get parameters() { return this._parameters; }
get valid() { return this._valid; }
set valid(valid) { this._valid = !!valid; }
get isFunction() { return this._isFunction; }
get isGetter() { return this._isGetter; }
get isVisual() { return this._isVisual; }
get stateModifiers() { return this._stateModifiers; }
swizzle(recording)
{
this._name = recording.swizzle(this._payloadName, WebInspector.Recording.Swizzle.String);
this._parameters = this._payloadParameters.map((item, i) => {
let type = this.parameterSwizzleTypeForTypeAtIndex(recording.type, i);
if (!type)
return item;
let swizzled = recording.swizzle(item, type);
if (swizzled === WebInspector.Recording.Swizzle.Invalid)
this._valid = false;
return swizzled;
});
this._isFunction = WebInspector.RecordingAction.isFunctionForType(recording.type, this._name);
this._isGetter = !this._isFunction && !this._parameters.length;
let visualNames = WebInspector.RecordingAction._visualNames[recording.type];
this._isVisual = visualNames ? visualNames.includes(this._name) : false;
this._stateModifiers = [this._name];
let stateModifiers = WebInspector.RecordingAction._stateModifiers[recording.type];
if (stateModifiers) {
let modifiedByAction = stateModifiers[this._name];
if (modifiedByAction)
this._stateModifiers = this._stateModifiers.concat(modifiedByAction);
}
}
parameterSwizzleTypeForTypeAtIndex(type, index)
{
let functionNames = WebInspector.RecordingAction._parameterSwizzleTypeForTypeAtIndex[type];
if (!functionNames)
return null;
let parameterLengths = functionNames[this._name];
if (!parameterLengths)
return null;
let argumentSwizzleTypes = parameterLengths[this._payloadParameters.length];
if (!argumentSwizzleTypes)
return null;
return argumentSwizzleTypes[index] || null;
}
toJSON()
{
return [this._payloadName, this._payloadParameters];
}
};
// This object instructs the frontend as to how to reconstruct deduplicated objects found in the
// "data" section of a recording payload. It will only swizzle values if they are of the expected
// type in the right index of the version of the action (determined by the number of parameters) for
// the recording type. Since a recording can be created by importing a JSON file, this is used to
// make sure that inputs are only considered valid if they conform to the structure defined below.
//
// For Example:
//
// IDL:
//
// void foo(optional DOMString s = "bar");
// void foo(DOMPath path, optional DOMString s = "bar");
// void foo(float a, float b, float c, float d);
//
// Swizzle Entries:
//
// - For the 1 parameter version, the parameter at index 0 needs to be swizzled as a string
// - For the 2 parameter version, the parameters need to be swizzled as a Path and String
// - For the 4 parameter version, numbers don't need to be swizzled, so it is not included
//
// "foo": {
// 1: {0: String}
// 2: {0: Path2D, 1: String}
// }
{
let {CanvasStyle, Element, Image, ImageData, Path2D, String} = WebInspector.Recording.Swizzle;
WebInspector.RecordingAction._parameterSwizzleTypeForTypeAtIndex = {
[WebInspector.Recording.Type.Canvas2D]: {
"clip": {
1: {0: String},
2: {0: Path2D, 1: String},
},
"createImageData": {
1: {0: ImageData},
},
"createPattern": {
2: {0: Image, 1: String},
},
"direction": {
1: {0: String},
},
"drawImage": {
3: {0: Image},
5: {0: Image},
9: {0: Image},
},
"drawImageFromRect": {
10: {0: Image, 9: String},
},
"drawFocusIfNeeded": {
1: {0: Element},
2: {0: Path2D, 1: Element},
},
"fill": {
1: {0: String},
2: {0: Path2D, 1: String},
},
"fillStyle": {
1: {0: CanvasStyle},
},
"fillText": {
3: {0: String},
4: {0: String},
},
"font": {
1: {0: String},
},
"globalCompositeOperation": {
1: {0: String},
},
"imageSmoothingQuality": {
1: {0: String},
},
"isPointInPath": {
4: {0: Path2D, 3: String},
},
"isPointInStroke": {
3: {0: Path2D, 3: String},
},
"lineCap": {
1: {0: String},
},
"lineJoin": {
1: {0: String},
},
"measureText": {
1: {0: String},
},
"putImageData": {
3: {0: ImageData},
7: {0: ImageData},
},
"setCompositeOperation": {
1: {0: String},
},
"setFillColor": {
1: {0: String},
2: {0: String},
},
"setLineCap": {
1: {0: String},
},
"setLineJoin": {
1: {0: String},
},
"setShadow": {
4: {3: String},
5: {3: String},
},
"setStrokeColor": {
1: {0: String},
2: {0: String},
},
"shadowColor": {
1: {0: String},
},
"stroke": {
1: {0: Path2D},
},
"strokeStyle": {
1: {0: CanvasStyle},
},
"strokeText": {
3: {0: String},
4: {0: String},
},
"textAlign": {
1: {0: String},
},
"textBaseline": {
1: {0: String},
},
"webkitPutImageData": {
3: {0: ImageData},
7: {0: ImageData},
},
},
};
}
WebInspector.RecordingAction._functionNames = {
[WebInspector.Recording.Type.Canvas2D]: [
"arc",
"arcTo",
"beginPath",
"bezierCurveTo",
"clearRect",
"clearShadow",
"clip",
"clip",
"closePath",
"commit",
"createImageData",
"createLinearGradient",
"createPattern",
"createRadialGradient",
"drawFocusIfNeeded",
"drawImage",
"drawImageFromRect",
"ellipse",
"fill",
"fill",
"fillRect",
"fillText",
"getImageData",
"getLineDash",
"isPointInPath",
"isPointInPath",
"isPointInStroke",
"isPointInStroke",
"lineTo",
"measureText",
"moveTo",
"putImageData",
"quadraticCurveTo",
"rect",
"resetTransform",
"restore",
"rotate",
"save",
"scale",
"setAlpha",
"setCompositeOperation",
"setFillColor",
"setLineCap",
"setLineDash",
"setLineJoin",
"setLineWidth",
"setMiterLimit",
"setShadow",
"setStrokeColor",
"setTransform",
"stroke",
"stroke",
"strokeRect",
"strokeText",
"transform",
"translate",
"webkitGetImageDataHD",
"webkitPutImageDataHD",
],
};
WebInspector.RecordingAction._visualNames = {
[WebInspector.Recording.Type.Canvas2D]: [
"clearRect",
"drawFocusIfNeeded",
"drawImage",
"drawImageFromRect",
"fill",
"fillRect",
"fillText",
"putImageData",
"stroke",
"strokeRect",
"strokeText",
"webkitPutImageDataHD",
],
};
WebInspector.RecordingAction._stateModifiers = {
[WebInspector.Recording.Type.Canvas2D]: {
clearShadow: ["shadowOffsetX", "shadowOffsetY", "shadowBlur", "shadowColor"],
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"],
},
};