1/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- / 2/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ 3/* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6"use strict"; 7 8var EXPORTED_SYMBOLS = ["ReadTopManifest", "CreateUrls"]; 9 10Cu.import("chrome://reftest/content/globals.jsm", this); 11Cu.import("chrome://reftest/content/reftest.jsm", this); 12Cu.import("resource://gre/modules/Services.jsm"); 13Cu.import("resource://gre/modules/NetUtil.jsm"); 14 15const NS_SCRIPTSECURITYMANAGER_CONTRACTID = "@mozilla.org/scriptsecuritymanager;1"; 16const NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX = "@mozilla.org/network/protocol;1?name="; 17const NS_XREAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1"; 18 19const RE_PROTOCOL = /^\w+:/; 20const RE_PREF_ITEM = /^(|test-|ref-)pref\((.+?),(.*)\)$/; 21 22 23function ReadTopManifest(aFileURL, aFilter) 24{ 25 var url = g.ioService.newURI(aFileURL); 26 if (!url) 27 throw "Expected a file or http URL for the manifest."; 28 29 g.manifestsLoaded = {}; 30 ReadManifest(url, aFilter); 31} 32 33// Note: If you materially change the reftest manifest parsing, 34// please keep the parser in print-manifest-dirs.py in sync. 35function ReadManifest(aURL, aFilter) 36{ 37 // Ensure each manifest is only read once. This assumes that manifests that 38 // are included with filters will be read via their include before they are 39 // read directly in the case of a duplicate 40 if (g.manifestsLoaded.hasOwnProperty(aURL.spec)) { 41 if (g.manifestsLoaded[aURL.spec] === null) 42 return; 43 else 44 aFilter = [aFilter[0], aFilter[1], true]; 45 } 46 g.manifestsLoaded[aURL.spec] = aFilter[1]; 47 48 var secMan = Cc[NS_SCRIPTSECURITYMANAGER_CONTRACTID] 49 .getService(Ci.nsIScriptSecurityManager); 50 51 var listURL = aURL; 52 var channel = NetUtil.newChannel({uri: aURL, loadUsingSystemPrincipal: true}); 53 var inputStream = channel.open2(); 54 if (channel instanceof Ci.nsIHttpChannel 55 && channel.responseStatus != 200) { 56 g.logger.error("HTTP ERROR : " + channel.responseStatus); 57 } 58 var streamBuf = getStreamContent(inputStream); 59 inputStream.close(); 60 var lines = streamBuf.split(/\n|\r|\r\n/); 61 62 // Build the sandbox for fails-if(), etc., condition evaluation. 63 var sandbox = BuildConditionSandbox(aURL); 64 var lineNo = 0; 65 var urlprefix = ""; 66 var defaultTestPrefSettings = [], defaultRefPrefSettings = []; 67 if (g.compareRetainedDisplayLists) { 68 AddRetainedDisplayListTestPrefs(sandbox, defaultTestPrefSettings, 69 defaultRefPrefSettings); 70 } 71 if (g.compareStyloToGecko) { 72 AddStyloTestPrefs(sandbox, defaultTestPrefSettings, 73 defaultRefPrefSettings); 74 } 75 for (var str of lines) { 76 ++lineNo; 77 if (str.charAt(0) == "#") 78 continue; // entire line was a comment 79 var i = str.search(/\s+#/); 80 if (i >= 0) 81 str = str.substring(0, i); 82 // strip leading and trailing whitespace 83 str = str.replace(/^\s*/, '').replace(/\s*$/, ''); 84 if (!str || str == "") 85 continue; 86 var items = str.split(/\s+/); // split on whitespace 87 88 if (items[0] == "url-prefix") { 89 if (items.length != 2) 90 throw "url-prefix requires one url in manifest file " + aURL.spec + " line " + lineNo; 91 urlprefix = items[1]; 92 continue; 93 } 94 95 if (items[0] == "default-preferences") { 96 var m; 97 var item; 98 defaultTestPrefSettings = []; 99 defaultRefPrefSettings = []; 100 items.shift(); 101 while ((item = items.shift())) { 102 if (!(m = item.match(RE_PREF_ITEM))) { 103 throw "Unexpected item in default-preferences list in manifest file " + aURL.spec + " line " + lineNo; 104 } 105 if (!AddPrefSettings(m[1], m[2], m[3], sandbox, defaultTestPrefSettings, defaultRefPrefSettings)) { 106 throw "Error in pref value in manifest file " + aURL.spec + " line " + lineNo; 107 } 108 } 109 if (g.compareRetainedDisplayLists) { 110 AddRetainedDisplayListTestPrefs(sandbox, defaultTestPrefSettings, 111 defaultRefPrefSettings); 112 } 113 if (g.compareStyloToGecko) { 114 AddStyloTestPrefs(sandbox, defaultTestPrefSettings, 115 defaultRefPrefSettings); 116 } 117 continue; 118 } 119 120 var expected_status = EXPECTED_PASS; 121 var allow_silent_fail = false; 122 var minAsserts = 0; 123 var maxAsserts = 0; 124 var needs_focus = false; 125 var slow = false; 126 var testPrefSettings = defaultTestPrefSettings.concat(); 127 var refPrefSettings = defaultRefPrefSettings.concat(); 128 var fuzzy_delta = { min: 0, max: 2 }; 129 var fuzzy_pixels = { min: 0, max: 1 }; 130 var chaosMode = false; 131 var nonSkipUsed = false; 132 133 while (items[0].match(/^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail|pref|test-pref|ref-pref|fuzzy|chaos-mode)/)) { 134 var item = items.shift(); 135 var stat; 136 var cond; 137 var m = item.match(/^(fails|random|skip|silentfail)-if(\(.*\))$/); 138 if (m) { 139 stat = m[1]; 140 // Note: m[2] contains the parentheses, and we want them. 141 cond = Cu.evalInSandbox(m[2], sandbox); 142 } else if (item.match(/^(fails|random|skip)$/)) { 143 stat = item; 144 cond = true; 145 } else if (item == "needs-focus") { 146 needs_focus = true; 147 cond = false; 148 } else if ((m = item.match(/^asserts\((\d+)(-\d+)?\)$/))) { 149 cond = false; 150 minAsserts = Number(m[1]); 151 maxAsserts = (m[2] == undefined) ? minAsserts 152 : Number(m[2].substring(1)); 153 } else if ((m = item.match(/^asserts-if\((.*?),(\d+)(-\d+)?\)$/))) { 154 cond = false; 155 if (Cu.evalInSandbox("(" + m[1] + ")", sandbox)) { 156 minAsserts = Number(m[2]); 157 maxAsserts = 158 (m[3] == undefined) ? minAsserts 159 : Number(m[3].substring(1)); 160 } 161 } else if (item == "slow") { 162 cond = false; 163 slow = true; 164 } else if ((m = item.match(/^require-or\((.*?)\)$/))) { 165 var args = m[1].split(/,/); 166 if (args.length != 2) { 167 throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": wrong number of args to require-or"; 168 } 169 var [precondition_str, fallback_action] = args; 170 var preconditions = precondition_str.split(/&&/); 171 cond = false; 172 for (var precondition of preconditions) { 173 if (precondition === "debugMode") { 174 // Currently unimplemented. Requires asynchronous 175 // JSD call + getting an event while no JS is running 176 stat = fallback_action; 177 cond = true; 178 break; 179 } else if (precondition === "true") { 180 // For testing 181 } else { 182 // Unknown precondition. Assume it is unimplemented. 183 stat = fallback_action; 184 cond = true; 185 break; 186 } 187 } 188 } else if ((m = item.match(/^slow-if\((.*?)\)$/))) { 189 cond = false; 190 if (Cu.evalInSandbox("(" + m[1] + ")", sandbox)) 191 slow = true; 192 } else if (item == "silentfail") { 193 cond = false; 194 allow_silent_fail = true; 195 } else if ((m = item.match(RE_PREF_ITEM))) { 196 cond = false; 197 if (!AddPrefSettings(m[1], m[2], m[3], sandbox, testPrefSettings, refPrefSettings)) { 198 throw "Error in pref value in manifest file " + aURL.spec + " line " + lineNo; 199 } 200 } else if ((m = item.match(/^fuzzy\((\d+)(-\d+)?,(\d+)(-\d+)?\)$/))) { 201 cond = false; 202 expected_status = EXPECTED_FUZZY; 203 fuzzy_delta = ExtractRange(m, 1); 204 fuzzy_pixels = ExtractRange(m, 3); 205 } else if ((m = item.match(/^fuzzy-if\((.*?),(\d+)(-\d+)?,(\d+)(-\d+)?\)$/))) { 206 cond = false; 207 if (Cu.evalInSandbox("(" + m[1] + ")", sandbox)) { 208 expected_status = EXPECTED_FUZZY; 209 fuzzy_delta = ExtractRange(m, 2); 210 fuzzy_pixels = ExtractRange(m, 4); 211 } 212 } else if (item == "chaos-mode") { 213 cond = false; 214 chaosMode = true; 215 } else { 216 throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": unexpected item " + item; 217 } 218 219 if (stat != "skip") { 220 nonSkipUsed = true; 221 } 222 223 if (cond) { 224 if (stat == "fails") { 225 expected_status = EXPECTED_FAIL; 226 } else if (stat == "random") { 227 expected_status = EXPECTED_RANDOM; 228 } else if (stat == "skip") { 229 expected_status = EXPECTED_DEATH; 230 } else if (stat == "silentfail") { 231 allow_silent_fail = true; 232 } 233 } 234 } 235 236 if (minAsserts > maxAsserts) { 237 throw "Bad range in manifest file " + aURL.spec + " line " + lineNo; 238 } 239 240 var runHttp = false; 241 var httpDepth; 242 if (items[0] == "HTTP") { 243 runHttp = (aURL.scheme == "file"); // We can't yet run the local HTTP server 244 // for non-local reftests. 245 httpDepth = 0; 246 items.shift(); 247 } else if (items[0].match(/HTTP\(\.\.(\/\.\.)*\)/)) { 248 // Accept HTTP(..), HTTP(../..), HTTP(../../..), etc. 249 runHttp = (aURL.scheme == "file"); // We can't yet run the local HTTP server 250 // for non-local reftests. 251 httpDepth = (items[0].length - 5) / 3; 252 items.shift(); 253 } 254 255 // do not prefix the url for include commands or urls specifying 256 // a protocol 257 if (urlprefix && items[0] != "include") { 258 if (items.length > 1 && !items[1].match(RE_PROTOCOL)) { 259 items[1] = urlprefix + items[1]; 260 } 261 if (items.length > 2 && !items[2].match(RE_PROTOCOL)) { 262 items[2] = urlprefix + items[2]; 263 } 264 } 265 266 var principal = secMan.createCodebasePrincipal(aURL, {}); 267 268 if (items[0] == "include") { 269 if (items.length != 2) 270 throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to include"; 271 if (runHttp) 272 throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": use of include with http"; 273 274 // If the expected_status is EXPECTED_PASS (the default) then allow 275 // the include. If it is EXPECTED_DEATH, that means there was a skip 276 // or skip-if annotation (with a true condition) on this include 277 // statement, so we should skip the include. Any other expected_status 278 // is disallowed since it's nonintuitive as to what the intended 279 // effect is. 280 if (nonSkipUsed) { 281 throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": include statement with annotation other than 'skip' or 'skip-if'"; 282 } else if (expected_status == EXPECTED_DEATH) { 283 g.logger.info("Skipping included manifest at " + aURL.spec + " line " + lineNo + " due to matching skip condition"); 284 } else { 285 // poor man's assertion 286 if (expected_status != EXPECTED_PASS) { 287 throw "Error in manifest file parsing code: we should never get expected_status=" + expected_status + " when nonSkipUsed=false (from " + aURL.spec + " line " + lineNo + ")"; 288 } 289 290 var incURI = g.ioService.newURI(items[1], null, listURL); 291 secMan.checkLoadURIWithPrincipal(principal, incURI, 292 Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT); 293 ReadManifest(incURI, aFilter); 294 } 295 } else if (items[0] == TYPE_LOAD || items[0] == TYPE_SCRIPT) { 296 if (items.length != 2) 297 throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to " + items[0]; 298 if (items[0] == TYPE_LOAD && expected_status != EXPECTED_PASS && expected_status != EXPECTED_DEATH) 299 throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect known failure type for load test"; 300 AddTestItem({ type: TYPE_LOAD, 301 expected: expected_status, 302 manifest: aURL.spec, 303 allowSilentFail: allow_silent_fail, 304 minAsserts: minAsserts, 305 maxAsserts: maxAsserts, 306 needsFocus: needs_focus, 307 slow: slow, 308 prefSettings1: testPrefSettings, 309 prefSettings2: refPrefSettings, 310 fuzzyMinDelta: fuzzy_delta.min, 311 fuzzyMaxDelta: fuzzy_delta.max, 312 fuzzyMinPixels: fuzzy_pixels.min, 313 fuzzyMaxPixels: fuzzy_pixels.max, 314 runHttp: runHttp, 315 httpDepth: httpDepth, 316 url1: items[1], 317 url2: null, 318 chaosMode: chaosMode }, aFilter); 319 } else if (items[0] == TYPE_REFTEST_EQUAL || items[0] == TYPE_REFTEST_NOTEQUAL || items[0] == TYPE_PRINT) { 320 if (items.length != 3) 321 throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": incorrect number of arguments to " + items[0]; 322 323 if (items[0] == TYPE_REFTEST_NOTEQUAL && 324 expected_status == EXPECTED_FUZZY && 325 (fuzzy_delta.min > 0 || fuzzy_pixels.min > 0)) { 326 throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": minimum fuzz must be zero for tests of type " + items[0]; 327 } 328 329 var type = items[0]; 330 if (g.compareStyloToGecko || g.compareRetainedDisplayLists) { 331 type = TYPE_REFTEST_EQUAL; 332 333 // We expect twice as many assertion failures when running in 334 // styloVsGecko mode because we run each test twice: once in 335 // Stylo mode and once in Gecko mode. 336 minAsserts *= 2; 337 maxAsserts *= 2; 338 339 // Skip the test if it is expected to fail in both Stylo and 340 // Gecko modes. It would unexpectedly "pass" in styloVsGecko 341 // mode when comparing the two failures, which is not a useful 342 // result. 343 if (expected_status === EXPECTED_FAIL || 344 expected_status === EXPECTED_RANDOM) { 345 expected_status = EXPECTED_DEATH; 346 } 347 } 348 349 AddTestItem({ type: type, 350 expected: expected_status, 351 manifest: aURL.spec, 352 allowSilentFail: allow_silent_fail, 353 minAsserts: minAsserts, 354 maxAsserts: maxAsserts, 355 needsFocus: needs_focus, 356 slow: slow, 357 prefSettings1: testPrefSettings, 358 prefSettings2: refPrefSettings, 359 fuzzyMinDelta: fuzzy_delta.min, 360 fuzzyMaxDelta: fuzzy_delta.max, 361 fuzzyMinPixels: fuzzy_pixels.min, 362 fuzzyMaxPixels: fuzzy_pixels.max, 363 runHttp: runHttp, 364 httpDepth: httpDepth, 365 url1: items[1], 366 url2: items[2], 367 chaosMode: chaosMode }, aFilter); 368 } else { 369 throw "Error in manifest file " + aURL.spec + " line " + lineNo + ": unknown test type " + items[0]; 370 } 371 } 372} 373 374// Read all available data from an input stream and return it 375// as a string. 376function getStreamContent(inputStream) 377{ 378 var streamBuf = ""; 379 var sis = Cc["@mozilla.org/scriptableinputstream;1"]. 380 createInstance(Ci.nsIScriptableInputStream); 381 sis.init(inputStream); 382 383 var available; 384 while ((available = sis.available()) != 0) { 385 streamBuf += sis.read(available); 386 } 387 388 return streamBuf; 389} 390 391// Build the sandbox for fails-if(), etc., condition evaluation. 392function BuildConditionSandbox(aURL) { 393 var sandbox = new Cu.Sandbox(aURL.spec); 394 var xr = Cc[NS_XREAPPINFO_CONTRACTID].getService(Ci.nsIXULRuntime); 395 var appInfo = Cc[NS_XREAPPINFO_CONTRACTID].getService(Ci.nsIXULAppInfo); 396 sandbox.isDebugBuild = g.debug.isDebugBuild; 397 var prefs = Cc["@mozilla.org/preferences-service;1"]. 398 getService(Ci.nsIPrefBranch); 399 var env = Cc["@mozilla.org/process/environment;1"]. 400 getService(Ci.nsIEnvironment); 401 402 sandbox.xulRuntime = Cu.cloneInto({widgetToolkit: xr.widgetToolkit, OS: xr.OS, XPCOMABI: xr.XPCOMABI}, sandbox); 403 404 var testRect = g.browser.getBoundingClientRect(); 405 sandbox.smallScreen = false; 406 if (g.containingWindow.innerWidth < 800 || g.containingWindow.innerHeight < 1000) { 407 sandbox.smallScreen = true; 408 } 409 410 var gfxInfo = (NS_GFXINFO_CONTRACTID in Cc) && Cc[NS_GFXINFO_CONTRACTID].getService(Ci.nsIGfxInfo); 411 let readGfxInfo = function (obj, key) { 412 if (g.contentGfxInfo && (key in g.contentGfxInfo)) { 413 return g.contentGfxInfo[key]; 414 } 415 return obj[key]; 416 } 417 418 try { 419 sandbox.d2d = readGfxInfo(gfxInfo, "D2DEnabled"); 420 sandbox.dwrite = readGfxInfo(gfxInfo, "DWriteEnabled"); 421 } catch (e) { 422 sandbox.d2d = false; 423 sandbox.dwrite = false; 424 } 425 426 var info = gfxInfo.getInfo(); 427 var canvasBackend = readGfxInfo(info, "AzureCanvasBackend"); 428 var contentBackend = readGfxInfo(info, "AzureContentBackend"); 429 var canvasAccelerated = readGfxInfo(info, "AzureCanvasAccelerated"); 430 431 sandbox.gpuProcess = gfxInfo.usingGPUProcess; 432 sandbox.azureCairo = canvasBackend == "cairo"; 433 sandbox.azureSkia = canvasBackend == "skia"; 434 sandbox.skiaContent = contentBackend == "skia"; 435 sandbox.azureSkiaGL = canvasAccelerated; // FIXME: assumes GL right now 436 // true if we are using the same Azure backend for rendering canvas and content 437 sandbox.contentSameGfxBackendAsCanvas = contentBackend == canvasBackend 438 || (contentBackend == "none" && canvasBackend == "cairo"); 439 440 sandbox.layersGPUAccelerated = 441 g.windowUtils.layerManagerType != "Basic"; 442 sandbox.d3d11 = 443 g.windowUtils.layerManagerType == "Direct3D 11"; 444 sandbox.d3d9 = 445 g.windowUtils.layerManagerType == "Direct3D 9"; 446 sandbox.layersOpenGL = 447 g.windowUtils.layerManagerType == "OpenGL"; 448 sandbox.webrender = 449 g.windowUtils.layerManagerType == "WebRender"; 450 sandbox.layersOMTC = 451 g.windowUtils.layerManagerRemote == true; 452 sandbox.advancedLayers = 453 g.windowUtils.usingAdvancedLayers == true; 454 sandbox.layerChecksEnabled = !sandbox.webrender; 455 456 sandbox.retainedDisplayList = 457 prefs.getBoolPref("layout.display-list.retain"); 458 459 // Shortcuts for widget toolkits. 460 sandbox.Android = xr.OS == "Android"; 461 sandbox.cocoaWidget = xr.widgetToolkit == "cocoa"; 462 sandbox.gtkWidget = xr.widgetToolkit == "gtk3"; 463 sandbox.qtWidget = xr.widgetToolkit == "qt"; 464 sandbox.winWidget = xr.widgetToolkit == "windows"; 465 466 // Scrollbars that are semi-transparent. See bug 1169666. 467 sandbox.transparentScrollbars = xr.widgetToolkit == "gtk3"; 468 469 if (sandbox.Android) { 470 var sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2); 471 472 // This is currently used to distinguish Android 4.0.3 (SDK version 15) 473 // and later from Android 2.x 474 sandbox.AndroidVersion = sysInfo.getPropertyAsInt32("version"); 475 } 476 477#if MOZ_ASAN 478 sandbox.AddressSanitizer = true; 479#else 480 sandbox.AddressSanitizer = false; 481#endif 482 483#if MOZ_WEBRTC 484 sandbox.webrtc = true; 485#else 486 sandbox.webrtc = false; 487#endif 488 489let retainedDisplayListsEnabled = prefs.getBoolPref("layout.display-list.retain", false); 490sandbox.retainedDisplayLists = retainedDisplayListsEnabled && !g.compareRetainedDisplayLists; 491sandbox.compareRetainedDisplayLists = g.compareRetainedDisplayLists; 492 493#ifdef MOZ_STYLO 494 let styloEnabled = false; 495 // Perhaps a bit redundant in places, but this is easier to compare with the 496 // the real check in `nsLayoutUtils.cpp` to ensure they test the same way. 497 if (env.get("STYLO_FORCE_ENABLED")) { 498 styloEnabled = true; 499 } else if (env.get("STYLO_FORCE_DISABLED")) { 500 styloEnabled = false; 501 } else { 502 styloEnabled = prefs.getBoolPref("layout.css.servo.enabled", false); 503 } 504 sandbox.stylo = styloEnabled && !g.compareStyloToGecko; 505 sandbox.styloVsGecko = g.compareStyloToGecko; 506#else 507 sandbox.stylo = false; 508 sandbox.styloVsGecko = false; 509#endif 510 511 sandbox.skiaPdf = false; 512 513#ifdef RELEASE_OR_BETA 514 sandbox.release_or_beta = true; 515#else 516 sandbox.release_or_beta = false; 517#endif 518 519 var hh = Cc[NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX + "http"]. 520 getService(Ci.nsIHttpProtocolHandler); 521 var httpProps = ["userAgent", "appName", "appVersion", "vendor", 522 "vendorSub", "product", "productSub", "platform", 523 "oscpu", "language", "misc"]; 524 sandbox.http = new sandbox.Object(); 525 httpProps.forEach((x) => sandbox.http[x] = hh[x]); 526 527 // Set OSX to be the Mac OS X version, as an integer, or undefined 528 // for other platforms. The integer is formed by 100 times the 529 // major version plus the minor version, so 1006 for 10.6, 1010 for 530 // 10.10, etc. 531 var osxmatch = /Mac OS X (\d+).(\d+)$/.exec(hh.oscpu); 532 sandbox.OSX = osxmatch ? parseInt(osxmatch[1]) * 100 + parseInt(osxmatch[2]) : undefined; 533 534 // see if we have the test plugin available, 535 // and set a sandox prop accordingly 536 sandbox.haveTestPlugin = !sandbox.Android && !!getTestPlugin("Test Plug-in"); 537 538 // Set a flag on sandbox if the windows default theme is active 539 sandbox.windowsDefaultTheme = g.containingWindow.matchMedia("(-moz-windows-default-theme)").matches; 540 541 try { 542 sandbox.nativeThemePref = !prefs.getBoolPref("mozilla.widget.disable-native-theme"); 543 } catch (e) { 544 sandbox.nativeThemePref = true; 545 } 546 sandbox.gpuProcessForceEnabled = prefs.getBoolPref("layers.gpu-process.force-enabled", false); 547 548 sandbox.prefs = Cu.cloneInto({ 549 getBoolPref: function(p) { return prefs.getBoolPref(p); }, 550 getIntPref: function(p) { return prefs.getIntPref(p); } 551 }, sandbox, { cloneFunctions: true }); 552 553 // Tests shouldn't care about this except for when they need to 554 // crash the content process 555 sandbox.browserIsRemote = g.browserIsRemote; 556 557 try { 558 sandbox.asyncPan = g.containingWindow.document.docShell.asyncPanZoomEnabled; 559 } catch (e) { 560 sandbox.asyncPan = false; 561 } 562 563 // Graphics features 564 sandbox.usesRepeatResampling = sandbox.d2d; 565 566 // Running in a test-verify session? 567 sandbox.verify = prefs.getBoolPref("reftest.verify", false); 568 569 if (!g.dumpedConditionSandbox) { 570 g.logger.info("Dumping JSON representation of sandbox"); 571 g.logger.info(JSON.stringify(Cu.waiveXrays(sandbox))); 572 g.dumpedConditionSandbox = true; 573 } 574 575 return sandbox; 576} 577 578function AddRetainedDisplayListTestPrefs(aSandbox, aTestPrefSettings, 579 aRefPrefSettings) { 580 AddPrefSettings("test-", "layout.display-list.retain", "true", aSandbox, 581 aTestPrefSettings, aRefPrefSettings); 582 AddPrefSettings("ref-", "layout.display-list.retain", "false", aSandbox, 583 aTestPrefSettings, aRefPrefSettings); 584} 585 586function AddStyloTestPrefs(aSandbox, aTestPrefSettings, aRefPrefSettings) { 587 AddPrefSettings("test-", "layout.css.servo.enabled", "true", aSandbox, 588 aTestPrefSettings, aRefPrefSettings); 589 AddPrefSettings("ref-", "layout.css.servo.enabled", "false", aSandbox, 590 aTestPrefSettings, aRefPrefSettings); 591} 592 593function AddPrefSettings(aWhere, aPrefName, aPrefValExpression, aSandbox, aTestPrefSettings, aRefPrefSettings) { 594 var prefVal = Cu.evalInSandbox("(" + aPrefValExpression + ")", aSandbox); 595 var prefType; 596 var valType = typeof(prefVal); 597 if (valType == "boolean") { 598 prefType = PREF_BOOLEAN; 599 } else if (valType == "string") { 600 prefType = PREF_STRING; 601 } else if (valType == "number" && (parseInt(prefVal) == prefVal)) { 602 prefType = PREF_INTEGER; 603 } else { 604 return false; 605 } 606 var setting = { name: aPrefName, 607 type: prefType, 608 value: prefVal }; 609 610 if ((g.compareStyloToGecko && aPrefName != "layout.css.servo.enabled") || 611 (g.compareRetainedDisplayLists && aPrefName != "layout.display-list.retain")) { 612 // ref-pref() is ignored, test-pref() and pref() are added to both 613 if (aWhere != "ref-") { 614 aTestPrefSettings.push(setting); 615 aRefPrefSettings.push(setting); 616 } 617 } else { 618 if (aWhere != "ref-") { 619 aTestPrefSettings.push(setting); 620 } 621 if (aWhere != "test-") { 622 aRefPrefSettings.push(setting); 623 } 624 } 625 return true; 626} 627 628function ExtractRange(matches, startIndex, defaultMin = 0) { 629 if (matches[startIndex + 1] === undefined) { 630 return { 631 min: defaultMin, 632 max: Number(matches[startIndex]) 633 }; 634 } 635 return { 636 min: Number(matches[startIndex]), 637 max: Number(matches[startIndex + 1].substring(1)) 638 }; 639} 640 641function ServeTestBase(aURL, depth) { 642 var listURL = aURL.QueryInterface(Ci.nsIFileURL); 643 var directory = listURL.file.parent; 644 645 // Allow serving a tree that's an ancestor of the directory containing 646 // the files so that they can use resources in ../ (etc.). 647 var dirPath = "/"; 648 while (depth > 0) { 649 dirPath = "/" + directory.leafName + dirPath; 650 directory = directory.parent; 651 --depth; 652 } 653 654 g.count++; 655 var path = "/" + Date.now() + "/" + g.count; 656 g.server.registerDirectory(path + "/", directory); 657 658 var secMan = Cc[NS_SCRIPTSECURITYMANAGER_CONTRACTID] 659 .getService(Ci.nsIScriptSecurityManager); 660 661 var testbase = g.ioService.newURI("http://localhost:" + g.httpServerPort + 662 path + dirPath); 663 664 // Give the testbase URI access to XUL and XBL 665 Services.perms.add(testbase, "allowXULXBL", Services.perms.ALLOW_ACTION); 666 return testbase; 667} 668 669function CreateUrls(test) { 670 let secMan = Cc[NS_SCRIPTSECURITYMANAGER_CONTRACTID] 671 .getService(Ci.nsIScriptSecurityManager); 672 673 let manifestURL = g.ioService.newURI(test.manifest); 674 let principal = secMan.createCodebasePrincipal(manifestURL, {}); 675 676 let testbase = manifestURL; 677 if (test.runHttp) 678 testbase = ServeTestBase(manifestURL, test.httpDepth) 679 680 function FileToURI(file) 681 { 682 if (file === null) 683 return file; 684 685 var testURI = g.ioService.newURI(file, null, testbase); 686 secMan.checkLoadURIWithPrincipal(principal, testURI, 687 Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT); 688 return testURI; 689 } 690 691 let files = [test.url1, test.url2]; 692 [test.url1, test.url2] = files.map(FileToURI); 693 if (test.url2 && g.compareStyloToGecko) 694 test.url2 = test.url1; 695 696 return test; 697} 698 699function AddTestItem(aTest, aFilter) { 700 if (!aFilter) 701 aFilter = [null, [], false]; 702 703 var {url1, url2} = CreateUrls(Object.assign({}, aTest)); 704 705 var globalFilter = aFilter[0]; 706 var manifestFilter = aFilter[1]; 707 var invertManifest = aFilter[2]; 708 if ((globalFilter && !globalFilter.test(url1.spec)) || 709 (manifestFilter && 710 !(invertManifest ^ manifestFilter.test(url1.spec)))) 711 return; 712 if (g.focusFilterMode == FOCUS_FILTER_NEEDS_FOCUS_TESTS && 713 !aTest.needsFocus) 714 return; 715 if (g.focusFilterMode == FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS && 716 aTest.needsFocus) 717 return; 718 719 if (url2 !== null) 720 aTest.identifier = [url1.spec, aTest.type, url2.spec]; 721 else 722 aTest.identifier = url1.spec; 723 g.urls.push(aTest); 724} 725