michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: "use strict"; michael@0: michael@0: const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; michael@0: michael@0: let { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); michael@0: michael@0: // Disable logging for all the tests. Both the debugger server and frontend will michael@0: // be affected by this pref. michael@0: let gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log"); michael@0: Services.prefs.setBoolPref("devtools.debugger.log", false); michael@0: michael@0: let { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); michael@0: let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {}); michael@0: let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {}); michael@0: let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); michael@0: let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {}); michael@0: let { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {}); michael@0: michael@0: let { CallWatcherFront } = devtools.require("devtools/server/actors/call-watcher"); michael@0: let { CanvasFront } = devtools.require("devtools/server/actors/canvas"); michael@0: let TiltGL = devtools.require("devtools/tilt/tilt-gl"); michael@0: let TargetFactory = devtools.TargetFactory; michael@0: let Toolbox = devtools.Toolbox; michael@0: michael@0: const EXAMPLE_URL = "http://example.com/browser/browser/devtools/canvasdebugger/test/"; michael@0: const SIMPLE_CANVAS_URL = EXAMPLE_URL + "doc_simple-canvas.html"; michael@0: const SIMPLE_CANVAS_TRANSPARENT_URL = EXAMPLE_URL + "doc_simple-canvas-transparent.html"; michael@0: const SIMPLE_CANVAS_DEEP_STACK_URL = EXAMPLE_URL + "doc_simple-canvas-deep-stack.html"; michael@0: michael@0: // All tests are asynchronous. michael@0: waitForExplicitFinish(); michael@0: michael@0: let gToolEnabled = Services.prefs.getBoolPref("devtools.canvasdebugger.enabled"); michael@0: michael@0: registerCleanupFunction(() => { michael@0: info("finish() was called, cleaning up..."); michael@0: Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging); michael@0: Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", gToolEnabled); michael@0: michael@0: // Some of yhese tests use a lot of memory due to GL contexts, so force a GC michael@0: // to help fragmentation. michael@0: info("Forcing GC after canvas debugger test."); michael@0: Cu.forceGC(); michael@0: }); michael@0: michael@0: function addTab(aUrl, aWindow) { michael@0: info("Adding tab: " + aUrl); michael@0: michael@0: let deferred = promise.defer(); michael@0: let targetWindow = aWindow || window; michael@0: let targetBrowser = targetWindow.gBrowser; michael@0: michael@0: targetWindow.focus(); michael@0: let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl); michael@0: let linkedBrowser = tab.linkedBrowser; michael@0: michael@0: linkedBrowser.addEventListener("load", function onLoad() { michael@0: linkedBrowser.removeEventListener("load", onLoad, true); michael@0: info("Tab added and finished loading: " + aUrl); michael@0: deferred.resolve(tab); michael@0: }, true); michael@0: michael@0: return deferred.promise; michael@0: } michael@0: michael@0: function removeTab(aTab, aWindow) { michael@0: info("Removing tab."); michael@0: michael@0: let deferred = promise.defer(); michael@0: let targetWindow = aWindow || window; michael@0: let targetBrowser = targetWindow.gBrowser; michael@0: let tabContainer = targetBrowser.tabContainer; michael@0: michael@0: tabContainer.addEventListener("TabClose", function onClose(aEvent) { michael@0: tabContainer.removeEventListener("TabClose", onClose, false); michael@0: info("Tab removed and finished closing."); michael@0: deferred.resolve(); michael@0: }, false); michael@0: michael@0: targetBrowser.removeTab(aTab); michael@0: return deferred.promise; michael@0: } michael@0: michael@0: function handleError(aError) { michael@0: ok(false, "Got an error: " + aError.message + "\n" + aError.stack); michael@0: finish(); michael@0: } michael@0: michael@0: let gRequiresWebGL = false; michael@0: michael@0: function ifTestingSupported() { michael@0: ok(false, "You need to define a 'ifTestingSupported' function."); michael@0: finish(); michael@0: } michael@0: michael@0: function ifTestingUnsupported() { michael@0: todo(false, "Skipping test because some required functionality isn't supported."); michael@0: finish(); michael@0: } michael@0: michael@0: function test() { michael@0: let generator = isTestingSupported() ? ifTestingSupported : ifTestingUnsupported; michael@0: Task.spawn(generator).then(null, handleError); michael@0: } michael@0: michael@0: function createCanvas() { michael@0: return document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); michael@0: } michael@0: michael@0: function isTestingSupported() { michael@0: if (!gRequiresWebGL) { michael@0: info("This test does not require WebGL support."); michael@0: return true; michael@0: } michael@0: michael@0: let supported = michael@0: !TiltGL.isWebGLForceEnabled() && michael@0: TiltGL.isWebGLSupported() && michael@0: TiltGL.create3DContext(createCanvas()); michael@0: michael@0: info("This test requires WebGL support."); michael@0: info("Apparently, WebGL is" + (supported ? "" : " not") + " supported."); michael@0: return supported; michael@0: } michael@0: michael@0: function once(aTarget, aEventName, aUseCapture = false) { michael@0: info("Waiting for event: '" + aEventName + "' on " + aTarget + "."); michael@0: michael@0: let deferred = promise.defer(); michael@0: michael@0: for (let [add, remove] of [ michael@0: ["on", "off"], // Use event emitter before DOM events for consistency michael@0: ["addEventListener", "removeEventListener"], michael@0: ["addListener", "removeListener"] michael@0: ]) { michael@0: if ((add in aTarget) && (remove in aTarget)) { michael@0: aTarget[add](aEventName, function onEvent(...aArgs) { michael@0: aTarget[remove](aEventName, onEvent, aUseCapture); michael@0: deferred.resolve(...aArgs); michael@0: }, aUseCapture); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: return deferred.promise; michael@0: } michael@0: michael@0: function waitForTick() { michael@0: let deferred = promise.defer(); michael@0: executeSoon(deferred.resolve); michael@0: return deferred.promise; michael@0: } michael@0: michael@0: function navigateInHistory(aTarget, aDirection, aWaitForTargetEvent = "navigate") { michael@0: executeSoon(() => content.history[aDirection]()); michael@0: return once(aTarget, aWaitForTargetEvent); michael@0: } michael@0: michael@0: function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") { michael@0: executeSoon(() => aTarget.activeTab.navigateTo(aUrl)); michael@0: return once(aTarget, aWaitForTargetEvent); michael@0: } michael@0: michael@0: function reload(aTarget, aWaitForTargetEvent = "navigate") { michael@0: executeSoon(() => aTarget.activeTab.reload()); michael@0: return once(aTarget, aWaitForTargetEvent); michael@0: } michael@0: michael@0: function initServer() { michael@0: if (!DebuggerServer.initialized) { michael@0: DebuggerServer.init(() => true); michael@0: DebuggerServer.addBrowserActors(); michael@0: } michael@0: } michael@0: michael@0: function initCallWatcherBackend(aUrl) { michael@0: info("Initializing a call watcher front."); michael@0: initServer(); michael@0: michael@0: return Task.spawn(function*() { michael@0: let tab = yield addTab(aUrl); michael@0: let target = TargetFactory.forTab(tab); michael@0: let debuggee = target.window.wrappedJSObject; michael@0: michael@0: yield target.makeRemote(); michael@0: michael@0: let front = new CallWatcherFront(target.client, target.form); michael@0: return [target, debuggee, front]; michael@0: }); michael@0: } michael@0: michael@0: function initCanavsDebuggerBackend(aUrl) { michael@0: info("Initializing a canvas debugger front."); michael@0: initServer(); michael@0: michael@0: return Task.spawn(function*() { michael@0: let tab = yield addTab(aUrl); michael@0: let target = TargetFactory.forTab(tab); michael@0: let debuggee = target.window.wrappedJSObject; michael@0: michael@0: yield target.makeRemote(); michael@0: michael@0: let front = new CanvasFront(target.client, target.form); michael@0: return [target, debuggee, front]; michael@0: }); michael@0: } michael@0: michael@0: function initCanavsDebuggerFrontend(aUrl) { michael@0: info("Initializing a canvas debugger pane."); michael@0: michael@0: return Task.spawn(function*() { michael@0: let tab = yield addTab(aUrl); michael@0: let target = TargetFactory.forTab(tab); michael@0: let debuggee = target.window.wrappedJSObject; michael@0: michael@0: yield target.makeRemote(); michael@0: michael@0: Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", true); michael@0: let toolbox = yield gDevTools.showToolbox(target, "canvasdebugger"); michael@0: let panel = toolbox.getCurrentPanel(); michael@0: return [target, debuggee, panel]; michael@0: }); michael@0: } michael@0: michael@0: function teardown(aPanel) { michael@0: info("Destroying the specified canvas debugger."); michael@0: michael@0: return promise.all([ michael@0: once(aPanel, "destroyed"), michael@0: removeTab(aPanel.target.tab) michael@0: ]); michael@0: }