From 9e259bd7f996a467b3edc1ef389dd3321da875ea Mon Sep 17 00:00:00 2001 From: Victor Porof Date: Wed, 20 Jan 2016 14:11:14 +0100 Subject: [PATCH] Bug 1226245 - Make CallWatcher generic, r=jsantell --- devtools/client/canvasdebugger/callslist.js | 2 - .../test/browser_canvas-actor-test-02.js | 2 +- .../test/browser_canvas-actor-test-03.js | 6 +- .../test/browser_canvas-actor-test-11.js | 6 +- .../test/browser_canvas-frontend-call-list.js | 16 +- .../browser_canvas-frontend-call-search.js | 2 +- devtools/server/actors/call-watcher.js | 380 ++++++++++++------ devtools/server/actors/canvas.js | 18 +- 8 files changed, 277 insertions(+), 155 deletions(-) diff --git a/devtools/client/canvasdebugger/callslist.js b/devtools/client/canvasdebugger/callslist.js index 123f039c5892..5db0ba5b34d1 100644 --- a/devtools/client/canvasdebugger/callslist.js +++ b/devtools/client/canvasdebugger/callslist.js @@ -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"; diff --git a/devtools/client/canvasdebugger/test/browser_canvas-actor-test-02.js b/devtools/client/canvasdebugger/test/browser_canvas-actor-test-02.js index bb3f00d8b67f..e435899d901d 100644 --- a/devtools/client/canvasdebugger/test/browser_canvas-actor-test-02.js +++ b/devtools/client/canvasdebugger/test/browser_canvas-actor-test-02.js @@ -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."); diff --git a/devtools/client/canvasdebugger/test/browser_canvas-actor-test-03.js b/devtools/client/canvasdebugger/test/browser_canvas-actor-test-03.js index ee29b98df75b..8a8a63780e5a 100644 --- a/devtools/client/canvasdebugger/test/browser_canvas-actor-test-03.js +++ b/devtools/client/canvasdebugger/test/browser_canvas-actor-test-03.js @@ -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); diff --git a/devtools/client/canvasdebugger/test/browser_canvas-actor-test-11.js b/devtools/client/canvasdebugger/test/browser_canvas-actor-test-11.js index a202b5d8caeb..47769fc275ae 100644 --- a/devtools/client/canvasdebugger/test/browser_canvas-actor-test-11.js +++ b/devtools/client/canvasdebugger/test/browser_canvas-actor-test-11.js @@ -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(); diff --git a/devtools/client/canvasdebugger/test/browser_canvas-frontend-call-list.js b/devtools/client/canvasdebugger/test/browser_canvas-frontend-call-list.js index 013830224f08..5f9ce876f512 100644 --- a/devtools/client/canvasdebugger/test/browser_canvas-frontend-call-list.js +++ b/devtools/client/canvasdebugger/test/browser_canvas-frontend-call-list.js @@ -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."); } diff --git a/devtools/client/canvasdebugger/test/browser_canvas-frontend-call-search.js b/devtools/client/canvasdebugger/test/browser_canvas-frontend-call-search.js index de2105bb827e..e865df391715 100644 --- a/devtools/client/canvasdebugger/test/browser_canvas-frontend-call-search.js +++ b/devtools/client/canvasdebugger/test/browser_canvas-frontend-call-search.js @@ -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); diff --git a/devtools/server/actors/call-watcher.js b/devtools/server/actors/call-watcher.js index b14ea7922f2f..4154b6192331 100644 --- a/devtools/server/actors/call-watcher.js +++ b/devtools/server/actors/call-watcher.js @@ -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]) + }, }; /** diff --git a/devtools/server/actors/canvas.js b/devtools/server/actors/canvas.js index 6f83d5e6c762..950e06b1796d 100644 --- a/devtools/server/actors/canvas.js +++ b/devtools/server/actors/canvas.js @@ -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;