layout/tools/reftest/reftest.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/tools/reftest/reftest.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2052 @@
     1.4 +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- /
     1.5 +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#if BOOTSTRAP
    1.11 +this.EXPORTED_SYMBOLS = ["OnRefTestLoad"];
    1.12 +#endif
    1.13 +
    1.14 +
    1.15 +const CC = Components.classes;
    1.16 +const CI = Components.interfaces;
    1.17 +const CR = Components.results;
    1.18 +
    1.19 +const XHTML_NS = "http://www.w3.org/1999/xhtml";
    1.20 +const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
    1.21 +
    1.22 +const NS_LOCAL_FILE_CONTRACTID = "@mozilla.org/file/local;1";
    1.23 +const NS_GFXINFO_CONTRACTID = "@mozilla.org/gfx/info;1";
    1.24 +const IO_SERVICE_CONTRACTID = "@mozilla.org/network/io-service;1";
    1.25 +const DEBUG_CONTRACTID = "@mozilla.org/xpcom/debug;1";
    1.26 +const NS_LOCALFILEINPUTSTREAM_CONTRACTID =
    1.27 +          "@mozilla.org/network/file-input-stream;1";
    1.28 +const NS_SCRIPTSECURITYMANAGER_CONTRACTID =
    1.29 +          "@mozilla.org/scriptsecuritymanager;1";
    1.30 +const NS_REFTESTHELPER_CONTRACTID =
    1.31 +          "@mozilla.org/reftest-helper;1";
    1.32 +const NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX =
    1.33 +          "@mozilla.org/network/protocol;1?name=";
    1.34 +const NS_XREAPPINFO_CONTRACTID =
    1.35 +          "@mozilla.org/xre/app-info;1";
    1.36 +const NS_DIRECTORY_SERVICE_CONTRACTID =
    1.37 +          "@mozilla.org/file/directory_service;1";
    1.38 +const NS_OBSERVER_SERVICE_CONTRACTID =
    1.39 +          "@mozilla.org/observer-service;1";
    1.40 +
    1.41 +Components.utils.import("resource://gre/modules/FileUtils.jsm");
    1.42 +
    1.43 +var gLoadTimeout = 0;
    1.44 +var gTimeoutHook = null;
    1.45 +var gRemote = false;
    1.46 +var gIgnoreWindowSize = false;
    1.47 +var gShuffle = false;
    1.48 +var gTotalChunks = 0;
    1.49 +var gThisChunk = 0;
    1.50 +var gContainingWindow = null;
    1.51 +var gURLFilterRegex = null;
    1.52 +const FOCUS_FILTER_ALL_TESTS = "all";
    1.53 +const FOCUS_FILTER_NEEDS_FOCUS_TESTS = "needs-focus";
    1.54 +const FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS = "non-needs-focus";
    1.55 +var gFocusFilterMode = FOCUS_FILTER_ALL_TESTS;
    1.56 +
    1.57 +// "<!--CLEAR-->"
    1.58 +const BLANK_URL_FOR_CLEARING = "data:text/html;charset=UTF-8,%3C%21%2D%2DCLEAR%2D%2D%3E";
    1.59 +
    1.60 +var gBrowser;
    1.61 +// Are we testing web content loaded in a separate process?
    1.62 +var gBrowserIsRemote;           // bool
    1.63 +// Are we using <iframe mozbrowser>?
    1.64 +var gBrowserIsIframe;           // bool
    1.65 +var gBrowserMessageManager;
    1.66 +var gCanvas1, gCanvas2;
    1.67 +// gCurrentCanvas is non-null between InitCurrentCanvasWithSnapshot and the next
    1.68 +// RecordResult.
    1.69 +var gCurrentCanvas = null;
    1.70 +var gURLs;
    1.71 +// Map from URI spec to the number of times it remains to be used
    1.72 +var gURIUseCounts;
    1.73 +// Map from URI spec to the canvas rendered for that URI
    1.74 +var gURICanvases;
    1.75 +var gTestResults = {
    1.76 +  // Successful...
    1.77 +  Pass: 0,
    1.78 +  LoadOnly: 0,
    1.79 +  // Unexpected...
    1.80 +  Exception: 0,
    1.81 +  FailedLoad: 0,
    1.82 +  UnexpectedFail: 0,
    1.83 +  UnexpectedPass: 0,
    1.84 +  AssertionUnexpected: 0,
    1.85 +  AssertionUnexpectedFixed: 0,
    1.86 +  // Known problems...
    1.87 +  KnownFail : 0,
    1.88 +  AssertionKnown: 0,
    1.89 +  Random : 0,
    1.90 +  Skip: 0,
    1.91 +  Slow: 0,
    1.92 +};
    1.93 +var gTotalTests = 0;
    1.94 +var gState;
    1.95 +var gCurrentURL;
    1.96 +var gTestLog = [];
    1.97 +var gServer;
    1.98 +var gCount = 0;
    1.99 +var gAssertionCount = 0;
   1.100 +
   1.101 +var gIOService;
   1.102 +var gDebug;
   1.103 +var gWindowUtils;
   1.104 +
   1.105 +var gSlowestTestTime = 0;
   1.106 +var gSlowestTestURL;
   1.107 +
   1.108 +var gDrawWindowFlags;
   1.109 +
   1.110 +var gExpectingProcessCrash = false;
   1.111 +var gExpectedCrashDumpFiles = [];
   1.112 +var gUnexpectedCrashDumpFiles = { };
   1.113 +var gCrashDumpDir;
   1.114 +var gFailedNoPaint = false;
   1.115 +
   1.116 +// The enabled-state of the test-plugins, stored so they can be reset later
   1.117 +var gTestPluginEnabledStates = null;
   1.118 +
   1.119 +const TYPE_REFTEST_EQUAL = '==';
   1.120 +const TYPE_REFTEST_NOTEQUAL = '!=';
   1.121 +const TYPE_LOAD = 'load';     // test without a reference (just test that it does
   1.122 +                              // not assert, crash, hang, or leak)
   1.123 +const TYPE_SCRIPT = 'script'; // test contains individual test results
   1.124 +
   1.125 +// The order of these constants matters, since when we have a status
   1.126 +// listed for a *manifest*, we combine the status with the status for
   1.127 +// the test by using the *larger*.
   1.128 +// FIXME: In the future, we may also want to use this rule for combining
   1.129 +// statuses that are on the same line (rather than making the last one
   1.130 +// win).
   1.131 +const EXPECTED_PASS = 0;
   1.132 +const EXPECTED_FAIL = 1;
   1.133 +const EXPECTED_RANDOM = 2;
   1.134 +const EXPECTED_DEATH = 3;  // test must be skipped to avoid e.g. crash/hang
   1.135 +const EXPECTED_FUZZY = 4;
   1.136 +
   1.137 +// types of preference value we might want to set for a specific test
   1.138 +const PREF_BOOLEAN = 0;
   1.139 +const PREF_STRING  = 1;
   1.140 +const PREF_INTEGER = 2;
   1.141 +
   1.142 +var gPrefsToRestore = [];
   1.143 +
   1.144 +const gProtocolRE = /^\w+:/;
   1.145 +const gPrefItemRE = /^(|test-|ref-)pref\((.+?),(.*)\)$/;
   1.146 +
   1.147 +var gHttpServerPort = -1;
   1.148 +
   1.149 +// whether to run slow tests or not
   1.150 +var gRunSlowTests = true;
   1.151 +
   1.152 +// whether we should skip caching canvases
   1.153 +var gNoCanvasCache = false;
   1.154 +
   1.155 +var gRecycledCanvases = new Array();
   1.156 +
   1.157 +// By default we just log to stdout
   1.158 +var gDumpLog = dump;
   1.159 +var gVerbose = false;
   1.160 +
   1.161 +// Only dump the sandbox once, because it doesn't depend on the
   1.162 +// manifest URL (yet!).
   1.163 +var gDumpedConditionSandbox = false;
   1.164 +
   1.165 +function LogWarning(str)
   1.166 +{
   1.167 +    gDumpLog("REFTEST INFO | " + str + "\n");
   1.168 +    gTestLog.push(str);
   1.169 +}
   1.170 +
   1.171 +function LogInfo(str)
   1.172 +{
   1.173 +    if (gVerbose)
   1.174 +        gDumpLog("REFTEST INFO | " + str + "\n");
   1.175 +    gTestLog.push(str);
   1.176 +}
   1.177 +
   1.178 +function FlushTestLog()
   1.179 +{
   1.180 +    if (!gVerbose) {
   1.181 +        // In verbose mode, we've dumped all these messages already.
   1.182 +        for (var i = 0; i < gTestLog.length; ++i) {
   1.183 +            gDumpLog("REFTEST INFO | Saved log: " + gTestLog[i] + "\n");
   1.184 +        }
   1.185 +    }
   1.186 +    gTestLog = [];
   1.187 +}
   1.188 +
   1.189 +function AllocateCanvas()
   1.190 +{
   1.191 +    if (gRecycledCanvases.length > 0)
   1.192 +        return gRecycledCanvases.shift();
   1.193 +
   1.194 +    var canvas = gContainingWindow.document.createElementNS(XHTML_NS, "canvas");
   1.195 +    var r = gBrowser.getBoundingClientRect();
   1.196 +    canvas.setAttribute("width", Math.ceil(r.width));
   1.197 +    canvas.setAttribute("height", Math.ceil(r.height));
   1.198 +
   1.199 +    return canvas;
   1.200 +}
   1.201 +
   1.202 +function ReleaseCanvas(canvas)
   1.203 +{
   1.204 +    // store a maximum of 2 canvases, if we're not caching
   1.205 +    if (!gNoCanvasCache || gRecycledCanvases.length < 2)
   1.206 +        gRecycledCanvases.push(canvas);
   1.207 +}
   1.208 +
   1.209 +function IDForEventTarget(event)
   1.210 +{
   1.211 +    try {
   1.212 +        return "'" + event.target.getAttribute('id') + "'";
   1.213 +    } catch (ex) {
   1.214 +        return "<unknown>";
   1.215 +    }
   1.216 +}
   1.217 +
   1.218 +function getTestPlugin(aName) {
   1.219 +  var ph = CC["@mozilla.org/plugin/host;1"].getService(CI.nsIPluginHost);
   1.220 +  var tags = ph.getPluginTags();
   1.221 +
   1.222 +  // Find the test plugin
   1.223 +  for (var i = 0; i < tags.length; i++) {
   1.224 +    if (tags[i].name == aName)
   1.225 +      return tags[i];
   1.226 +  }
   1.227 +
   1.228 +  LogWarning("Failed to find the test-plugin.");
   1.229 +  return null;
   1.230 +}
   1.231 +
   1.232 +this.OnRefTestLoad = function OnRefTestLoad(win)
   1.233 +{
   1.234 +    gCrashDumpDir = CC[NS_DIRECTORY_SERVICE_CONTRACTID]
   1.235 +                    .getService(CI.nsIProperties)
   1.236 +                    .get("ProfD", CI.nsIFile);
   1.237 +    gCrashDumpDir.append("minidumps");
   1.238 +
   1.239 +    var env = CC["@mozilla.org/process/environment;1"].
   1.240 +              getService(CI.nsIEnvironment);
   1.241 +    gVerbose = !!env.get("MOZ_REFTEST_VERBOSE");
   1.242 +
   1.243 +    var prefs = Components.classes["@mozilla.org/preferences-service;1"].
   1.244 +                getService(Components.interfaces.nsIPrefBranch);
   1.245 +    try {
   1.246 +        gBrowserIsRemote = prefs.getBoolPref("browser.tabs.remote.autostart");
   1.247 +    } catch (e) {
   1.248 +        gBrowserIsRemote = false;
   1.249 +    }
   1.250 +
   1.251 +    try {
   1.252 +      gBrowserIsIframe = prefs.getBoolPref("reftest.browser.iframe.enabled");
   1.253 +    } catch (e) {
   1.254 +      gBrowserIsIframe = false;
   1.255 +    }
   1.256 +
   1.257 +    if (win === undefined || win == null) {
   1.258 +      win = window;
   1.259 +    }
   1.260 +    if (gContainingWindow == null && win != null) {
   1.261 +      gContainingWindow = win;
   1.262 +    }
   1.263 +
   1.264 +    if (gBrowserIsIframe) {
   1.265 +      gBrowser = gContainingWindow.document.createElementNS(XHTML_NS, "iframe");
   1.266 +      gBrowser.setAttribute("mozbrowser", "");
   1.267 +      gBrowser.setAttribute("mozapp", prefs.getCharPref("browser.manifestURL"));
   1.268 +    } else {
   1.269 +      gBrowser = gContainingWindow.document.createElementNS(XUL_NS, "xul:browser");
   1.270 +    }
   1.271 +    gBrowser.setAttribute("id", "browser");
   1.272 +    gBrowser.setAttribute("type", "content-primary");
   1.273 +    gBrowser.setAttribute("remote", gBrowserIsRemote ? "true" : "false");
   1.274 +    gBrowser.setAttribute("mozasyncpanzoom", "true");
   1.275 +    // Make sure the browser element is exactly 800x1000, no matter
   1.276 +    // what size our window is
   1.277 +    gBrowser.setAttribute("style", "min-width: 800px; min-height: 1000px; max-width: 800px; max-height: 1000px");
   1.278 +
   1.279 +#ifdef BOOTSTRAP
   1.280 +#ifdef REFTEST_B2G
   1.281 +    var doc = gContainingWindow.document.getElementsByTagName("html")[0];
   1.282 +#else
   1.283 +    var doc = gContainingWindow.document.getElementById('main-window');
   1.284 +#endif
   1.285 +    while (doc.hasChildNodes()) {
   1.286 +      doc.removeChild(doc.firstChild);
   1.287 +    }
   1.288 +    doc.appendChild(gBrowser);
   1.289 +#else
   1.290 +    document.getElementById("reftest-window").appendChild(gBrowser);
   1.291 +#endif
   1.292 +
   1.293 +    // reftests should have the test plugins enabled, not click-to-play
   1.294 +    let plugin1 = getTestPlugin("Test Plug-in");
   1.295 +    let plugin2 = getTestPlugin("Second Test Plug-in");
   1.296 +    if (plugin1 && plugin2) {
   1.297 +      gTestPluginEnabledStates = [plugin1.enabledState, plugin2.enabledState];
   1.298 +      plugin1.enabledState = CI.nsIPluginTag.STATE_ENABLED;
   1.299 +      plugin2.enabledState = CI.nsIPluginTag.STATE_ENABLED;
   1.300 +    } else {
   1.301 +      LogWarning("Could not get test plugin tags.");
   1.302 +    }
   1.303 +
   1.304 +    gBrowserMessageManager = gBrowser.QueryInterface(CI.nsIFrameLoaderOwner)
   1.305 +                                     .frameLoader.messageManager;
   1.306 +    // The content script waits for the initial onload, then notifies
   1.307 +    // us.
   1.308 +    RegisterMessageListenersAndLoadContentScript();
   1.309 +}
   1.310 +
   1.311 +function InitAndStartRefTests()
   1.312 +{
   1.313 +    /* These prefs are optional, so we don't need to spit an error to the log */
   1.314 +    try {
   1.315 +        var prefs = Components.classes["@mozilla.org/preferences-service;1"].
   1.316 +                    getService(Components.interfaces.nsIPrefBranch);
   1.317 +    } catch(e) {
   1.318 +        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + e + "\n");
   1.319 +    }
   1.320 +
   1.321 +    try {
   1.322 +      prefs.setBoolPref("android.widget_paints_background", false);
   1.323 +    } catch (e) {}
   1.324 +
   1.325 +    /* set the gLoadTimeout */
   1.326 +    try {
   1.327 +        gLoadTimeout = prefs.getIntPref("reftest.timeout");
   1.328 +    } catch(e) {
   1.329 +        gLoadTimeout = 5 * 60 * 1000; //5 minutes as per bug 479518
   1.330 +    }
   1.331 +
   1.332 +    /* Get the logfile for android tests */
   1.333 +    try {
   1.334 +        var logFile = prefs.getCharPref("reftest.logFile");
   1.335 +        if (logFile) {
   1.336 +            try {
   1.337 +                var f = FileUtils.File(logFile);
   1.338 +                var mfl = FileUtils.openFileOutputStream(f, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
   1.339 +                // Set to mirror to stdout as well as the file
   1.340 +                gDumpLog = function (msg) {
   1.341 +#ifdef BOOTSTRAP
   1.342 +#ifdef REFTEST_B2G
   1.343 +                    dump(msg);
   1.344 +#else
   1.345 +                    //NOTE: on android-xul, we have a libc crash if we do a dump with %7s in the string
   1.346 +#endif
   1.347 +#else
   1.348 +                    dump(msg);
   1.349 +#endif
   1.350 +                    mfl.write(msg, msg.length);
   1.351 +                };
   1.352 +            }
   1.353 +            catch(e) {
   1.354 +                // If there is a problem, just use stdout
   1.355 +                gDumpLog = dump;
   1.356 +            }
   1.357 +        }
   1.358 +    } catch(e) {}
   1.359 +
   1.360 +    try {
   1.361 +        gRemote = prefs.getBoolPref("reftest.remote");
   1.362 +    } catch(e) {
   1.363 +        gRemote = false;
   1.364 +    }
   1.365 +
   1.366 +    try {
   1.367 +        gIgnoreWindowSize = prefs.getBoolPref("reftest.ignoreWindowSize");
   1.368 +    } catch(e) {
   1.369 +        gIgnoreWindowSize = false;
   1.370 +    }
   1.371 +
   1.372 +    /* Support for running a chunk (subset) of tests.  In separate try as this is optional */
   1.373 +    try {
   1.374 +        gTotalChunks = prefs.getIntPref("reftest.totalChunks");
   1.375 +        gThisChunk = prefs.getIntPref("reftest.thisChunk");
   1.376 +    }
   1.377 +    catch(e) {
   1.378 +        gTotalChunks = 0;
   1.379 +        gThisChunk = 0;
   1.380 +    }
   1.381 +
   1.382 +    try {
   1.383 +        gURLFilterRegex = new RegExp(prefs.getCharPref("reftest.filter"));
   1.384 +    } catch(e) {}
   1.385 +
   1.386 +    try {
   1.387 +        gFocusFilterMode = prefs.getCharPref("reftest.focusFilterMode");
   1.388 +    } catch(e) {}
   1.389 +
   1.390 +    gWindowUtils = gContainingWindow.QueryInterface(CI.nsIInterfaceRequestor).getInterface(CI.nsIDOMWindowUtils);
   1.391 +    if (!gWindowUtils || !gWindowUtils.compareCanvases)
   1.392 +        throw "nsIDOMWindowUtils inteface missing";
   1.393 +
   1.394 +    gIOService = CC[IO_SERVICE_CONTRACTID].getService(CI.nsIIOService);
   1.395 +    gDebug = CC[DEBUG_CONTRACTID].getService(CI.nsIDebug2);
   1.396 +
   1.397 +    RegisterProcessCrashObservers();
   1.398 +
   1.399 +    if (gRemote) {
   1.400 +        gServer = null;
   1.401 +    } else {
   1.402 +        // not all gecko applications autoregister xpcom components
   1.403 +        if (CC["@mozilla.org/server/jshttp;1"] === undefined) {
   1.404 +            var file = CC["@mozilla.org/file/directory_service;1"].
   1.405 +                        getService(CI.nsIProperties).get("ProfD", CI.nsIFile);
   1.406 +            file.appendRelativePath("extensions/reftest@mozilla.org/chrome.manifest");
   1.407 +
   1.408 +            registrar = Components.manager.QueryInterface(CI.nsIComponentRegistrar);
   1.409 +            registrar.autoRegister(file);
   1.410 +        }
   1.411 +        gServer = CC["@mozilla.org/server/jshttp;1"].
   1.412 +                      createInstance(CI.nsIHttpServer);
   1.413 +    }
   1.414 +    try {
   1.415 +        if (gServer)
   1.416 +            StartHTTPServer();
   1.417 +    } catch (ex) {
   1.418 +        //gBrowser.loadURI('data:text/plain,' + ex);
   1.419 +        ++gTestResults.Exception;
   1.420 +        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n");
   1.421 +        DoneTests();
   1.422 +    }
   1.423 +
   1.424 +    // Focus the content browser.
   1.425 +    if (gFocusFilterMode != FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS) {
   1.426 +        gBrowser.focus();
   1.427 +    }
   1.428 +
   1.429 +    StartTests();
   1.430 +}
   1.431 +
   1.432 +function StartHTTPServer()
   1.433 +{
   1.434 +    gServer.registerContentType("sjs", "sjs");
   1.435 +    gServer.start(-1);
   1.436 +    gHttpServerPort = gServer.identity.primaryPort;
   1.437 +}
   1.438 +
   1.439 +// Perform a Fisher-Yates shuffle of the array.
   1.440 +function Shuffle(array)
   1.441 +{
   1.442 +    for (var i = array.length - 1; i > 0; i--) {
   1.443 +        var j = Math.floor(Math.random() * (i + 1));
   1.444 +        var temp = array[i];
   1.445 +        array[i] = array[j];
   1.446 +        array[j] = temp;
   1.447 +    }
   1.448 +}
   1.449 +
   1.450 +function StartTests()
   1.451 +{
   1.452 +    var uri;
   1.453 +#if BOOTSTRAP
   1.454 +    /* These prefs are optional, so we don't need to spit an error to the log */
   1.455 +    try {
   1.456 +        var prefs = Components.classes["@mozilla.org/preferences-service;1"].
   1.457 +                    getService(Components.interfaces.nsIPrefBranch);
   1.458 +    } catch(e) {
   1.459 +        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + e + "\n");
   1.460 +    }
   1.461 +
   1.462 +    try {
   1.463 +        gNoCanvasCache = prefs.getIntPref("reftest.nocache");
   1.464 +    } catch(e) {
   1.465 +        gNoCanvasCache = false;
   1.466 +    }
   1.467 +
   1.468 +    try {
   1.469 +      gShuffle = prefs.getBoolPref("reftest.shuffle");
   1.470 +    } catch (e) {
   1.471 +      gShuffle = false;
   1.472 +    }
   1.473 +
   1.474 +    try {
   1.475 +        gRunSlowTests = prefs.getIntPref("reftest.skipslowtests");
   1.476 +    } catch(e) {
   1.477 +        gRunSlowTests = false;
   1.478 +    }
   1.479 +
   1.480 +    try {
   1.481 +        uri = prefs.getCharPref("reftest.uri");
   1.482 +    } catch(e) {
   1.483 +        uri = "";
   1.484 +    }
   1.485 +
   1.486 +    if (uri == "") {
   1.487 +        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | Unable to find reftest.uri pref.  Please ensure your profile is setup properly\n");
   1.488 +        DoneTests();
   1.489 +    }
   1.490 +#else
   1.491 +    try {
   1.492 +        // Need to read the manifest once we have gHttpServerPort..
   1.493 +        var args = window.arguments[0].wrappedJSObject;
   1.494 +
   1.495 +        if ("nocache" in args && args["nocache"])
   1.496 +            gNoCanvasCache = true;
   1.497 +
   1.498 +        if ("skipslowtests" in args && args.skipslowtests)
   1.499 +            gRunSlowTests = false;
   1.500 +
   1.501 +        uri = args.uri;
   1.502 +    } catch (e) {
   1.503 +        ++gTestResults.Exception;
   1.504 +        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n");
   1.505 +        DoneTests();
   1.506 +    }
   1.507 +#endif
   1.508 +
   1.509 +    if (gShuffle) {
   1.510 +        gNoCanvasCache = true;
   1.511 +    }
   1.512 +
   1.513 +    try {
   1.514 +        ReadTopManifest(uri);
   1.515 +        BuildUseCounts();
   1.516 +
   1.517 +        // Filter tests which will be skipped to get a more even distribution when chunking
   1.518 +        // tURLs is a temporary array containing all active tests
   1.519 +        var tURLs = new Array();
   1.520 +        for (var i = 0; i < gURLs.length; ++i) {
   1.521 +            if (gURLs[i].expected == EXPECTED_DEATH)
   1.522 +                continue;
   1.523 +
   1.524 +            if (gURLs[i].needsFocus && !Focus())
   1.525 +                continue;
   1.526 +
   1.527 +            if (gURLs[i].slow && !gRunSlowTests)
   1.528 +                continue;
   1.529 +
   1.530 +            tURLs.push(gURLs[i]);
   1.531 +        }
   1.532 +
   1.533 +        gDumpLog("REFTEST INFO | Discovered " + gURLs.length + " tests, after filtering SKIP tests, we have " + tURLs.length + "\n");
   1.534 +
   1.535 +        if (gTotalChunks > 0 && gThisChunk > 0) {
   1.536 +            // Calculate start and end indices of this chunk if tURLs array were
   1.537 +            // divided evenly
   1.538 +            var testsPerChunk = tURLs.length / gTotalChunks;
   1.539 +            var start = Math.round((gThisChunk-1) * testsPerChunk);
   1.540 +            var end = Math.round(gThisChunk * testsPerChunk);
   1.541 +
   1.542 +            // Map these indices onto the gURLs array. This avoids modifying the
   1.543 +            // gURLs array which prevents skipped tests from showing up in the log
   1.544 +            start = gThisChunk == 1 ? 0 : gURLs.indexOf(tURLs[start]);
   1.545 +            end = gThisChunk == gTotalChunks ? gURLs.length : gURLs.indexOf(tURLs[end + 1]) - 1;
   1.546 +            gURLs = gURLs.slice(start, end);
   1.547 +
   1.548 +            gDumpLog("REFTEST INFO | Running chunk " + gThisChunk + " out of " + gTotalChunks + " chunks.  ");
   1.549 +            gDumpLog("tests " + (start+1) + "-" + end + "/" + gURLs.length + "\n");
   1.550 +        }
   1.551 +
   1.552 +        if (gShuffle) {
   1.553 +            Shuffle(gURLs);
   1.554 +        }
   1.555 +
   1.556 +        gTotalTests = gURLs.length;
   1.557 +
   1.558 +        if (!gTotalTests)
   1.559 +            throw "No tests to run";
   1.560 +
   1.561 +        gURICanvases = {};
   1.562 +        StartCurrentTest();
   1.563 +    } catch (ex) {
   1.564 +        //gBrowser.loadURI('data:text/plain,' + ex);
   1.565 +        ++gTestResults.Exception;
   1.566 +        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n");
   1.567 +        DoneTests();
   1.568 +    }
   1.569 +}
   1.570 +
   1.571 +function OnRefTestUnload()
   1.572 +{
   1.573 +  let plugin1 = getTestPlugin("Test Plug-in");
   1.574 +  let plugin2 = getTestPlugin("Second Test Plug-in");
   1.575 +  if (plugin1 && plugin2) {
   1.576 +    plugin1.enabledState = gTestPluginEnabledStates[0];
   1.577 +    plugin2.enabledState = gTestPluginEnabledStates[1];
   1.578 +  } else {
   1.579 +    LogWarning("Failed to get test plugin tags.");
   1.580 +  }
   1.581 +}
   1.582 +
   1.583 +// Read all available data from an input stream and return it
   1.584 +// as a string.
   1.585 +function getStreamContent(inputStream)
   1.586 +{
   1.587 +    var streamBuf = "";
   1.588 +    var sis = CC["@mozilla.org/scriptableinputstream;1"].
   1.589 +                  createInstance(CI.nsIScriptableInputStream);
   1.590 +    sis.init(inputStream);
   1.591 +
   1.592 +    var available;
   1.593 +    while ((available = sis.available()) != 0) {
   1.594 +        streamBuf += sis.read(available);
   1.595 +    }
   1.596 +
   1.597 +    return streamBuf;
   1.598 +}
   1.599 +
   1.600 +// Build the sandbox for fails-if(), etc., condition evaluation.
   1.601 +function BuildConditionSandbox(aURL) {
   1.602 +    var sandbox = new Components.utils.Sandbox(aURL.spec);
   1.603 +    var xr = CC[NS_XREAPPINFO_CONTRACTID].getService(CI.nsIXULRuntime);
   1.604 +    var appInfo = CC[NS_XREAPPINFO_CONTRACTID].getService(CI.nsIXULAppInfo);
   1.605 +    sandbox.isDebugBuild = gDebug.isDebugBuild;
   1.606 +    sandbox.xulRuntime = {widgetToolkit: xr.widgetToolkit, OS: xr.OS, __exposedProps__: { widgetToolkit: "r", OS: "r", XPCOMABI: "r", shell: "r" } };
   1.607 +
   1.608 +    // xr.XPCOMABI throws exception for configurations without full ABI
   1.609 +    // support (mobile builds on ARM)
   1.610 +    try {
   1.611 +        sandbox.xulRuntime.XPCOMABI = xr.XPCOMABI;
   1.612 +    } catch(e) {
   1.613 +        sandbox.xulRuntime.XPCOMABI = "";
   1.614 +    }
   1.615 +
   1.616 +    var testRect = gBrowser.getBoundingClientRect();
   1.617 +    sandbox.smallScreen = false;
   1.618 +    if (gContainingWindow.innerWidth < 800 || gContainingWindow.innerHeight < 1000) {
   1.619 +        sandbox.smallScreen = true;
   1.620 +    }
   1.621 +
   1.622 +    var gfxInfo = (NS_GFXINFO_CONTRACTID in CC) && CC[NS_GFXINFO_CONTRACTID].getService(CI.nsIGfxInfo);
   1.623 +    try {
   1.624 +      sandbox.d2d = gfxInfo.D2DEnabled;
   1.625 +    } catch (e) {
   1.626 +      sandbox.d2d = false;
   1.627 +    }
   1.628 +    var info = gfxInfo.getInfo();
   1.629 +    sandbox.azureQuartz = info.AzureCanvasBackend == "quartz";
   1.630 +    sandbox.azureSkia = info.AzureCanvasBackend == "skia";
   1.631 +    sandbox.azureSkiaGL = info.AzureSkiaAccelerated; // FIXME: assumes GL right now
   1.632 +    // true if we are using the same Azure backend for rendering canvas and content
   1.633 +    sandbox.contentSameGfxBackendAsCanvas = info.AzureContentBackend == info.AzureCanvasBackend
   1.634 +                                            || (info.AzureContentBackend == "none" && info.AzureCanvasBackend == "cairo");
   1.635 +
   1.636 +    sandbox.layersGPUAccelerated =
   1.637 +      gWindowUtils.layerManagerType != "Basic";
   1.638 +    sandbox.layersOpenGL =
   1.639 +      gWindowUtils.layerManagerType == "OpenGL";
   1.640 +    sandbox.layersOMTC =
   1.641 +      gWindowUtils.layerManagerRemote == true;
   1.642 +
   1.643 +    // Shortcuts for widget toolkits.
   1.644 +    sandbox.B2G = xr.widgetToolkit == "gonk";
   1.645 +    sandbox.B2GDT = appInfo.name.toLowerCase() == "b2g" && !sandbox.B2G;
   1.646 +    sandbox.Android = xr.OS == "Android" && !sandbox.B2G;
   1.647 +    sandbox.cocoaWidget = xr.widgetToolkit == "cocoa";
   1.648 +    sandbox.gtk2Widget = xr.widgetToolkit == "gtk2";
   1.649 +    sandbox.qtWidget = xr.widgetToolkit == "qt";
   1.650 +    sandbox.winWidget = xr.widgetToolkit == "windows";
   1.651 +
   1.652 +    if (sandbox.Android) {
   1.653 +        var sysInfo = CC["@mozilla.org/system-info;1"].getService(CI.nsIPropertyBag2);
   1.654 +
   1.655 +        // This is currently used to distinguish Android 4.0.3 (SDK version 15)
   1.656 +        // and later from Android 2.x
   1.657 +        sandbox.AndroidVersion = sysInfo.getPropertyAsInt32("version");
   1.658 +    }
   1.659 +
   1.660 +#if MOZ_ASAN
   1.661 +    sandbox.AddressSanitizer = true;
   1.662 +#else
   1.663 +    sandbox.AddressSanitizer = false;
   1.664 +#endif
   1.665 +
   1.666 +#if MOZ_WEBRTC
   1.667 +    sandbox.webrtc = true;
   1.668 +#else
   1.669 +    sandbox.webrtc = false;
   1.670 +#endif
   1.671 +
   1.672 +    var hh = CC[NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX + "http"].
   1.673 +                 getService(CI.nsIHttpProtocolHandler);
   1.674 +    sandbox.http = { __exposedProps__: {} };
   1.675 +    for each (var prop in [ "userAgent", "appName", "appVersion",
   1.676 +                            "vendor", "vendorSub",
   1.677 +                            "product", "productSub",
   1.678 +                            "platform", "oscpu", "language", "misc" ]) {
   1.679 +        sandbox.http[prop] = hh[prop];
   1.680 +        sandbox.http.__exposedProps__[prop] = "r";
   1.681 +    }
   1.682 +
   1.683 +    // Set OSX to the Mac OS X version for Mac, and 0 otherwise.
   1.684 +    var osxmatch = /Mac OS X (\d+.\d+)$/.exec(hh.oscpu);
   1.685 +    sandbox.OSX = osxmatch ? parseFloat(osxmatch[1]) : 0;
   1.686 +
   1.687 +    // see if we have the test plugin available,
   1.688 +    // and set a sandox prop accordingly
   1.689 +    var navigator = gContainingWindow.navigator;
   1.690 +    var testPlugin = navigator.plugins["Test Plug-in"];
   1.691 +    sandbox.haveTestPlugin = !!testPlugin;
   1.692 +
   1.693 +    // Set a flag on sandbox if the windows default theme is active
   1.694 +    var box = gContainingWindow.document.createElement("box");
   1.695 +    box.setAttribute("id", "_box_windowsDefaultTheme");
   1.696 +    gContainingWindow.document.documentElement.appendChild(box);
   1.697 +    sandbox.windowsDefaultTheme = (gContainingWindow.getComputedStyle(box, null).display == "none");
   1.698 +    gContainingWindow.document.documentElement.removeChild(box);
   1.699 +
   1.700 +    var prefs = CC["@mozilla.org/preferences-service;1"].
   1.701 +                getService(CI.nsIPrefBranch);
   1.702 +    try {
   1.703 +        sandbox.nativeThemePref = !prefs.getBoolPref("mozilla.widget.disable-native-theme");
   1.704 +    } catch (e) {
   1.705 +        sandbox.nativeThemePref = true;
   1.706 +    }
   1.707 +
   1.708 +    sandbox.prefs = {
   1.709 +        __exposedProps__: {
   1.710 +            getBoolPref: 'r',
   1.711 +            getIntPref: 'r',
   1.712 +        },
   1.713 +        _prefs:      prefs,
   1.714 +        getBoolPref: function(p) { return this._prefs.getBoolPref(p); },
   1.715 +        getIntPref:  function(p) { return this._prefs.getIntPref(p); }
   1.716 +    }
   1.717 +
   1.718 +    sandbox.testPluginIsOOP = function () {
   1.719 +        try {
   1.720 +            netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   1.721 +        } catch (ex) {}
   1.722 +
   1.723 +        var prefservice = Components.classes["@mozilla.org/preferences-service;1"]
   1.724 +                                    .getService(CI.nsIPrefBranch);
   1.725 +
   1.726 +        var testPluginIsOOP = false;
   1.727 +        if (navigator.platform.indexOf("Mac") == 0) {
   1.728 +            var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"]
   1.729 +                                       .getService(CI.nsIXULAppInfo)
   1.730 +                                       .QueryInterface(CI.nsIXULRuntime);
   1.731 +            if (xulRuntime.XPCOMABI.match(/x86-/)) {
   1.732 +                try {
   1.733 +                    testPluginIsOOP = prefservice.getBoolPref("dom.ipc.plugins.enabled.i386.test.plugin");
   1.734 +                } catch (e) {
   1.735 +                    testPluginIsOOP = prefservice.getBoolPref("dom.ipc.plugins.enabled.i386");
   1.736 +                }
   1.737 +            }
   1.738 +            else if (xulRuntime.XPCOMABI.match(/x86_64-/)) {
   1.739 +                try {
   1.740 +                    testPluginIsOOP = prefservice.getBoolPref("dom.ipc.plugins.enabled.x86_64.test.plugin");
   1.741 +                } catch (e) {
   1.742 +                    testPluginIsOOP = prefservice.getBoolPref("dom.ipc.plugins.enabled.x86_64");
   1.743 +                }
   1.744 +            }
   1.745 +        }
   1.746 +        else {
   1.747 +            testPluginIsOOP = prefservice.getBoolPref("dom.ipc.plugins.enabled");
   1.748 +        }
   1.749 +
   1.750 +        return testPluginIsOOP;
   1.751 +    };
   1.752 +
   1.753 +    // Tests shouldn't care about this except for when they need to
   1.754 +    // crash the content process
   1.755 +    sandbox.browserIsRemote = gBrowserIsRemote;
   1.756 +
   1.757 +    // Distinguish the Fennecs:
   1.758 +    sandbox.xulFennec    = sandbox.Android &&  sandbox.browserIsRemote;
   1.759 +    sandbox.nativeFennec = sandbox.Android && !sandbox.browserIsRemote;
   1.760 +
   1.761 +    if (!gDumpedConditionSandbox) {
   1.762 +        dump("REFTEST INFO | Dumping JSON representation of sandbox \n");
   1.763 +        dump("REFTEST INFO | " + JSON.stringify(sandbox) + " \n");
   1.764 +        gDumpedConditionSandbox = true;
   1.765 +    }
   1.766 +    return sandbox;
   1.767 +}
   1.768 +
   1.769 +function AddPrefSettings(aWhere, aPrefName, aPrefValExpression, aSandbox, aTestPrefSettings, aRefPrefSettings)
   1.770 +{
   1.771 +    var prefVal = Components.utils.evalInSandbox("(" + aPrefValExpression + ")", aSandbox);
   1.772 +    var prefType;
   1.773 +    var valType = typeof(prefVal);
   1.774 +    if (valType == "boolean") {
   1.775 +        prefType = PREF_BOOLEAN;
   1.776 +    } else if (valType == "string") {
   1.777 +        prefType = PREF_STRING;
   1.778 +    } else if (valType == "number" && (parseInt(prefVal) == prefVal)) {
   1.779 +        prefType = PREF_INTEGER;
   1.780 +    } else {
   1.781 +        return false;
   1.782 +    }
   1.783 +    var setting = { name: aPrefName,
   1.784 +                    type: prefType,
   1.785 +                    value: prefVal };
   1.786 +    if (aWhere != "ref-") {
   1.787 +        aTestPrefSettings.push(setting);
   1.788 +    }
   1.789 +    if (aWhere != "test-") {
   1.790 +        aRefPrefSettings.push(setting);
   1.791 +    }
   1.792 +    return true;
   1.793 +}
   1.794 +
   1.795 +function ReadTopManifest(aFileURL)
   1.796 +{
   1.797 +    gURLs = new Array();
   1.798 +    var url = gIOService.newURI(aFileURL, null, null);
   1.799 +    if (!url)
   1.800 +        throw "Expected a file or http URL for the manifest.";
   1.801 +    ReadManifest(url, EXPECTED_PASS);
   1.802 +}
   1.803 +
   1.804 +function AddTestItem(aTest)
   1.805 +{
   1.806 +    if (gURLFilterRegex && !gURLFilterRegex.test(aTest.url1.spec))
   1.807 +        return;
   1.808 +    if (gFocusFilterMode == FOCUS_FILTER_NEEDS_FOCUS_TESTS &&
   1.809 +        !aTest.needsFocus)
   1.810 +        return;
   1.811 +    if (gFocusFilterMode == FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS &&
   1.812 +        aTest.needsFocus)
   1.813 +        return;
   1.814 +    gURLs.push(aTest);
   1.815 +}
   1.816 +
   1.817 +// Note: If you materially change the reftest manifest parsing,
   1.818 +// please keep the parser in print-manifest-dirs.py in sync.
   1.819 +function ReadManifest(aURL, inherited_status)
   1.820 +{
   1.821 +    var secMan = CC[NS_SCRIPTSECURITYMANAGER_CONTRACTID]
   1.822 +                     .getService(CI.nsIScriptSecurityManager);
   1.823 +
   1.824 +    var listURL = aURL;
   1.825 +    var channel = gIOService.newChannelFromURI(aURL);
   1.826 +    var inputStream = channel.open();
   1.827 +    if (channel instanceof Components.interfaces.nsIHttpChannel
   1.828 +        && channel.responseStatus != 200) {
   1.829 +      gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | HTTP ERROR : " +
   1.830 +        channel.responseStatus + "\n");
   1.831 +    }
   1.832 +    var streamBuf = getStreamContent(inputStream);
   1.833 +    inputStream.close();
   1.834 +    var lines = streamBuf.split(/\n|\r|\r\n/);
   1.835 +
   1.836 +    // Build the sandbox for fails-if(), etc., condition evaluation.
   1.837 +    var sandbox = BuildConditionSandbox(aURL);
   1.838 +    var lineNo = 0;
   1.839 +    var urlprefix = "";
   1.840 +    var defaultTestPrefSettings = [], defaultRefPrefSettings = [];
   1.841 +    for each (var str in lines) {
   1.842 +        ++lineNo;
   1.843 +        if (str.charAt(0) == "#")
   1.844 +            continue; // entire line was a comment
   1.845 +        var i = str.search(/\s+#/);
   1.846 +        if (i >= 0)
   1.847 +            str = str.substring(0, i);
   1.848 +        // strip leading and trailing whitespace
   1.849 +        str = str.replace(/^\s*/, '').replace(/\s*$/, '');
   1.850 +        if (!str || str == "")
   1.851 +            continue;
   1.852 +        var items = str.split(/\s+/); // split on whitespace
   1.853 +
   1.854 +        if (items[0] == "url-prefix") {
   1.855 +            if (items.length != 2)
   1.856 +                throw "url-prefix requires one url in manifest file " + aURL.spec + " line " + lineNo;
   1.857 +            urlprefix = items[1];
   1.858 +            continue;
   1.859 +        }
   1.860 +
   1.861 +        if (items[0] == "default-preferences") {
   1.862 +            var m;
   1.863 +            var item;
   1.864 +            defaultTestPrefSettings = [];
   1.865 +            defaultRefPrefSettings = [];
   1.866 +            items.shift();
   1.867 +            while ((item = items.shift())) {
   1.868 +                if (!(m = item.match(gPrefItemRE))) {
   1.869 +                    throw "Unexpected item in default-preferences list in manifest file " + aURL.spec + " line " + lineNo;
   1.870 +                }
   1.871 +                if (!AddPrefSettings(m[1], m[2], m[3], sandbox, defaultTestPrefSettings, defaultRefPrefSettings)) {
   1.872 +                    throw "Error in pref value in manifest file " + aURL.spec + " line " + lineNo;
   1.873 +                }
   1.874 +            }
   1.875 +            continue;
   1.876 +        }
   1.877 +
   1.878 +        var expected_status = EXPECTED_PASS;
   1.879 +        var allow_silent_fail = false;
   1.880 +        var minAsserts = 0;
   1.881 +        var maxAsserts = 0;
   1.882 +        var needs_focus = false;
   1.883 +        var slow = false;
   1.884 +        var testPrefSettings = defaultTestPrefSettings.concat();
   1.885 +        var refPrefSettings = defaultRefPrefSettings.concat();
   1.886 +        var fuzzy_max_delta = 2;
   1.887 +        var fuzzy_max_pixels = 1;
   1.888 +
   1.889 +        while (items[0].match(/^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail|pref|test-pref|ref-pref|fuzzy)/)) {
   1.890 +            var item = items.shift();
   1.891 +            var stat;
   1.892 +            var cond;
   1.893 +            var m = item.match(/^(fails|random|skip|silentfail)-if(\(.*\))$/);
   1.894 +            if (m) {
   1.895 +                stat = m[1];
   1.896 +                // Note: m[2] contains the parentheses, and we want them.
   1.897 +                cond = Components.utils.evalInSandbox(m[2], sandbox);
   1.898 +            } else if (item.match(/^(fails|random|skip)$/)) {
   1.899 +                stat = item;
   1.900 +                cond = true;
   1.901 +            } else if (item == "needs-focus") {
   1.902 +                needs_focus = true;
   1.903 +                cond = false;
   1.904 +            } else if ((m = item.match(/^asserts\((\d+)(-\d+)?\)$/))) {
   1.905 +                cond = false;
   1.906 +                minAsserts = Number(m[1]);
   1.907 +                maxAsserts = (m[2] == undefined) ? minAsserts
   1.908 +                                                 : Number(m[2].substring(1));
   1.909 +            } else if ((m = item.match(/^asserts-if\((.*?),(\d+)(-\d+)?\)$/))) {
   1.910 +                cond = false;
   1.911 +                if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox)) {
   1.912 +                    minAsserts = Number(m[2]);
   1.913 +                    maxAsserts =
   1.914 +                      (m[3] == undefined) ? minAsserts
   1.915 +                                          : Number(m[3].substring(1));
   1.916 +                }
   1.917 +            } else if (item == "slow") {
   1.918 +                cond = false;
   1.919 +                slow = true;
   1.920 +            } else if ((m = item.match(/^require-or\((.*?)\)$/))) {
   1.921 +                var args = m[1].split(/,/);
   1.922 +                if (args.length != 2) {
   1.923 +                    throw "Error 7 in manifest file " + aURL.spec + " line " + lineNo + ": wrong number of args to require-or";
   1.924 +                }
   1.925 +                var [precondition_str, fallback_action] = args;
   1.926 +                var preconditions = precondition_str.split(/&&/);
   1.927 +                cond = false;
   1.928 +                for each (var precondition in preconditions) {
   1.929 +                    if (precondition === "debugMode") {
   1.930 +                        // Currently unimplemented. Requires asynchronous
   1.931 +                        // JSD call + getting an event while no JS is running
   1.932 +                        stat = fallback_action;
   1.933 +                        cond = true;
   1.934 +                        break;
   1.935 +                    } else if (precondition === "true") {
   1.936 +                        // For testing
   1.937 +                    } else {
   1.938 +                        // Unknown precondition. Assume it is unimplemented.
   1.939 +                        stat = fallback_action;
   1.940 +                        cond = true;
   1.941 +                        break;
   1.942 +                    }
   1.943 +                }
   1.944 +            } else if ((m = item.match(/^slow-if\((.*?)\)$/))) {
   1.945 +                cond = false;
   1.946 +                if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox))
   1.947 +                    slow = true;
   1.948 +            } else if (item == "silentfail") {
   1.949 +                cond = false;
   1.950 +                allow_silent_fail = true;
   1.951 +            } else if ((m = item.match(gPrefItemRE))) {
   1.952 +                cond = false;
   1.953 +                if (!AddPrefSettings(m[1], m[2], m[3], sandbox, testPrefSettings, refPrefSettings)) {
   1.954 +                    throw "Error in pref value in manifest file " + aURL.spec + " line " + lineNo;
   1.955 +                }
   1.956 +            } else if ((m = item.match(/^fuzzy\((\d+),(\d+)\)$/))) {
   1.957 +              cond = false;
   1.958 +              expected_status = EXPECTED_FUZZY;
   1.959 +              fuzzy_max_delta = Number(m[1]);
   1.960 +              fuzzy_max_pixels = Number(m[2]);
   1.961 +            } else if ((m = item.match(/^fuzzy-if\((.*?),(\d+),(\d+)\)$/))) {
   1.962 +              cond = false;
   1.963 +              if (Components.utils.evalInSandbox("(" + m[1] + ")", sandbox)) {
   1.964 +                expected_status = EXPECTED_FUZZY;
   1.965 +                fuzzy_max_delta = Number(m[2]);
   1.966 +                fuzzy_max_pixels = Number(m[3]);
   1.967 +              }
   1.968 +            } else {
   1.969 +                throw "Error 1 in manifest file " + aURL.spec + " line " + lineNo;
   1.970 +            }
   1.971 +
   1.972 +            if (cond) {
   1.973 +                if (stat == "fails") {
   1.974 +                    expected_status = EXPECTED_FAIL;
   1.975 +                } else if (stat == "random") {
   1.976 +                    expected_status = EXPECTED_RANDOM;
   1.977 +                } else if (stat == "skip") {
   1.978 +                    expected_status = EXPECTED_DEATH;
   1.979 +                } else if (stat == "silentfail") {
   1.980 +                    allow_silent_fail = true;
   1.981 +                }
   1.982 +            }
   1.983 +        }
   1.984 +
   1.985 +        expected_status = Math.max(expected_status, inherited_status);
   1.986 +
   1.987 +        if (minAsserts > maxAsserts) {
   1.988 +            throw "Bad range in manifest file " + aURL.spec + " line " + lineNo;
   1.989 +        }
   1.990 +
   1.991 +        var runHttp = false;
   1.992 +        var httpDepth;
   1.993 +        if (items[0] == "HTTP") {
   1.994 +            runHttp = (aURL.scheme == "file"); // We can't yet run the local HTTP server
   1.995 +                                               // for non-local reftests.
   1.996 +            httpDepth = 0;
   1.997 +            items.shift();
   1.998 +        } else if (items[0].match(/HTTP\(\.\.(\/\.\.)*\)/)) {
   1.999 +            // Accept HTTP(..), HTTP(../..), HTTP(../../..), etc.
  1.1000 +            runHttp = (aURL.scheme == "file"); // We can't yet run the local HTTP server
  1.1001 +                                               // for non-local reftests.
  1.1002 +            httpDepth = (items[0].length - 5) / 3;
  1.1003 +            items.shift();
  1.1004 +        }
  1.1005 +
  1.1006 +        // do not prefix the url for include commands or urls specifying
  1.1007 +        // a protocol
  1.1008 +        if (urlprefix && items[0] != "include") {
  1.1009 +            if (items.length > 1 && !items[1].match(gProtocolRE)) {
  1.1010 +                items[1] = urlprefix + items[1];
  1.1011 +            }
  1.1012 +            if (items.length > 2 && !items[2].match(gProtocolRE)) {
  1.1013 +                items[2] = urlprefix + items[2];
  1.1014 +            }
  1.1015 +        }
  1.1016 +
  1.1017 +        var principal = secMan.getSimpleCodebasePrincipal(aURL);
  1.1018 +
  1.1019 +        if (items[0] == "include") {
  1.1020 +            if (items.length != 2 || runHttp)
  1.1021 +                throw "Error 2 in manifest file " + aURL.spec + " line " + lineNo;
  1.1022 +            var incURI = gIOService.newURI(items[1], null, listURL);
  1.1023 +            secMan.checkLoadURIWithPrincipal(principal, incURI,
  1.1024 +                                             CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
  1.1025 +            ReadManifest(incURI, expected_status);
  1.1026 +        } else if (items[0] == TYPE_LOAD) {
  1.1027 +            if (items.length != 2 ||
  1.1028 +                (expected_status != EXPECTED_PASS &&
  1.1029 +                 expected_status != EXPECTED_DEATH))
  1.1030 +                throw "Error 3 in manifest file " + aURL.spec + " line " + lineNo;
  1.1031 +            var [testURI] = runHttp
  1.1032 +                            ? ServeFiles(principal, httpDepth,
  1.1033 +                                         listURL, [items[1]])
  1.1034 +                            : [gIOService.newURI(items[1], null, listURL)];
  1.1035 +            var prettyPath = runHttp
  1.1036 +                           ? gIOService.newURI(items[1], null, listURL).spec
  1.1037 +                           : testURI.spec;
  1.1038 +            secMan.checkLoadURIWithPrincipal(principal, testURI,
  1.1039 +                                             CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
  1.1040 +            AddTestItem({ type: TYPE_LOAD,
  1.1041 +                          expected: expected_status,
  1.1042 +                          allowSilentFail: allow_silent_fail,
  1.1043 +                          prettyPath: prettyPath,
  1.1044 +                          minAsserts: minAsserts,
  1.1045 +                          maxAsserts: maxAsserts,
  1.1046 +                          needsFocus: needs_focus,
  1.1047 +                          slow: slow,
  1.1048 +                          prefSettings1: testPrefSettings,
  1.1049 +                          prefSettings2: refPrefSettings,
  1.1050 +                          fuzzyMaxDelta: fuzzy_max_delta,
  1.1051 +                          fuzzyMaxPixels: fuzzy_max_pixels,
  1.1052 +                          url1: testURI,
  1.1053 +                          url2: null });
  1.1054 +        } else if (items[0] == TYPE_SCRIPT) {
  1.1055 +            if (items.length != 2)
  1.1056 +                throw "Error 4 in manifest file " + aURL.spec + " line " + lineNo;
  1.1057 +            var [testURI] = runHttp
  1.1058 +                            ? ServeFiles(principal, httpDepth,
  1.1059 +                                         listURL, [items[1]])
  1.1060 +                            : [gIOService.newURI(items[1], null, listURL)];
  1.1061 +            var prettyPath = runHttp
  1.1062 +                           ? gIOService.newURI(items[1], null, listURL).spec
  1.1063 +                           : testURI.spec;
  1.1064 +            secMan.checkLoadURIWithPrincipal(principal, testURI,
  1.1065 +                                             CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
  1.1066 +            AddTestItem({ type: TYPE_SCRIPT,
  1.1067 +                          expected: expected_status,
  1.1068 +                          allowSilentFail: allow_silent_fail,
  1.1069 +                          prettyPath: prettyPath,
  1.1070 +                          minAsserts: minAsserts,
  1.1071 +                          maxAsserts: maxAsserts,
  1.1072 +                          needsFocus: needs_focus,
  1.1073 +                          slow: slow,
  1.1074 +                          prefSettings1: testPrefSettings,
  1.1075 +                          prefSettings2: refPrefSettings,
  1.1076 +                          fuzzyMaxDelta: fuzzy_max_delta,
  1.1077 +                          fuzzyMaxPixels: fuzzy_max_pixels,
  1.1078 +                          url1: testURI,
  1.1079 +                          url2: null });
  1.1080 +        } else if (items[0] == TYPE_REFTEST_EQUAL || items[0] == TYPE_REFTEST_NOTEQUAL) {
  1.1081 +            if (items.length != 3)
  1.1082 +                throw "Error 5 in manifest file " + aURL.spec + " line " + lineNo;
  1.1083 +            var [testURI, refURI] = runHttp
  1.1084 +                                  ? ServeFiles(principal, httpDepth,
  1.1085 +                                               listURL, [items[1], items[2]])
  1.1086 +                                  : [gIOService.newURI(items[1], null, listURL),
  1.1087 +                                     gIOService.newURI(items[2], null, listURL)];
  1.1088 +            var prettyPath = runHttp
  1.1089 +                           ? gIOService.newURI(items[1], null, listURL).spec
  1.1090 +                           : testURI.spec;
  1.1091 +            secMan.checkLoadURIWithPrincipal(principal, testURI,
  1.1092 +                                             CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
  1.1093 +            secMan.checkLoadURIWithPrincipal(principal, refURI,
  1.1094 +                                             CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
  1.1095 +            AddTestItem({ type: items[0],
  1.1096 +                          expected: expected_status,
  1.1097 +                          allowSilentFail: allow_silent_fail,
  1.1098 +                          prettyPath: prettyPath,
  1.1099 +                          minAsserts: minAsserts,
  1.1100 +                          maxAsserts: maxAsserts,
  1.1101 +                          needsFocus: needs_focus,
  1.1102 +                          slow: slow,
  1.1103 +                          prefSettings1: testPrefSettings,
  1.1104 +                          prefSettings2: refPrefSettings,
  1.1105 +                          fuzzyMaxDelta: fuzzy_max_delta,
  1.1106 +                          fuzzyMaxPixels: fuzzy_max_pixels,
  1.1107 +                          url1: testURI,
  1.1108 +                          url2: refURI });
  1.1109 +        } else {
  1.1110 +            throw "Error 6 in manifest file " + aURL.spec + " line " + lineNo;
  1.1111 +        }
  1.1112 +    }
  1.1113 +}
  1.1114 +
  1.1115 +function AddURIUseCount(uri)
  1.1116 +{
  1.1117 +    if (uri == null)
  1.1118 +        return;
  1.1119 +
  1.1120 +    var spec = uri.spec;
  1.1121 +    if (spec in gURIUseCounts) {
  1.1122 +        gURIUseCounts[spec]++;
  1.1123 +    } else {
  1.1124 +        gURIUseCounts[spec] = 1;
  1.1125 +    }
  1.1126 +}
  1.1127 +
  1.1128 +function BuildUseCounts()
  1.1129 +{
  1.1130 +    gURIUseCounts = {};
  1.1131 +    for (var i = 0; i < gURLs.length; ++i) {
  1.1132 +        var url = gURLs[i];
  1.1133 +        if (url.expected != EXPECTED_DEATH &&
  1.1134 +            (url.type == TYPE_REFTEST_EQUAL ||
  1.1135 +             url.type == TYPE_REFTEST_NOTEQUAL)) {
  1.1136 +            if (url.prefSettings1.length == 0) {
  1.1137 +                AddURIUseCount(gURLs[i].url1);
  1.1138 +            }
  1.1139 +            if (url.prefSettings2.length == 0) {
  1.1140 +                AddURIUseCount(gURLs[i].url2);
  1.1141 +            }
  1.1142 +        }
  1.1143 +    }
  1.1144 +}
  1.1145 +
  1.1146 +function ServeFiles(manifestPrincipal, depth, aURL, files)
  1.1147 +{
  1.1148 +    var listURL = aURL.QueryInterface(CI.nsIFileURL);
  1.1149 +    var directory = listURL.file.parent;
  1.1150 +
  1.1151 +    // Allow serving a tree that's an ancestor of the directory containing
  1.1152 +    // the files so that they can use resources in ../ (etc.).
  1.1153 +    var dirPath = "/";
  1.1154 +    while (depth > 0) {
  1.1155 +        dirPath = "/" + directory.leafName + dirPath;
  1.1156 +        directory = directory.parent;
  1.1157 +        --depth;
  1.1158 +    }
  1.1159 +
  1.1160 +    gCount++;
  1.1161 +    var path = "/" + Date.now() + "/" + gCount;
  1.1162 +    gServer.registerDirectory(path + "/", directory);
  1.1163 +
  1.1164 +    var secMan = CC[NS_SCRIPTSECURITYMANAGER_CONTRACTID]
  1.1165 +                     .getService(CI.nsIScriptSecurityManager);
  1.1166 +
  1.1167 +    var testbase = gIOService.newURI("http://localhost:" + gHttpServerPort +
  1.1168 +                                     path + dirPath, null, null);
  1.1169 +
  1.1170 +    function FileToURI(file)
  1.1171 +    {
  1.1172 +        // Only serve relative URIs via the HTTP server, not absolute
  1.1173 +        // ones like about:blank.
  1.1174 +        var testURI = gIOService.newURI(file, null, testbase);
  1.1175 +
  1.1176 +        // XXX necessary?  manifestURL guaranteed to be file, others always HTTP
  1.1177 +        secMan.checkLoadURIWithPrincipal(manifestPrincipal, testURI,
  1.1178 +                                         CI.nsIScriptSecurityManager.DISALLOW_SCRIPT);
  1.1179 +
  1.1180 +        return testURI;
  1.1181 +    }
  1.1182 +
  1.1183 +    return files.map(FileToURI);
  1.1184 +}
  1.1185 +
  1.1186 +// Return true iff this window is focused when this function returns.
  1.1187 +function Focus()
  1.1188 +{
  1.1189 +    var fm = CC["@mozilla.org/focus-manager;1"].getService(CI.nsIFocusManager);
  1.1190 +    fm.focusedWindow = gContainingWindow;
  1.1191 +#ifdef XP_MACOSX
  1.1192 +    try {
  1.1193 +        var dock = CC["@mozilla.org/widget/macdocksupport;1"].getService(CI.nsIMacDockSupport);
  1.1194 +        dock.activateApplication(true);
  1.1195 +    } catch(ex) {
  1.1196 +    }
  1.1197 +#endif // XP_MACOSX
  1.1198 +    return true;
  1.1199 +}
  1.1200 +
  1.1201 +function Blur()
  1.1202 +{
  1.1203 +    // On non-remote reftests, this will transfer focus to the dummy window
  1.1204 +    // we created to hold focus for non-needs-focus tests.  Buggy tests
  1.1205 +    // (ones which require focus but don't request needs-focus) will then
  1.1206 +    // fail.
  1.1207 +    gContainingWindow.blur();
  1.1208 +}
  1.1209 +
  1.1210 +function StartCurrentTest()
  1.1211 +{
  1.1212 +    gTestLog = [];
  1.1213 +
  1.1214 +    // make sure we don't run tests that are expected to kill the browser
  1.1215 +    while (gURLs.length > 0) {
  1.1216 +        var test = gURLs[0];
  1.1217 +        if (test.expected == EXPECTED_DEATH) {
  1.1218 +            ++gTestResults.Skip;
  1.1219 +            gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec + " | (SKIP)\n");
  1.1220 +            gURLs.shift();
  1.1221 +        } else if (test.needsFocus && !Focus()) {
  1.1222 +            // FIXME: Marking this as a known fail is dangerous!  What
  1.1223 +            // if it starts failing all the time?
  1.1224 +            ++gTestResults.Skip;
  1.1225 +            gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec + " | (SKIPPED; COULDN'T GET FOCUS)\n");
  1.1226 +            gURLs.shift();
  1.1227 +        } else if (test.slow && !gRunSlowTests) {
  1.1228 +            ++gTestResults.Slow;
  1.1229 +            gDumpLog("REFTEST TEST-KNOWN-SLOW | " + test.url1.spec + " | (SLOW)\n");
  1.1230 +            gURLs.shift();
  1.1231 +        } else {
  1.1232 +            break;
  1.1233 +        }
  1.1234 +    }
  1.1235 +
  1.1236 +    if (gURLs.length == 0) {
  1.1237 +        RestoreChangedPreferences();
  1.1238 +        DoneTests();
  1.1239 +    }
  1.1240 +    else {
  1.1241 +        gDumpLog("REFTEST TEST-START | " + gURLs[0].prettyPath + "\n");
  1.1242 +        if (!gURLs[0].needsFocus) {
  1.1243 +            Blur();
  1.1244 +        }
  1.1245 +        var currentTest = gTotalTests - gURLs.length;
  1.1246 +        gContainingWindow.document.title = "reftest: " + currentTest + " / " + gTotalTests +
  1.1247 +            " (" + Math.floor(100 * (currentTest / gTotalTests)) + "%)";
  1.1248 +        StartCurrentURI(1);
  1.1249 +    }
  1.1250 +}
  1.1251 +
  1.1252 +function StartCurrentURI(aState)
  1.1253 +{
  1.1254 +    gState = aState;
  1.1255 +    gCurrentURL = gURLs[0]["url" + aState].spec;
  1.1256 +
  1.1257 +    RestoreChangedPreferences();
  1.1258 +
  1.1259 +    var prefSettings = gURLs[0]["prefSettings" + aState];
  1.1260 +    if (prefSettings.length > 0) {
  1.1261 +        var prefs = Components.classes["@mozilla.org/preferences-service;1"].
  1.1262 +                    getService(Components.interfaces.nsIPrefBranch);
  1.1263 +        var badPref = undefined;
  1.1264 +        try {
  1.1265 +            prefSettings.forEach(function(ps) {
  1.1266 +                var oldVal;
  1.1267 +                if (ps.type == PREF_BOOLEAN) {
  1.1268 +                    try {
  1.1269 +                        oldVal = prefs.getBoolPref(ps.name);
  1.1270 +                    } catch (e) {
  1.1271 +                        badPref = "boolean preference '" + ps.name + "'";
  1.1272 +                        throw "bad pref";
  1.1273 +                    }
  1.1274 +                } else if (ps.type == PREF_STRING) {
  1.1275 +                    try {
  1.1276 +                        oldVal = prefs.getCharPref(ps.name);
  1.1277 +                    } catch (e) {
  1.1278 +                        badPref = "string preference '" + ps.name + "'";
  1.1279 +                        throw "bad pref";
  1.1280 +                    }
  1.1281 +                } else if (ps.type == PREF_INTEGER) {
  1.1282 +                    try {
  1.1283 +                        oldVal = prefs.getIntPref(ps.name);
  1.1284 +                    } catch (e) {
  1.1285 +                        badPref = "integer preference '" + ps.name + "'";
  1.1286 +                        throw "bad pref";
  1.1287 +                    }
  1.1288 +                } else {
  1.1289 +                    throw "internal error - unknown preference type";
  1.1290 +                }
  1.1291 +                if (oldVal != ps.value) {
  1.1292 +                    gPrefsToRestore.push( { name: ps.name,
  1.1293 +                                            type: ps.type,
  1.1294 +                                            value: oldVal } );
  1.1295 +                    var value = ps.value;
  1.1296 +                    if (ps.type == PREF_BOOLEAN) {
  1.1297 +                        prefs.setBoolPref(ps.name, value);
  1.1298 +                    } else if (ps.type == PREF_STRING) {
  1.1299 +                        prefs.setCharPref(ps.name, value);
  1.1300 +                        value = '"' + value + '"';
  1.1301 +                    } else if (ps.type == PREF_INTEGER) {
  1.1302 +                        prefs.setIntPref(ps.name, value);
  1.1303 +                    }
  1.1304 +                    gDumpLog("SET PREFERENCE pref(" + ps.name + "," + value + ")\n");
  1.1305 +                }
  1.1306 +            });
  1.1307 +        } catch (e) {
  1.1308 +            if (e == "bad pref") {
  1.1309 +                var test = gURLs[0];
  1.1310 +                if (test.expected == EXPECTED_FAIL) {
  1.1311 +                    gDumpLog("REFTEST TEST-KNOWN-FAIL | " + test.url1.spec +
  1.1312 +                             " | (SKIPPED; " + badPref + " not known or wrong type)\n");
  1.1313 +                    ++gTestResults.Skip;
  1.1314 +                } else {
  1.1315 +                    gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + test.url1.spec +
  1.1316 +                             " | " + badPref + " not known or wrong type\n");
  1.1317 +                    ++gTestResults.UnexpectedFail;
  1.1318 +                }
  1.1319 +            } else {
  1.1320 +                throw e;
  1.1321 +            }
  1.1322 +        }
  1.1323 +        if (badPref != undefined) {
  1.1324 +            // skip the test that had a bad preference
  1.1325 +            gURLs.shift();
  1.1326 +
  1.1327 +            StartCurrentTest();
  1.1328 +            return;
  1.1329 +        }
  1.1330 +    }
  1.1331 +
  1.1332 +    if (prefSettings.length == 0 &&
  1.1333 +        gURICanvases[gCurrentURL] &&
  1.1334 +        (gURLs[0].type == TYPE_REFTEST_EQUAL ||
  1.1335 +         gURLs[0].type == TYPE_REFTEST_NOTEQUAL) &&
  1.1336 +        gURLs[0].maxAsserts == 0) {
  1.1337 +        // Pretend the document loaded --- RecordResult will notice
  1.1338 +        // there's already a canvas for this URL
  1.1339 +        gContainingWindow.setTimeout(RecordResult, 0);
  1.1340 +    } else {
  1.1341 +        var currentTest = gTotalTests - gURLs.length;
  1.1342 +        gDumpLog("REFTEST TEST-LOAD | " + gCurrentURL + " | " + currentTest + " / " + gTotalTests +
  1.1343 +            " (" + Math.floor(100 * (currentTest / gTotalTests)) + "%)\n");
  1.1344 +        LogInfo("START " + gCurrentURL);
  1.1345 +        var type = gURLs[0].type
  1.1346 +        if (TYPE_SCRIPT == type) {
  1.1347 +            SendLoadScriptTest(gCurrentURL, gLoadTimeout);
  1.1348 +        } else {
  1.1349 +            SendLoadTest(type, gCurrentURL, gLoadTimeout);
  1.1350 +        }
  1.1351 +    }
  1.1352 +}
  1.1353 +
  1.1354 +function DoneTests()
  1.1355 +{
  1.1356 +    gDumpLog("REFTEST FINISHED: Slowest test took " + gSlowestTestTime +
  1.1357 +         "ms (" + gSlowestTestURL + ")\n");
  1.1358 +
  1.1359 +    gDumpLog("REFTEST INFO | Result summary:\n");
  1.1360 +    var count = gTestResults.Pass + gTestResults.LoadOnly;
  1.1361 +    gDumpLog("REFTEST INFO | Successful: " + count + " (" +
  1.1362 +             gTestResults.Pass + " pass, " +
  1.1363 +             gTestResults.LoadOnly + " load only)\n");
  1.1364 +    count = gTestResults.Exception + gTestResults.FailedLoad +
  1.1365 +            gTestResults.UnexpectedFail + gTestResults.UnexpectedPass +
  1.1366 +            gTestResults.AssertionUnexpected +
  1.1367 +            gTestResults.AssertionUnexpectedFixed;
  1.1368 +    gDumpLog("REFTEST INFO | Unexpected: " + count + " (" +
  1.1369 +             gTestResults.UnexpectedFail + " unexpected fail, " +
  1.1370 +             gTestResults.UnexpectedPass + " unexpected pass, " +
  1.1371 +             gTestResults.AssertionUnexpected + " unexpected asserts, " +
  1.1372 +             gTestResults.AssertionUnexpectedFixed + " unexpected fixed asserts, " +
  1.1373 +             gTestResults.FailedLoad + " failed load, " +
  1.1374 +             gTestResults.Exception + " exception)\n");
  1.1375 +    count = gTestResults.KnownFail + gTestResults.AssertionKnown +
  1.1376 +            gTestResults.Random + gTestResults.Skip + gTestResults.Slow;
  1.1377 +    gDumpLog("REFTEST INFO | Known problems: " + count + " (" +
  1.1378 +             gTestResults.KnownFail + " known fail, " +
  1.1379 +             gTestResults.AssertionKnown + " known asserts, " +
  1.1380 +             gTestResults.Random + " random, " +
  1.1381 +             gTestResults.Skip + " skipped, " +
  1.1382 +             gTestResults.Slow + " slow)\n");
  1.1383 +
  1.1384 +    gDumpLog("REFTEST INFO | Total canvas count = " + gRecycledCanvases.length + "\n");
  1.1385 +
  1.1386 +    gDumpLog("REFTEST TEST-START | Shutdown\n");
  1.1387 +    function onStopped() {
  1.1388 +        let appStartup = CC["@mozilla.org/toolkit/app-startup;1"].getService(CI.nsIAppStartup);
  1.1389 +        appStartup.quit(CI.nsIAppStartup.eForceQuit);
  1.1390 +    }
  1.1391 +    if (gServer) {
  1.1392 +        gServer.stop(onStopped);
  1.1393 +    }
  1.1394 +    else {
  1.1395 +        onStopped();
  1.1396 +    }
  1.1397 +}
  1.1398 +
  1.1399 +function UpdateCanvasCache(url, canvas)
  1.1400 +{
  1.1401 +    var spec = url.spec;
  1.1402 +
  1.1403 +    --gURIUseCounts[spec];
  1.1404 +
  1.1405 +    if (gNoCanvasCache || gURIUseCounts[spec] == 0) {
  1.1406 +        ReleaseCanvas(canvas);
  1.1407 +        delete gURICanvases[spec];
  1.1408 +    } else if (gURIUseCounts[spec] > 0) {
  1.1409 +        gURICanvases[spec] = canvas;
  1.1410 +    } else {
  1.1411 +        throw "Use counts were computed incorrectly";
  1.1412 +    }
  1.1413 +}
  1.1414 +
  1.1415 +// Recompute drawWindow flags for every drawWindow operation.
  1.1416 +// We have to do this every time since our window can be
  1.1417 +// asynchronously resized (e.g. by the window manager, to make
  1.1418 +// it fit on screen) at unpredictable times.
  1.1419 +// Fortunately this is pretty cheap.
  1.1420 +function DoDrawWindow(ctx, x, y, w, h)
  1.1421 +{
  1.1422 +    var flags = ctx.DRAWWINDOW_DRAW_CARET | ctx.DRAWWINDOW_DRAW_VIEW;
  1.1423 +    var testRect = gBrowser.getBoundingClientRect();
  1.1424 +    if (gIgnoreWindowSize ||
  1.1425 +        (0 <= testRect.left &&
  1.1426 +         0 <= testRect.top &&
  1.1427 +         gContainingWindow.innerWidth >= testRect.right &&
  1.1428 +         gContainingWindow.innerHeight >= testRect.bottom)) {
  1.1429 +        // We can use the window's retained layer manager
  1.1430 +        // because the window is big enough to display the entire
  1.1431 +        // browser element
  1.1432 +        flags |= ctx.DRAWWINDOW_USE_WIDGET_LAYERS;
  1.1433 +    } else if (gBrowserIsRemote) {
  1.1434 +        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | can't drawWindow remote content\n");
  1.1435 +        ++gTestResults.Exception;
  1.1436 +    }
  1.1437 +
  1.1438 +    if (gDrawWindowFlags != flags) {
  1.1439 +        // Every time the flags change, dump the new state.
  1.1440 +        gDrawWindowFlags = flags;
  1.1441 +        var flagsStr = "DRAWWINDOW_DRAW_CARET | DRAWWINDOW_DRAW_VIEW";
  1.1442 +        if (flags & ctx.DRAWWINDOW_USE_WIDGET_LAYERS) {
  1.1443 +            flagsStr += " | DRAWWINDOW_USE_WIDGET_LAYERS";
  1.1444 +        } else {
  1.1445 +            // Output a special warning because we need to be able to detect
  1.1446 +            // this whenever it happens.
  1.1447 +            gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | WARNING: USE_WIDGET_LAYERS disabled\n");
  1.1448 +        }
  1.1449 +        gDumpLog("REFTEST INFO | drawWindow flags = " + flagsStr +
  1.1450 +                 "; window size = " + gContainingWindow.innerWidth + "," + gContainingWindow.innerHeight +
  1.1451 +                 "; test browser size = " + testRect.width + "," + testRect.height +
  1.1452 +                 "\n");
  1.1453 +    }
  1.1454 +
  1.1455 +    LogInfo("DoDrawWindow " + x + "," + y + "," + w + "," + h);
  1.1456 +    ctx.drawWindow(gContainingWindow, x, y, w, h, "rgb(255,255,255)",
  1.1457 +                   gDrawWindowFlags);
  1.1458 +}
  1.1459 +
  1.1460 +function InitCurrentCanvasWithSnapshot()
  1.1461 +{
  1.1462 +    LogInfo("Initializing canvas snapshot");
  1.1463 +
  1.1464 +    if (gURLs[0].type == TYPE_LOAD || gURLs[0].type == TYPE_SCRIPT) {
  1.1465 +        // We don't want to snapshot this kind of test
  1.1466 +        return false;
  1.1467 +    }
  1.1468 +
  1.1469 +    if (!gCurrentCanvas) {
  1.1470 +        gCurrentCanvas = AllocateCanvas();
  1.1471 +    }
  1.1472 +
  1.1473 +    var ctx = gCurrentCanvas.getContext("2d");
  1.1474 +    DoDrawWindow(ctx, 0, 0, gCurrentCanvas.width, gCurrentCanvas.height);
  1.1475 +    return true;
  1.1476 +}
  1.1477 +
  1.1478 +function UpdateCurrentCanvasForInvalidation(rects)
  1.1479 +{
  1.1480 +    LogInfo("Updating canvas for invalidation");
  1.1481 +
  1.1482 +    if (!gCurrentCanvas) {
  1.1483 +        return;
  1.1484 +    }
  1.1485 +
  1.1486 +    var ctx = gCurrentCanvas.getContext("2d");
  1.1487 +    for (var i = 0; i < rects.length; ++i) {
  1.1488 +        var r = rects[i];
  1.1489 +        // Set left/top/right/bottom to pixel boundaries
  1.1490 +        var left = Math.floor(r.left);
  1.1491 +        var top = Math.floor(r.top);
  1.1492 +        var right = Math.ceil(r.right);
  1.1493 +        var bottom = Math.ceil(r.bottom);
  1.1494 +
  1.1495 +        ctx.save();
  1.1496 +        ctx.translate(left, top);
  1.1497 +        DoDrawWindow(ctx, left, top, right - left, bottom - top);
  1.1498 +        ctx.restore();
  1.1499 +    }
  1.1500 +}
  1.1501 +
  1.1502 +function UpdateWholeCurrentCanvasForInvalidation()
  1.1503 +{
  1.1504 +    LogInfo("Updating entire canvas for invalidation");
  1.1505 +
  1.1506 +    if (!gCurrentCanvas) {
  1.1507 +        return;
  1.1508 +    }
  1.1509 +
  1.1510 +    var ctx = gCurrentCanvas.getContext("2d");
  1.1511 +    DoDrawWindow(ctx, 0, 0, gCurrentCanvas.width, gCurrentCanvas.height);
  1.1512 +}
  1.1513 +
  1.1514 +function RecordResult(testRunTime, errorMsg, scriptResults)
  1.1515 +{
  1.1516 +    LogInfo("RecordResult fired");
  1.1517 +
  1.1518 +    // Keep track of which test was slowest, and how long it took.
  1.1519 +    if (testRunTime > gSlowestTestTime) {
  1.1520 +        gSlowestTestTime = testRunTime;
  1.1521 +        gSlowestTestURL  = gCurrentURL;
  1.1522 +    }
  1.1523 +
  1.1524 +    // Not 'const ...' because of 'EXPECTED_*' value dependency.
  1.1525 +    var outputs = {};
  1.1526 +    const randomMsg = "(EXPECTED RANDOM)";
  1.1527 +    outputs[EXPECTED_PASS] = {
  1.1528 +        true:  {s: "TEST-PASS"                  , n: "Pass"},
  1.1529 +        false: {s: "TEST-UNEXPECTED-FAIL"       , n: "UnexpectedFail"}
  1.1530 +    };
  1.1531 +    outputs[EXPECTED_FAIL] = {
  1.1532 +        true:  {s: "TEST-UNEXPECTED-PASS"       , n: "UnexpectedPass"},
  1.1533 +        false: {s: "TEST-KNOWN-FAIL"            , n: "KnownFail"}
  1.1534 +    };
  1.1535 +    outputs[EXPECTED_RANDOM] = {
  1.1536 +        true:  {s: "TEST-PASS" + randomMsg      , n: "Random"},
  1.1537 +        false: {s: "TEST-KNOWN-FAIL" + randomMsg, n: "Random"}
  1.1538 +    };
  1.1539 +    outputs[EXPECTED_FUZZY] = outputs[EXPECTED_PASS];
  1.1540 +
  1.1541 +    var output;
  1.1542 +
  1.1543 +    if (gURLs[0].type == TYPE_LOAD) {
  1.1544 +        ++gTestResults.LoadOnly;
  1.1545 +        gDumpLog("REFTEST TEST-PASS | " + gURLs[0].prettyPath + " | (LOAD ONLY)\n");
  1.1546 +        gCurrentCanvas = null;
  1.1547 +        FinishTestItem();
  1.1548 +        return;
  1.1549 +    }
  1.1550 +    if (gURLs[0].type == TYPE_SCRIPT) {
  1.1551 +        var expected = gURLs[0].expected;
  1.1552 +
  1.1553 +        if (errorMsg) {
  1.1554 +            // Force an unexpected failure to alert the test author to fix the test.
  1.1555 +            expected = EXPECTED_PASS;
  1.1556 +        } else if (scriptResults.length == 0) {
  1.1557 +             // This failure may be due to a JavaScript Engine bug causing
  1.1558 +             // early termination of the test. If we do not allow silent
  1.1559 +             // failure, report an error.
  1.1560 +             if (!gURLs[0].allowSilentFail)
  1.1561 +                 errorMsg = "No test results reported. (SCRIPT)\n";
  1.1562 +             else
  1.1563 +                 gDumpLog("REFTEST INFO | An expected silent failure occurred \n");
  1.1564 +        }
  1.1565 +
  1.1566 +        if (errorMsg) {
  1.1567 +            output = outputs[expected][false];
  1.1568 +            ++gTestResults[output.n];
  1.1569 +            var result = "REFTEST " + output.s + " | " +
  1.1570 +                gURLs[0].prettyPath + " | " + // the URL being tested
  1.1571 +                errorMsg;
  1.1572 +
  1.1573 +            gDumpLog(result);
  1.1574 +            FinishTestItem();
  1.1575 +            return;
  1.1576 +        }
  1.1577 +
  1.1578 +        var anyFailed = scriptResults.some(function(result) { return !result.passed; });
  1.1579 +        var outputPair;
  1.1580 +        if (anyFailed && expected == EXPECTED_FAIL) {
  1.1581 +            // If we're marked as expected to fail, and some (but not all) tests
  1.1582 +            // passed, treat those tests as though they were marked random
  1.1583 +            // (since we can't tell whether they were really intended to be
  1.1584 +            // marked failing or not).
  1.1585 +            outputPair = { true: outputs[EXPECTED_RANDOM][true],
  1.1586 +                           false: outputs[expected][false] };
  1.1587 +        } else {
  1.1588 +            outputPair = outputs[expected];
  1.1589 +        }
  1.1590 +        var index = 0;
  1.1591 +        scriptResults.forEach(function(result) {
  1.1592 +                var output = outputPair[result.passed];
  1.1593 +
  1.1594 +                ++gTestResults[output.n];
  1.1595 +                result = "REFTEST " + output.s + " | " +
  1.1596 +                    gURLs[0].prettyPath + " | " + // the URL being tested
  1.1597 +                    result.description + " item " + (++index) + "\n";
  1.1598 +                gDumpLog(result);
  1.1599 +            });
  1.1600 +
  1.1601 +        if (anyFailed && expected == EXPECTED_PASS) {
  1.1602 +            FlushTestLog();
  1.1603 +        }
  1.1604 +
  1.1605 +        FinishTestItem();
  1.1606 +        return;
  1.1607 +    }
  1.1608 +
  1.1609 +    if (gURLs[0]["prefSettings" + gState].length == 0 &&
  1.1610 +        gURICanvases[gCurrentURL]) {
  1.1611 +        gCurrentCanvas = gURICanvases[gCurrentURL];
  1.1612 +    }
  1.1613 +    if (gCurrentCanvas == null) {
  1.1614 +        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | program error managing snapshots\n");
  1.1615 +        ++gTestResults.Exception;
  1.1616 +    }
  1.1617 +    if (gState == 1) {
  1.1618 +        gCanvas1 = gCurrentCanvas;
  1.1619 +    } else {
  1.1620 +        gCanvas2 = gCurrentCanvas;
  1.1621 +    }
  1.1622 +    gCurrentCanvas = null;
  1.1623 +
  1.1624 +    ResetRenderingState();
  1.1625 +
  1.1626 +    switch (gState) {
  1.1627 +        case 1:
  1.1628 +            // First document has been loaded.
  1.1629 +            // Proceed to load the second document.
  1.1630 +
  1.1631 +            CleanUpCrashDumpFiles();
  1.1632 +            StartCurrentURI(2);
  1.1633 +            break;
  1.1634 +        case 2:
  1.1635 +            // Both documents have been loaded. Compare the renderings and see
  1.1636 +            // if the comparison result matches the expected result specified
  1.1637 +            // in the manifest.
  1.1638 +
  1.1639 +            // number of different pixels
  1.1640 +            var differences;
  1.1641 +            // whether the two renderings match:
  1.1642 +            var equal;
  1.1643 +            var maxDifference = {};
  1.1644 +
  1.1645 +            differences = gWindowUtils.compareCanvases(gCanvas1, gCanvas2, maxDifference);
  1.1646 +            equal = (differences == 0);
  1.1647 +
  1.1648 +            // what is expected on this platform (PASS, FAIL, or RANDOM)
  1.1649 +            var expected = gURLs[0].expected;
  1.1650 +
  1.1651 +            if (maxDifference.value > 0 && maxDifference.value <= gURLs[0].fuzzyMaxDelta &&
  1.1652 +                differences <= gURLs[0].fuzzyMaxPixels) {
  1.1653 +                if (equal) {
  1.1654 +                    throw "Inconsistent result from compareCanvases.";
  1.1655 +                }
  1.1656 +                equal = expected == EXPECTED_FUZZY;
  1.1657 +                gDumpLog("REFTEST fuzzy match\n");
  1.1658 +            }
  1.1659 +
  1.1660 +            // whether the comparison result matches what is in the manifest
  1.1661 +            var test_passed = (equal == (gURLs[0].type == TYPE_REFTEST_EQUAL)) && !gFailedNoPaint;
  1.1662 +
  1.1663 +            output = outputs[expected][test_passed];
  1.1664 +
  1.1665 +            ++gTestResults[output.n];
  1.1666 +
  1.1667 +            // It's possible that we failed both reftest-no-paint and the normal comparison, but we don't
  1.1668 +            // have a way to annotate these separately, so just print an error for the no-paint failure.
  1.1669 +            if (gFailedNoPaint) {
  1.1670 +                if (expected == EXPECTED_FAIL) {
  1.1671 +                    gDumpLog("REFTEST TEST-KNOWN-FAIL | " + gURLs[0].prettyPath + " | failed reftest-no-paint\n");
  1.1672 +                } else {
  1.1673 +                    gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gURLs[0].prettyPath + " | failed reftest-no-paint\n");
  1.1674 +                }
  1.1675 +            } else {
  1.1676 +                var result = "REFTEST " + output.s + " | " +
  1.1677 +                             gURLs[0].prettyPath + " | "; // the URL being tested
  1.1678 +                switch (gURLs[0].type) {
  1.1679 +                    case TYPE_REFTEST_NOTEQUAL:
  1.1680 +                        result += "image comparison (!=)";
  1.1681 +                        break;
  1.1682 +                    case TYPE_REFTEST_EQUAL:
  1.1683 +                        result += "image comparison (==)";
  1.1684 +                        break;
  1.1685 +                }
  1.1686 +
  1.1687 +                if (!test_passed && expected == EXPECTED_PASS ||
  1.1688 +                    !test_passed && expected == EXPECTED_FUZZY ||
  1.1689 +                    test_passed && expected == EXPECTED_FAIL) {
  1.1690 +                    if (!equal) {
  1.1691 +                        result += ", max difference: " + maxDifference.value + ", number of differing pixels: " + differences + "\n";
  1.1692 +                        result += "REFTEST   IMAGE 1 (TEST): " + gCanvas1.toDataURL() + "\n";
  1.1693 +                        result += "REFTEST   IMAGE 2 (REFERENCE): " + gCanvas2.toDataURL() + "\n";
  1.1694 +                    } else {
  1.1695 +                        result += "\n";
  1.1696 +                        result += "REFTEST   IMAGE: " + gCanvas1.toDataURL() + "\n";
  1.1697 +                    }
  1.1698 +                } else {
  1.1699 +                    result += "\n";
  1.1700 +                }
  1.1701 +
  1.1702 +                gDumpLog(result);
  1.1703 +            }
  1.1704 +
  1.1705 +            if (!test_passed && expected == EXPECTED_PASS) {
  1.1706 +                FlushTestLog();
  1.1707 +            }
  1.1708 +
  1.1709 +            if (gURLs[0].prefSettings1.length == 0) {
  1.1710 +                UpdateCanvasCache(gURLs[0].url1, gCanvas1);
  1.1711 +            }
  1.1712 +            if (gURLs[0].prefSettings2.length == 0) {
  1.1713 +                UpdateCanvasCache(gURLs[0].url2, gCanvas2);
  1.1714 +            }
  1.1715 +
  1.1716 +            CleanUpCrashDumpFiles();
  1.1717 +            FinishTestItem();
  1.1718 +            break;
  1.1719 +        default:
  1.1720 +            throw "Unexpected state.";
  1.1721 +    }
  1.1722 +}
  1.1723 +
  1.1724 +function LoadFailed(why)
  1.1725 +{
  1.1726 +    ++gTestResults.FailedLoad;
  1.1727 +    // Once bug 896840 is fixed, this can go away, but for now it will give log
  1.1728 +    // output that is TBPL starable for bug 789751 and bug 720452.
  1.1729 +    if (!why) {
  1.1730 +        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | load failed with unknown reason\n");
  1.1731 +    }
  1.1732 +    gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " +
  1.1733 +         gURLs[0]["url" + gState].spec + " | load failed: " + why + "\n");
  1.1734 +    FlushTestLog();
  1.1735 +    FinishTestItem();
  1.1736 +}
  1.1737 +
  1.1738 +function RemoveExpectedCrashDumpFiles()
  1.1739 +{
  1.1740 +    if (gExpectingProcessCrash) {
  1.1741 +        for each (let crashFilename in gExpectedCrashDumpFiles) {
  1.1742 +            let file = gCrashDumpDir.clone();
  1.1743 +            file.append(crashFilename);
  1.1744 +            if (file.exists()) {
  1.1745 +                file.remove(false);
  1.1746 +            }
  1.1747 +        }
  1.1748 +    }
  1.1749 +    gExpectedCrashDumpFiles.length = 0;
  1.1750 +}
  1.1751 +
  1.1752 +function FindUnexpectedCrashDumpFiles()
  1.1753 +{
  1.1754 +    if (!gCrashDumpDir.exists()) {
  1.1755 +        return;
  1.1756 +    }
  1.1757 +
  1.1758 +    let entries = gCrashDumpDir.directoryEntries;
  1.1759 +    if (!entries) {
  1.1760 +        return;
  1.1761 +    }
  1.1762 +
  1.1763 +    let foundCrashDumpFile = false;
  1.1764 +    while (entries.hasMoreElements()) {
  1.1765 +        let file = entries.getNext().QueryInterface(CI.nsIFile);
  1.1766 +        let path = String(file.path);
  1.1767 +        if (path.match(/\.(dmp|extra)$/) && !gUnexpectedCrashDumpFiles[path]) {
  1.1768 +            if (!foundCrashDumpFile) {
  1.1769 +                ++gTestResults.UnexpectedFail;
  1.1770 +                foundCrashDumpFile = true;
  1.1771 +                gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL +
  1.1772 +                         " | This test left crash dumps behind, but we weren't expecting it to!\n");
  1.1773 +            }
  1.1774 +            gDumpLog("REFTEST INFO | Found unexpected crash dump file " + path +
  1.1775 +                     ".\n");
  1.1776 +            gUnexpectedCrashDumpFiles[path] = true;
  1.1777 +        }
  1.1778 +    }
  1.1779 +}
  1.1780 +
  1.1781 +function CleanUpCrashDumpFiles()
  1.1782 +{
  1.1783 +    RemoveExpectedCrashDumpFiles();
  1.1784 +    FindUnexpectedCrashDumpFiles();
  1.1785 +    gExpectingProcessCrash = false;
  1.1786 +}
  1.1787 +
  1.1788 +function FinishTestItem()
  1.1789 +{
  1.1790 +    // Replace document with BLANK_URL_FOR_CLEARING in case there are
  1.1791 +    // assertions when unloading.
  1.1792 +    gDumpLog("REFTEST INFO | Loading a blank page\n");
  1.1793 +    // After clearing, content will notify us of the assertion count
  1.1794 +    // and tests will continue.
  1.1795 +    SetAsyncScroll(false);
  1.1796 +    SendClear();
  1.1797 +    gFailedNoPaint = false;
  1.1798 +}
  1.1799 +
  1.1800 +function DoAssertionCheck(numAsserts)
  1.1801 +{
  1.1802 +    if (gDebug.isDebugBuild) {
  1.1803 +        if (gBrowserIsRemote) {
  1.1804 +            // Count chrome-process asserts too when content is out of
  1.1805 +            // process.
  1.1806 +            var newAssertionCount = gDebug.assertionCount;
  1.1807 +            var numLocalAsserts = newAssertionCount - gAssertionCount;
  1.1808 +            gAssertionCount = newAssertionCount;
  1.1809 +
  1.1810 +            numAsserts += numLocalAsserts;
  1.1811 +        }
  1.1812 +
  1.1813 +        var minAsserts = gURLs[0].minAsserts;
  1.1814 +        var maxAsserts = gURLs[0].maxAsserts;
  1.1815 +
  1.1816 +        var expectedAssertions = "expected " + minAsserts;
  1.1817 +        if (minAsserts != maxAsserts) {
  1.1818 +            expectedAssertions += " to " + maxAsserts;
  1.1819 +        }
  1.1820 +        expectedAssertions += " assertions";
  1.1821 +
  1.1822 +        if (numAsserts < minAsserts) {
  1.1823 +            ++gTestResults.AssertionUnexpectedFixed;
  1.1824 +            gDumpLog("REFTEST TEST-UNEXPECTED-PASS | " + gURLs[0].prettyPath +
  1.1825 +                 " | assertion count " + numAsserts + " is less than " +
  1.1826 +                 expectedAssertions + "\n");
  1.1827 +        } else if (numAsserts > maxAsserts) {
  1.1828 +            ++gTestResults.AssertionUnexpected;
  1.1829 +            gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gURLs[0].prettyPath +
  1.1830 +                 " | assertion count " + numAsserts + " is more than " +
  1.1831 +                 expectedAssertions + "\n");
  1.1832 +        } else if (numAsserts != 0) {
  1.1833 +            ++gTestResults.AssertionKnown;
  1.1834 +            gDumpLog("REFTEST TEST-KNOWN-FAIL | " + gURLs[0].prettyPath +
  1.1835 +                 " | assertion count " + numAsserts + " matches " +
  1.1836 +                 expectedAssertions + "\n");
  1.1837 +        }
  1.1838 +    }
  1.1839 +
  1.1840 +    gDumpLog("REFTEST TEST-END | " + gURLs[0].prettyPath + "\n");
  1.1841 +
  1.1842 +    // And start the next test.
  1.1843 +    gURLs.shift();
  1.1844 +    StartCurrentTest();
  1.1845 +}
  1.1846 +
  1.1847 +function ResetRenderingState()
  1.1848 +{
  1.1849 +    SendResetRenderingState();
  1.1850 +    // We would want to clear any viewconfig here, if we add support for it
  1.1851 +}
  1.1852 +
  1.1853 +function RestoreChangedPreferences()
  1.1854 +{
  1.1855 +    if (gPrefsToRestore.length > 0) {
  1.1856 +        var prefs = Components.classes["@mozilla.org/preferences-service;1"].
  1.1857 +                    getService(Components.interfaces.nsIPrefBranch);
  1.1858 +        gPrefsToRestore.reverse();
  1.1859 +        gPrefsToRestore.forEach(function(ps) {
  1.1860 +            var value = ps.value;
  1.1861 +            if (ps.type == PREF_BOOLEAN) {
  1.1862 +                prefs.setBoolPref(ps.name, value);
  1.1863 +            } else if (ps.type == PREF_STRING) {
  1.1864 +                prefs.setCharPref(ps.name, value);
  1.1865 +                value = '"' + value + '"';
  1.1866 +            } else if (ps.type == PREF_INTEGER) {
  1.1867 +                prefs.setIntPref(ps.name, value);
  1.1868 +            }
  1.1869 +            gDumpLog("RESTORE PREFERENCE pref(" + ps.name + "," + value + ")\n");
  1.1870 +        });
  1.1871 +        gPrefsToRestore = [];
  1.1872 +    }
  1.1873 +}
  1.1874 +
  1.1875 +function RegisterMessageListenersAndLoadContentScript()
  1.1876 +{
  1.1877 +    gBrowserMessageManager.addMessageListener(
  1.1878 +        "reftest:AssertionCount",
  1.1879 +        function (m) { RecvAssertionCount(m.json.count); }
  1.1880 +    );
  1.1881 +    gBrowserMessageManager.addMessageListener(
  1.1882 +        "reftest:ContentReady",
  1.1883 +        function (m) { return RecvContentReady() }
  1.1884 +    );
  1.1885 +    gBrowserMessageManager.addMessageListener(
  1.1886 +        "reftest:Exception",
  1.1887 +        function (m) { RecvException(m.json.what) }
  1.1888 +    );
  1.1889 +    gBrowserMessageManager.addMessageListener(
  1.1890 +        "reftest:FailedLoad",
  1.1891 +        function (m) { RecvFailedLoad(m.json.why); }
  1.1892 +    );
  1.1893 +    gBrowserMessageManager.addMessageListener(
  1.1894 +        "reftest:FailedNoPaint",
  1.1895 +        function (m) { RecvFailedNoPaint(); }
  1.1896 +    );
  1.1897 +    gBrowserMessageManager.addMessageListener(
  1.1898 +        "reftest:InitCanvasWithSnapshot",
  1.1899 +        function (m) { return RecvInitCanvasWithSnapshot(); }
  1.1900 +    );
  1.1901 +    gBrowserMessageManager.addMessageListener(
  1.1902 +        "reftest:Log",
  1.1903 +        function (m) { RecvLog(m.json.type, m.json.msg); }
  1.1904 +    );
  1.1905 +    gBrowserMessageManager.addMessageListener(
  1.1906 +        "reftest:ScriptResults",
  1.1907 +        function (m) { RecvScriptResults(m.json.runtimeMs, m.json.error, m.json.results); }
  1.1908 +    );
  1.1909 +    gBrowserMessageManager.addMessageListener(
  1.1910 +        "reftest:TestDone",
  1.1911 +        function (m) { RecvTestDone(m.json.runtimeMs); }
  1.1912 +    );
  1.1913 +    gBrowserMessageManager.addMessageListener(
  1.1914 +        "reftest:UpdateCanvasForInvalidation",
  1.1915 +        function (m) { RecvUpdateCanvasForInvalidation(m.json.rects); }
  1.1916 +    );
  1.1917 +    gBrowserMessageManager.addMessageListener(
  1.1918 +        "reftest:UpdateWholeCanvasForInvalidation",
  1.1919 +        function (m) { RecvUpdateWholeCanvasForInvalidation(); }
  1.1920 +    );
  1.1921 +    gBrowserMessageManager.addMessageListener(
  1.1922 +        "reftest:ExpectProcessCrash",
  1.1923 +        function (m) { RecvExpectProcessCrash(); }
  1.1924 +    );
  1.1925 +    gBrowserMessageManager.addMessageListener(
  1.1926 +        "reftest:EnableAsyncScroll",
  1.1927 +        function (m) { SetAsyncScroll(true); }
  1.1928 +    );
  1.1929 +
  1.1930 +    gBrowserMessageManager.loadFrameScript("chrome://reftest/content/reftest-content.js", true, true);
  1.1931 +}
  1.1932 +
  1.1933 +function SetAsyncScroll(enabled)
  1.1934 +{
  1.1935 +    gBrowser.QueryInterface(CI.nsIFrameLoaderOwner).frameLoader.renderMode =
  1.1936 +        enabled ? CI.nsIFrameLoader.RENDER_MODE_ASYNC_SCROLL :
  1.1937 +                  CI.nsIFrameLoader.RENDER_MODE_DEFAULT;
  1.1938 +}
  1.1939 +
  1.1940 +function RecvAssertionCount(count)
  1.1941 +{
  1.1942 +    DoAssertionCheck(count);
  1.1943 +}
  1.1944 +
  1.1945 +function RecvContentReady()
  1.1946 +{
  1.1947 +    InitAndStartRefTests();
  1.1948 +    return { remote: gBrowserIsRemote };
  1.1949 +}
  1.1950 +
  1.1951 +function RecvException(what)
  1.1952 +{
  1.1953 +    gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | " + what + "\n");
  1.1954 +    ++gTestResults.Exception;
  1.1955 +}
  1.1956 +
  1.1957 +function RecvFailedLoad(why)
  1.1958 +{
  1.1959 +    LoadFailed(why);
  1.1960 +}
  1.1961 +
  1.1962 +function RecvFailedNoPaint()
  1.1963 +{
  1.1964 +    gFailedNoPaint = true;
  1.1965 +}
  1.1966 +
  1.1967 +function RecvInitCanvasWithSnapshot()
  1.1968 +{
  1.1969 +    var painted = InitCurrentCanvasWithSnapshot();
  1.1970 +    return { painted: painted };
  1.1971 +}
  1.1972 +
  1.1973 +function RecvLog(type, msg)
  1.1974 +{
  1.1975 +    msg = "[CONTENT] "+ msg;
  1.1976 +    if (type == "info") {
  1.1977 +        LogInfo(msg);
  1.1978 +    } else if (type == "warning") {
  1.1979 +        LogWarning(msg);
  1.1980 +    } else {
  1.1981 +        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | unknown log type " + type + "\n");
  1.1982 +        ++gTestResults.Exception;
  1.1983 +    }
  1.1984 +}
  1.1985 +
  1.1986 +function RecvScriptResults(runtimeMs, error, results)
  1.1987 +{
  1.1988 +    RecordResult(runtimeMs, error, results);
  1.1989 +}
  1.1990 +
  1.1991 +function RecvTestDone(runtimeMs)
  1.1992 +{
  1.1993 +    RecordResult(runtimeMs, '', [ ]);
  1.1994 +}
  1.1995 +
  1.1996 +function RecvUpdateCanvasForInvalidation(rects)
  1.1997 +{
  1.1998 +    UpdateCurrentCanvasForInvalidation(rects);
  1.1999 +}
  1.2000 +
  1.2001 +function RecvUpdateWholeCanvasForInvalidation()
  1.2002 +{
  1.2003 +    UpdateWholeCurrentCanvasForInvalidation();
  1.2004 +}
  1.2005 +
  1.2006 +function OnProcessCrashed(subject, topic, data)
  1.2007 +{
  1.2008 +    var id;
  1.2009 +    subject = subject.QueryInterface(CI.nsIPropertyBag2);
  1.2010 +    if (topic == "plugin-crashed") {
  1.2011 +        id = subject.getPropertyAsAString("pluginDumpID");
  1.2012 +    } else if (topic == "ipc:content-shutdown") {
  1.2013 +        id = subject.getPropertyAsAString("dumpID");
  1.2014 +    }
  1.2015 +    if (id) {
  1.2016 +        gExpectedCrashDumpFiles.push(id + ".dmp");
  1.2017 +        gExpectedCrashDumpFiles.push(id + ".extra");
  1.2018 +    }
  1.2019 +}
  1.2020 +
  1.2021 +function RegisterProcessCrashObservers()
  1.2022 +{
  1.2023 +    var os = CC[NS_OBSERVER_SERVICE_CONTRACTID]
  1.2024 +             .getService(CI.nsIObserverService);
  1.2025 +    os.addObserver(OnProcessCrashed, "plugin-crashed", false);
  1.2026 +    os.addObserver(OnProcessCrashed, "ipc:content-shutdown", false);
  1.2027 +}
  1.2028 +
  1.2029 +function RecvExpectProcessCrash()
  1.2030 +{
  1.2031 +    gExpectingProcessCrash = true;
  1.2032 +}
  1.2033 +
  1.2034 +function SendClear()
  1.2035 +{
  1.2036 +    gBrowserMessageManager.sendAsyncMessage("reftest:Clear");
  1.2037 +}
  1.2038 +
  1.2039 +function SendLoadScriptTest(uri, timeout)
  1.2040 +{
  1.2041 +    gBrowserMessageManager.sendAsyncMessage("reftest:LoadScriptTest",
  1.2042 +                                            { uri: uri, timeout: timeout });
  1.2043 +}
  1.2044 +
  1.2045 +function SendLoadTest(type, uri, timeout)
  1.2046 +{
  1.2047 +    gBrowserMessageManager.sendAsyncMessage("reftest:LoadTest",
  1.2048 +                                            { type: type, uri: uri, timeout: timeout }
  1.2049 +    );
  1.2050 +}
  1.2051 +
  1.2052 +function SendResetRenderingState()
  1.2053 +{
  1.2054 +    gBrowserMessageManager.sendAsyncMessage("reftest:ResetRenderingState");
  1.2055 +}

mercurial