mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
Bug 1226245 - Make CallWatcher generic, r=jsantell
This commit is contained in:
parent
ed87fa4de9
commit
9e259bd7f9
@ -81,8 +81,6 @@ var CallsListView = Heritage.extend(WidgetMethods, {
|
||||
gutter.appendChild(index);
|
||||
contents.appendChild(gutter);
|
||||
|
||||
// Not all function calls have a caller that was stringified (e.g.
|
||||
// context calls have a "gl" or "ctx" caller preview).
|
||||
if (call.callerPreview) {
|
||||
let context = document.createElement("label");
|
||||
context.className = "plain call-item-context";
|
||||
|
@ -40,7 +40,7 @@ function* ifTestingSupported() {
|
||||
is(functionCalls[0].line, 25,
|
||||
"The called function's line is correct.");
|
||||
|
||||
is(functionCalls[0].callerPreview, "ctx",
|
||||
is(functionCalls[0].callerPreview, "Object",
|
||||
"The called function's caller preview is correct.");
|
||||
is(functionCalls[0].argsPreview, "0, 0, 128, 128",
|
||||
"The called function's args preview is correct.");
|
||||
|
@ -41,7 +41,7 @@ function* ifTestingSupported() {
|
||||
"The first called function's line is correct.");
|
||||
is(functionCalls[0].argsPreview, "0, 0, 128, 128",
|
||||
"The first called function's args preview is correct.");
|
||||
is(functionCalls[0].callerPreview, "ctx",
|
||||
is(functionCalls[0].callerPreview, "Object",
|
||||
"The first called function's caller preview is correct.");
|
||||
|
||||
is(functionCalls[6].type, CallWatcherFront.METHOD_FUNCTION,
|
||||
@ -54,7 +54,7 @@ function* ifTestingSupported() {
|
||||
"The penultimate called function's line is correct.");
|
||||
is(functionCalls[6].argsPreview, "10, 10, 55, 50",
|
||||
"The penultimate called function's args preview is correct.");
|
||||
is(functionCalls[6].callerPreview, "ctx",
|
||||
is(functionCalls[6].callerPreview, "Object",
|
||||
"The penultimate called function's caller preview is correct.");
|
||||
|
||||
is(functionCalls[7].type, CallWatcherFront.METHOD_FUNCTION,
|
||||
@ -67,7 +67,7 @@ function* ifTestingSupported() {
|
||||
"The last called function's line is correct.");
|
||||
ok(functionCalls[7].argsPreview.includes("Function"),
|
||||
"The last called function's args preview is correct.");
|
||||
is(functionCalls[7].callerPreview, "",
|
||||
is(functionCalls[7].callerPreview, "Object",
|
||||
"The last called function's caller preview is correct.");
|
||||
|
||||
yield removeTab(target.tab);
|
||||
|
@ -41,7 +41,7 @@ function* ifTestingSupported() {
|
||||
"The first called function's line is correct.");
|
||||
is(functionCalls[0].argsPreview, "0, 0, 128, 128",
|
||||
"The first called function's args preview is correct.");
|
||||
is(functionCalls[0].callerPreview, "ctx",
|
||||
is(functionCalls[0].callerPreview, "Object",
|
||||
"The first called function's caller preview is correct.");
|
||||
|
||||
is(functionCalls[6].type, CallWatcherFront.METHOD_FUNCTION,
|
||||
@ -54,7 +54,7 @@ function* ifTestingSupported() {
|
||||
"The penultimate called function's line is correct.");
|
||||
is(functionCalls[6].argsPreview, "10, 10, 55, 50",
|
||||
"The penultimate called function's args preview is correct.");
|
||||
is(functionCalls[6].callerPreview, "ctx",
|
||||
is(functionCalls[6].callerPreview, "Object",
|
||||
"The penultimate called function's caller preview is correct.");
|
||||
|
||||
is(functionCalls[7].type, CallWatcherFront.METHOD_FUNCTION,
|
||||
@ -67,7 +67,7 @@ function* ifTestingSupported() {
|
||||
"The last called function's line is correct.");
|
||||
ok(functionCalls[7].argsPreview.includes("Function"),
|
||||
"The last called function's args preview is correct.");
|
||||
is(functionCalls[7].callerPreview, "",
|
||||
is(functionCalls[7].callerPreview, "Object",
|
||||
"The last called function's caller preview is correct.");
|
||||
|
||||
let firstNonDrawCall = yield functionCalls[1].getDetails();
|
||||
|
@ -21,22 +21,22 @@ function* ifTestingSupported() {
|
||||
"All the function calls should now be displayed in the UI.");
|
||||
|
||||
testItem(CallsListView.getItemAtIndex(0),
|
||||
"1", "ctx", "clearRect", "(0, 0, 128, 128)", "doc_simple-canvas.html:25");
|
||||
"1", "Object", "clearRect", "(0, 0, 128, 128)", "doc_simple-canvas.html:25");
|
||||
|
||||
testItem(CallsListView.getItemAtIndex(1),
|
||||
"2", "ctx", "fillStyle", " = rgb(192, 192, 192)", "doc_simple-canvas.html:20");
|
||||
"2", "Object", "fillStyle", " = rgb(192, 192, 192)", "doc_simple-canvas.html:20");
|
||||
testItem(CallsListView.getItemAtIndex(2),
|
||||
"3", "ctx", "fillRect", "(0, 0, 128, 128)", "doc_simple-canvas.html:21");
|
||||
"3", "Object", "fillRect", "(0, 0, 128, 128)", "doc_simple-canvas.html:21");
|
||||
|
||||
testItem(CallsListView.getItemAtIndex(3),
|
||||
"4", "ctx", "fillStyle", " = rgba(0, 0, 192, 0.5)", "doc_simple-canvas.html:20");
|
||||
"4", "Object", "fillStyle", " = rgba(0, 0, 192, 0.5)", "doc_simple-canvas.html:20");
|
||||
testItem(CallsListView.getItemAtIndex(4),
|
||||
"5", "ctx", "fillRect", "(30, 30, 55, 50)", "doc_simple-canvas.html:21");
|
||||
"5", "Object", "fillRect", "(30, 30, 55, 50)", "doc_simple-canvas.html:21");
|
||||
|
||||
testItem(CallsListView.getItemAtIndex(5),
|
||||
"6", "ctx", "fillStyle", " = rgba(192, 0, 0, 0.5)", "doc_simple-canvas.html:20");
|
||||
"6", "Object", "fillStyle", " = rgba(192, 0, 0, 0.5)", "doc_simple-canvas.html:20");
|
||||
testItem(CallsListView.getItemAtIndex(6),
|
||||
"7", "ctx", "fillRect", "(10, 10, 55, 50)", "doc_simple-canvas.html:21");
|
||||
"7", "Object", "fillRect", "(10, 10, 55, 50)", "doc_simple-canvas.html:21");
|
||||
|
||||
testItem(CallsListView.getItemAtIndex(7),
|
||||
"8", "", "requestAnimationFrame", "(Function)", "doc_simple-canvas.html:30");
|
||||
@ -53,7 +53,7 @@ function* ifTestingSupported() {
|
||||
is($(".call-item-context", item.target).getAttribute("value"), context,
|
||||
"The item's context label has the correct text.");
|
||||
} else {
|
||||
is($(".call-item-context", item.target), null,
|
||||
is($(".call-item-context", item.target) + "", "[object XULElement]",
|
||||
"The item's context label should not be available.");
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ function* ifTestingSupported() {
|
||||
"The visible item's line has the expected value.");
|
||||
is(CallsListView.visibleItems[0].attachment.actor.argsPreview, "0, 0, 128, 128",
|
||||
"The visible item's args have the expected value.");
|
||||
is(CallsListView.visibleItems[0].attachment.actor.callerPreview, "ctx",
|
||||
is(CallsListView.visibleItems[0].attachment.actor.callerPreview, "Object",
|
||||
"The visible item's caller has the expected value.");
|
||||
|
||||
let secondRecordingFinished = once(window, EVENTS.SNAPSHOT_RECORDING_FINISHED);
|
||||
|
@ -56,7 +56,7 @@ var FunctionCallActor = protocol.ActorClass({
|
||||
* @param array stack
|
||||
* The called function's stack, as a list of { name, file, line } objects.
|
||||
* @param number timestamp
|
||||
* The timestamp of draw-related functions
|
||||
* The performance.now() timestamp when the function was called.
|
||||
* @param array args
|
||||
* The called function's arguments.
|
||||
* @param any result
|
||||
@ -69,6 +69,7 @@ var FunctionCallActor = protocol.ActorClass({
|
||||
protocol.Actor.prototype.initialize.call(this, conn);
|
||||
|
||||
this.details = {
|
||||
global: global,
|
||||
type: type,
|
||||
name: name,
|
||||
stack: stack,
|
||||
@ -77,49 +78,39 @@ var FunctionCallActor = protocol.ActorClass({
|
||||
|
||||
// Store a weak reference to all objects so we don't
|
||||
// prevent natural GC if `holdWeak` was passed into
|
||||
// setup as truthy. Used in the Web Audio Editor.
|
||||
// setup as truthy.
|
||||
if (holdWeak) {
|
||||
let weakRefs = {
|
||||
window: Cu.getWeakReference(window),
|
||||
caller: Cu.getWeakReference(caller),
|
||||
args: Cu.getWeakReference(args),
|
||||
result: Cu.getWeakReference(result),
|
||||
args: Cu.getWeakReference(args)
|
||||
};
|
||||
|
||||
Object.defineProperties(this.details, {
|
||||
window: { get: () => weakRefs.window.get() },
|
||||
caller: { get: () => weakRefs.caller.get() },
|
||||
result: { get: () => weakRefs.result.get() },
|
||||
args: { get: () => weakRefs.args.get() },
|
||||
timestamp: { get: () => weakRefs.timestamp.get() },
|
||||
result: { get: () => weakRefs.result.get() },
|
||||
});
|
||||
}
|
||||
// Otherwise, hold strong references to the objects.
|
||||
else {
|
||||
this.details.window = window;
|
||||
this.details.caller = caller;
|
||||
this.details.result = result;
|
||||
this.details.args = args;
|
||||
this.details.timestamp = timestamp;
|
||||
this.details.result = result;
|
||||
}
|
||||
|
||||
this.meta = {
|
||||
global: -1,
|
||||
previews: { caller: "", args: "" }
|
||||
// The caller, args and results are string names for now. It would
|
||||
// certainly be nicer if they were Object actors. Make this smarter, so
|
||||
// that the frontend can inspect each argument, be it object or primitive.
|
||||
// Bug 978960.
|
||||
this.details.previews = {
|
||||
caller: this._generateStringPreview(caller),
|
||||
args: this._generateArgsPreview(args),
|
||||
result: this._generateStringPreview(result)
|
||||
};
|
||||
|
||||
if (global == "WebGLRenderingContext") {
|
||||
this.meta.global = CallWatcherFront.CANVAS_WEBGL_CONTEXT;
|
||||
} else if (global == "CanvasRenderingContext2D") {
|
||||
this.meta.global = CallWatcherFront.CANVAS_2D_CONTEXT;
|
||||
} else if (global == "window") {
|
||||
this.meta.global = CallWatcherFront.UNKNOWN_SCOPE;
|
||||
} else {
|
||||
this.meta.global = CallWatcherFront.GLOBAL_SCOPE;
|
||||
}
|
||||
|
||||
this.meta.previews.caller = this._generateCallerPreview();
|
||||
this.meta.previews.args = this._generateArgsPreview();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -134,8 +125,9 @@ var FunctionCallActor = protocol.ActorClass({
|
||||
file: this.details.stack[0].file,
|
||||
line: this.details.stack[0].line,
|
||||
timestamp: this.details.timestamp,
|
||||
callerPreview: this.meta.previews.caller,
|
||||
argsPreview: this.meta.previews.args
|
||||
callerPreview: this.details.previews.caller,
|
||||
argsPreview: this.details.previews.args,
|
||||
resultPreview: this.details.previews.result
|
||||
};
|
||||
},
|
||||
|
||||
@ -169,45 +161,37 @@ var FunctionCallActor = protocol.ActorClass({
|
||||
response: { info: RetVal("call-details") }
|
||||
}),
|
||||
|
||||
/**
|
||||
* Serializes the caller's name so that it can be easily be transferred
|
||||
* as a string, but still be useful when displayed in a potential UI.
|
||||
*
|
||||
* @return string
|
||||
* The caller's name as a string.
|
||||
*/
|
||||
_generateCallerPreview: function() {
|
||||
let global = this.meta.global;
|
||||
if (global == CallWatcherFront.CANVAS_WEBGL_CONTEXT) {
|
||||
return "gl";
|
||||
}
|
||||
if (global == CallWatcherFront.CANVAS_2D_CONTEXT) {
|
||||
return "ctx";
|
||||
}
|
||||
return "";
|
||||
},
|
||||
|
||||
/**
|
||||
* Serializes the arguments so that they can be easily be transferred
|
||||
* as a string, but still be useful when displayed in a potential UI.
|
||||
*
|
||||
* @param array args
|
||||
* The source arguments.
|
||||
* @return string
|
||||
* The arguments as a string.
|
||||
*/
|
||||
_generateArgsPreview: function() {
|
||||
let { caller, args, name } = this.details;
|
||||
let { global } = this.meta;
|
||||
_generateArgsPreview: function(args) {
|
||||
let { global, name, caller } = this.details;
|
||||
|
||||
// Get method signature to determine if there are any enums
|
||||
// used in this method.
|
||||
let enumArgs = (CallWatcherFront.ENUM_METHODS[global] || {})[name];
|
||||
if (typeof enumArgs === "function") {
|
||||
enumArgs = enumArgs(args);
|
||||
let methodSignatureEnums;
|
||||
|
||||
let knownGlobal = CallWatcherFront.KNOWN_METHODS[global];
|
||||
if (knownGlobal) {
|
||||
let knownMethod = knownGlobal[name];
|
||||
if (knownMethod) {
|
||||
let isOverloaded = typeof knownMethod.enums === "function";
|
||||
if (isOverloaded) {
|
||||
methodSignatureEnums = methodSignatureEnums(args);
|
||||
} else {
|
||||
methodSignatureEnums = knownMethod.enums;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: All of this sucks. Make this smarter, so that the frontend
|
||||
// can inspect each argument, be it object or primitive. Bug 978960.
|
||||
let serializeArgs = () => args.map((arg, i) => {
|
||||
// XXX: Bug 978960.
|
||||
if (arg === undefined) {
|
||||
return "undefined";
|
||||
}
|
||||
@ -222,13 +206,39 @@ var FunctionCallActor = protocol.ActorClass({
|
||||
}
|
||||
// If this argument matches the method's signature
|
||||
// and is an enum, change it to its constant name.
|
||||
if (enumArgs && enumArgs.indexOf(i) !== -1) {
|
||||
if (methodSignatureEnums && methodSignatureEnums.has(i)) {
|
||||
return getBitToEnumValue(global, caller, arg);
|
||||
}
|
||||
return arg;
|
||||
return arg + "";
|
||||
});
|
||||
|
||||
return serializeArgs().join(", ");
|
||||
},
|
||||
|
||||
/**
|
||||
* Serializes the data so that it can be easily be transferred
|
||||
* as a string, but still be useful when displayed in a potential UI.
|
||||
*
|
||||
* @param object data
|
||||
* The source data.
|
||||
* @return string
|
||||
* The arguments as a string.
|
||||
*/
|
||||
_generateStringPreview: function(data) {
|
||||
// XXX: Bug 978960.
|
||||
if (data === undefined) {
|
||||
return "undefined";
|
||||
}
|
||||
if (data === null) {
|
||||
return "null";
|
||||
}
|
||||
if (typeof data == "function") {
|
||||
return "Function";
|
||||
}
|
||||
if (typeof data == "object") {
|
||||
return "Object";
|
||||
}
|
||||
return data + "";
|
||||
}
|
||||
});
|
||||
|
||||
@ -253,6 +263,7 @@ var FunctionCallFront = protocol.FrontClass(FunctionCallActor, {
|
||||
this.timestamp = form.timestamp;
|
||||
this.callerPreview = form.callerPreview;
|
||||
this.argsPreview = form.argsPreview;
|
||||
this.resultPreview = form.resultPreview;
|
||||
}
|
||||
});
|
||||
|
||||
@ -283,6 +294,7 @@ var CallWatcherActor = exports.CallWatcherActor = protocol.ActorClass({
|
||||
return;
|
||||
}
|
||||
this._initialized = true;
|
||||
this._timestampEpoch = 0;
|
||||
|
||||
this._functionCalls = [];
|
||||
this._tracedGlobals = tracedGlobals || [];
|
||||
@ -342,10 +354,10 @@ var CallWatcherActor = exports.CallWatcherActor = protocol.ActorClass({
|
||||
}),
|
||||
|
||||
/**
|
||||
* Initialize frame start timestamp for measuring
|
||||
* Initialize the timestamp epoch used to offset function call timestamps.
|
||||
*/
|
||||
initFrameStartTimestamp: method(function() {
|
||||
this._frameStartTimestamp = this.tabActor.window.performance.now();
|
||||
initTimestampEpoch: method(function() {
|
||||
this._timestampEpoch = this.tabActor.window.performance.now();
|
||||
}),
|
||||
|
||||
/**
|
||||
@ -378,18 +390,18 @@ var CallWatcherActor = exports.CallWatcherActor = protocol.ActorClass({
|
||||
* while recording. We're doing this to avoid the event emitter overhead,
|
||||
* since this is expected to be a very hot function.
|
||||
*/
|
||||
onCall: function() {},
|
||||
onCall: null,
|
||||
|
||||
/**
|
||||
* Invoked whenever the current tab actor's document global is created.
|
||||
*/
|
||||
_onGlobalCreated: function({window, id, isTopLevel}) {
|
||||
let self = this;
|
||||
|
||||
// TODO: bug 981748, support more than just the top-level documents.
|
||||
if (!isTopLevel) {
|
||||
return;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
this._tracedWindowId = id;
|
||||
|
||||
let unwrappedWindow = XPCNativeWrapper.unwrap(window);
|
||||
@ -439,9 +451,9 @@ var CallWatcherActor = exports.CallWatcherActor = protocol.ActorClass({
|
||||
}
|
||||
|
||||
if (self._recording) {
|
||||
let timestamp = self.tabActor.window.performance.now() - self._frameStartTimestamp;
|
||||
let stack = getStack(name);
|
||||
let type = CallWatcherFront.METHOD_FUNCTION;
|
||||
let stack = getStack(name);
|
||||
let timestamp = self.tabActor.window.performance.now() - self._timestampEpoch;
|
||||
callback(unwrappedWindow, global, this, type, name, stack, timestamp, args, result);
|
||||
}
|
||||
return result;
|
||||
@ -469,9 +481,9 @@ var CallWatcherActor = exports.CallWatcherActor = protocol.ActorClass({
|
||||
let result = Cu.waiveXrays(originalGetter.apply(this, args));
|
||||
|
||||
if (self._recording) {
|
||||
let timestamp = self.tabActor.window.performance.now() - self._frameStartTimestamp;
|
||||
let stack = getStack(name);
|
||||
let type = CallWatcherFront.GETTER_FUNCTION;
|
||||
let stack = getStack(name);
|
||||
let timestamp = self.tabActor.window.performance.now() - self._timestampEpoch;
|
||||
callback(unwrappedWindow, global, this, type, name, stack, timestamp, args, result);
|
||||
}
|
||||
return result;
|
||||
@ -481,9 +493,9 @@ var CallWatcherActor = exports.CallWatcherActor = protocol.ActorClass({
|
||||
originalSetter.apply(this, args);
|
||||
|
||||
if (self._recording) {
|
||||
let timestamp = self.tabActor.window.performance.now() - self._frameStartTimestamp;
|
||||
let stack = getStack(name);
|
||||
let type = CallWatcherFront.SETTER_FUNCTION;
|
||||
let stack = getStack(name);
|
||||
let timestamp = self.tabActor.window.performance.now() - self._timestampEpoch;
|
||||
callback(unwrappedWindow, global, this, type, name, stack, timestamp, args, undefined);
|
||||
}
|
||||
},
|
||||
@ -554,6 +566,7 @@ var CallWatcherActor = exports.CallWatcherActor = protocol.ActorClass({
|
||||
if (this._tracedWindowId == id) {
|
||||
this.pauseRecording();
|
||||
this.eraseRecording();
|
||||
this._timestampEpoch = 0;
|
||||
}
|
||||
},
|
||||
|
||||
@ -566,13 +579,18 @@ var CallWatcherActor = exports.CallWatcherActor = protocol.ActorClass({
|
||||
if (this._finalized) {
|
||||
return;
|
||||
}
|
||||
|
||||
let functionCall = new FunctionCallActor(this.conn, details, this._holdWeak);
|
||||
|
||||
if (this._storeCalls) {
|
||||
this._functionCalls.push(functionCall);
|
||||
}
|
||||
|
||||
this.onCall(functionCall);
|
||||
if (this.onCall) {
|
||||
this.onCall(functionCall);
|
||||
} else {
|
||||
emit(this, "call", functionCall);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -593,71 +611,177 @@ CallWatcherFront.METHOD_FUNCTION = 0;
|
||||
CallWatcherFront.GETTER_FUNCTION = 1;
|
||||
CallWatcherFront.SETTER_FUNCTION = 2;
|
||||
|
||||
CallWatcherFront.GLOBAL_SCOPE = 0;
|
||||
CallWatcherFront.UNKNOWN_SCOPE = 1;
|
||||
CallWatcherFront.CANVAS_WEBGL_CONTEXT = 2;
|
||||
CallWatcherFront.CANVAS_2D_CONTEXT = 3;
|
||||
CallWatcherFront.KNOWN_METHODS = {};
|
||||
|
||||
CallWatcherFront.ENUM_METHODS = {};
|
||||
CallWatcherFront.ENUM_METHODS[CallWatcherFront.CANVAS_2D_CONTEXT] = {
|
||||
asyncDrawXULElement: [6],
|
||||
drawWindow: [6]
|
||||
CallWatcherFront.KNOWN_METHODS["CanvasRenderingContext2D"] = {
|
||||
asyncDrawXULElement: {
|
||||
enums: new Set([6]),
|
||||
},
|
||||
drawWindow: {
|
||||
enums: new Set([6])
|
||||
},
|
||||
};
|
||||
|
||||
CallWatcherFront.ENUM_METHODS[CallWatcherFront.CANVAS_WEBGL_CONTEXT] = {
|
||||
activeTexture: [0],
|
||||
bindBuffer: [0],
|
||||
bindFramebuffer: [0],
|
||||
bindRenderbuffer: [0],
|
||||
bindTexture: [0],
|
||||
blendEquation: [0],
|
||||
blendEquationSeparate: [0, 1],
|
||||
blendFunc: [0, 1],
|
||||
blendFuncSeparate: [0, 1, 2, 3],
|
||||
bufferData: [0, 1, 2],
|
||||
bufferSubData: [0, 1],
|
||||
checkFramebufferStatus: [0],
|
||||
clear: [0],
|
||||
compressedTexImage2D: [0, 2],
|
||||
compressedTexSubImage2D: [0, 6],
|
||||
copyTexImage2D: [0, 2],
|
||||
copyTexSubImage2D: [0],
|
||||
createShader: [0],
|
||||
cullFace: [0],
|
||||
depthFunc: [0],
|
||||
disable: [0],
|
||||
drawArrays: [0],
|
||||
drawElements: [0, 2],
|
||||
enable: [0],
|
||||
framebufferRenderbuffer: [0, 1, 2],
|
||||
framebufferTexture2D: [0, 1, 2],
|
||||
frontFace: [0],
|
||||
generateMipmap: [0],
|
||||
getBufferParameter: [0, 1],
|
||||
getParameter: [0],
|
||||
getFramebufferAttachmentParameter: [0, 1, 2],
|
||||
getProgramParameter: [1],
|
||||
getRenderbufferParameter: [0, 1],
|
||||
getShaderParameter: [1],
|
||||
getShaderPrecisionFormat: [0, 1],
|
||||
getTexParameter: [0, 1],
|
||||
getVertexAttrib: [1],
|
||||
getVertexAttribOffset: [1],
|
||||
hint: [0, 1],
|
||||
isEnabled: [0],
|
||||
pixelStorei: [0],
|
||||
readPixels: [4, 5],
|
||||
renderbufferStorage: [0, 1],
|
||||
stencilFunc: [0],
|
||||
stencilFuncSeparate: [0, 1],
|
||||
stencilMaskSeparate: [0],
|
||||
stencilOp: [0, 1, 2],
|
||||
stencilOpSeparate: [0, 1, 2, 3],
|
||||
texImage2D: (args) => args.length > 6 ? [0, 2, 6, 7] : [0, 2, 3, 4],
|
||||
texParameterf: [0, 1],
|
||||
texParameteri: [0, 1, 2],
|
||||
texSubImage2D: (args) => args.length === 9 ? [0, 6, 7] : [0, 4, 5],
|
||||
vertexAttribPointer: [2]
|
||||
CallWatcherFront.KNOWN_METHODS["WebGLRenderingContext"] = {
|
||||
activeTexture: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
bindBuffer: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
bindFramebuffer: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
bindRenderbuffer: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
bindTexture: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
blendEquation: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
blendEquationSeparate: {
|
||||
enums: new Set([0, 1]),
|
||||
},
|
||||
blendFunc: {
|
||||
enums: new Set([0, 1]),
|
||||
},
|
||||
blendFuncSeparate: {
|
||||
enums: new Set([0, 1, 2, 3]),
|
||||
},
|
||||
bufferData: {
|
||||
enums: new Set([0, 1, 2]),
|
||||
},
|
||||
bufferSubData: {
|
||||
enums: new Set([0, 1]),
|
||||
},
|
||||
checkFramebufferStatus: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
clear: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
compressedTexImage2D: {
|
||||
enums: new Set([0, 2]),
|
||||
},
|
||||
compressedTexSubImage2D: {
|
||||
enums: new Set([0, 6]),
|
||||
},
|
||||
copyTexImage2D: {
|
||||
enums: new Set([0, 2]),
|
||||
},
|
||||
copyTexSubImage2D: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
createShader: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
cullFace: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
depthFunc: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
disable: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
drawArrays: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
drawElements: {
|
||||
enums: new Set([0, 2]),
|
||||
},
|
||||
enable: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
framebufferRenderbuffer: {
|
||||
enums: new Set([0, 1, 2]),
|
||||
},
|
||||
framebufferTexture2D: {
|
||||
enums: new Set([0, 1, 2]),
|
||||
},
|
||||
frontFace: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
generateMipmap: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
getBufferParameter: {
|
||||
enums: new Set([0, 1]),
|
||||
},
|
||||
getParameter: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
getFramebufferAttachmentParameter: {
|
||||
enums: new Set([0, 1, 2]),
|
||||
},
|
||||
getProgramParameter: {
|
||||
enums: new Set([1]),
|
||||
},
|
||||
getRenderbufferParameter: {
|
||||
enums: new Set([0, 1]),
|
||||
},
|
||||
getShaderParameter: {
|
||||
enums: new Set([1]),
|
||||
},
|
||||
getShaderPrecisionFormat: {
|
||||
enums: new Set([0, 1]),
|
||||
},
|
||||
getTexParameter: {
|
||||
enums: new Set([0, 1]),
|
||||
},
|
||||
getVertexAttrib: {
|
||||
enums: new Set([1]),
|
||||
},
|
||||
getVertexAttribOffset: {
|
||||
enums: new Set([1]),
|
||||
},
|
||||
hint: {
|
||||
enums: new Set([0, 1]),
|
||||
},
|
||||
isEnabled: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
pixelStorei: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
readPixels: {
|
||||
enums: new Set([4, 5]),
|
||||
},
|
||||
renderbufferStorage: {
|
||||
enums: new Set([0, 1]),
|
||||
},
|
||||
stencilFunc: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
stencilFuncSeparate: {
|
||||
enums: new Set([0, 1]),
|
||||
},
|
||||
stencilMaskSeparate: {
|
||||
enums: new Set([0]),
|
||||
},
|
||||
stencilOp: {
|
||||
enums: new Set([0, 1, 2]),
|
||||
},
|
||||
stencilOpSeparate: {
|
||||
enums: new Set([0, 1, 2, 3]),
|
||||
},
|
||||
texImage2D: {
|
||||
enums: args => args.length > 6 ? new Set([0, 2, 6, 7]) : new Set([0, 2, 3, 4]),
|
||||
},
|
||||
texParameterf: {
|
||||
enums: new Set([0, 1]),
|
||||
},
|
||||
texParameteri: {
|
||||
enums: new Set([0, 1, 2]),
|
||||
},
|
||||
texSubImage2D: {
|
||||
enums: args => args.length === 9 ? new Set([0, 6, 7]) : new Set([0, 4, 5]),
|
||||
},
|
||||
vertexAttribPointer: {
|
||||
enums: new Set([2])
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -147,7 +147,7 @@ var FrameSnapshotActor = protocol.ActorClass({
|
||||
*/
|
||||
generateScreenshotFor: method(function(functionCall) {
|
||||
let caller = functionCall.details.caller;
|
||||
let global = functionCall.meta.global;
|
||||
let global = functionCall.details.global;
|
||||
|
||||
let canvas = this._contentCanvas;
|
||||
let calls = this._functionCalls;
|
||||
@ -170,10 +170,10 @@ var FrameSnapshotActor = protocol.ActorClass({
|
||||
|
||||
// Depending on the canvas' context, generating a screenshot is done
|
||||
// in different ways.
|
||||
if (global == CallWatcherFront.CANVAS_WEBGL_CONTEXT) {
|
||||
if (global == "WebGLRenderingContext") {
|
||||
screenshot = ContextUtils.getPixelsForWebGL(replayContext, left, top, width, height);
|
||||
screenshot.flipped = true;
|
||||
} else if (global == CallWatcherFront.CANVAS_2D_CONTEXT) {
|
||||
} else if (global == "CanvasRenderingContext2D") {
|
||||
screenshot = ContextUtils.getPixelsFor2D(replayContext, left, top, width, height);
|
||||
screenshot.flipped = false;
|
||||
}
|
||||
@ -326,7 +326,7 @@ var CanvasActor = exports.CanvasActor = protocol.ActorClass({
|
||||
|
||||
this._recordingContainsDrawCall = false;
|
||||
this._callWatcher.eraseRecording();
|
||||
this._callWatcher.initFrameStartTimestamp();
|
||||
this._callWatcher.initTimestampEpoch();
|
||||
this._webGLPrimitiveCounter.resetCounts();
|
||||
this._callWatcher.resumeRecording();
|
||||
|
||||
@ -463,7 +463,7 @@ var CanvasActor = exports.CanvasActor = protocol.ActorClass({
|
||||
_handleDrawCall: function(functionCall) {
|
||||
let functionCalls = this._callWatcher.pauseRecording();
|
||||
let caller = functionCall.details.caller;
|
||||
let global = functionCall.meta.global;
|
||||
let global = functionCall.details.global;
|
||||
|
||||
let contentCanvas = this._lastDrawCallCanvas = caller.canvas;
|
||||
let index = this._lastDrawCallIndex = functionCalls.indexOf(functionCall);
|
||||
@ -478,7 +478,7 @@ var CanvasActor = exports.CanvasActor = protocol.ActorClass({
|
||||
|
||||
// Create a thumbnail on every draw call on the canvas context, to augment
|
||||
// the respective function call actor with this additional data.
|
||||
if (global == CallWatcherFront.CANVAS_WEBGL_CONTEXT) {
|
||||
if (global == "WebGLRenderingContext") {
|
||||
// Check if drawing to a custom framebuffer (when rendering to texture).
|
||||
// Don't create a thumbnail in this particular case.
|
||||
let framebufferBinding = caller.getParameter(caller.FRAMEBUFFER_BINDING);
|
||||
@ -487,7 +487,7 @@ var CanvasActor = exports.CanvasActor = protocol.ActorClass({
|
||||
thumbnail.flipped = this._lastThumbnailFlipped = true;
|
||||
thumbnail.index = index;
|
||||
}
|
||||
} else if (global == CallWatcherFront.CANVAS_2D_CONTEXT) {
|
||||
} else if (global == "CanvasRenderingContext2D") {
|
||||
thumbnail = ContextUtils.getPixelsFor2D(caller, 0, 0, w, h, dimensions);
|
||||
thumbnail.flipped = this._lastThumbnailFlipped = false;
|
||||
thumbnail.index = index;
|
||||
@ -673,7 +673,7 @@ var ContextUtils = {
|
||||
// required GL state (like recompiling shaders, setting global flags, etc.)
|
||||
// in an entirely new canvas. However, special care is needed to not
|
||||
// permanently affect the existing GL state in the process.
|
||||
if (contextType == CallWatcherFront.CANVAS_WEBGL_CONTEXT) {
|
||||
if (contextType == "WebGLRenderingContext") {
|
||||
// To keep things fast, replay the context calls on a framebuffer
|
||||
// of smaller dimensions than the actual canvas (maximum 256x256 pixels).
|
||||
let scaling = Math.min(CanvasFront.WEBGL_SCREENSHOT_MAX_HEIGHT, h) / h;
|
||||
@ -697,7 +697,7 @@ var ContextUtils = {
|
||||
};
|
||||
}
|
||||
// In case of 2D contexts, draw everything on a separate canvas context.
|
||||
else if (contextType == CallWatcherFront.CANVAS_2D_CONTEXT) {
|
||||
else if (contextType == "CanvasRenderingContext2D") {
|
||||
let contentDocument = canvas.ownerDocument;
|
||||
let replayCanvas = contentDocument.createElement("canvas");
|
||||
replayCanvas.width = w;
|
||||
|
Loading…
Reference in New Issue
Block a user