Bug 1405349 - [reftest] Refactor manifest parsing from reftest.jsm to standalone module, r?jmaher draft
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Mon, 02 Oct 2017 12:03:43 -0400
changeset 680036 754230d6222e79b250300b8a54db9f33d8958299
parent 680024 196dadb2fe500e75c6fbddcac78106648676cf10
child 735743 4f5aa2752136f6a1ae48a5266ed711a4d53e5efb
push id84377
push userahalberstadt@mozilla.com
push dateFri, 13 Oct 2017 12:27:52 +0000
reviewersjmaher
bugs1405349
milestone58.0a1
Bug 1405349 - [reftest] Refactor manifest parsing from reftest.jsm to standalone module, r?jmaher There are two motivations for this change. First, reftest.jsm has become very large and monolithic. It has lots of global state and is hard to modify without breaking something. This change is a first attempt at dividing reftest.jsm into multiple standalone(ish) modules. This will make it easier to comprehend and extend. Second, we'd like to implement "run-by-manifest" mode for reftest. This means we'll restart the browser between each manifest run. This means much of the state which is normally stored in global variables in reftest.jsm, will instead need to be stored in python. A prerequisite to doing that is parsing the manifests before starting the test suite. A prerequisite to that is moving the manifest parsing code into a standalone JSM. This is the first step. MozReview-Commit-ID: 42epTs8EU1O
layout/tools/reftest/globals.jsm
layout/tools/reftest/jar.mn
layout/tools/reftest/manifest.jsm
layout/tools/reftest/reftest.jsm
new file mode 100644
--- /dev/null
+++ b/layout/tools/reftest/globals.jsm
@@ -0,0 +1,160 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+this.EXPORTED_SYMBOLS = [];
+
+for (let [key, val] of Object.entries({
+  /* Constants */
+  XHTML_NS: "http://www.w3.org/1999/xhtml",
+  XUL_NS: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
+
+  NS_LOCAL_FILE_CONTRACTID: "@mozilla.org/file/local;1",
+  NS_GFXINFO_CONTRACTID: "@mozilla.org/gfx/info;1",
+  IO_SERVICE_CONTRACTID: "@mozilla.org/network/io-service;1",
+  DEBUG_CONTRACTID: "@mozilla.org/xpcom/debug;1",
+  NS_DIRECTORY_SERVICE_CONTRACTID: "@mozilla.org/file/directory_service;1",
+  NS_OBSERVER_SERVICE_CONTRACTID: "@mozilla.org/observer-service;1",
+
+  TYPE_REFTEST_EQUAL: '==',
+  TYPE_REFTEST_NOTEQUAL: '!=',
+  TYPE_LOAD: 'load',     // test without a reference (just test that it does
+                         // not assert, crash, hang, or leak)
+  TYPE_SCRIPT: 'script', // test contains individual test results
+  TYPE_PRINT: 'print',   // test and reference will be printed to PDF's and
+                         // compared structurally
+
+  // The order of these constants matters, since when we have a status
+  // listed for a *manifest*, we combine the status with the status for
+  // the test by using the *larger*.
+  // FIXME: In the future, we may also want to use this rule for combining
+  // statuses that are on the same line (rather than making the last one
+  // win).
+  EXPECTED_PASS: 0,
+  EXPECTED_FAIL: 1,
+  EXPECTED_RANDOM: 2,
+  EXPECTED_DEATH: 3,     // test must be skipped to avoid e.g. crash/hang
+  EXPECTED_FUZZY: 4,
+
+  // types of preference value we might want to set for a specific test
+  PREF_BOOLEAN: 0,
+  PREF_STRING: 1,
+  PREF_INTEGER: 2,
+
+  FOCUS_FILTER_ALL_TESTS: "all",
+  FOCUS_FILTER_NEEDS_FOCUS_TESTS: "needs-focus",
+  FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS: "non-needs-focus",
+
+  // "<!--CLEAR-->"
+  BLANK_URL_FOR_CLEARING: "data:text/html;charset=UTF-8,%3C%21%2D%2DCLEAR%2D%2D%3E",
+
+  /* Globals */
+  g: {
+    loadTimeout: 0,
+    timeoutHook: null,
+    remote: false,
+    ignoreWindowSize: false,
+    shuffle: false,
+    repeat: null,
+    runUntilFailure: false,
+    cleanupPendingCrashes: false,
+    totalChunks: 0,
+    thisChunk: 0,
+    containingWindow: null,
+    urlFilterRegex: {},
+    contentGfxInfo: null,
+    focusFilterMode: "all",
+    compareStyloToGecko: false,
+
+    browser: undefined,
+    // Are we testing web content loaded in a separate process?
+    browserIsRemote: undefined,        // bool
+    // Are we using <iframe mozbrowser>?
+    browserIsIframe: undefined,        // bool
+    browserMessageManager: undefined,  // bool
+    canvas1: undefined,
+    canvas2: undefined,
+    // gCurrentCanvas is non-null between InitCurrentCanvasWithSnapshot and the next
+    // RecordResult.
+    currentCanvas: null,
+    urls: undefined,
+    // Map from URI spec to the number of times it remains to be used
+    uriUseCounts: undefined,
+    // Map from URI spec to the canvas rendered for that URI
+    uriCanvases: undefined,
+    testResults: {
+      // Successful...
+      Pass: 0,
+      LoadOnly: 0,
+      // Unexpected...
+      Exception: 0,
+      FailedLoad: 0,
+      UnexpectedFail: 0,
+      UnexpectedPass: 0,
+      AssertionUnexpected: 0,
+      AssertionUnexpectedFixed: 0,
+      // Known problems...
+      KnownFail : 0,
+      AssertionKnown: 0,
+      Random : 0,
+      Skip: 0,
+      Slow: 0,
+    },
+    totalTests: 0,
+    state: undefined,
+    currentURL: undefined,
+    testLog: [],
+    logLevel: undefined,
+    logFile: null,
+    logger: undefined,
+    server: undefined,
+    count: 0,
+    assertionCount: 0,
+
+    ioService: undefined,
+    debug: undefined,
+    windowUtils: undefined,
+
+    slowestTestTime: 0,
+    slowestTestURL: undefined,
+    failedUseWidgetLayers: false,
+
+    drawWindowFlags: undefined,
+
+    expectingProcessCrash: false,
+    expectedCrashDumpFiles: [],
+    unexpectedCrashDumpFiles: {},
+    crashDumpDir: undefined,
+    pendingCrashDumpDir: undefined,
+    failedNoPaint: false,
+    failedOpaqueLayer: false,
+    failedOpaqueLayerMessages: [],
+    failedAssignedLayer: false,
+    failedAssignedLayerMessages: [],
+
+    startAfter: undefined,
+    suiteStarted: false,
+
+    // The enabled-state of the test-plugins, stored so they can be reset later
+    testPluginEnabledStates: null,
+    prefsToRestore: [],
+    httpServerPort: -1,
+
+    // whether to run slow tests or not
+    runSlowTests: true,
+
+    // whether we should skip caching canvases
+    noCanvasCache: false,
+    recycledCanvases: new Array(),
+    testPrintOutput: null,
+
+    manifestsLoaded: {},
+    // Only dump the sandbox once, because it doesn't depend on the
+    // manifest URL (yet!).
+    dumpedConditionSandbox: false,
+  }
+})) {
+  this[key] = val;
+  this.EXPORTED_SYMBOLS.push(key);
+}
--- a/layout/tools/reftest/jar.mn
+++ b/layout/tools/reftest/jar.mn
@@ -1,8 +1,10 @@
 reftest.jar:
 % content reftest %content/
+  content/globals.jsm (globals.jsm)
   content/reftest-content.js (reftest-content.js)
   content/AsyncSpellCheckTestHelper.jsm (../../../editor/AsyncSpellCheckTestHelper.jsm)
   content/httpd.jsm (../../../netwerk/test/httpserver/httpd.js)
   content/StructuredLog.jsm (../../../testing/modules/StructuredLog.jsm)
+*  content/manifest.jsm (manifest.jsm)
 *  content/reftest.jsm (reftest.jsm)
   content/reftest.xul (reftest.xul)
new file mode 100644
--- /dev/null
+++ b/layout/tools/reftest/manifest.jsm
@@ -0,0 +1,717 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- /
+/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["ReadTopManifest"];
+
+var CC = Components.classes;
+const CI = Components.interfaces;
+const CU = Components.utils;
+
+CU.import("chrome://reftest/content/globals.jsm", this);
+CU.import("chrome://reftest/content/reftest.jsm", this);
+CU.import("resource://gre/modules/Services.jsm");
+CU.import("resource://gre/modules/NetUtil.jsm");
+
+const NS_SCRIPTSECURITYMANAGER_CONTRACTID = "@mozilla.org/scriptsecuritymanager;1";
+const NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX = "@mozilla.org/network/protocol;1?name=";
+const NS_XREAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
+
+const RE_PROTOCOL = /^\w+:/;
+const RE_PREF_ITEM = /^(|test-|ref-)pref\((.+?),(.*)\)$/;
+
+
+function ReadTopManifest(aFileURL, aFilter)
+{
+    var url = g.ioService.newURI(aFileURL);
+    if (!url)
+        throw "Expected a file or http URL for the manifest.";
+
+    g.manifestsLoaded = {};
+    ReadManifest(url, EXPECTED_PASS, aFilter);
+}
+
+// Note: If you materially change the reftest manifest parsing,
+// please keep the parser in print-manifest-dirs.py in sync.
+function ReadManifest(aURL, inherited_status, aFilter)
+{
+    // Ensure each manifest is only read once. This assumes that manifests that are
+    // included with an unusual inherited_status or filters will be read via their
+    // include before they are read directly in the case of a duplicate
+    if (g.manifestsLoaded.hasOwnProperty(aURL.spec)) {
+        if (g.manifestsLoaded[aURL.spec] === null)
+            return;
+        else
+            aFilter = [aFilter[0], aFilter[1], true];
+    }
+    g.manifestsLoaded[aURL.spec] = aFilter[1];
+
+    var secMan = CC[NS_SCRIPTSECURITYMANAGER_CONTRACTID]
+                     .getService(CI.nsIScriptSecurityManager);
+
+    var listURL = aURL;
+    var channel = NetUtil.newChannel({uri: aURL, loadUsingSystemPrincipal: true});
+    var inputStream = channel.open2();
+    if (channel instanceof Components.interfaces.nsIHttpChannel
+        && channel.responseStatus != 200) {
+      g.logger.error("HTTP ERROR : " + channel.responseStatus);
+    }
+    var streamBuf = getStreamContent(inputStream);
+    inputStream.close();
+    var lines = streamBuf.split(/\n|\r|\r\n/);
+
+    // Build the sandbox for fails-if(), etc., condition evaluation.
+    var sandbox = BuildConditionSandbox(aURL);
+    var lineNo = 0;
+    var urlprefix = "";
+    var defaultTestPrefSettings = [], defaultRefPrefSettings = [];
+    if (g.compareStyloToGecko) {
+        AddStyloTestPrefs(sandbox, defaultTestPrefSettings,
+                          defaultRefPrefSettings);
+    }
+    for (var str of lines) {
+        ++lineNo;
+        if (str.charAt(0) == "#")
+            continue; // entire line was a comment
+        var i = str.search(/\s+#/);
+        if (i >= 0)
+            str = str.substring(0, i);
+        // strip leading and trailing whitespace
+        str = str.replace(/^\s*/, '').replace(/\s*$/, '');
+        if (!str || str == "")
+            continue;
+        var items = str.split(/\s+/); // split on whitespace
+
+        if (items[0] == "url-prefix") {
+            if (items.length != 2)
+                throw "url-prefix requires one url in manifest file " + aURL.spec + " line " + lineNo;
+            urlprefix = items[1];
+            continue;
+        }
+
+        if (items[0] == "default-preferences") {
+            var m;
+            var item;
+            defaultTestPrefSettings = [];
+            defaultRefPrefSettings = [];
+            items.shift();
+            while ((item = items.shift())) {
+                if (!(m = item.match(RE_PREF_ITEM))) {
+                    throw "Unexpected item in default-preferences list in manifest file " + aURL.spec + " line " + lineNo;
+                }
+                if (!AddPrefSettings(m[1], m[2], m[3], sandbox, defaultTestPrefSettings, defaultRefPrefSettings)) {
+                    throw "Error in pref value in manifest file " + aURL.spec + " line " + lineNo;
+                }
+            }
+            if (g.compareStyloToGecko) {
+                AddStyloTestPrefs(sandbox, defaultTestPrefSettings,
+                                  defaultRefPrefSettings);
+            }
+            continue;
+        }
+
+        var expected_status = EXPECTED_PASS;
+        var allow_silent_fail = false;
+        var minAsserts = 0;
+        var maxAsserts = 0;
+        var needs_focus = false;
+        var slow = false;
+        var testPrefSettings = defaultTestPrefSettings.concat();
+        var refPrefSettings = defaultRefPrefSettings.concat();
+        var fuzzy_delta = { min: 0, max: 2 };
+        var fuzzy_pixels = { min: 0, max: 1 };
+        var chaosMode = false;
+
+        while (items[0].match(/^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail|pref|test-pref|ref-pref|fuzzy|chaos-mode)/)) {
+            var item = items.shift();
+            var stat;
+            var cond;
+            var m = item.match(/^(fails|random|skip|silentfail)-if(\(.*\))$/);
+            if (m) {
+                stat = m[1];
+                // Note: m[2] contains the parentheses, and we want them.
+                cond = Components.utils.evalInSandbox(m[2], sandbox);
+            } else if (item.match(/^(fails|random|skip)$/)) {
+                stat = item;
+                cond = true;
+            } else if (item == "needs-focus") {
+                needs_focus = true;
+                cond = false;
+            } else if ((m = item.match(/^asserts\((\d+)(-\d+)?\)$/))) {
+                cond = false;
+                minAsserts = Number(m[1]);
+                maxAsserts = (m[2] == undefined) ? minAsserts
+                                                 : Number(m[2].substring(1));
+            } else if ((m = item.match(/^asserts-if\((.*?),(\d+)(-\d+)?\)$/))) {
+                cond = false;
+                if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox)) {
+                    minAsserts = Number(m[2]);
+                    maxAsserts =
+                      (m[3] == undefined) ? minAsserts
+                                          : Number(m[3].substring(1));
+                }
+            } else if (item == "slow") {
+                cond = false;
+                slow = true;
+            } else if ((m = item.match(/^require-or\((.*?)\)$/))) {
+                var args = m[1].split(/,/);
+                if (args.length != 2) {
+                    throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": wrong number of args to require-or";
+                }
+                var [precondition_str, fallback_action] = args;
+                var preconditions = precondition_str.split(/&&/);
+                cond = false;
+                for (var precondition of preconditions) {
+                    if (precondition === "debugMode") {
+                        // Currently unimplemented. Requires asynchronous
+                        // JSD call + getting an event while no JS is running
+                        stat = fallback_action;
+                        cond = true;
+                        break;
+                    } else if (precondition === "true") {
+                        // For testing
+                    } else {
+                        // Unknown precondition. Assume it is unimplemented.
+                        stat = fallback_action;
+                        cond = true;
+                        break;
+                    }
+                }
+            } else if ((m = item.match(/^slow-if\((.*?)\)$/))) {
+                cond = false;
+                if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox))
+                    slow = true;
+            } else if (item == "silentfail") {
+                cond = false;
+                allow_silent_fail = true;
+            } else if ((m = item.match(RE_PREF_ITEM))) {
+                cond = false;
+                if (!AddPrefSettings(m[1], m[2], m[3], sandbox, testPrefSettings, refPrefSettings)) {
+                    throw "Error in pref value in manifest file " + aURL.spec + " line " + lineNo;
+                }
+            } else if ((m = item.match(/^fuzzy\((\d+)(-\d+)?,(\d+)(-\d+)?\)$/))) {
+              cond = false;
+              expected_status = EXPECTED_FUZZY;
+              fuzzy_delta = ExtractRange(m, 1);
+              fuzzy_pixels = ExtractRange(m, 3);
+            } else if ((m = item.match(/^fuzzy-if\((.*?),(\d+)(-\d+)?,(\d+)(-\d+)?\)$/))) {
+              cond = false;
+              if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox)) {
+                expected_status = EXPECTED_FUZZY;
+                fuzzy_delta = ExtractRange(m, 2);
+                fuzzy_pixels = ExtractRange(m, 4);
+              }
+            } else if (item == "chaos-mode") {
+                cond = false;
+                chaosMode = true;
+            } else {
+                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": unexpected item " + item;
+            }
+
+            if (cond) {
+                if (stat == "fails") {
+                    expected_status = EXPECTED_FAIL;
+                } else if (stat == "random") {
+                    expected_status = EXPECTED_RANDOM;
+                } else if (stat == "skip") {
+                    expected_status = EXPECTED_DEATH;
+                } else if (stat == "silentfail") {
+                    allow_silent_fail = true;
+                }
+            }
+        }
+
+        expected_status = Math.max(expected_status, inherited_status);
+
+        if (minAsserts > maxAsserts) {
+            throw "Bad range in manifest file " + aURL.spec + " line " + lineNo;
+        }
+
+        var runHttp = false;
+        var httpDepth;
+        if (items[0] == "HTTP") {
+            runHttp = (aURL.scheme == "file"); // We can't yet run the local HTTP server
+                                               // for non-local reftests.
+            httpDepth = 0;
+            items.shift();
+        } else if (items[0].match(/HTTP\(\.\.(\/\.\.)*\)/)) {
+            // Accept HTTP(..), HTTP(../..), HTTP(../../..), etc.
+            runHttp = (aURL.scheme == "file"); // We can't yet run the local HTTP server
+                                               // for non-local reftests.
+            httpDepth = (items[0].length - 5) / 3;
+            items.shift();
+        }
+
+        // do not prefix the url for include commands or urls specifying
+        // a protocol
+        if (urlprefix && items[0] != "include") {
+            if (items.length > 1 && !items[1].match(RE_PROTOCOL)) {
+                items[1] = urlprefix + items[1];
+            }
+            if (items.length > 2 && !items[2].match(RE_PROTOCOL)) {
+                items[2] = urlprefix + items[2];
+            }
+        }
+
+        var principal = secMan.createCodebasePrincipal(aURL, {});
+
+        if (items[0] == "include") {
+            if (items.length != 2)
+                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to include";
+            if (runHttp)
+                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": use of include with http";
+            var incURI = g.ioService.newURI(items[1], null, listURL);
+            secMan.checkLoadURIWithPrincipal(principal, incURI,
+                                             CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
+            ReadManifest(incURI, expected_status, aFilter);
+        } else if (items[0] == TYPE_LOAD) {
+            if (items.length != 2)
+                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to load";
+            if (expected_status != EXPECTED_PASS &&
+                expected_status != EXPECTED_DEATH)
+                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect known failure type for load test";
+            var [testURI] = runHttp
+                            ? ServeFiles(principal, httpDepth,
+                                         listURL, [items[1]])
+                            : [g.ioService.newURI(items[1], null, listURL)];
+            var prettyPath = runHttp
+                           ? g.ioService.newURI(items[1], null, listURL).spec
+                           : testURI.spec;
+            secMan.checkLoadURIWithPrincipal(principal, testURI,
+                                             CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
+            AddTestItem({ type: TYPE_LOAD,
+                          expected: expected_status,
+                          allowSilentFail: allow_silent_fail,
+                          prettyPath: prettyPath,
+                          minAsserts: minAsserts,
+                          maxAsserts: maxAsserts,
+                          needsFocus: needs_focus,
+                          slow: slow,
+                          prefSettings1: testPrefSettings,
+                          prefSettings2: refPrefSettings,
+                          fuzzyMinDelta: fuzzy_delta.min,
+                          fuzzyMaxDelta: fuzzy_delta.max,
+                          fuzzyMinPixels: fuzzy_pixels.min,
+                          fuzzyMaxPixels: fuzzy_pixels.max,
+                          url1: testURI,
+                          url2: null,
+                          chaosMode: chaosMode }, aFilter);
+        } else if (items[0] == TYPE_SCRIPT) {
+            if (items.length != 2)
+                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to script";
+            var [testURI] = runHttp
+                            ? ServeFiles(principal, httpDepth,
+                                         listURL, [items[1]])
+                            : [g.ioService.newURI(items[1], null, listURL)];
+            var prettyPath = runHttp
+                           ? g.ioService.newURI(items[1], null, listURL).spec
+                           : testURI.spec;
+            secMan.checkLoadURIWithPrincipal(principal, testURI,
+                                             CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
+            AddTestItem({ type: TYPE_SCRIPT,
+                          expected: expected_status,
+                          allowSilentFail: allow_silent_fail,
+                          prettyPath: prettyPath,
+                          minAsserts: minAsserts,
+                          maxAsserts: maxAsserts,
+                          needsFocus: needs_focus,
+                          slow: slow,
+                          prefSettings1: testPrefSettings,
+                          prefSettings2: refPrefSettings,
+                          fuzzyMinDelta: fuzzy_delta.min,
+                          fuzzyMaxDelta: fuzzy_delta.max,
+                          fuzzyMinPixels: fuzzy_pixels.min,
+                          fuzzyMaxPixels: fuzzy_pixels.max,
+                          url1: testURI,
+                          url2: null,
+                          chaosMode: chaosMode }, aFilter);
+        } else if (items[0] == TYPE_REFTEST_EQUAL || items[0] == TYPE_REFTEST_NOTEQUAL || items[0] == TYPE_PRINT) {
+            if (items.length != 3)
+                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to " + items[0];
+
+            if (items[0] == TYPE_REFTEST_NOTEQUAL &&
+                expected_status == EXPECTED_FUZZY &&
+                (fuzzy_delta.min > 0 || fuzzy_pixels.min > 0)) {
+                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": minimum fuzz must be zero for tests of type " + items[0];
+            }
+
+            var [testURI, refURI] = runHttp
+                                  ? ServeFiles(principal, httpDepth,
+                                               listURL, [items[1], items[2]])
+                                  : [g.ioService.newURI(items[1], null, listURL),
+                                     g.ioService.newURI(items[2], null, listURL)];
+            var prettyPath = runHttp
+                           ? g.ioService.newURI(items[1], null, listURL).spec
+                           : testURI.spec;
+            secMan.checkLoadURIWithPrincipal(principal, testURI,
+                                             CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
+            secMan.checkLoadURIWithPrincipal(principal, refURI,
+                                             CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
+            var type = items[0];
+            if (g.compareStyloToGecko) {
+                type = TYPE_REFTEST_EQUAL;
+                refURI = testURI;
+
+                // We expect twice as many assertion failures when running in
+                // styloVsGecko mode because we run each test twice: once in
+                // Stylo mode and once in Gecko mode.
+                minAsserts *= 2;
+                maxAsserts *= 2;
+
+                // Skip the test if it is expected to fail in both Stylo and
+                // Gecko modes. It would unexpectedly "pass" in styloVsGecko
+                // mode when comparing the two failures, which is not a useful
+                // result.
+                if (expected_status === EXPECTED_FAIL ||
+                    expected_status === EXPECTED_RANDOM) {
+                    expected_status = EXPECTED_DEATH;
+                }
+            }
+
+            AddTestItem({ type: type,
+                          expected: expected_status,
+                          allowSilentFail: allow_silent_fail,
+                          prettyPath: prettyPath,
+                          minAsserts: minAsserts,
+                          maxAsserts: maxAsserts,
+                          needsFocus: needs_focus,
+                          slow: slow,
+                          prefSettings1: testPrefSettings,
+                          prefSettings2: refPrefSettings,
+                          fuzzyMinDelta: fuzzy_delta.min,
+                          fuzzyMaxDelta: fuzzy_delta.max,
+                          fuzzyMinPixels: fuzzy_pixels.min,
+                          fuzzyMaxPixels: fuzzy_pixels.max,
+                          url1: testURI,
+                          url2: refURI,
+                          chaosMode: chaosMode }, aFilter);
+        } else {
+            throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": unknown test type " + items[0];
+        }
+    }
+}
+
+// Read all available data from an input stream and return it
+// as a string.
+function getStreamContent(inputStream)
+{
+    var streamBuf = "";
+    var sis = CC["@mozilla.org/scriptableinputstream;1"].
+                  createInstance(CI.nsIScriptableInputStream);
+    sis.init(inputStream);
+
+    var available;
+    while ((available = sis.available()) != 0) {
+        streamBuf += sis.read(available);
+    }
+
+    return streamBuf;
+}
+
+// Build the sandbox for fails-if(), etc., condition evaluation.
+function BuildConditionSandbox(aURL) {
+    var sandbox = new Components.utils.Sandbox(aURL.spec);
+    var xr = CC[NS_XREAPPINFO_CONTRACTID].getService(CI.nsIXULRuntime);
+    var appInfo = CC[NS_XREAPPINFO_CONTRACTID].getService(CI.nsIXULAppInfo);
+    sandbox.isDebugBuild = g.debug.isDebugBuild;
+    var prefs = CC["@mozilla.org/preferences-service;1"].
+                getService(CI.nsIPrefBranch);
+    var env = CC["@mozilla.org/process/environment;1"].
+                getService(CI.nsIEnvironment);
+
+    sandbox.xulRuntime = CU.cloneInto({widgetToolkit: xr.widgetToolkit, OS: xr.OS, XPCOMABI: xr.XPCOMABI}, sandbox);
+
+    var testRect = g.browser.getBoundingClientRect();
+    sandbox.smallScreen = false;
+    if (g.containingWindow.innerWidth < 800 || g.containingWindow.innerHeight < 1000) {
+        sandbox.smallScreen = true;
+    }
+
+    var gfxInfo = (NS_GFXINFO_CONTRACTID in CC) && CC[NS_GFXINFO_CONTRACTID].getService(CI.nsIGfxInfo);
+    let readGfxInfo = function (obj, key) {
+      if (g.contentGfxInfo && (key in g.contentGfxInfo)) {
+        return g.contentGfxInfo[key];
+      }
+      return obj[key];
+    }
+
+    try {
+      sandbox.d2d = readGfxInfo(gfxInfo, "D2DEnabled");
+      sandbox.dwrite = readGfxInfo(gfxInfo, "DWriteEnabled");
+    } catch (e) {
+      sandbox.d2d = false;
+      sandbox.dwrite = false;
+    }
+
+    var info = gfxInfo.getInfo();
+    var canvasBackend = readGfxInfo(info, "AzureCanvasBackend");
+    var contentBackend = readGfxInfo(info, "AzureContentBackend");
+    var canvasAccelerated = readGfxInfo(info, "AzureCanvasAccelerated");
+
+    sandbox.gpuProcess = gfxInfo.usingGPUProcess;
+    sandbox.azureCairo = canvasBackend == "cairo";
+    sandbox.azureSkia = canvasBackend == "skia";
+    sandbox.skiaContent = contentBackend == "skia";
+    sandbox.azureSkiaGL = canvasAccelerated; // FIXME: assumes GL right now
+    // true if we are using the same Azure backend for rendering canvas and content
+    sandbox.contentSameGfxBackendAsCanvas = contentBackend == canvasBackend
+                                            || (contentBackend == "none" && canvasBackend == "cairo");
+
+    sandbox.layersGPUAccelerated =
+      g.windowUtils.layerManagerType != "Basic";
+    sandbox.d3d11 =
+      g.windowUtils.layerManagerType == "Direct3D 11";
+    sandbox.d3d9 =
+      g.windowUtils.layerManagerType == "Direct3D 9";
+    sandbox.layersOpenGL =
+      g.windowUtils.layerManagerType == "OpenGL";
+    sandbox.webrender =
+      g.windowUtils.layerManagerType == "WebRender";
+    sandbox.layersOMTC =
+      g.windowUtils.layerManagerRemote == true;
+    sandbox.advancedLayers =
+      g.windowUtils.usingAdvancedLayers == true;
+    sandbox.layerChecksEnabled = !sandbox.webrender;
+
+    // Shortcuts for widget toolkits.
+    sandbox.Android = xr.OS == "Android";
+    sandbox.cocoaWidget = xr.widgetToolkit == "cocoa";
+    sandbox.gtkWidget = xr.widgetToolkit == "gtk2"
+                        || xr.widgetToolkit == "gtk3";
+    sandbox.qtWidget = xr.widgetToolkit == "qt";
+    sandbox.winWidget = xr.widgetToolkit == "windows";
+
+    // Scrollbars that are semi-transparent. See bug 1169666.
+    sandbox.transparentScrollbars = xr.widgetToolkit == "gtk3";
+
+    if (sandbox.Android) {
+        var sysInfo = CC["@mozilla.org/system-info;1"].getService(CI.nsIPropertyBag2);
+
+        // This is currently used to distinguish Android 4.0.3 (SDK version 15)
+        // and later from Android 2.x
+        sandbox.AndroidVersion = sysInfo.getPropertyAsInt32("version");
+    }
+
+#if MOZ_ASAN
+    sandbox.AddressSanitizer = true;
+#else
+    sandbox.AddressSanitizer = false;
+#endif
+
+#if MOZ_WEBRTC
+    sandbox.webrtc = true;
+#else
+    sandbox.webrtc = false;
+#endif
+
+#ifdef MOZ_STYLO
+    let styloEnabled = false;
+    // Perhaps a bit redundant in places, but this is easier to compare with the
+    // the real check in `nsLayoutUtils.cpp` to ensure they test the same way.
+    if (env.get("STYLO_FORCE_ENABLED")) {
+        styloEnabled = true;
+    } else if (env.get("STYLO_FORCE_DISABLED")) {
+        styloEnabled = false;
+    } else {
+        styloEnabled = prefs.getBoolPref("layout.css.servo.enabled", false);
+    }
+    sandbox.stylo = styloEnabled && !g.compareStyloToGecko;
+    sandbox.styloVsGecko = g.compareStyloToGecko;
+#else
+    sandbox.stylo = false;
+    sandbox.styloVsGecko = false;
+#endif
+
+// Printing via Skia PDF is only supported on Mac for now.
+#ifdef XP_MACOSX && MOZ_ENABLE_SKIA_PDF
+    sandbox.skiaPdf = true;
+#else
+    sandbox.skiaPdf = false;
+#endif
+
+#ifdef RELEASE_OR_BETA
+    sandbox.release_or_beta = true;
+#else
+    sandbox.release_or_beta = false;
+#endif
+
+    var hh = CC[NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX + "http"].
+                 getService(CI.nsIHttpProtocolHandler);
+    var httpProps = ["userAgent", "appName", "appVersion", "vendor",
+                     "vendorSub", "product", "productSub", "platform",
+                     "oscpu", "language", "misc"];
+    sandbox.http = new sandbox.Object();
+    httpProps.forEach((x) => sandbox.http[x] = hh[x]);
+
+    // Set OSX to be the Mac OS X version, as an integer, or undefined
+    // for other platforms.  The integer is formed by 100 times the
+    // major version plus the minor version, so 1006 for 10.6, 1010 for
+    // 10.10, etc.
+    var osxmatch = /Mac OS X (\d+).(\d+)$/.exec(hh.oscpu);
+    sandbox.OSX = osxmatch ? parseInt(osxmatch[1]) * 100 + parseInt(osxmatch[2]) : undefined;
+
+    // see if we have the test plugin available,
+    // and set a sandox prop accordingly
+    sandbox.haveTestPlugin = !sandbox.Android && !!getTestPlugin("Test Plug-in");
+
+    // Set a flag on sandbox if the windows default theme is active
+    sandbox.windowsDefaultTheme = g.containingWindow.matchMedia("(-moz-windows-default-theme)").matches;
+
+    try {
+        sandbox.nativeThemePref = !prefs.getBoolPref("mozilla.widget.disable-native-theme");
+    } catch (e) {
+        sandbox.nativeThemePref = true;
+    }
+    sandbox.gpuProcessForceEnabled = prefs.getBoolPref("layers.gpu-process.force-enabled", false);
+
+    sandbox.prefs = CU.cloneInto({
+        getBoolPref: function(p) { return prefs.getBoolPref(p); },
+        getIntPref:  function(p) { return prefs.getIntPref(p); }
+    }, sandbox, { cloneFunctions: true });
+
+    // Tests shouldn't care about this except for when they need to
+    // crash the content process
+    sandbox.browserIsRemote = g.browserIsRemote;
+
+    try {
+        sandbox.asyncPan = g.containingWindow.document.docShell.asyncPanZoomEnabled;
+    } catch (e) {
+        sandbox.asyncPan = false;
+    }
+
+    // Graphics features
+    sandbox.usesRepeatResampling = sandbox.d2d;
+
+    if (!g.dumpedConditionSandbox) {
+        g.logger.info("Dumping JSON representation of sandbox");
+        g.logger.info(JSON.stringify(CU.waiveXrays(sandbox)));
+        g.dumpedConditionSandbox = true;
+    }
+
+    return sandbox;
+}
+
+function AddStyloTestPrefs(aSandbox, aTestPrefSettings, aRefPrefSettings) {
+    AddPrefSettings("test-", "layout.css.servo.enabled", "true", aSandbox,
+                    aTestPrefSettings, aRefPrefSettings);
+    AddPrefSettings("ref-", "layout.css.servo.enabled", "false", aSandbox,
+                    aTestPrefSettings, aRefPrefSettings);
+}
+
+function AddPrefSettings(aWhere, aPrefName, aPrefValExpression, aSandbox, aTestPrefSettings, aRefPrefSettings) {
+    var prefVal = Components.utils.evalInSandbox("(" + aPrefValExpression + ")", aSandbox);
+    var prefType;
+    var valType = typeof(prefVal);
+    if (valType == "boolean") {
+        prefType = PREF_BOOLEAN;
+    } else if (valType == "string") {
+        prefType = PREF_STRING;
+    } else if (valType == "number" && (parseInt(prefVal) == prefVal)) {
+        prefType = PREF_INTEGER;
+    } else {
+        return false;
+    }
+    var setting = { name: aPrefName,
+                    type: prefType,
+                    value: prefVal };
+
+    if (g.compareStyloToGecko && aPrefName != "layout.css.servo.enabled") {
+        // ref-pref() is ignored, test-pref() and pref() are added to both
+        if (aWhere != "ref-") {
+            aTestPrefSettings.push(setting);
+            aRefPrefSettings.push(setting);
+        }
+    } else {
+        if (aWhere != "ref-") {
+            aTestPrefSettings.push(setting);
+        }
+        if (aWhere != "test-") {
+            aRefPrefSettings.push(setting);
+        }
+    }
+    return true;
+}
+
+function ExtractRange(matches, startIndex, defaultMin = 0) {
+    if (matches[startIndex + 1] === undefined) {
+        return {
+            min: defaultMin,
+            max: Number(matches[startIndex])
+        };
+    }
+    return {
+        min: Number(matches[startIndex]),
+        max: Number(matches[startIndex + 1].substring(1))
+    };
+}
+
+function ServeFiles(manifestPrincipal, depth, aURL, files) {
+    var listURL = aURL.QueryInterface(CI.nsIFileURL);
+    var directory = listURL.file.parent;
+
+    // Allow serving a tree that's an ancestor of the directory containing
+    // the files so that they can use resources in ../ (etc.).
+    var dirPath = "/";
+    while (depth > 0) {
+        dirPath = "/" + directory.leafName + dirPath;
+        directory = directory.parent;
+        --depth;
+    }
+
+    g.count++;
+    var path = "/" + Date.now() + "/" + g.count;
+    g.server.registerDirectory(path + "/", directory);
+
+    var secMan = CC[NS_SCRIPTSECURITYMANAGER_CONTRACTID]
+                     .getService(CI.nsIScriptSecurityManager);
+
+    var testbase = g.ioService.newURI("http://localhost:" + g.httpServerPort +
+                                     path + dirPath);
+
+    // Give the testbase URI access to XUL and XBL
+    Services.perms.add(testbase, "allowXULXBL", Services.perms.ALLOW_ACTION);
+
+    function FileToURI(file)
+    {
+        // Only serve relative URIs via the HTTP server, not absolute
+        // ones like about:blank.
+        var testURI = g.ioService.newURI(file, null, testbase);
+
+        // XXX necessary?  manifestURL guaranteed to be file, others always HTTP
+        secMan.checkLoadURIWithPrincipal(manifestPrincipal, testURI,
+                                         CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
+
+        return testURI;
+    }
+
+    return files.map(FileToURI);
+}
+
+function AddTestItem(aTest, aFilter) {
+    if (!aFilter)
+        aFilter = [null, [], false];
+
+    var globalFilter = aFilter[0];
+    var manifestFilter = aFilter[1];
+    var invertManifest = aFilter[2];
+    if ((globalFilter && !globalFilter.test(aTest.url1.spec)) ||
+        (manifestFilter &&
+         !(invertManifest ^ manifestFilter.test(aTest.url1.spec))))
+        return;
+    if (g.focusFilterMode == FOCUS_FILTER_NEEDS_FOCUS_TESTS &&
+        !aTest.needsFocus)
+        return;
+    if (g.focusFilterMode == FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS &&
+        aTest.needsFocus)
+        return;
+
+    if (aTest.url2 !== null)
+        aTest.identifier = [aTest.prettyPath, aTest.type, aTest.url2.spec];
+    else
+        aTest.identifier = aTest.prettyPath;
+
+    g.urls.push(aTest);
+}
--- a/layout/tools/reftest/reftest.jsm
+++ b/layout/tools/reftest/reftest.jsm
@@ -1,46 +1,30 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- /
 /* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-this.EXPORTED_SYMBOLS = ["OnRefTestLoad", "OnRefTestUnload"];
+this.EXPORTED_SYMBOLS = [
+    "OnRefTestLoad",
+    "OnRefTestUnload",
+    "getTestPlugin"
+];
 
 var CC = Components.classes;
 const CI = Components.interfaces;
 const CR = Components.results;
 const CU = Components.utils;
 
-const XHTML_NS = "http://www.w3.org/1999/xhtml";
-const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-
-const NS_LOCAL_FILE_CONTRACTID = "@mozilla.org/file/local;1";
-const NS_GFXINFO_CONTRACTID = "@mozilla.org/gfx/info;1";
-const IO_SERVICE_CONTRACTID = "@mozilla.org/network/io-service;1";
-const DEBUG_CONTRACTID = "@mozilla.org/xpcom/debug;1";
-const NS_LOCALFILEINPUTSTREAM_CONTRACTID =
-          "@mozilla.org/network/file-input-stream;1";
-const NS_SCRIPTSECURITYMANAGER_CONTRACTID =
-          "@mozilla.org/scriptsecuritymanager;1";
-const NS_REFTESTHELPER_CONTRACTID =
-          "@mozilla.org/reftest-helper;1";
-const NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX =
-          "@mozilla.org/network/protocol;1?name=";
-const NS_XREAPPINFO_CONTRACTID =
-          "@mozilla.org/xre/app-info;1";
-const NS_DIRECTORY_SERVICE_CONTRACTID =
-          "@mozilla.org/file/directory_service;1";
-const NS_OBSERVER_SERVICE_CONTRACTID =
-          "@mozilla.org/observer-service;1";
-
 CU.import("resource://gre/modules/FileUtils.jsm");
+CU.import("chrome://reftest/content/globals.jsm", this);
 CU.import("chrome://reftest/content/httpd.jsm", this);
+CU.import("chrome://reftest/content/manifest.jsm", this);
 CU.import("chrome://reftest/content/StructuredLog.jsm", this);
 CU.import("resource://gre/modules/Services.jsm");
 CU.import("resource://gre/modules/NetUtil.jsm");
 CU.import('resource://gre/modules/XPCOMUtils.jsm');
 
 XPCOMUtils.defineLazyGetter(this, "OS", function() {
     const { OS } = CU.import("resource://gre/modules/osfile.jsm");
     return OS;
@@ -49,225 +33,87 @@ XPCOMUtils.defineLazyGetter(this, "OS", 
 XPCOMUtils.defineLazyGetter(this, "PDFJS", function() {
     const { require } = CU.import("resource://gre/modules/commonjs/toolkit/require.js", {});
     return {
         main: require('resource://pdf.js/build/pdf.js'),
         worker: require('resource://pdf.js/build/pdf.worker.js')
     };
 });
 
-var gLoadTimeout = 0;
-var gTimeoutHook = null;
-var gRemote = false;
-var gIgnoreWindowSize = false;
-var gShuffle = false;
-var gRepeat = null;
-var gRunUntilFailure = false;
-var gCleanupPendingCrashes = false;
-var gTotalChunks = 0;
-var gThisChunk = 0;
-var gContainingWindow = null;
-var gURLFilterRegex = {};
-var gContentGfxInfo = null;
-const FOCUS_FILTER_ALL_TESTS = "all";
-const FOCUS_FILTER_NEEDS_FOCUS_TESTS = "needs-focus";
-const FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS = "non-needs-focus";
-var gFocusFilterMode = FOCUS_FILTER_ALL_TESTS;
-var gCompareStyloToGecko = false;
-
-// "<!--CLEAR-->"
-const BLANK_URL_FOR_CLEARING = "data:text/html;charset=UTF-8,%3C%21%2D%2DCLEAR%2D%2D%3E";
-
-var gBrowser;
-// Are we testing web content loaded in a separate process?
-var gBrowserIsRemote;           // bool
-// Are we using <iframe mozbrowser>?
-var gBrowserIsIframe;           // bool
-var gBrowserMessageManager;
-var gCanvas1, gCanvas2;
-// gCurrentCanvas is non-null between InitCurrentCanvasWithSnapshot and the next
-// RecordResult.
-var gCurrentCanvas = null;
-var gURLs;
-var gManifestsLoaded = {};
-// Map from URI spec to the number of times it remains to be used
-var gURIUseCounts;
-// Map from URI spec to the canvas rendered for that URI
-var gURICanvases;
-var gTestResults = {
-  // Successful...
-  Pass: 0,
-  LoadOnly: 0,
-  // Unexpected...
-  Exception: 0,
-  FailedLoad: 0,
-  UnexpectedFail: 0,
-  UnexpectedPass: 0,
-  AssertionUnexpected: 0,
-  AssertionUnexpectedFixed: 0,
-  // Known problems...
-  KnownFail : 0,
-  AssertionKnown: 0,
-  Random : 0,
-  Skip: 0,
-  Slow: 0,
-};
-var gTotalTests = 0;
-var gState;
-var gCurrentURL;
-var gTestLog = [];
-var gLogLevel;
-var gServer;
-var gCount = 0;
-var gAssertionCount = 0;
-
-var gIOService;
-var gDebug;
-var gWindowUtils;
-
-var gSlowestTestTime = 0;
-var gSlowestTestURL;
-var gFailedUseWidgetLayers = false;
-
-var gDrawWindowFlags;
-
-var gExpectingProcessCrash = false;
-var gExpectedCrashDumpFiles = [];
-var gUnexpectedCrashDumpFiles = { };
-var gCrashDumpDir;
-var gPendingCrashDumpDir;
-var gFailedNoPaint = false;
-var gFailedOpaqueLayer = false;
-var gFailedOpaqueLayerMessages = [];
-var gFailedAssignedLayer = false;
-var gFailedAssignedLayerMessages = [];
-
-var gStartAfter = undefined;
-var gSuiteStarted = false
-
-// The enabled-state of the test-plugins, stored so they can be reset later
-var gTestPluginEnabledStates = null;
-
-const TYPE_REFTEST_EQUAL = '==';
-const TYPE_REFTEST_NOTEQUAL = '!=';
-const TYPE_LOAD = 'load';     // test without a reference (just test that it does
-                              // not assert, crash, hang, or leak)
-const TYPE_SCRIPT = 'script'; // test contains individual test results
-const TYPE_PRINT = 'print'; // test and reference will be printed to PDF's and
-                            // compared structurally
-
-// The order of these constants matters, since when we have a status
-// listed for a *manifest*, we combine the status with the status for
-// the test by using the *larger*.
-// FIXME: In the future, we may also want to use this rule for combining
-// statuses that are on the same line (rather than making the last one
-// win).
-const EXPECTED_PASS = 0;
-const EXPECTED_FAIL = 1;
-const EXPECTED_RANDOM = 2;
-const EXPECTED_DEATH = 3;  // test must be skipped to avoid e.g. crash/hang
-const EXPECTED_FUZZY = 4;
-
-// types of preference value we might want to set for a specific test
-const PREF_BOOLEAN = 0;
-const PREF_STRING  = 1;
-const PREF_INTEGER = 2;
-
-var gPrefsToRestore = [];
-
-const gProtocolRE = /^\w+:/;
-const gPrefItemRE = /^(|test-|ref-)pref\((.+?),(.*)\)$/;
-
-var gHttpServerPort = -1;
-
-// whether to run slow tests or not
-var gRunSlowTests = true;
-
-// whether we should skip caching canvases
-var gNoCanvasCache = false;
-
-var gRecycledCanvases = new Array();
-
-// Only dump the sandbox once, because it doesn't depend on the
-// manifest URL (yet!).
-var gDumpedConditionSandbox = false;
-
-var gTestPrintOutput = null;
-
 function HasUnexpectedResult()
 {
-    return gTestResults.Exception > 0 ||
-           gTestResults.FailedLoad > 0 ||
-           gTestResults.UnexpectedFail > 0 ||
-           gTestResults.UnexpectedPass > 0 ||
-           gTestResults.AssertionUnexpected > 0 ||
-           gTestResults.AssertionUnexpectedFixed > 0;
+    return g.testResults.Exception > 0 ||
+           g.testResults.FailedLoad > 0 ||
+           g.testResults.UnexpectedFail > 0 ||
+           g.testResults.UnexpectedPass > 0 ||
+           g.testResults.AssertionUnexpected > 0 ||
+           g.testResults.AssertionUnexpectedFixed > 0;
 }
 
 // By default we just log to stdout
-var gLogFile = null;
 var gDumpFn = function(line) {
   dump(line);
-  if (gLogFile) {
-    gLogFile.write(line, line.length);
+  if (g.logFile) {
+    g.logFile.write(line, line.length);
   }
 }
 var gDumpRawLog = function(record) {
   // Dump JSON representation of data on a single line
   var line = "\n" + JSON.stringify(record) + "\n";
   dump(line);
 
-  if (gLogFile) {
-    gLogFile.write(line, line.length);
+  if (g.logFile) {
+    g.logFile.write(line, line.length);
   }
 }
-var logger = new StructuredLogger('reftest', gDumpRawLog);
+g.logger = new StructuredLogger('reftest', gDumpRawLog);
+var logger = g.logger;
 
 function TestBuffer(str)
 {
   logger.debug(str);
-  gTestLog.push(str);
+  g.testLog.push(str);
 }
 
 function FlushTestBuffer()
 {
   // In debug mode, we've dumped all these messages already.
-  if (gLogLevel !== 'debug') {
-    for (var i = 0; i < gTestLog.length; ++i) {
-      logger.info("Saved log: " + gTestLog[i]);
+  if (g.logLevel !== 'debug') {
+    for (var i = 0; i < g.testLog.length; ++i) {
+      logger.info("Saved log: " + g.testLog[i]);
     }
   }
-  gTestLog = [];
+  g.testLog = [];
 }
 
 function LogWidgetLayersFailure()
 {
   logger.error("USE_WIDGET_LAYERS disabled because the screen resolution is too low. This falls back to an alternate rendering path (that may not be representative) and is not implemented with e10s enabled.");
   logger.error("Consider increasing your screen resolution, or adding '--disable-e10s' to your './mach reftest' command");
 }
 
 function AllocateCanvas()
 {
-    if (gRecycledCanvases.length > 0) {
-        return gRecycledCanvases.shift();
+    if (g.recycledCanvases.length > 0) {
+        return g.recycledCanvases.shift();
     }
 
-    var canvas = gContainingWindow.document.createElementNS(XHTML_NS, "canvas");
-    var r = gBrowser.getBoundingClientRect();
+    var canvas = g.containingWindow.document.createElementNS(XHTML_NS, "canvas");
+    var r = g.browser.getBoundingClientRect();
     canvas.setAttribute("width", Math.ceil(r.width));
     canvas.setAttribute("height", Math.ceil(r.height));
 
     return canvas;
 }
 
 function ReleaseCanvas(canvas)
 {
     // store a maximum of 2 canvases, if we're not caching
-    if (!gNoCanvasCache || gRecycledCanvases.length < 2) {
-        gRecycledCanvases.push(canvas);
+    if (!g.noCanvasCache || g.recycledCanvases.length < 2) {
+        g.recycledCanvases.push(canvas);
     }
 }
 
 function IDForEventTarget(event)
 {
     try {
         return "'" + event.target.getAttribute('id') + "'";
     } catch (ex) {
@@ -286,82 +132,82 @@ function getTestPlugin(aName) {
   }
 
   logger.warning("Failed to find the test-plugin.");
   return null;
 }
 
 function OnRefTestLoad(win)
 {
-    gCrashDumpDir = CC[NS_DIRECTORY_SERVICE_CONTRACTID]
+    g.crashDumpDir = CC[NS_DIRECTORY_SERVICE_CONTRACTID]
                     .getService(CI.nsIProperties)
                     .get("ProfD", CI.nsIFile);
-    gCrashDumpDir.append("minidumps");
+    g.crashDumpDir.append("minidumps");
 
-    gPendingCrashDumpDir = CC[NS_DIRECTORY_SERVICE_CONTRACTID]
+    g.pendingCrashDumpDir = CC[NS_DIRECTORY_SERVICE_CONTRACTID]
                     .getService(CI.nsIProperties)
                     .get("UAppData", CI.nsIFile);
-    gPendingCrashDumpDir.append("Crash Reports");
-    gPendingCrashDumpDir.append("pending");
+    g.pendingCrashDumpDir.append("Crash Reports");
+    g.pendingCrashDumpDir.append("pending");
 
     var env = CC["@mozilla.org/process/environment;1"].
               getService(CI.nsIEnvironment);
 
     var prefs = Components.classes["@mozilla.org/preferences-service;1"].
                 getService(Components.interfaces.nsIPrefBranch);
-    gBrowserIsRemote = prefs.getBoolPref("browser.tabs.remote.autostart", false);
+    g.browserIsRemote = prefs.getBoolPref("browser.tabs.remote.autostart", false);
 
-    gBrowserIsIframe = prefs.getBoolPref("reftest.browser.iframe.enabled", false);
+    g.browserIsIframe = prefs.getBoolPref("reftest.browser.iframe.enabled", false);
 
-    gLogLevel = prefs.getCharPref("reftest.logLevel", "info");
+    g.logLevel = prefs.getCharPref("reftest.logLevel", "info");
 
     if (win === undefined || win == null) {
       win = window;
     }
-    if (gContainingWindow == null && win != null) {
-      gContainingWindow = win;
+    if (g.containingWindow == null && win != null) {
+      g.containingWindow = win;
     }
 
-    if (gBrowserIsIframe) {
-      gBrowser = gContainingWindow.document.createElementNS(XHTML_NS, "iframe");
-      gBrowser.setAttribute("mozbrowser", "");
+    if (g.browserIsIframe) {
+      g.browser = g.containingWindow.document.createElementNS(XHTML_NS, "iframe");
+      g.browser.setAttribute("mozbrowser", "");
     } else {
-      gBrowser = gContainingWindow.document.createElementNS(XUL_NS, "xul:browser");
-      gBrowser.setAttribute("class", "lightweight");
+      g.browser = g.containingWindow.document.createElementNS(XUL_NS, "xul:browser");
+      g.browser.setAttribute("class", "lightweight");
     }
-    gBrowser.setAttribute("id", "browser");
-    gBrowser.setAttribute("type", "content");
-    gBrowser.setAttribute("primary", "true");
-    gBrowser.setAttribute("remote", gBrowserIsRemote ? "true" : "false");
+    g.browser.setAttribute("id", "browser");
+    g.browser.setAttribute("type", "content");
+    g.browser.setAttribute("primary", "true");
+    g.browser.setAttribute("remote", g.browserIsRemote ? "true" : "false");
     // Make sure the browser element is exactly 800x1000, no matter
     // what size our window is
-    gBrowser.setAttribute("style", "padding: 0px; margin: 0px; border:none; min-width: 800px; min-height: 1000px; max-width: 800px; max-height: 1000px");
+    g.browser.setAttribute("style", "padding: 0px; margin: 0px; border:none; min-width: 800px; min-height: 1000px; max-width: 800px; max-height: 1000px");
 
     if (Services.appinfo.OS == "Android") {
-      let doc = gContainingWindow.document.getElementById('main-window');
+      let doc = g.containingWindow.document.getElementById('main-window');
       while (doc.hasChildNodes()) {
         doc.firstChild.remove();
       }
-      doc.appendChild(gBrowser);
+      doc.appendChild(g.browser);
     } else {
-      document.getElementById("reftest-window").appendChild(gBrowser);
+      document.getElementById("reftest-window").appendChild(g.browser);
     }
 
     // reftests should have the test plugins enabled, not click-to-play
     let plugin1 = getTestPlugin("Test Plug-in");
     let plugin2 = getTestPlugin("Second Test Plug-in");
     if (plugin1 && plugin2) {
-      gTestPluginEnabledStates = [plugin1.enabledState, plugin2.enabledState];
+      g.testPluginEnabledStates = [plugin1.enabledState, plugin2.enabledState];
       plugin1.enabledState = CI.nsIPluginTag.STATE_ENABLED;
       plugin2.enabledState = CI.nsIPluginTag.STATE_ENABLED;
     } else {
       logger.warning("Could not get test plugin tags.");
     }
 
-    gBrowserMessageManager = gBrowser.frameLoader.messageManager;
+    g.browserMessageManager = g.browser.frameLoader.messageManager;
     // The content script waits for the initial onload, then notifies
     // us.
     RegisterMessageListenersAndLoadContentScript();
 }
 
 function InitAndStartRefTests()
 {
     /* These prefs are optional, so we don't need to spit an error to the log */
@@ -371,172 +217,171 @@ function InitAndStartRefTests()
     } catch(e) {
         logger.error("EXCEPTION: " + e);
     }
 
     try {
       prefs.setBoolPref("android.widget_paints_background", false);
     } catch (e) {}
 
-    /* set the gLoadTimeout */
+    /* set the g.loadTimeout */
     try {
-        gLoadTimeout = prefs.getIntPref("reftest.timeout");
+        g.loadTimeout = prefs.getIntPref("reftest.timeout");
     } catch(e) {
-        gLoadTimeout = 5 * 60 * 1000; //5 minutes as per bug 479518
+        g.loadTimeout = 5 * 60 * 1000; //5 minutes as per bug 479518
     }
 
     /* Get the logfile for android tests */
     try {
         var logFile = prefs.getCharPref("reftest.logFile");
         if (logFile) {
             var f = FileUtils.File(logFile);
-            gLogFile = FileUtils.openFileOutputStream(f, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
+            g.logFile = FileUtils.openFileOutputStream(f, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
         }
     } catch(e) {}
 
-    gRemote = prefs.getBoolPref("reftest.remote", false);
+    g.remote = prefs.getBoolPref("reftest.remote", false);
 
-    gIgnoreWindowSize = prefs.getBoolPref("reftest.ignoreWindowSize", false);
+    g.ignoreWindowSize = prefs.getBoolPref("reftest.ignoreWindowSize", false);
 
     /* Support for running a chunk (subset) of tests.  In separate try as this is optional */
     try {
-        gTotalChunks = prefs.getIntPref("reftest.totalChunks");
-        gThisChunk = prefs.getIntPref("reftest.thisChunk");
+        g.totalChunks = prefs.getIntPref("reftest.totalChunks");
+        g.thisChunk = prefs.getIntPref("reftest.thisChunk");
     }
     catch(e) {
-        gTotalChunks = 0;
-        gThisChunk = 0;
+        g.totalChunks = 0;
+        g.thisChunk = 0;
     }
 
     try {
-        gFocusFilterMode = prefs.getCharPref("reftest.focusFilterMode");
+        g.focusFilterMode = prefs.getCharPref("reftest.focusFilterMode");
     } catch(e) {}
 
     try {
-        gStartAfter = prefs.getCharPref("reftest.startAfter");
+        g.startAfter = prefs.getCharPref("reftest.startAfter");
     } catch(e) {
-        gStartAfter = undefined;
+        g.startAfter = undefined;
     }
 
 #ifdef MOZ_STYLO
     try {
-        gCompareStyloToGecko = prefs.getBoolPref("reftest.compareStyloToGecko");
+        g.compareStyloToGecko = prefs.getBoolPref("reftest.compareStyloToGecko");
     } catch(e) {}
 #endif
 
 #ifdef MOZ_ENABLE_SKIA_PDF
     try {
         // We have to disable printing via parent or else silent print operations
         // (the type that we use here) would be treated as non-silent -- in other
         // words, a print dialog would appear for each print operation, which
         // would interrupt the test run.
         // See http://searchfox.org/mozilla-central/rev/bd39b6170f04afeefc751a23bb04e18bbd10352b/layout/printing/nsPrintEngine.cpp#617
         prefs.setBoolPref("print.print_via_parent", false);
     } catch (e) {
         /* uh oh, print reftests may not work... */
     }
 #endif
 
-    gWindowUtils = gContainingWindow.QueryInterface(CI.nsIInterfaceRequestor).getInterface(CI.nsIDOMWindowUtils);
-    if (!gWindowUtils || !gWindowUtils.compareCanvases)
+    g.windowUtils = g.containingWindow.QueryInterface(CI.nsIInterfaceRequestor).getInterface(CI.nsIDOMWindowUtils);
+    if (!g.windowUtils || !g.windowUtils.compareCanvases)
         throw "nsIDOMWindowUtils inteface missing";
 
-    gIOService = CC[IO_SERVICE_CONTRACTID].getService(CI.nsIIOService);
-    gDebug = CC[DEBUG_CONTRACTID].getService(CI.nsIDebug2);
+    g.ioService = CC[IO_SERVICE_CONTRACTID].getService(CI.nsIIOService);
+    g.debug = CC[DEBUG_CONTRACTID].getService(CI.nsIDebug2);
 
     RegisterProcessCrashObservers();
 
-    if (gRemote) {
-        gServer = null;
+    if (g.remote) {
+        g.server = null;
     } else {
-        gServer = new HttpServer();
+        g.server = new HttpServer();
     }
     try {
-        if (gServer)
+        if (g.server)
             StartHTTPServer();
     } catch (ex) {
-        //gBrowser.loadURI('data:text/plain,' + ex);
-        ++gTestResults.Exception;
+        //g.browser.loadURI('data:text/plain,' + ex);
+        ++g.testResults.Exception;
         logger.error("EXCEPTION: " + ex);
         DoneTests();
     }
 
     // Focus the content browser.
-    if (gFocusFilterMode != FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS) {
-        gBrowser.addEventListener("focus", StartTests, true);
-        gBrowser.focus();
+    if (g.focusFilterMode != FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS) {
+        g.browser.addEventListener("focus", StartTests, true);
+        g.browser.focus();
     } else {
         StartTests();
     }
 }
 
 function StartHTTPServer()
 {
-    gServer.registerContentType("sjs", "sjs");
-    gServer.start(-1);
-    gHttpServerPort = gServer.identity.primaryPort;
+    g.server.registerContentType("sjs", "sjs");
+    g.server.start(-1);
+    g.httpServerPort = g.server.identity.primaryPort;
 }
 
 // Perform a Fisher-Yates shuffle of the array.
 function Shuffle(array)
 {
     for (var i = array.length - 1; i > 0; i--) {
         var j = Math.floor(Math.random() * (i + 1));
         var temp = array[i];
         array[i] = array[j];
         array[j] = temp;
     }
 }
 
 function StartTests()
 {
-    if (gFocusFilterMode != FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS) {
-        gBrowser.removeEventListener("focus", StartTests, true);
+    if (g.focusFilterMode != FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS) {
+        g.browser.removeEventListener("focus", StartTests, true);
     }
 
     var manifests;
     /* These prefs are optional, so we don't need to spit an error to the log */
     try {
         var prefs = Components.classes["@mozilla.org/preferences-service;1"].
                     getService(Components.interfaces.nsIPrefBranch);
     } catch(e) {
         logger.error("EXCEPTION: " + e);
     }
 
-    gNoCanvasCache = prefs.getIntPref("reftest.nocache", false);
+    g.noCanvasCache = prefs.getIntPref("reftest.nocache", false);
 
-    gShuffle = prefs.getBoolPref("reftest.shuffle", false);
+    g.shuffle = prefs.getBoolPref("reftest.shuffle", false);
 
-    gRunUntilFailure = prefs.getBoolPref("reftest.runUntilFailure", false);
+    g.runUntilFailure = prefs.getBoolPref("reftest.runUntilFailure", false);
 
-    gCleanupPendingCrashes = prefs.getBoolPref("reftest.cleanupPendingCrashes", false);
+    g.cleanupPendingCrashes = prefs.getBoolPref("reftest.cleanupPendingCrashes", false);
 
     // Check if there are any crash dump files from the startup procedure, before
     // we start running the first test. Otherwise the first test might get
     // blamed for producing a crash dump file when that was not the case.
     CleanUpCrashDumpFiles();
 
     // When we repeat this function is called again, so really only want to set
-    // gRepeat once.
-    if (gRepeat == null) {
-      gRepeat = prefs.getIntPref("reftest.repeat", 0);
+    // g.repeat once.
+    if (g.repeat == null) {
+      g.repeat = prefs.getIntPref("reftest.repeat", 0);
     }
 
-    gRunSlowTests = prefs.getIntPref("reftest.skipslowtests", false);
+    g.runSlowTests = prefs.getIntPref("reftest.skipslowtests", false);
 
-    if (gShuffle) {
-        gNoCanvasCache = true;
+    if (g.shuffle) {
+        g.noCanvasCache = true;
     }
 
-    gURLs = [];
-    gManifestsLoaded = {};
+    g.urls = [];
 
     try {
         var manifests = JSON.parse(prefs.getCharPref("reftest.manifests"));
-        gURLFilterRegex = manifests[null];
+        g.urlsFilterRegex = manifests[null];
     } catch(e) {
         logger.error("Unable to find reftest.manifests pref.  Please ensure your profile is setup properly");
         DoneTests();
     }
 
     try {
         var globalFilter = manifests.hasOwnProperty("") ? new RegExp(manifests[""]) : null;
         var manifestURLs = Object.keys(manifests);
@@ -549,919 +394,225 @@ function StartTests()
             var filter = manifests[manifestURL] ? new RegExp(manifests[manifestURL]) : null;
             ReadTopManifest(manifestURL, [globalFilter, filter, false]);
         });
         BuildUseCounts();
 
         // Filter tests which will be skipped to get a more even distribution when chunking
         // tURLs is a temporary array containing all active tests
         var tURLs = new Array();
-        for (var i = 0; i < gURLs.length; ++i) {
-            if (gURLs[i].expected == EXPECTED_DEATH)
+        for (var i = 0; i < g.urls.length; ++i) {
+            if (g.urls[i].expected == EXPECTED_DEATH)
                 continue;
 
-            if (gURLs[i].needsFocus && !Focus())
+            if (g.urls[i].needsFocus && !Focus())
                 continue;
 
-            if (gURLs[i].slow && !gRunSlowTests)
+            if (g.urls[i].slow && !g.runSlowTests)
                 continue;
 
-            tURLs.push(gURLs[i]);
+            tURLs.push(g.urls[i]);
         }
 
         var numActiveTests = tURLs.length;
 
-        if (gTotalChunks > 0 && gThisChunk > 0) {
+        if (g.totalChunks > 0 && g.thisChunk > 0) {
             // Calculate start and end indices of this chunk if tURLs array were
             // divided evenly
-            var testsPerChunk = tURLs.length / gTotalChunks;
-            var start = Math.round((gThisChunk-1) * testsPerChunk);
-            var end = Math.round(gThisChunk * testsPerChunk);
+            var testsPerChunk = tURLs.length / g.totalChunks;
+            var start = Math.round((g.thisChunk-1) * testsPerChunk);
+            var end = Math.round(g.thisChunk * testsPerChunk);
             numActiveTests = end - start;
 
-            // Map these indices onto the gURLs array. This avoids modifying the
-            // gURLs array which prevents skipped tests from showing up in the log
-            start = gThisChunk == 1 ? 0 : gURLs.indexOf(tURLs[start]);
-            end = gThisChunk == gTotalChunks ? gURLs.length : gURLs.indexOf(tURLs[end + 1]) - 1;
+            // Map these indices onto the g.urls array. This avoids modifying the
+            // g.urls array which prevents skipped tests from showing up in the log
+            start = g.thisChunk == 1 ? 0 : g.urls.indexOf(tURLs[start]);
+            end = g.thisChunk == g.totalChunks ? g.urls.length : g.urls.indexOf(tURLs[end + 1]) - 1;
 
-            logger.info("Running chunk " + gThisChunk + " out of " + gTotalChunks + " chunks.  " +
-                "tests " + (start+1) + "-" + end + "/" + gURLs.length);
+            logger.info("Running chunk " + g.thisChunk + " out of " + g.totalChunks + " chunks.  " +
+                "tests " + (start+1) + "-" + end + "/" + g.urls.length);
 
-            gURLs = gURLs.slice(start, end);
+            g.urls = g.urls.slice(start, end);
         }
 
-        if (gStartAfter === undefined && !gSuiteStarted) {
-            var ids = gURLs.map(function(obj) {
+        if (g.startAfter === undefined && !g.suiteStarted) {
+            var ids = g.urls.map(function(obj) {
                 return obj.identifier;
             });
-            logger.suiteStart(ids, {"skipped": gURLs.length - numActiveTests});
-            gSuiteStarted = true
+            logger.suiteStart(ids, {"skipped": g.urls.length - numActiveTests});
+            g.suiteStarted = true
         }
 
-        if (gShuffle) {
-            if (gStartAfter !== undefined) {
+        if (g.shuffle) {
+            if (g.startAfter !== undefined) {
                 logger.error("Can't resume from a crashed test when " +
                              "--shuffle is enabled, continue by shuffling " +
                              "all the tests");
                 DoneTests();
                 return;
             }
-            Shuffle(gURLs);
-        } else if (gStartAfter !== undefined) {
+            Shuffle(g.urls);
+        } else if (g.startAfter !== undefined) {
             // Skip through previously crashed test
             // We have to do this after chunking so we don't break the numbers
-            var crash_idx = gURLs.map(function(url) {
+            var crash_idx = g.urls.map(function(url) {
                 return url['url1']['spec'];
-            }).indexOf(gStartAfter);
+            }).indexOf(g.startAfter);
             if (crash_idx == -1) {
                 throw "Can't find the previously crashed test";
             }
-            gURLs = gURLs.slice(crash_idx + 1);
+            g.urls = g.urls.slice(crash_idx + 1);
         }
 
-        gTotalTests = gURLs.length;
+        g.totalTests = g.urls.length;
 
-        if (!gTotalTests)
+        if (!g.totalTests)
             throw "No tests to run";
 
-        gURICanvases = {};
+        g.uriCanvases = {};
         StartCurrentTest();
     } catch (ex) {
-        //gBrowser.loadURI('data:text/plain,' + ex);
-        ++gTestResults.Exception;
+        //g.browser.loadURI('data:text/plain,' + ex);
+        ++g.testResults.Exception;
         logger.error("EXCEPTION: " + ex);
         DoneTests();
     }
 }
 
 function OnRefTestUnload()
 {
   let plugin1 = getTestPlugin("Test Plug-in");
   let plugin2 = getTestPlugin("Second Test Plug-in");
   if (plugin1 && plugin2) {
-    plugin1.enabledState = gTestPluginEnabledStates[0];
-    plugin2.enabledState = gTestPluginEnabledStates[1];
+    plugin1.enabledState = g.testPluginEnabledStates[0];
+    plugin2.enabledState = g.testPluginEnabledStates[1];
   } else {
     logger.warning("Failed to get test plugin tags.");
   }
 }
 
-// Read all available data from an input stream and return it
-// as a string.
-function getStreamContent(inputStream)
-{
-    var streamBuf = "";
-    var sis = CC["@mozilla.org/scriptableinputstream;1"].
-                  createInstance(CI.nsIScriptableInputStream);
-    sis.init(inputStream);
-
-    var available;
-    while ((available = sis.available()) != 0) {
-        streamBuf += sis.read(available);
-    }
-
-    return streamBuf;
-}
-
-// Build the sandbox for fails-if(), etc., condition evaluation.
-function BuildConditionSandbox(aURL) {
-    var sandbox = new Components.utils.Sandbox(aURL.spec);
-    var xr = CC[NS_XREAPPINFO_CONTRACTID].getService(CI.nsIXULRuntime);
-    var appInfo = CC[NS_XREAPPINFO_CONTRACTID].getService(CI.nsIXULAppInfo);
-    sandbox.isDebugBuild = gDebug.isDebugBuild;
-    var prefs = CC["@mozilla.org/preferences-service;1"].
-                getService(CI.nsIPrefBranch);
-    var env = CC["@mozilla.org/process/environment;1"].
-                getService(CI.nsIEnvironment);
-
-    sandbox.xulRuntime = CU.cloneInto({widgetToolkit: xr.widgetToolkit, OS: xr.OS, XPCOMABI: xr.XPCOMABI}, sandbox);
-
-    var testRect = gBrowser.getBoundingClientRect();
-    sandbox.smallScreen = false;
-    if (gContainingWindow.innerWidth < 800 || gContainingWindow.innerHeight < 1000) {
-        sandbox.smallScreen = true;
-    }
-
-    var gfxInfo = (NS_GFXINFO_CONTRACTID in CC) && CC[NS_GFXINFO_CONTRACTID].getService(CI.nsIGfxInfo);
-    let readGfxInfo = function (obj, key) {
-      if (gContentGfxInfo && (key in gContentGfxInfo)) {
-        return gContentGfxInfo[key];
-      }
-      return obj[key];
-    }
-
-    try {
-      sandbox.d2d = readGfxInfo(gfxInfo, "D2DEnabled");
-      sandbox.dwrite = readGfxInfo(gfxInfo, "DWriteEnabled");
-    } catch (e) {
-      sandbox.d2d = false;
-      sandbox.dwrite = false;
-    }
-
-    var info = gfxInfo.getInfo();
-    var canvasBackend = readGfxInfo(info, "AzureCanvasBackend");
-    var contentBackend = readGfxInfo(info, "AzureContentBackend");
-    var canvasAccelerated = readGfxInfo(info, "AzureCanvasAccelerated");
-
-    sandbox.gpuProcess = gfxInfo.usingGPUProcess;
-    sandbox.azureCairo = canvasBackend == "cairo";
-    sandbox.azureSkia = canvasBackend == "skia";
-    sandbox.skiaContent = contentBackend == "skia";
-    sandbox.azureSkiaGL = canvasAccelerated; // FIXME: assumes GL right now
-    // true if we are using the same Azure backend for rendering canvas and content
-    sandbox.contentSameGfxBackendAsCanvas = contentBackend == canvasBackend
-                                            || (contentBackend == "none" && canvasBackend == "cairo");
-
-    sandbox.layersGPUAccelerated =
-      gWindowUtils.layerManagerType != "Basic";
-    sandbox.d3d11 =
-      gWindowUtils.layerManagerType == "Direct3D 11";
-    sandbox.d3d9 =
-      gWindowUtils.layerManagerType == "Direct3D 9";
-    sandbox.layersOpenGL =
-      gWindowUtils.layerManagerType == "OpenGL";
-    sandbox.webrender =
-      gWindowUtils.layerManagerType == "WebRender";
-    sandbox.layersOMTC =
-      gWindowUtils.layerManagerRemote == true;
-    sandbox.advancedLayers =
-      gWindowUtils.usingAdvancedLayers == true;
-    sandbox.layerChecksEnabled = !sandbox.webrender;
-
-    // Shortcuts for widget toolkits.
-    sandbox.Android = xr.OS == "Android";
-    sandbox.cocoaWidget = xr.widgetToolkit == "cocoa";
-    sandbox.gtkWidget = xr.widgetToolkit == "gtk2"
-                        || xr.widgetToolkit == "gtk3";
-    sandbox.qtWidget = xr.widgetToolkit == "qt";
-    sandbox.winWidget = xr.widgetToolkit == "windows";
-
-    // Scrollbars that are semi-transparent. See bug 1169666.
-    sandbox.transparentScrollbars = xr.widgetToolkit == "gtk3";
-
-    if (sandbox.Android) {
-        var sysInfo = CC["@mozilla.org/system-info;1"].getService(CI.nsIPropertyBag2);
-
-        // This is currently used to distinguish Android 4.0.3 (SDK version 15)
-        // and later from Android 2.x
-        sandbox.AndroidVersion = sysInfo.getPropertyAsInt32("version");
-    }
-
-#if MOZ_ASAN
-    sandbox.AddressSanitizer = true;
-#else
-    sandbox.AddressSanitizer = false;
-#endif
-
-#if MOZ_WEBRTC
-    sandbox.webrtc = true;
-#else
-    sandbox.webrtc = false;
-#endif
-
-#ifdef MOZ_STYLO
-    let styloEnabled = false;
-    // Perhaps a bit redundant in places, but this is easier to compare with the
-    // the real check in `nsLayoutUtils.cpp` to ensure they test the same way.
-    if (env.get("STYLO_FORCE_ENABLED")) {
-        styloEnabled = true;
-    } else if (env.get("STYLO_FORCE_DISABLED")) {
-        styloEnabled = false;
-    } else {
-        styloEnabled = prefs.getBoolPref("layout.css.servo.enabled", false);
-    }
-    sandbox.stylo = styloEnabled && !gCompareStyloToGecko;
-    sandbox.styloVsGecko = gCompareStyloToGecko;
-#else
-    sandbox.stylo = false;
-    sandbox.styloVsGecko = false;
-#endif
-
-// Printing via Skia PDF is only supported on Mac for now.
-#ifdef XP_MACOSX && MOZ_ENABLE_SKIA_PDF
-    sandbox.skiaPdf = true;
-#else
-    sandbox.skiaPdf = false;
-#endif
-
-#ifdef RELEASE_OR_BETA
-    sandbox.release_or_beta = true;
-#else
-    sandbox.release_or_beta = false;
-#endif
-
-    var hh = CC[NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX + "http"].
-                 getService(CI.nsIHttpProtocolHandler);
-    var httpProps = ["userAgent", "appName", "appVersion", "vendor",
-                     "vendorSub", "product", "productSub", "platform",
-                     "oscpu", "language", "misc"];
-    sandbox.http = new sandbox.Object();
-    httpProps.forEach((x) => sandbox.http[x] = hh[x]);
-
-    // Set OSX to be the Mac OS X version, as an integer, or undefined
-    // for other platforms.  The integer is formed by 100 times the
-    // major version plus the minor version, so 1006 for 10.6, 1010 for
-    // 10.10, etc.
-    var osxmatch = /Mac OS X (\d+).(\d+)$/.exec(hh.oscpu);
-    sandbox.OSX = osxmatch ? parseInt(osxmatch[1]) * 100 + parseInt(osxmatch[2]) : undefined;
-
-    // see if we have the test plugin available,
-    // and set a sandox prop accordingly
-    sandbox.haveTestPlugin = !sandbox.Android && !!getTestPlugin("Test Plug-in");
-
-    // Set a flag on sandbox if the windows default theme is active
-    sandbox.windowsDefaultTheme = gContainingWindow.matchMedia("(-moz-windows-default-theme)").matches;
-
-    try {
-        sandbox.nativeThemePref = !prefs.getBoolPref("mozilla.widget.disable-native-theme");
-    } catch (e) {
-        sandbox.nativeThemePref = true;
-    }
-    sandbox.gpuProcessForceEnabled = prefs.getBoolPref("layers.gpu-process.force-enabled", false);
-
-    sandbox.prefs = CU.cloneInto({
-        getBoolPref: function(p) { return prefs.getBoolPref(p); },
-        getIntPref:  function(p) { return prefs.getIntPref(p); }
-    }, sandbox, { cloneFunctions: true });
-
-    // Tests shouldn't care about this except for when they need to
-    // crash the content process
-    sandbox.browserIsRemote = gBrowserIsRemote;
-
-    try {
-        sandbox.asyncPan = gContainingWindow.document.docShell.asyncPanZoomEnabled;
-    } catch (e) {
-        sandbox.asyncPan = false;
-    }
-
-    // Graphics features
-    sandbox.usesRepeatResampling = sandbox.d2d;
-
-    if (!gDumpedConditionSandbox) {
-        logger.info("Dumping JSON representation of sandbox");
-        logger.info(JSON.stringify(CU.waiveXrays(sandbox)));
-        gDumpedConditionSandbox = true;
-    }
-
-    return sandbox;
-}
-
-function AddPrefSettings(aWhere, aPrefName, aPrefValExpression, aSandbox, aTestPrefSettings, aRefPrefSettings)
-{
-    var prefVal = Components.utils.evalInSandbox("(" + aPrefValExpression + ")", aSandbox);
-    var prefType;
-    var valType = typeof(prefVal);
-    if (valType == "boolean") {
-        prefType = PREF_BOOLEAN;
-    } else if (valType == "string") {
-        prefType = PREF_STRING;
-    } else if (valType == "number" && (parseInt(prefVal) == prefVal)) {
-        prefType = PREF_INTEGER;
-    } else {
-        return false;
-    }
-    var setting = { name: aPrefName,
-                    type: prefType,
-                    value: prefVal };
-
-    if (gCompareStyloToGecko && aPrefName != "layout.css.servo.enabled") {
-        // ref-pref() is ignored, test-pref() and pref() are added to both
-        if (aWhere != "ref-") {
-            aTestPrefSettings.push(setting);
-            aRefPrefSettings.push(setting);
-        }
-    } else {
-        if (aWhere != "ref-") {
-            aTestPrefSettings.push(setting);
-        }
-        if (aWhere != "test-") {
-            aRefPrefSettings.push(setting);
-        }
-    }
-    return true;
-}
-
-function ReadTopManifest(aFileURL, aFilter)
-{
-    var url = gIOService.newURI(aFileURL);
-    if (!url)
-        throw "Expected a file or http URL for the manifest.";
-    ReadManifest(url, EXPECTED_PASS, aFilter);
-}
-
-function AddTestItem(aTest, aFilter)
-{
-    if (!aFilter)
-        aFilter = [null, [], false];
-
-    var globalFilter = aFilter[0];
-    var manifestFilter = aFilter[1];
-    var invertManifest = aFilter[2];
-    if ((globalFilter && !globalFilter.test(aTest.url1.spec)) ||
-        (manifestFilter &&
-         !(invertManifest ^ manifestFilter.test(aTest.url1.spec))))
-        return;
-    if (gFocusFilterMode == FOCUS_FILTER_NEEDS_FOCUS_TESTS &&
-        !aTest.needsFocus)
-        return;
-    if (gFocusFilterMode == FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS &&
-        aTest.needsFocus)
-        return;
-
-    if (aTest.url2 !== null)
-        aTest.identifier = [aTest.prettyPath, aTest.type, aTest.url2.spec];
-    else
-        aTest.identifier = aTest.prettyPath;
-
-    gURLs.push(aTest);
-}
-
-function AddStyloTestPrefs(aSandbox, aTestPrefSettings, aRefPrefSettings)
-{
-    AddPrefSettings("test-", "layout.css.servo.enabled", "true", aSandbox,
-                    aTestPrefSettings, aRefPrefSettings);
-    AddPrefSettings("ref-", "layout.css.servo.enabled", "false", aSandbox,
-                    aTestPrefSettings, aRefPrefSettings);
-}
-
-function ExtractRange(matches, startIndex, defaultMin = 0) {
-    if (matches[startIndex + 1] === undefined) {
-        return {
-            min: defaultMin,
-            max: Number(matches[startIndex])
-        };
-    }
-    return {
-        min: Number(matches[startIndex]),
-        max: Number(matches[startIndex + 1].substring(1))
-    };
-}
-
-// Note: If you materially change the reftest manifest parsing,
-// please keep the parser in print-manifest-dirs.py in sync.
-function ReadManifest(aURL, inherited_status, aFilter)
-{
-    // Ensure each manifest is only read once. This assumes that manifests that are
-    // included with an unusual inherited_status or filters will be read via their
-    // include before they are read directly in the case of a duplicate
-    if (gManifestsLoaded.hasOwnProperty(aURL.spec)) {
-        if (gManifestsLoaded[aURL.spec] === null)
-            return;
-        else
-            aFilter = [aFilter[0], aFilter[1], true];
-    }
-    gManifestsLoaded[aURL.spec] = aFilter[1];
-
-    var secMan = CC[NS_SCRIPTSECURITYMANAGER_CONTRACTID]
-                     .getService(CI.nsIScriptSecurityManager);
-
-    var listURL = aURL;
-    var channel = NetUtil.newChannel({uri: aURL, loadUsingSystemPrincipal: true});
-    var inputStream = channel.open2();
-    if (channel instanceof Components.interfaces.nsIHttpChannel
-        && channel.responseStatus != 200) {
-      logger.error("HTTP ERROR : " + channel.responseStatus);
-    }
-    var streamBuf = getStreamContent(inputStream);
-    inputStream.close();
-    var lines = streamBuf.split(/\n|\r|\r\n/);
-
-    // Build the sandbox for fails-if(), etc., condition evaluation.
-    var sandbox = BuildConditionSandbox(aURL);
-    var lineNo = 0;
-    var urlprefix = "";
-    var defaultTestPrefSettings = [], defaultRefPrefSettings = [];
-    if (gCompareStyloToGecko) {
-        AddStyloTestPrefs(sandbox, defaultTestPrefSettings,
-                          defaultRefPrefSettings);
-    }
-    for (var str of lines) {
-        ++lineNo;
-        if (str.charAt(0) == "#")
-            continue; // entire line was a comment
-        var i = str.search(/\s+#/);
-        if (i >= 0)
-            str = str.substring(0, i);
-        // strip leading and trailing whitespace
-        str = str.replace(/^\s*/, '').replace(/\s*$/, '');
-        if (!str || str == "")
-            continue;
-        var items = str.split(/\s+/); // split on whitespace
-
-        if (items[0] == "url-prefix") {
-            if (items.length != 2)
-                throw "url-prefix requires one url in manifest file " + aURL.spec + " line " + lineNo;
-            urlprefix = items[1];
-            continue;
-        }
-
-        if (items[0] == "default-preferences") {
-            var m;
-            var item;
-            defaultTestPrefSettings = [];
-            defaultRefPrefSettings = [];
-            items.shift();
-            while ((item = items.shift())) {
-                if (!(m = item.match(gPrefItemRE))) {
-                    throw "Unexpected item in default-preferences list in manifest file " + aURL.spec + " line " + lineNo;
-                }
-                if (!AddPrefSettings(m[1], m[2], m[3], sandbox, defaultTestPrefSettings, defaultRefPrefSettings)) {
-                    throw "Error in pref value in manifest file " + aURL.spec + " line " + lineNo;
-                }
-            }
-            if (gCompareStyloToGecko) {
-                AddStyloTestPrefs(sandbox, defaultTestPrefSettings,
-                                  defaultRefPrefSettings);
-            }
-            continue;
-        }
-
-        var expected_status = EXPECTED_PASS;
-        var allow_silent_fail = false;
-        var minAsserts = 0;
-        var maxAsserts = 0;
-        var needs_focus = false;
-        var slow = false;
-        var testPrefSettings = defaultTestPrefSettings.concat();
-        var refPrefSettings = defaultRefPrefSettings.concat();
-        var fuzzy_delta = { min: 0, max: 2 };
-        var fuzzy_pixels = { min: 0, max: 1 };
-        var chaosMode = false;
-
-        while (items[0].match(/^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail|pref|test-pref|ref-pref|fuzzy|chaos-mode)/)) {
-            var item = items.shift();
-            var stat;
-            var cond;
-            var m = item.match(/^(fails|random|skip|silentfail)-if(\(.*\))$/);
-            if (m) {
-                stat = m[1];
-                // Note: m[2] contains the parentheses, and we want them.
-                cond = Components.utils.evalInSandbox(m[2], sandbox);
-            } else if (item.match(/^(fails|random|skip)$/)) {
-                stat = item;
-                cond = true;
-            } else if (item == "needs-focus") {
-                needs_focus = true;
-                cond = false;
-            } else if ((m = item.match(/^asserts\((\d+)(-\d+)?\)$/))) {
-                cond = false;
-                minAsserts = Number(m[1]);
-                maxAsserts = (m[2] == undefined) ? minAsserts
-                                                 : Number(m[2].substring(1));
-            } else if ((m = item.match(/^asserts-if\((.*?),(\d+)(-\d+)?\)$/))) {
-                cond = false;
-                if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox)) {
-                    minAsserts = Number(m[2]);
-                    maxAsserts =
-                      (m[3] == undefined) ? minAsserts
-                                          : Number(m[3].substring(1));
-                }
-            } else if (item == "slow") {
-                cond = false;
-                slow = true;
-            } else if ((m = item.match(/^require-or\((.*?)\)$/))) {
-                var args = m[1].split(/,/);
-                if (args.length != 2) {
-                    throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": wrong number of args to require-or";
-                }
-                var [precondition_str, fallback_action] = args;
-                var preconditions = precondition_str.split(/&&/);
-                cond = false;
-                for (var precondition of preconditions) {
-                    if (precondition === "debugMode") {
-                        // Currently unimplemented. Requires asynchronous
-                        // JSD call + getting an event while no JS is running
-                        stat = fallback_action;
-                        cond = true;
-                        break;
-                    } else if (precondition === "true") {
-                        // For testing
-                    } else {
-                        // Unknown precondition. Assume it is unimplemented.
-                        stat = fallback_action;
-                        cond = true;
-                        break;
-                    }
-                }
-            } else if ((m = item.match(/^slow-if\((.*?)\)$/))) {
-                cond = false;
-                if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox))
-                    slow = true;
-            } else if (item == "silentfail") {
-                cond = false;
-                allow_silent_fail = true;
-            } else if ((m = item.match(gPrefItemRE))) {
-                cond = false;
-                if (!AddPrefSettings(m[1], m[2], m[3], sandbox, testPrefSettings, refPrefSettings)) {
-                    throw "Error in pref value in manifest file " + aURL.spec + " line " + lineNo;
-                }
-            } else if ((m = item.match(/^fuzzy\((\d+)(-\d+)?,(\d+)(-\d+)?\)$/))) {
-              cond = false;
-              expected_status = EXPECTED_FUZZY;
-              fuzzy_delta = ExtractRange(m, 1);
-              fuzzy_pixels = ExtractRange(m, 3);
-            } else if ((m = item.match(/^fuzzy-if\((.*?),(\d+)(-\d+)?,(\d+)(-\d+)?\)$/))) {
-              cond = false;
-              if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox)) {
-                expected_status = EXPECTED_FUZZY;
-                fuzzy_delta = ExtractRange(m, 2);
-                fuzzy_pixels = ExtractRange(m, 4);
-              }
-            } else if (item == "chaos-mode") {
-                cond = false;
-                chaosMode = true;
-            } else {
-                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": unexpected item " + item;
-            }
-
-            if (cond) {
-                if (stat == "fails") {
-                    expected_status = EXPECTED_FAIL;
-                } else if (stat == "random") {
-                    expected_status = EXPECTED_RANDOM;
-                } else if (stat == "skip") {
-                    expected_status = EXPECTED_DEATH;
-                } else if (stat == "silentfail") {
-                    allow_silent_fail = true;
-                }
-            }
-        }
-
-        expected_status = Math.max(expected_status, inherited_status);
-
-        if (minAsserts > maxAsserts) {
-            throw "Bad range in manifest file " + aURL.spec + " line " + lineNo;
-        }
-
-        var runHttp = false;
-        var httpDepth;
-        if (items[0] == "HTTP") {
-            runHttp = (aURL.scheme == "file"); // We can't yet run the local HTTP server
-                                               // for non-local reftests.
-            httpDepth = 0;
-            items.shift();
-        } else if (items[0].match(/HTTP\(\.\.(\/\.\.)*\)/)) {
-            // Accept HTTP(..), HTTP(../..), HTTP(../../..), etc.
-            runHttp = (aURL.scheme == "file"); // We can't yet run the local HTTP server
-                                               // for non-local reftests.
-            httpDepth = (items[0].length - 5) / 3;
-            items.shift();
-        }
-
-        // do not prefix the url for include commands or urls specifying
-        // a protocol
-        if (urlprefix && items[0] != "include") {
-            if (items.length > 1 && !items[1].match(gProtocolRE)) {
-                items[1] = urlprefix + items[1];
-            }
-            if (items.length > 2 && !items[2].match(gProtocolRE)) {
-                items[2] = urlprefix + items[2];
-            }
-        }
-
-        var principal = secMan.createCodebasePrincipal(aURL, {});
-
-        if (items[0] == "include") {
-            if (items.length != 2)
-                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to include";
-            if (runHttp)
-                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": use of include with http";
-            var incURI = gIOService.newURI(items[1], null, listURL);
-            secMan.checkLoadURIWithPrincipal(principal, incURI,
-                                             CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
-            ReadManifest(incURI, expected_status, aFilter);
-        } else if (items[0] == TYPE_LOAD) {
-            if (items.length != 2)
-                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to load";
-            if (expected_status != EXPECTED_PASS &&
-                expected_status != EXPECTED_DEATH)
-                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect known failure type for load test";
-            var [testURI] = runHttp
-                            ? ServeFiles(principal, httpDepth,
-                                         listURL, [items[1]])
-                            : [gIOService.newURI(items[1], null, listURL)];
-            var prettyPath = runHttp
-                           ? gIOService.newURI(items[1], null, listURL).spec
-                           : testURI.spec;
-            secMan.checkLoadURIWithPrincipal(principal, testURI,
-                                             CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
-            AddTestItem({ type: TYPE_LOAD,
-                          expected: expected_status,
-                          allowSilentFail: allow_silent_fail,
-                          prettyPath: prettyPath,
-                          minAsserts: minAsserts,
-                          maxAsserts: maxAsserts,
-                          needsFocus: needs_focus,
-                          slow: slow,
-                          prefSettings1: testPrefSettings,
-                          prefSettings2: refPrefSettings,
-                          fuzzyMinDelta: fuzzy_delta.min,
-                          fuzzyMaxDelta: fuzzy_delta.max,
-                          fuzzyMinPixels: fuzzy_pixels.min,
-                          fuzzyMaxPixels: fuzzy_pixels.max,
-                          url1: testURI,
-                          url2: null,
-                          chaosMode: chaosMode }, aFilter);
-        } else if (items[0] == TYPE_SCRIPT) {
-            if (items.length != 2)
-                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to script";
-            var [testURI] = runHttp
-                            ? ServeFiles(principal, httpDepth,
-                                         listURL, [items[1]])
-                            : [gIOService.newURI(items[1], null, listURL)];
-            var prettyPath = runHttp
-                           ? gIOService.newURI(items[1], null, listURL).spec
-                           : testURI.spec;
-            secMan.checkLoadURIWithPrincipal(principal, testURI,
-                                             CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
-            AddTestItem({ type: TYPE_SCRIPT,
-                          expected: expected_status,
-                          allowSilentFail: allow_silent_fail,
-                          prettyPath: prettyPath,
-                          minAsserts: minAsserts,
-                          maxAsserts: maxAsserts,
-                          needsFocus: needs_focus,
-                          slow: slow,
-                          prefSettings1: testPrefSettings,
-                          prefSettings2: refPrefSettings,
-                          fuzzyMinDelta: fuzzy_delta.min,
-                          fuzzyMaxDelta: fuzzy_delta.max,
-                          fuzzyMinPixels: fuzzy_pixels.min,
-                          fuzzyMaxPixels: fuzzy_pixels.max,
-                          url1: testURI,
-                          url2: null,
-                          chaosMode: chaosMode }, aFilter);
-        } else if (items[0] == TYPE_REFTEST_EQUAL || items[0] == TYPE_REFTEST_NOTEQUAL || items[0] == TYPE_PRINT) {
-            if (items.length != 3)
-                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to " + items[0];
-
-            if (items[0] == TYPE_REFTEST_NOTEQUAL &&
-                expected_status == EXPECTED_FUZZY &&
-                (fuzzy_delta.min > 0 || fuzzy_pixels.min > 0)) {
-                throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": minimum fuzz must be zero for tests of type " + items[0];
-            }
-
-            var [testURI, refURI] = runHttp
-                                  ? ServeFiles(principal, httpDepth,
-                                               listURL, [items[1], items[2]])
-                                  : [gIOService.newURI(items[1], null, listURL),
-                                     gIOService.newURI(items[2], null, listURL)];
-            var prettyPath = runHttp
-                           ? gIOService.newURI(items[1], null, listURL).spec
-                           : testURI.spec;
-            secMan.checkLoadURIWithPrincipal(principal, testURI,
-                                             CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
-            secMan.checkLoadURIWithPrincipal(principal, refURI,
-                                             CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
-            var type = items[0];
-            if (gCompareStyloToGecko) {
-                type = TYPE_REFTEST_EQUAL;
-                refURI = testURI;
-
-                // We expect twice as many assertion failures when running in
-                // styloVsGecko mode because we run each test twice: once in
-                // Stylo mode and once in Gecko mode.
-                minAsserts *= 2;
-                maxAsserts *= 2;
-
-                // Skip the test if it is expected to fail in both Stylo and
-                // Gecko modes. It would unexpectedly "pass" in styloVsGecko
-                // mode when comparing the two failures, which is not a useful
-                // result.
-                if (expected_status === EXPECTED_FAIL ||
-                    expected_status === EXPECTED_RANDOM) {
-                    expected_status = EXPECTED_DEATH;
-                }
-            }
-
-            AddTestItem({ type: type,
-                          expected: expected_status,
-                          allowSilentFail: allow_silent_fail,
-                          prettyPath: prettyPath,
-                          minAsserts: minAsserts,
-                          maxAsserts: maxAsserts,
-                          needsFocus: needs_focus,
-                          slow: slow,
-                          prefSettings1: testPrefSettings,
-                          prefSettings2: refPrefSettings,
-                          fuzzyMinDelta: fuzzy_delta.min,
-                          fuzzyMaxDelta: fuzzy_delta.max,
-                          fuzzyMinPixels: fuzzy_pixels.min,
-                          fuzzyMaxPixels: fuzzy_pixels.max,
-                          url1: testURI,
-                          url2: refURI,
-                          chaosMode: chaosMode }, aFilter);
-        } else {
-            throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": unknown test type " + items[0];
-        }
-    }
-}
-
 function AddURIUseCount(uri)
 {
     if (uri == null)
         return;
 
     var spec = uri.spec;
-    if (spec in gURIUseCounts) {
-        gURIUseCounts[spec]++;
+    if (spec in g.uriUseCounts) {
+        g.uriUseCounts[spec]++;
     } else {
-        gURIUseCounts[spec] = 1;
+        g.uriUseCounts[spec] = 1;
     }
 }
 
 function BuildUseCounts()
 {
-    if (gNoCanvasCache) {
+    if (g.noCanvasCache) {
         return;
     }
 
-    gURIUseCounts = {};
-    for (var i = 0; i < gURLs.length; ++i) {
-        var url = gURLs[i];
+    g.uriUseCounts = {};
+    for (var i = 0; i < g.urls.length; ++i) {
+        var url = g.urls[i];
         if (url.expected != EXPECTED_DEATH &&
             (url.type == TYPE_REFTEST_EQUAL ||
              url.type == TYPE_REFTEST_NOTEQUAL)) {
             if (url.prefSettings1.length == 0) {
-                AddURIUseCount(gURLs[i].url1);
+                AddURIUseCount(g.urls[i].url1);
             }
             if (url.prefSettings2.length == 0) {
-                AddURIUseCount(gURLs[i].url2);
+                AddURIUseCount(g.urls[i].url2);
             }
         }
     }
 }
 
-function ServeFiles(manifestPrincipal, depth, aURL, files)
-{
-    var listURL = aURL.QueryInterface(CI.nsIFileURL);
-    var directory = listURL.file.parent;
-
-    // Allow serving a tree that's an ancestor of the directory containing
-    // the files so that they can use resources in ../ (etc.).
-    var dirPath = "/";
-    while (depth > 0) {
-        dirPath = "/" + directory.leafName + dirPath;
-        directory = directory.parent;
-        --depth;
-    }
-
-    gCount++;
-    var path = "/" + Date.now() + "/" + gCount;
-    gServer.registerDirectory(path + "/", directory);
-
-    var secMan = CC[NS_SCRIPTSECURITYMANAGER_CONTRACTID]
-                     .getService(CI.nsIScriptSecurityManager);
-
-    var testbase = gIOService.newURI("http://localhost:" + gHttpServerPort +
-                                     path + dirPath);
-
-    // Give the testbase URI access to XUL and XBL
-    Services.perms.add(testbase, "allowXULXBL", Services.perms.ALLOW_ACTION);
-
-    function FileToURI(file)
-    {
-        // Only serve relative URIs via the HTTP server, not absolute
-        // ones like about:blank.
-        var testURI = gIOService.newURI(file, null, testbase);
-
-        // XXX necessary?  manifestURL guaranteed to be file, others always HTTP
-        secMan.checkLoadURIWithPrincipal(manifestPrincipal, testURI,
-                                         CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
-
-        return testURI;
-    }
-
-    return files.map(FileToURI);
-}
-
 // Return true iff this window is focused when this function returns.
 function Focus()
 {
     var fm = CC["@mozilla.org/focus-manager;1"].getService(CI.nsIFocusManager);
-    fm.focusedWindow = gContainingWindow;
+    fm.focusedWindow = g.containingWindow;
 #ifdef XP_MACOSX
     try {
         var dock = CC["@mozilla.org/widget/macdocksupport;1"].getService(CI.nsIMacDockSupport);
         dock.activateApplication(true);
     } catch(ex) {
     }
 #endif // XP_MACOSX
     return true;
 }
 
 function Blur()
 {
     // On non-remote reftests, this will transfer focus to the dummy window
     // we created to hold focus for non-needs-focus tests.  Buggy tests
     // (ones which require focus but don't request needs-focus) will then
     // fail.
-    gContainingWindow.blur();
+    g.containingWindow.blur();
 }
 
 function StartCurrentTest()
 {
-    gTestLog = [];
+    g.testLog = [];
 
     // make sure we don't run tests that are expected to kill the browser
-    while (gURLs.length > 0) {
-        var test = gURLs[0];
+    while (g.urls.length > 0) {
+        var test = g.urls[0];
         logger.testStart(test.identifier);
         if (test.expected == EXPECTED_DEATH) {
-            ++gTestResults.Skip;
+            ++g.testResults.Skip;
             logger.testEnd(test.identifier, "SKIP");
-            gURLs.shift();
+            g.urls.shift();
         } else if (test.needsFocus && !Focus()) {
             // FIXME: Marking this as a known fail is dangerous!  What
             // if it starts failing all the time?
-            ++gTestResults.Skip;
+            ++g.testResults.Skip;
             logger.testEnd(test.identifier, "SKIP", null, "(COULDN'T GET FOCUS)");
-            gURLs.shift();
-        } else if (test.slow && !gRunSlowTests) {
-            ++gTestResults.Slow;
+            g.urls.shift();
+        } else if (test.slow && !g.runSlowTests) {
+            ++g.testResults.Slow;
             logger.testEnd(test.identifier, "SKIP", null, "(SLOW)");
-            gURLs.shift();
+            g.urls.shift();
         } else {
             break;
         }
     }
 
-    if ((gURLs.length == 0 && gRepeat == 0) ||
-        (gRunUntilFailure && HasUnexpectedResult())) {
+    if ((g.urls.length == 0 && g.repeat == 0) ||
+        (g.runUntilFailure && HasUnexpectedResult())) {
         RestoreChangedPreferences();
         DoneTests();
-    } else if (gURLs.length == 0 && gRepeat > 0) {
+    } else if (g.urls.length == 0 && g.repeat > 0) {
         // Repeat
-        gRepeat--;
+        g.repeat--;
         StartTests();
     } else {
-        if (gURLs[0].chaosMode) {
-            gWindowUtils.enterChaosMode();
+        if (g.urls[0].chaosMode) {
+            g.windowUtils.enterChaosMode();
         }
-        if (!gURLs[0].needsFocus) {
+        if (!g.urls[0].needsFocus) {
             Blur();
         }
-        var currentTest = gTotalTests - gURLs.length;
-        gContainingWindow.document.title = "reftest: " + currentTest + " / " + gTotalTests +
-            " (" + Math.floor(100 * (currentTest / gTotalTests)) + "%)";
+        var currentTest = g.totalTests - g.urls.length;
+        g.containingWindow.document.title = "reftest: " + currentTest + " / " + g.totalTests +
+            " (" + Math.floor(100 * (currentTest / g.totalTests)) + "%)";
         StartCurrentURI(1);
     }
 }
 
 function StartCurrentURI(aState)
 {
-    gState = aState;
-    gCurrentURL = gURLs[0]["url" + aState].spec;
+    g.state = aState;
+    g.currentURL = g.urls[0]["url" + aState].spec;
 
     RestoreChangedPreferences();
 
     var prefs = Components.classes["@mozilla.org/preferences-service;1"].
         getService(Components.interfaces.nsIPrefBranch);
 
-    var prefSettings = gURLs[0]["prefSettings" + aState];
+    var prefSettings = g.urls[0]["prefSettings" + aState];
     if (prefSettings.length > 0) {
         var badPref = undefined;
         try {
             prefSettings.forEach(function(ps) {
                 var oldVal;
                 if (ps.type == PREF_BOOLEAN) {
                     try {
                         oldVal = prefs.getBoolPref(ps.name);
@@ -1482,231 +633,231 @@ function StartCurrentURI(aState)
                     } catch (e) {
                         badPref = "integer preference '" + ps.name + "'";
                         throw "bad pref";
                     }
                 } else {
                     throw "internal error - unknown preference type";
                 }
                 if (oldVal != ps.value) {
-                    gPrefsToRestore.push( { name: ps.name,
+                    g.prefsToRestore.push( { name: ps.name,
                                             type: ps.type,
                                             value: oldVal } );
                     var value = ps.value;
                     if (ps.type == PREF_BOOLEAN) {
                         prefs.setBoolPref(ps.name, value);
                     } else if (ps.type == PREF_STRING) {
                         prefs.setCharPref(ps.name, value);
                         value = '"' + value + '"';
                     } else if (ps.type == PREF_INTEGER) {
                         prefs.setIntPref(ps.name, value);
                     }
                     logger.info("SET PREFERENCE pref(" + ps.name + "," + value + ")");
                 }
             });
         } catch (e) {
             if (e == "bad pref") {
-                var test = gURLs[0];
+                var test = g.urls[0];
                 if (test.expected == EXPECTED_FAIL) {
                     logger.testEnd(test.identifier, "FAIL", "FAIL",
                                    "(SKIPPED; " + badPref + " not known or wrong type)");
-                    ++gTestResults.Skip;
+                    ++g.testResults.Skip;
                 } else {
                     logger.testEnd(test.identifier, "FAIL", "PASS",
                                    badPref + " not known or wrong type");
-                    ++gTestResults.UnexpectedFail;
+                    ++g.testResults.UnexpectedFail;
                 }
 
                 // skip the test that had a bad preference
-                gURLs.shift();
+                g.urls.shift();
                 StartCurrentTest();
                 return;
             } else {
                 throw e;
             }
         }
     }
 
     if (prefSettings.length == 0 &&
-        gURICanvases[gCurrentURL] &&
-        (gURLs[0].type == TYPE_REFTEST_EQUAL ||
-         gURLs[0].type == TYPE_REFTEST_NOTEQUAL) &&
-        gURLs[0].maxAsserts == 0) {
+        g.uriCanvases[g.currentURL] &&
+        (g.urls[0].type == TYPE_REFTEST_EQUAL ||
+         g.urls[0].type == TYPE_REFTEST_NOTEQUAL) &&
+        g.urls[0].maxAsserts == 0) {
         // Pretend the document loaded --- RecordResult will notice
         // there's already a canvas for this URL
-        gContainingWindow.setTimeout(RecordResult, 0);
+        g.containingWindow.setTimeout(RecordResult, 0);
     } else {
-        var currentTest = gTotalTests - gURLs.length;
+        var currentTest = g.totalTests - g.urls.length;
         // Log this to preserve the same overall log format,
         // should be removed if the format is updated
-        gDumpFn("REFTEST TEST-LOAD | " + gCurrentURL + " | " + currentTest + " / " + gTotalTests +
-                " (" + Math.floor(100 * (currentTest / gTotalTests)) + "%)\n");
-        TestBuffer("START " + gCurrentURL);
-        var type = gURLs[0].type
+        gDumpFn("REFTEST TEST-LOAD | " + g.currentURL + " | " + currentTest + " / " + g.totalTests +
+                " (" + Math.floor(100 * (currentTest / g.totalTests)) + "%)\n");
+        TestBuffer("START " + g.currentURL);
+        var type = g.urls[0].type
         if (TYPE_SCRIPT == type) {
-            SendLoadScriptTest(gCurrentURL, gLoadTimeout);
+            SendLoadScriptTest(g.currentURL, g.loadTimeout);
         } else if (TYPE_PRINT == type) {
-            SendLoadPrintTest(gCurrentURL, gLoadTimeout);
+            SendLoadPrintTest(g.currentURL, g.loadTimeout);
         } else {
-            SendLoadTest(type, gCurrentURL, gLoadTimeout);
+            SendLoadTest(type, g.currentURL, g.loadTimeout);
         }
     }
 }
 
 function DoneTests()
 {
-    logger.suiteEnd({'results': gTestResults});
-    gSuiteStarted = false
-    logger.info("Slowest test took " + gSlowestTestTime + "ms (" + gSlowestTestURL + ")");
-    logger.info("Total canvas count = " + gRecycledCanvases.length);
-    if (gFailedUseWidgetLayers) {
+    logger.suiteEnd({'results': g.testResults});
+    g.suiteStarted = false
+    logger.info("Slowest test took " + g.slowestTestTime + "ms (" + g.slowestTestURL + ")");
+    logger.info("Total canvas count = " + g.recycledCanvases.length);
+    if (g.failedUseWidgetLayers) {
         LogWidgetLayersFailure();
     }
 
     function onStopped() {
         let appStartup = CC["@mozilla.org/toolkit/app-startup;1"].getService(CI.nsIAppStartup);
         appStartup.quit(CI.nsIAppStartup.eForceQuit);
     }
-    if (gServer) {
-        gServer.stop(onStopped);
+    if (g.server) {
+        g.server.stop(onStopped);
     }
     else {
         onStopped();
     }
 }
 
 function UpdateCanvasCache(url, canvas)
 {
     var spec = url.spec;
 
-    --gURIUseCounts[spec];
+    --g.uriUseCounts[spec];
 
-    if (gURIUseCounts[spec] == 0) {
+    if (g.uriUseCounts[spec] == 0) {
         ReleaseCanvas(canvas);
-        delete gURICanvases[spec];
-    } else if (gURIUseCounts[spec] > 0) {
-        gURICanvases[spec] = canvas;
+        delete g.uriCanvases[spec];
+    } else if (g.uriUseCounts[spec] > 0) {
+        g.uriCanvases[spec] = canvas;
     } else {
         throw "Use counts were computed incorrectly";
     }
 }
 
 // Recompute drawWindow flags for every drawWindow operation.
 // We have to do this every time since our window can be
 // asynchronously resized (e.g. by the window manager, to make
 // it fit on screen) at unpredictable times.
 // Fortunately this is pretty cheap.
 function DoDrawWindow(ctx, x, y, w, h)
 {
     var flags = ctx.DRAWWINDOW_DRAW_CARET | ctx.DRAWWINDOW_DRAW_VIEW;
-    var testRect = gBrowser.getBoundingClientRect();
-    if (gIgnoreWindowSize ||
+    var testRect = g.browser.getBoundingClientRect();
+    if (g.ignoreWindowSize ||
         (0 <= testRect.left &&
          0 <= testRect.top &&
-         gContainingWindow.innerWidth >= testRect.right &&
-         gContainingWindow.innerHeight >= testRect.bottom)) {
+         g.containingWindow.innerWidth >= testRect.right &&
+         g.containingWindow.innerHeight >= testRect.bottom)) {
         // We can use the window's retained layer manager
         // because the window is big enough to display the entire
         // browser element
         flags |= ctx.DRAWWINDOW_USE_WIDGET_LAYERS;
-    } else if (gBrowserIsRemote) {
-        logger.error(gCurrentURL + " | can't drawWindow remote content");
-        ++gTestResults.Exception;
+    } else if (g.browserIsRemote) {
+        logger.error(g.currentURL + " | can't drawWindow remote content");
+        ++g.testResults.Exception;
     }
 
-    if (gDrawWindowFlags != flags) {
+    if (g.drawWindowFlags != flags) {
         // Every time the flags change, dump the new state.
-        gDrawWindowFlags = flags;
+        g.drawWindowFlags = flags;
         var flagsStr = "DRAWWINDOW_DRAW_CARET | DRAWWINDOW_DRAW_VIEW";
         if (flags & ctx.DRAWWINDOW_USE_WIDGET_LAYERS) {
             flagsStr += " | DRAWWINDOW_USE_WIDGET_LAYERS";
         } else {
             // Output a special warning because we need to be able to detect
             // this whenever it happens.
             LogWidgetLayersFailure();
-            gFailedUseWidgetLayers = true;
+            g.failedUseWidgetLayers = true;
         }
         logger.info("drawWindow flags = " + flagsStr +
-                    "; window size = " + gContainingWindow.innerWidth + "," + gContainingWindow.innerHeight +
+                    "; window size = " + g.containingWindow.innerWidth + "," + g.containingWindow.innerHeight +
                     "; test browser size = " + testRect.width + "," + testRect.height);
     }
 
     TestBuffer("DoDrawWindow " + x + "," + y + "," + w + "," + h);
-    ctx.drawWindow(gContainingWindow, x, y, w, h, "rgb(255,255,255)",
-                   gDrawWindowFlags);
+    ctx.drawWindow(g.containingWindow, x, y, w, h, "rgb(255,255,255)",
+                   g.drawWindowFlags);
 }
 
 function InitCurrentCanvasWithSnapshot()
 {
     TestBuffer("Initializing canvas snapshot");
 
-    if (gURLs[0].type == TYPE_LOAD || gURLs[0].type == TYPE_SCRIPT || gURLs[0].type == TYPE_PRINT) {
+    if (g.urls[0].type == TYPE_LOAD || g.urls[0].type == TYPE_SCRIPT || g.urls[0].type == TYPE_PRINT) {
         // We don't want to snapshot this kind of test
         return false;
     }
 
-    if (!gCurrentCanvas) {
-        gCurrentCanvas = AllocateCanvas();
+    if (!g.currentCanvas) {
+        g.currentCanvas = AllocateCanvas();
     }
 
-    var ctx = gCurrentCanvas.getContext("2d");
-    DoDrawWindow(ctx, 0, 0, gCurrentCanvas.width, gCurrentCanvas.height);
+    var ctx = g.currentCanvas.getContext("2d");
+    DoDrawWindow(ctx, 0, 0, g.currentCanvas.width, g.currentCanvas.height);
     return true;
 }
 
 function UpdateCurrentCanvasForInvalidation(rects)
 {
     TestBuffer("Updating canvas for invalidation");
 
-    if (!gCurrentCanvas) {
+    if (!g.currentCanvas) {
         return;
     }
 
-    var ctx = gCurrentCanvas.getContext("2d");
+    var ctx = g.currentCanvas.getContext("2d");
     for (var i = 0; i < rects.length; ++i) {
         var r = rects[i];
         // Set left/top/right/bottom to pixel boundaries
         var left = Math.floor(r.left);
         var top = Math.floor(r.top);
         var right = Math.ceil(r.right);
         var bottom = Math.ceil(r.bottom);
 
         // Clamp the values to the canvas size
-        left = Math.max(0, Math.min(left, gCurrentCanvas.width));
-        top = Math.max(0, Math.min(top, gCurrentCanvas.height));
-        right = Math.max(0, Math.min(right, gCurrentCanvas.width));
-        bottom = Math.max(0, Math.min(bottom, gCurrentCanvas.height));
+        left = Math.max(0, Math.min(left, g.currentCanvas.width));
+        top = Math.max(0, Math.min(top, g.currentCanvas.height));
+        right = Math.max(0, Math.min(right, g.currentCanvas.width));
+        bottom = Math.max(0, Math.min(bottom, g.currentCanvas.height));
 
         ctx.save();
         ctx.translate(left, top);
         DoDrawWindow(ctx, left, top, right - left, bottom - top);
         ctx.restore();
     }
 }
 
 function UpdateWholeCurrentCanvasForInvalidation()
 {
     TestBuffer("Updating entire canvas for invalidation");
 
-    if (!gCurrentCanvas) {
+    if (!g.currentCanvas) {
         return;
     }
 
-    var ctx = gCurrentCanvas.getContext("2d");
-    DoDrawWindow(ctx, 0, 0, gCurrentCanvas.width, gCurrentCanvas.height);
+    var ctx = g.currentCanvas.getContext("2d");
+    DoDrawWindow(ctx, 0, 0, g.currentCanvas.width, g.currentCanvas.height);
 }
 
 function RecordResult(testRunTime, errorMsg, typeSpecificResults)
 {
     TestBuffer("RecordResult fired");
 
     // Keep track of which test was slowest, and how long it took.
-    if (testRunTime > gSlowestTestTime) {
-        gSlowestTestTime = testRunTime;
-        gSlowestTestURL  = gCurrentURL;
+    if (testRunTime > g.slowestTestTime) {
+        g.slowestTestTime = testRunTime;
+        g.slowestTestURL  = g.currentURL;
     }
 
     // Not 'const ...' because of 'EXPECTED_*' value dependency.
     var outputs = {};
     outputs[EXPECTED_PASS] = {
         true:  {s: ["PASS", "PASS"], n: "Pass"},
         false: {s: ["FAIL", "PASS"], n: "UnexpectedFail"}
     };
@@ -1719,45 +870,45 @@ function RecordResult(testRunTime, error
         false: {s: ["FAIL", "FAIL"], n: "Random"}
     };
     // for EXPECTED_FUZZY we need special handling because we can have
     // Pass, UnexpectedPass, or UnexpectedFail
 
     var output;
     var extra;
 
-    if (gURLs[0].type == TYPE_LOAD) {
-        ++gTestResults.LoadOnly;
-        logger.testStatus(gURLs[0].identifier, "(LOAD ONLY)", "PASS", "PASS");
-        gCurrentCanvas = null;
+    if (g.urls[0].type == TYPE_LOAD) {
+        ++g.testResults.LoadOnly;
+        logger.testStatus(g.urls[0].identifier, "(LOAD ONLY)", "PASS", "PASS");
+        g.currentCanvas = null;
         FinishTestItem();
         return;
     }
-    if (gURLs[0].type == TYPE_PRINT) {
-        switch (gState) {
+    if (g.urls[0].type == TYPE_PRINT) {
+        switch (g.state) {
         case 1:
             // First document has been loaded.
-            gTestPrintOutput = typeSpecificResults;
+            g.testPrintOutput = typeSpecificResults;
             // Proceed to load the second document.
             CleanUpCrashDumpFiles();
             StartCurrentURI(2);
             break;
         case 2:
-            let pathToTestPdf = gTestPrintOutput;
+            let pathToTestPdf = g.testPrintOutput;
             let pathToRefPdf = typeSpecificResults;
             comparePdfs(pathToTestPdf, pathToRefPdf, function(error, results) {
-                let expected = gURLs[0].expected;
+                let expected = g.urls[0].expected;
                 // TODO: We should complain here if results is empty!
                 // (If it's empty, we'll spuriously succeed, regardless of
                 // our expectations)
                 if (error) {
                     output = outputs[expected][false];
                     extra = { status_msg: output.n };
-                    ++gTestResults[output.n];
-                    logger.testEnd(gURLs[0].identifier, output.s[0], output.s[1],
+                    ++g.testResults[output.n];
+                    logger.testEnd(g.urls[0].identifier, output.s[0], output.s[1],
                                    error.message, null, extra);
                 } else {
                     let outputPair = outputs[expected];
                     if (expected === EXPECTED_FAIL) {
                        let failureResults = results.filter(function (result) { return !result.passed });
                        if (failureResults.length > 0) {
                          // We got an expected failure. Let's get rid of the
                          // passes from the results so we don't trigger
@@ -1765,50 +916,50 @@ function RecordResult(testRunTime, error
                          results = failureResults;
                        }
                        // (else, we expected a failure but got none!
                        // Leave results untouched so we can log them.)
                     }
                     results.forEach(function(result) {
                         output = outputPair[result.passed];
                         let extra = { status_msg: output.n };
-                        ++gTestResults[output.n];
-                        logger.testEnd(gURLs[0].identifier, output.s[0], output.s[1],
+                        ++g.testResults[output.n];
+                        logger.testEnd(g.urls[0].identifier, output.s[0], output.s[1],
                                        result.description, null, extra);
                     });
                 }
                 FinishTestItem();
             });
             break;
         default:
             throw "Unexpected state.";
         }
         return;
     }
-    if (gURLs[0].type == TYPE_SCRIPT) {
-        var expected = gURLs[0].expected;
+    if (g.urls[0].type == TYPE_SCRIPT) {
+        var expected = g.urls[0].expected;
 
         if (errorMsg) {
             // Force an unexpected failure to alert the test author to fix the test.
             expected = EXPECTED_PASS;
         } else if (typeSpecificResults.length == 0) {
              // This failure may be due to a JavaScript Engine bug causing
              // early termination of the test. If we do not allow silent
              // failure, report an error.
-             if (!gURLs[0].allowSilentFail)
+             if (!g.urls[0].allowSilentFail)
                  errorMsg = "No test results reported. (SCRIPT)\n";
              else
                  logger.info("An expected silent failure occurred");
         }
 
         if (errorMsg) {
             output = outputs[expected][false];
             extra = { status_msg: output.n };
-            ++gTestResults[output.n];
-            logger.testStatus(gURLs[0].identifier, errorMsg, output.s[0], output.s[1], null, null, extra);
+            ++g.testResults[output.n];
+            logger.testStatus(g.urls[0].identifier, errorMsg, output.s[0], output.s[1], null, null, extra);
             FinishTestItem();
             return;
         }
 
         var anyFailed = typeSpecificResults.some(function(result) { return !result.passed; });
         var outputPair;
         if (anyFailed && expected == EXPECTED_FAIL) {
             // If we're marked as expected to fail, and some (but not all) tests
@@ -1820,47 +971,47 @@ function RecordResult(testRunTime, error
         } else {
             outputPair = outputs[expected];
         }
         var index = 0;
         typeSpecificResults.forEach(function(result) {
                 var output = outputPair[result.passed];
                 var extra = { status_msg: output.n };
 
-                ++gTestResults[output.n];
-                logger.testStatus(gURLs[0].identifier, result.description + " item " + (++index),
+                ++g.testResults[output.n];
+                logger.testStatus(g.urls[0].identifier, result.description + " item " + (++index),
                                   output.s[0], output.s[1], null, null, extra);
             });
 
         if (anyFailed && expected == EXPECTED_PASS) {
             FlushTestBuffer();
         }
 
         FinishTestItem();
         return;
     }
 
-    if (gURLs[0]["prefSettings" + gState].length == 0 &&
-        gURICanvases[gCurrentURL]) {
-        gCurrentCanvas = gURICanvases[gCurrentURL];
+    if (g.urls[0]["prefSettings" + g.state].length == 0 &&
+        g.uriCanvases[g.currentURL]) {
+        g.currentCanvas = g.uriCanvases[g.currentURL];
     }
-    if (gCurrentCanvas == null) {
-        logger.error(gCurrentURL, "program error managing snapshots");
-        ++gTestResults.Exception;
+    if (g.currentCanvas == null) {
+        logger.error(g.currentURL, "program error managing snapshots");
+        ++g.testResults.Exception;
     }
-    if (gState == 1) {
-        gCanvas1 = gCurrentCanvas;
+    if (g.state == 1) {
+        g.canvas1 = g.currentCanvas;
     } else {
-        gCanvas2 = gCurrentCanvas;
+        g.canvas2 = g.currentCanvas;
     }
-    gCurrentCanvas = null;
+    g.currentCanvas = null;
 
     ResetRenderingState();
 
-    switch (gState) {
+    switch (g.state) {
         case 1:
             // First document has been loaded.
             // Proceed to load the second document.
 
             CleanUpCrashDumpFiles();
             StartCurrentURI(2);
             break;
         case 2:
@@ -1872,48 +1023,48 @@ function RecordResult(testRunTime, error
             var differences;
             // whether the two renderings match:
             var equal;
             var maxDifference = {};
             // whether the allowed fuzziness from the annotations is exceeded
             // by the actual comparison results
             var fuzz_exceeded = false;
 
-            differences = gWindowUtils.compareCanvases(gCanvas1, gCanvas2, maxDifference);
+            differences = g.windowUtils.compareCanvases(g.canvas1, g.canvas2, maxDifference);
             equal = (differences == 0);
 
             if (maxDifference.value > 0 && equal) {
                 throw "Inconsistent result from compareCanvases.";
             }
 
             // what is expected on this platform (PASS, FAIL, or RANDOM)
-            var expected = gURLs[0].expected;
+            var expected = g.urls[0].expected;
 
             if (expected == EXPECTED_FUZZY) {
                 logger.info(`REFTEST fuzzy test ` +
-                            `(${gURLs[0].fuzzyMinDelta}, ${gURLs[0].fuzzyMinPixels}) <= ` +
+                            `(${g.urls[0].fuzzyMinDelta}, ${g.urls[0].fuzzyMinPixels}) <= ` +
                             `(${maxDifference.value}, ${differences}) <= ` +
-                            `(${gURLs[0].fuzzyMaxDelta}, ${gURLs[0].fuzzyMaxPixels})`);
-                fuzz_exceeded = maxDifference.value > gURLs[0].fuzzyMaxDelta ||
-                                differences > gURLs[0].fuzzyMaxPixels;
+                            `(${g.urls[0].fuzzyMaxDelta}, ${g.urls[0].fuzzyMaxPixels})`);
+                fuzz_exceeded = maxDifference.value > g.urls[0].fuzzyMaxDelta ||
+                                differences > g.urls[0].fuzzyMaxPixels;
                 equal = !fuzz_exceeded &&
-                        maxDifference.value >= gURLs[0].fuzzyMinDelta &&
-                        differences >= gURLs[0].fuzzyMinPixels;
+                        maxDifference.value >= g.urls[0].fuzzyMinDelta &&
+                        differences >= g.urls[0].fuzzyMinPixels;
             }
 
-            var failedExtraCheck = gFailedNoPaint || gFailedOpaqueLayer || gFailedAssignedLayer;
+            var failedExtraCheck = g.failedNoPaint || g.failedOpaqueLayer || g.failedAssignedLayer;
 
             // whether the comparison result matches what is in the manifest
-            var test_passed = (equal == (gURLs[0].type == TYPE_REFTEST_EQUAL)) && !failedExtraCheck;
+            var test_passed = (equal == (g.urls[0].type == TYPE_REFTEST_EQUAL)) && !failedExtraCheck;
 
             if (expected != EXPECTED_FUZZY) {
                 output = outputs[expected][test_passed];
             } else if (test_passed) {
                 output = {s: ["PASS", "PASS"], n: "Pass"};
-            } else if (gURLs[0].type == TYPE_REFTEST_EQUAL &&
+            } else if (g.urls[0].type == TYPE_REFTEST_EQUAL &&
                        !failedExtraCheck &&
                        !fuzz_exceeded) {
                 // If we get here, that means we had an '==' type test where
                 // at least one of the actual difference values was below the
                 // allowed range, but nothing else was wrong. So let's produce
                 // UNEXPECTED-PASS in this scenario. Also, if we enter this
                 // branch, 'equal' must be false so let's assert that to guard
                 // against logic errors.
@@ -1922,74 +1073,74 @@ function RecordResult(testRunTime, error
                 }
                 output = {s: ["PASS", "FAIL"], n: "UnexpectedPass"};
             } else {
                 // In all other cases we fail the test
                 output = {s: ["FAIL", "PASS"], n: "UnexpectedFail"};
             }
             extra = { status_msg: output.n };
 
-            ++gTestResults[output.n];
+            ++g.testResults[output.n];
 
             // It's possible that we failed both an "extra check" and the normal comparison, but we don't
             // have a way to annotate these separately, so just print an error for the extra check failures.
             if (failedExtraCheck) {
                 var failures = [];
-                if (gFailedNoPaint) {
+                if (g.failedNoPaint) {
                     failures.push("failed reftest-no-paint");
                 }
-                // The gFailed*Messages arrays will contain messages from both the test and the reference.
-                if (gFailedOpaqueLayer) {
-                    failures.push("failed reftest-opaque-layer: " + gFailedOpaqueLayerMessages.join(", "));
+                // The g.failed*Messages arrays will contain messages from both the test and the reference.
+                if (g.failedOpaqueLayer) {
+                    failures.push("failed reftest-opaque-layer: " + g.failedOpaqueLayerMessages.join(", "));
                 }
-                if (gFailedAssignedLayer) {
-                    failures.push("failed reftest-assigned-layer: " + gFailedAssignedLayerMessages.join(", "));
+                if (g.failedAssignedLayer) {
+                    failures.push("failed reftest-assigned-layer: " + g.failedAssignedLayerMessages.join(", "));
                 }
                 var failureString = failures.join(", ");
-                logger.testStatus(gURLs[0].identifier, failureString, output.s[0], output.s[1], null, null, extra);
+                logger.testStatus(g.urls[0].identifier, failureString, output.s[0], output.s[1], null, null, extra);
             } else {
                 var message = "image comparison, max difference: " + maxDifference.value +
                               ", number of differing pixels: " + differences;
                 if (!test_passed && expected == EXPECTED_PASS ||
                     !test_passed && expected == EXPECTED_FUZZY ||
                     test_passed && expected == EXPECTED_FAIL) {
                     if (!equal) {
                         extra.max_difference = maxDifference.value;
                         extra.differences = differences;
-                        var image1 = gCanvas1.toDataURL();
-                        var image2 = gCanvas2.toDataURL();
+                        var image1 = g.canvas1.toDataURL();
+                        var image2 = g.canvas2.toDataURL();
                         extra.reftest_screenshots = [
-                            {url:gURLs[0].identifier[0],
+                            {url:g.urls[0].identifier[0],
                              screenshot: image1.slice(image1.indexOf(",") + 1)},
-                            gURLs[0].identifier[1],
-                            {url:gURLs[0].identifier[2],
+                            g.urls[0].identifier[1],
+                            {url:g.urls[0].identifier[2],
                              screenshot: image2.slice(image2.indexOf(",") + 1)}
                         ];
                         extra.image1 = image1;
                         extra.image2 = image2;
                     } else {
-                        var image1 = gCanvas1.toDataURL();
+                        var image1 = g.canvas1.toDataURL();
                         extra.reftest_screenshots = [
-                            {url:gURLs[0].identifier[0],
+                            {url:g.urls[0].identifier[0],
                              screenshot: image1.slice(image1.indexOf(",") + 1)}
                         ];
                         extra.image1 = image1;
                     }
                 }
-                logger.testStatus(gURLs[0].identifier, message, output.s[0], output.s[1], null, null, extra);
+                logger.testStatus(g.urls[0].identifier, message, output.s[0], output.s[1], null, null, extra);
 
-                if (gNoCanvasCache) {
-                    ReleaseCanvas(gCanvas1);
-                    ReleaseCanvas(gCanvas2);
+                if (g.noCanvasCache) {
+                    ReleaseCanvas(g.canvas1);
+                    ReleaseCanvas(g.canvas2);
                 } else {
-                    if (gURLs[0].prefSettings1.length == 0) {
-                        UpdateCanvasCache(gURLs[0].url1, gCanvas1);
+                    if (g.urls[0].prefSettings1.length == 0) {
+                        UpdateCanvasCache(g.urls[0].url1, g.canvas1);
                     }
-                    if (gURLs[0].prefSettings2.length == 0) {
-                        UpdateCanvasCache(gURLs[0].url2, gCanvas2);
+                    if (g.urls[0].prefSettings2.length == 0) {
+                        UpdateCanvasCache(g.urls[0].url2, g.canvas2);
                     }
                 }
             }
 
             if ((!test_passed && expected == EXPECTED_PASS) || (test_passed && expected == EXPECTED_FAIL)) {
                 FlushTestBuffer();
             }
 
@@ -1998,304 +1149,304 @@ function RecordResult(testRunTime, error
             break;
         default:
             throw "Unexpected state.";
     }
 }
 
 function LoadFailed(why)
 {
-    ++gTestResults.FailedLoad;
+    ++g.testResults.FailedLoad;
     // Once bug 896840 is fixed, this can go away, but for now it will give log
     // output that is TBPL starable for bug 789751 and bug 720452.
     if (!why) {
         logger.error("load failed with unknown reason");
     }
-    logger.testStatus(gURLs[0].identifier, "load failed: " + why, "FAIL", "PASS");
+    logger.testStatus(g.urls[0].identifier, "load failed: " + why, "FAIL", "PASS");
     FlushTestBuffer();
     FinishTestItem();
 }
 
 function RemoveExpectedCrashDumpFiles()
 {
-    if (gExpectingProcessCrash) {
-        for (let crashFilename of gExpectedCrashDumpFiles) {
-            let file = gCrashDumpDir.clone();
+    if (g.expectingProcessCrash) {
+        for (let crashFilename of g.expectedCrashDumpFiles) {
+            let file = g.crashDumpDir.clone();
             file.append(crashFilename);
             if (file.exists()) {
                 file.remove(false);
             }
         }
     }
-    gExpectedCrashDumpFiles.length = 0;
+    g.expectedCrashDumpFiles.length = 0;
 }
 
 function FindUnexpectedCrashDumpFiles()
 {
-    if (!gCrashDumpDir.exists()) {
+    if (!g.crashDumpDir.exists()) {
         return;
     }
 
-    let entries = gCrashDumpDir.directoryEntries;
+    let entries = g.crashDumpDir.directoryEntries;
     if (!entries) {
         return;
     }
 
     let foundCrashDumpFile = false;
     while (entries.hasMoreElements()) {
         let file = entries.getNext().QueryInterface(CI.nsIFile);
         let path = String(file.path);
-        if (path.match(/\.(dmp|extra)$/) && !gUnexpectedCrashDumpFiles[path]) {
+        if (path.match(/\.(dmp|extra)$/) && !g.unexpectedCrashDumpFiles[path]) {
             if (!foundCrashDumpFile) {
-                ++gTestResults.UnexpectedFail;
+                ++g.testResults.UnexpectedFail;
                 foundCrashDumpFile = true;
-                if (gCurrentURL) {
-                    logger.testStatus(gURLs[0].identifier, "crash-check", "FAIL", "PASS", "This test left crash dumps behind, but we weren't expecting it to!");
+                if (g.currentURL) {
+                    logger.testStatus(g.urls[0].identifier, "crash-check", "FAIL", "PASS", "This test left crash dumps behind, but we weren't expecting it to!");
                 } else {
                     logger.error("Harness startup left crash dumps behind, but we weren't expecting it to!");
                 }
             }
             logger.info("Found unexpected crash dump file " + path);
-            gUnexpectedCrashDumpFiles[path] = true;
+            g.unexpectedCrashDumpFiles[path] = true;
         }
     }
 }
 
 function RemovePendingCrashDumpFiles()
 {
-    if (!gPendingCrashDumpDir.exists()) {
+    if (!g.pendingCrashDumpDir.exists()) {
         return;
     }
 
-    let entries = gPendingCrashDumpDir.directoryEntries;
+    let entries = g.pendingCrashDumpDir.directoryEntries;
     while (entries.hasMoreElements()) {
         let file = entries.getNext().QueryInterface(CI.nsIFile);
         if (file.isFile()) {
           file.remove(false);
           logger.info("This test left pending crash dumps; deleted "+file.path);
         }
     }
 }
 
 function CleanUpCrashDumpFiles()
 {
     RemoveExpectedCrashDumpFiles();
     FindUnexpectedCrashDumpFiles();
-    if (gCleanupPendingCrashes) {
+    if (g.cleanupPendingCrashes) {
       RemovePendingCrashDumpFiles();
     }
-    gExpectingProcessCrash = false;
+    g.expectingProcessCrash = false;
 }
 
 function FinishTestItem()
 {
-    logger.testEnd(gURLs[0].identifier, "OK");
+    logger.testEnd(g.urls[0].identifier, "OK");
 
     // Replace document with BLANK_URL_FOR_CLEARING in case there are
     // assertions when unloading.
     logger.debug("Loading a blank page");
     // After clearing, content will notify us of the assertion count
     // and tests will continue.
     SendClear();
-    gFailedNoPaint = false;
-    gFailedOpaqueLayer = false;
-    gFailedOpaqueLayerMessages = [];
-    gFailedAssignedLayer = false;
-    gFailedAssignedLayerMessages = [];
+    g.failedNoPaint = false;
+    g.failedOpaqueLayer = false;
+    g.failedOpaqueLayerMessages = [];
+    g.failedAssignedLayer = false;
+    g.failedAssignedLayerMessages = [];
 }
 
 function DoAssertionCheck(numAsserts)
 {
-    if (gDebug.isDebugBuild) {
-        if (gBrowserIsRemote) {
+    if (g.debug.isDebugBuild) {
+        if (g.browserIsRemote) {
             // Count chrome-process asserts too when content is out of
             // process.
-            var newAssertionCount = gDebug.assertionCount;
-            var numLocalAsserts = newAssertionCount - gAssertionCount;
-            gAssertionCount = newAssertionCount;
+            var newAssertionCount = g.debug.assertionCount;
+            var numLocalAsserts = newAssertionCount - g.assertionCount;
+            g.assertionCount = newAssertionCount;
 
             numAsserts += numLocalAsserts;
         }
 
-        var minAsserts = gURLs[0].minAsserts;
-        var maxAsserts = gURLs[0].maxAsserts;
+        var minAsserts = g.urls[0].minAsserts;
+        var maxAsserts = g.urls[0].maxAsserts;
 
-        logger.assertionCount(gURLs[0].identifier, numAsserts, minAsserts, maxAsserts);
+        logger.assertionCount(g.urls[0].identifier, numAsserts, minAsserts, maxAsserts);
     }
 
-    if (gURLs[0].chaosMode) {
-        gWindowUtils.leaveChaosMode();
+    if (g.urls[0].chaosMode) {
+        g.windowUtils.leaveChaosMode();
     }
 
     // And start the next test.
-    gURLs.shift();
+    g.urls.shift();
     StartCurrentTest();
 }
 
 function ResetRenderingState()
 {
     SendResetRenderingState();
     // We would want to clear any viewconfig here, if we add support for it
 }
 
 function RestoreChangedPreferences()
 {
-    if (gPrefsToRestore.length > 0) {
+    if (g.prefsToRestore.length > 0) {
         var prefs = Components.classes["@mozilla.org/preferences-service;1"].
                     getService(Components.interfaces.nsIPrefBranch);
-        gPrefsToRestore.reverse();
-        gPrefsToRestore.forEach(function(ps) {
+        g.prefsToRestore.reverse();
+        g.prefsToRestore.forEach(function(ps) {
             var value = ps.value;
             if (ps.type == PREF_BOOLEAN) {
                 prefs.setBoolPref(ps.name, value);
             } else if (ps.type == PREF_STRING) {
                 prefs.setCharPref(ps.name, value);
                 value = '"' + value + '"';
             } else if (ps.type == PREF_INTEGER) {
                 prefs.setIntPref(ps.name, value);
             }
             logger.info("RESTORE PREFERENCE pref(" + ps.name + "," + value + ")");
         });
-        gPrefsToRestore = [];
+        g.prefsToRestore = [];
     }
 }
 
 function RegisterMessageListenersAndLoadContentScript()
 {
-    gBrowserMessageManager.addMessageListener(
+    g.browserMessageManager.addMessageListener(
         "reftest:AssertionCount",
         function (m) { RecvAssertionCount(m.json.count); }
     );
-    gBrowserMessageManager.addMessageListener(
+    g.browserMessageManager.addMessageListener(
         "reftest:ContentReady",
         function (m) { return RecvContentReady(m.data); }
     );
-    gBrowserMessageManager.addMessageListener(
+    g.browserMessageManager.addMessageListener(
         "reftest:Exception",
         function (m) { RecvException(m.json.what) }
     );
-    gBrowserMessageManager.addMessageListener(
+    g.browserMessageManager.addMessageListener(
         "reftest:FailedLoad",
         function (m) { RecvFailedLoad(m.json.why); }
     );
-    gBrowserMessageManager.addMessageListener(
+    g.browserMessageManager.addMessageListener(
         "reftest:FailedNoPaint",
         function (m) { RecvFailedNoPaint(); }
     );
-    gBrowserMessageManager.addMessageListener(
+    g.browserMessageManager.addMessageListener(
         "reftest:FailedOpaqueLayer",
         function (m) { RecvFailedOpaqueLayer(m.json.why); }
     );
-    gBrowserMessageManager.addMessageListener(
+    g.browserMessageManager.addMessageListener(
         "reftest:FailedAssignedLayer",
         function (m) { RecvFailedAssignedLayer(m.json.why); }
     );
-    gBrowserMessageManager.addMessageListener(
+    g.browserMessageManager.addMessageListener(
         "reftest:InitCanvasWithSnapshot",
         function (m) { return RecvInitCanvasWithSnapshot(); }
     );
-    gBrowserMessageManager.addMessageListener(
+    g.browserMessageManager.addMessageListener(
         "reftest:Log",
         function (m) { RecvLog(m.json.type, m.json.msg); }
     );
-    gBrowserMessageManager.addMessageListener(
+    g.browserMessageManager.addMessageListener(
         "reftest:ScriptResults",
         function (m) { RecvScriptResults(m.json.runtimeMs, m.json.error, m.json.results); }
     );
-    gBrowserMessageManager.addMessageListener(
+    g.browserMessageManager.addMessageListener(
         "reftest:PrintResult",
         function (m) { RecvPrintResult(m.json.runtimeMs, m.json.status, m.json.fileName); }
     );
-    gBrowserMessageManager.addMessageListener(
+    g.browserMessageManager.addMessageListener(
         "reftest:TestDone",
         function (m) { RecvTestDone(m.json.runtimeMs); }
     );
-    gBrowserMessageManager.addMessageListener(
+    g.browserMessageManager.addMessageListener(
         "reftest:UpdateCanvasForInvalidation",
         function (m) { RecvUpdateCanvasForInvalidation(m.json.rects); }
     );
-    gBrowserMessageManager.addMessageListener(
+    g.browserMessageManager.addMessageListener(
         "reftest:UpdateWholeCanvasForInvalidation",
         function (m) { RecvUpdateWholeCanvasForInvalidation(); }
     );
-    gBrowserMessageManager.addMessageListener(
+    g.browserMessageManager.addMessageListener(
         "reftest:ExpectProcessCrash",
         function (m) { RecvExpectProcessCrash(); }
     );
 
-    gBrowserMessageManager.loadFrameScript("chrome://reftest/content/reftest-content.js", true, true);
+    g.browserMessageManager.loadFrameScript("chrome://reftest/content/reftest-content.js", true, true);
 }
 
 function RecvAssertionCount(count)
 {
     DoAssertionCheck(count);
 }
 
 function RecvContentReady(info)
 {
-    gContentGfxInfo = info.gfx;
+    g.contentGfxInfo = info.gfx;
     InitAndStartRefTests();
-    return { remote: gBrowserIsRemote };
+    return { remote: g.browserIsRemote };
 }
 
 function RecvException(what)
 {
-    logger.error(gCurrentURL + " | " + what);
-    ++gTestResults.Exception;
+    logger.error(g.currentURL + " | " + what);
+    ++g.testResults.Exception;
 }
 
 function RecvFailedLoad(why)
 {
     LoadFailed(why);
 }
 
 function RecvFailedNoPaint()
 {
-    gFailedNoPaint = true;
+    g.failedNoPaint = true;
 }
 
 function RecvFailedOpaqueLayer(why) {
-    gFailedOpaqueLayer = true;
-    gFailedOpaqueLayerMessages.push(why);
+    g.failedOpaqueLayer = true;
+    g.failedOpaqueLayerMessages.push(why);
 }
 
 function RecvFailedAssignedLayer(why) {
-    gFailedAssignedLayer = true;
-    gFailedAssignedLayerMessages.push(why);
+    g.failedAssignedLayer = true;
+    g.failedAssignedLayerMessages.push(why);
 }
 
 function RecvInitCanvasWithSnapshot()
 {
     var painted = InitCurrentCanvasWithSnapshot();
     return { painted: painted };
 }
 
 function RecvLog(type, msg)
 {
     msg = "[CONTENT] " + msg;
     if (type == "info") {
         TestBuffer(msg);
     } else if (type == "warning") {
         logger.warning(msg);
     } else {
-        logger.error("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | unknown log type " + type + "\n");
-        ++gTestResults.Exception;
+        logger.error("REFTEST TEST-UNEXPECTED-FAIL | " + g.currentURL + " | unknown log type " + type + "\n");
+        ++g.testResults.Exception;
     }
 }
 
 function RecvScriptResults(runtimeMs, error, results)
 {
     RecordResult(runtimeMs, error, results);
 }
 
 function RecvPrintResult(runtimeMs, status, fileName)
 {
     if (!Components.isSuccessCode(status)) {
-      logger.error("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | error during printing\n");
-      ++gTestResults.Exception;
+      logger.error("REFTEST TEST-UNEXPECTED-FAIL | " + g.currentURL + " | error during printing\n");
+      ++g.testResults.Exception;
     }
     RecordResult(runtimeMs, '', fileName);
 }
 
 function RecvTestDone(runtimeMs)
 {
     RecordResult(runtimeMs, '', [ ]);
 }
@@ -2315,61 +1466,61 @@ function OnProcessCrashed(subject, topic
     var id;
     subject = subject.QueryInterface(CI.nsIPropertyBag2);
     if (topic == "plugin-crashed") {
         id = subject.getPropertyAsAString("pluginDumpID");
     } else if (topic == "ipc:content-shutdown") {
         id = subject.getPropertyAsAString("dumpID");
     }
     if (id) {
-        gExpectedCrashDumpFiles.push(id + ".dmp");
-        gExpectedCrashDumpFiles.push(id + ".extra");
+        g.expectedCrashDumpFiles.push(id + ".dmp");
+        g.expectedCrashDumpFiles.push(id + ".extra");
     }
 }
 
 function RegisterProcessCrashObservers()
 {
     var os = CC[NS_OBSERVER_SERVICE_CONTRACTID]
              .getService(CI.nsIObserverService);
     os.addObserver(OnProcessCrashed, "plugin-crashed");
     os.addObserver(OnProcessCrashed, "ipc:content-shutdown");
 }
 
 function RecvExpectProcessCrash()
 {
-    gExpectingProcessCrash = true;
+    g.expectingProcessCrash = true;
 }
 
 function SendClear()
 {
-    gBrowserMessageManager.sendAsyncMessage("reftest:Clear");
+    g.browserMessageManager.sendAsyncMessage("reftest:Clear");
 }
 
 function SendLoadScriptTest(uri, timeout)
 {
-    gBrowserMessageManager.sendAsyncMessage("reftest:LoadScriptTest",
+    g.browserMessageManager.sendAsyncMessage("reftest:LoadScriptTest",
                                             { uri: uri, timeout: timeout });
 }
 
 function SendLoadPrintTest(uri, timeout)
 {
-    gBrowserMessageManager.sendAsyncMessage("reftest:LoadPrintTest",
+    g.browserMessageManager.sendAsyncMessage("reftest:LoadPrintTest",
                                             { uri: uri, timeout: timeout });
 }
 
 function SendLoadTest(type, uri, timeout)
 {
-    gBrowserMessageManager.sendAsyncMessage("reftest:LoadTest",
+    g.browserMessageManager.sendAsyncMessage("reftest:LoadTest",
                                             { type: type, uri: uri, timeout: timeout }
     );
 }
 
 function SendResetRenderingState()
 {
-    gBrowserMessageManager.sendAsyncMessage("reftest:ResetRenderingState");
+    g.browserMessageManager.sendAsyncMessage("reftest:ResetRenderingState");
 }
 
 function readPdf(path, callback) {
     OS.File.open(path, { read: true }).then(function (file) {
         file.flush().then(function() {
             file.read().then(function (data) {
                 let fakePort = new PDFJS.main.LoopbackPort(true);
                 PDFJS.worker.WorkerMessageHandler.initializeFromPort(fakePort);