From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- layout/tools/reftest/manifest.sys.mjs | 1046 +++++++++++++++++++++++++++++++++ 1 file changed, 1046 insertions(+) create mode 100644 layout/tools/reftest/manifest.sys.mjs (limited to 'layout/tools/reftest/manifest.sys.mjs') diff --git a/layout/tools/reftest/manifest.sys.mjs b/layout/tools/reftest/manifest.sys.mjs new file mode 100644 index 0000000000..4be0afde57 --- /dev/null +++ b/layout/tools/reftest/manifest.sys.mjs @@ -0,0 +1,1046 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { globals } from "resource://reftest/globals.sys.mjs"; + +const { + NS_GFXINFO_CONTRACTID, + + TYPE_REFTEST_EQUAL, + TYPE_REFTEST_NOTEQUAL, + TYPE_LOAD, + TYPE_SCRIPT, + TYPE_PRINT, + + EXPECTED_PASS, + EXPECTED_FAIL, + EXPECTED_RANDOM, + EXPECTED_FUZZY, + + PREF_BOOLEAN, + PREF_STRING, + PREF_INTEGER, + + FOCUS_FILTER_NEEDS_FOCUS_TESTS, + FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS, + + g, +} = globals; + +import { NetUtil } from "resource://gre/modules/NetUtil.sys.mjs"; +import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; + +const NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX = + "@mozilla.org/network/protocol;1?name="; + +const RE_PROTOCOL = /^\w+:/; +const RE_PREF_ITEM = /^(|test-|ref-)pref\((.+?),(.*)\)$/; + +export function ReadTopManifest(aFileURL, aFilter, aManifestID) { + var url = g.ioService.newURI(aFileURL); + if (!url) { + throw new Error("Expected a file or http URL for the manifest."); + } + + g.manifestsLoaded = {}; + ReadManifest(url, aFilter, aManifestID); +} + +// Note: If you materially change the reftest manifest parsing, +// please keep the parser in layout/tools/reftest/__init__.py in sync. +// eslint-disable-next-line complexity +function ReadManifest(aURL, aFilter, aManifestID) { + // Ensure each manifest is only read once. This assumes that manifests that + // are included with filters will be read via their include before they are + // read directly in the case of a duplicate + if (g.manifestsLoaded.hasOwnProperty(aURL.spec)) { + if (g.manifestsLoaded[aURL.spec] === null) { + return; + } + aFilter = [aFilter[0], aFilter[1], true]; + } + g.manifestsLoaded[aURL.spec] = aFilter[1]; + + var listURL = aURL; + var channel = NetUtil.newChannel({ + uri: aURL, + loadUsingSystemPrincipal: true, + }); + try { + var inputStream = channel.open(); + } catch (e) { + g.logger.error("failed to open manifest at : " + aURL.spec); + throw new Error(e); + } + if (channel instanceof Ci.nsIHttpChannel && channel.responseStatus != 200) { + g.logger.error("HTTP ERROR : " + channel.responseStatus); + } + var streamBuf = getStreamContent(inputStream); + inputStream.close(); + var lines = streamBuf.split(/\n|\r|\r\n/); + + // The sandbox for fails-if(), etc., condition evaluation. This is not + // always required and so is created on demand. + var sandbox; + function GetOrCreateSandbox() { + if (!sandbox) { + sandbox = BuildConditionSandbox(aURL); + } + return sandbox; + } + + var lineNo = 0; + var urlprefix = ""; + var defaults = []; + var defaultTestPrefSettings = [], + defaultRefPrefSettings = []; + if (g.compareRetainedDisplayLists) { + AddRetainedDisplayListTestPrefs( + GetOrCreateSandbox(), + defaultTestPrefSettings, + defaultRefPrefSettings + ); + } + for (var str of lines) { + ++lineNo; + if (str.charAt(0) == "#") { + continue; + } // entire line was a comment + var i = str.search(/\s+#/); + if (i >= 0) { + str = str.substring(0, i); + } + // strip leading and trailing whitespace + str = str.replace(/^\s*/, "").replace(/\s*$/, ""); + if (!str || str == "") { + continue; + } + var items = str.split(/\s+/); // split on whitespace + + if (items[0] == "url-prefix") { + if (items.length != 2) { + throw new Error( + "url-prefix requires one url in manifest file " + + aURL.spec + + " line " + + lineNo + ); + } + urlprefix = items[1]; + continue; + } + + if (items[0] == "defaults") { + items.shift(); + defaults = items; + continue; + } + + var expected_status = EXPECTED_PASS; + var allow_silent_fail = false; + var minAsserts = 0; + var maxAsserts = 0; + var needs_focus = false; + var slow = false; + var skip = false; + var testPrefSettings = defaultTestPrefSettings.concat(); + var refPrefSettings = defaultRefPrefSettings.concat(); + var fuzzy_delta = { min: 0, max: 2 }; + var fuzzy_pixels = { min: 0, max: 1 }; + var chaosMode = false; + var wrCapture = { test: false, ref: false }; + var nonSkipUsed = false; + var noAutoFuzz = false; + + var origLength = items.length; + items = defaults.concat(items); + while ( + items[0].match( + /^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail|pref|test-pref|ref-pref|fuzzy|chaos-mode|wr-capture|wr-capture-ref|noautofuzz)/ + ) + ) { + var item = items.shift(); + var stat; + var cond; + var m = item.match(/^(fails|random|skip|silentfail)-if(\(.*\))$/); + if (m) { + stat = m[1]; + // Note: m[2] contains the parentheses, and we want them. + cond = Cu.evalInSandbox(m[2], GetOrCreateSandbox()); + } else if (item.match(/^(fails|random|skip)$/)) { + stat = item; + cond = true; + } else if (item == "needs-focus") { + needs_focus = true; + cond = false; + } else if ((m = item.match(/^asserts\((\d+)(-\d+)?\)$/))) { + cond = false; + minAsserts = Number(m[1]); + maxAsserts = m[2] == undefined ? minAsserts : Number(m[2].substring(1)); + } else if ((m = item.match(/^asserts-if\((.*?),(\d+)(-\d+)?\)$/))) { + cond = false; + if (Cu.evalInSandbox("(" + m[1] + ")", GetOrCreateSandbox())) { + minAsserts = Number(m[2]); + maxAsserts = + m[3] == undefined ? minAsserts : Number(m[3].substring(1)); + } + } else if (item == "slow") { + cond = false; + slow = true; + } else if ((m = item.match(/^require-or\((.*?)\)$/))) { + var args = m[1].split(/,/); + if (args.length != 2) { + throw new Error( + "Error in manifest file " + + aURL.spec + + " line " + + lineNo + + ": wrong number of args to require-or" + ); + } + var [precondition_str, fallback_action] = args; + var preconditions = precondition_str.split(/&&/); + cond = false; + for (var precondition of preconditions) { + if (precondition === "debugMode") { + // Currently unimplemented. Requires asynchronous + // JSD call + getting an event while no JS is running + stat = fallback_action; + cond = true; + break; + } else if (precondition === "true") { + // For testing + } else { + // Unknown precondition. Assume it is unimplemented. + stat = fallback_action; + cond = true; + break; + } + } + } else if ((m = item.match(/^slow-if\((.*?)\)$/))) { + cond = false; + if (Cu.evalInSandbox("(" + m[1] + ")", GetOrCreateSandbox())) { + slow = true; + } + } else if (item == "silentfail") { + cond = false; + allow_silent_fail = true; + } else if ((m = item.match(RE_PREF_ITEM))) { + cond = false; + if ( + !AddPrefSettings( + m[1], + m[2], + m[3], + GetOrCreateSandbox(), + testPrefSettings, + refPrefSettings + ) + ) { + throw new Error( + "Error in pref value in manifest file " + + aURL.spec + + " line " + + lineNo + ); + } + } else if ((m = item.match(/^fuzzy\((\d+)-(\d+),(\d+)-(\d+)\)$/))) { + cond = false; + expected_status = EXPECTED_FUZZY; + fuzzy_delta = ExtractRange(m, 1); + fuzzy_pixels = ExtractRange(m, 3); + } else if ( + (m = item.match(/^fuzzy-if\((.*?),(\d+)-(\d+),(\d+)-(\d+)\)$/)) + ) { + cond = false; + if (Cu.evalInSandbox("(" + m[1] + ")", GetOrCreateSandbox())) { + expected_status = EXPECTED_FUZZY; + fuzzy_delta = ExtractRange(m, 2); + fuzzy_pixels = ExtractRange(m, 4); + } + } else if (item == "chaos-mode") { + cond = false; + chaosMode = true; + } else if (item == "wr-capture") { + cond = false; + wrCapture.test = true; + } else if (item == "wr-capture-ref") { + cond = false; + wrCapture.ref = true; + } else if (item == "noautofuzz") { + cond = false; + noAutoFuzz = true; + } else { + throw new Error( + "Error in manifest file " + + aURL.spec + + " line " + + lineNo + + ": unexpected item " + + item + ); + } + + if (stat != "skip") { + nonSkipUsed = true; + } + + if (cond) { + if (stat == "fails") { + expected_status = EXPECTED_FAIL; + } else if (stat == "random") { + expected_status = EXPECTED_RANDOM; + } else if (stat == "skip") { + skip = true; + } else if (stat == "silentfail") { + allow_silent_fail = true; + } + } + } + + if (items.length > origLength) { + // Implies we broke out of the loop before we finished processing + // defaults. This means defaults contained an invalid token. + throw new Error( + "Error in manifest file " + + aURL.spec + + " line " + + lineNo + + ": invalid defaults token '" + + items[0] + + "'" + ); + } + + if (minAsserts > maxAsserts) { + throw new Error( + "Bad range in manifest file " + aURL.spec + " line " + lineNo + ); + } + + var runHttp = false; + var httpDepth; + if (items[0] == "HTTP") { + runHttp = aURL.scheme == "file"; // We can't yet run the local HTTP server + // for non-local reftests. + httpDepth = 0; + items.shift(); + } else if (items[0].match(/HTTP\(\.\.(\/\.\.)*\)/)) { + // Accept HTTP(..), HTTP(../..), HTTP(../../..), etc. + runHttp = aURL.scheme == "file"; // We can't yet run the local HTTP server + // for non-local reftests. + httpDepth = (items[0].length - 5) / 3; + items.shift(); + } + + // do not prefix the url for include commands or urls specifying + // a protocol + if (urlprefix && items[0] != "include") { + if (items.length > 1 && !items[1].match(RE_PROTOCOL)) { + items[1] = urlprefix + items[1]; + } + if (items.length > 2 && !items[2].match(RE_PROTOCOL)) { + items[2] = urlprefix + items[2]; + } + } + + var principal = Services.scriptSecurityManager.createContentPrincipal( + aURL, + {} + ); + + if (items[0] == "include") { + if (items.length != 2) { + throw new Error( + "Error in manifest file " + + aURL.spec + + " line " + + lineNo + + ": incorrect number of arguments to include" + ); + } + if (runHttp) { + throw new Error( + "Error in manifest file " + + aURL.spec + + " line " + + lineNo + + ": use of include with http" + ); + } + + // If the expected_status is EXPECTED_PASS (the default) then allow + // the include. If 'skip' is true, that means there was a skip + // or skip-if annotation (with a true condition) on this include + // statement, so we should skip the include. Any other expected_status + // is disallowed since it's nonintuitive as to what the intended + // effect is. + if (nonSkipUsed) { + throw new Error( + "Error in manifest file " + + aURL.spec + + " line " + + lineNo + + ": include statement with annotation other than 'skip' or 'skip-if'" + ); + } else if (skip) { + g.logger.info( + "Skipping included manifest at " + + aURL.spec + + " line " + + lineNo + + " due to matching skip condition" + ); + } else { + // poor man's assertion + if (expected_status != EXPECTED_PASS) { + throw new Error( + "Error in manifest file parsing code: we should never get expected_status=" + + expected_status + + " when nonSkipUsed=false (from " + + aURL.spec + + " line " + + lineNo + + ")" + ); + } + + var incURI = g.ioService.newURI(items[1], null, listURL); + Services.scriptSecurityManager.checkLoadURIWithPrincipal( + principal, + incURI, + Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT + ); + + // Cannot use nsIFile or similar to manipulate the manifest ID; although it appears + // path-like, it does not refer to an actual path in the filesystem. + var newManifestID = aManifestID; + var included = items[1]; + // Remove included manifest file name. + // eg. dir1/dir2/reftest.list -> dir1/dir2 + var pos = included.lastIndexOf("/"); + if (pos <= 0) { + included = ""; + } else { + included = included.substring(0, pos); + } + // Simplify references to parent directories. + // eg. dir1/dir2/../dir3 -> dir1/dir3 + while (included.startsWith("../")) { + pos = newManifestID.lastIndexOf("/"); + if (pos < 0) { + pos = 0; + } + newManifestID = newManifestID.substring(0, pos); + included = included.substring(3); + } + // Use a new manifest ID if the included manifest is in a different directory. + if (included.length) { + if (newManifestID.length) { + newManifestID = newManifestID + "/" + included; + } else { + // parent directory includes may refer to the topsrcdir + newManifestID = included; + } + } + ReadManifest(incURI, aFilter, newManifestID); + } + } else if (items[0] == TYPE_LOAD || items[0] == TYPE_SCRIPT) { + let type = items[0]; + if (items.length != 2) { + throw new Error( + "Error in manifest file " + + aURL.spec + + " line " + + lineNo + + ": incorrect number of arguments to " + + type + ); + } + if (type == TYPE_LOAD && expected_status != EXPECTED_PASS) { + throw new Error( + "Error in manifest file " + + aURL.spec + + " line " + + lineNo + + ": incorrect known failure type for load test" + ); + } + AddTestItem( + { + type, + expected: expected_status, + manifest: aURL.spec, + manifestID: TestIdentifier(aURL.spec, aManifestID), + allowSilentFail: allow_silent_fail, + minAsserts, + maxAsserts, + needsFocus: needs_focus, + slow, + skip, + prefSettings1: testPrefSettings, + prefSettings2: refPrefSettings, + fuzzyMinDelta: fuzzy_delta.min, + fuzzyMaxDelta: fuzzy_delta.max, + fuzzyMinPixels: fuzzy_pixels.min, + fuzzyMaxPixels: fuzzy_pixels.max, + runHttp, + httpDepth, + url1: items[1], + url2: null, + chaosMode, + wrCapture, + noAutoFuzz, + }, + aFilter, + aManifestID + ); + } else if ( + items[0] == TYPE_REFTEST_EQUAL || + items[0] == TYPE_REFTEST_NOTEQUAL || + items[0] == TYPE_PRINT + ) { + if (items.length != 3) { + throw new Error( + "Error in manifest file " + + aURL.spec + + " line " + + lineNo + + ": incorrect number of arguments to " + + items[0] + ); + } + + if ( + items[0] == TYPE_REFTEST_NOTEQUAL && + expected_status == EXPECTED_FUZZY && + (fuzzy_delta.min > 0 || fuzzy_pixels.min > 0) + ) { + throw new Error( + "Error in manifest file " + + aURL.spec + + " line " + + lineNo + + ": minimum fuzz must be zero for tests of type " + + items[0] + ); + } + + let type = items[0]; + if (g.compareRetainedDisplayLists) { + type = TYPE_REFTEST_EQUAL; + + // We expect twice as many assertion failures when comparing + // tests because we run each test twice. + minAsserts *= 2; + maxAsserts *= 2; + + // Skip the test if it is expected to fail in both modes. + // It would unexpectedly "pass" in comparison mode mode when + // comparing the two failures, which is not a useful result. + if ( + expected_status === EXPECTED_FAIL || + expected_status === EXPECTED_RANDOM + ) { + skip = true; + } + } + + AddTestItem( + { + type, + expected: expected_status, + manifest: aURL.spec, + manifestID: TestIdentifier(aURL.spec, aManifestID), + allowSilentFail: allow_silent_fail, + minAsserts, + maxAsserts, + needsFocus: needs_focus, + slow, + skip, + prefSettings1: testPrefSettings, + prefSettings2: refPrefSettings, + fuzzyMinDelta: fuzzy_delta.min, + fuzzyMaxDelta: fuzzy_delta.max, + fuzzyMinPixels: fuzzy_pixels.min, + fuzzyMaxPixels: fuzzy_pixels.max, + runHttp, + httpDepth, + url1: items[1], + url2: items[2], + chaosMode, + wrCapture, + noAutoFuzz, + }, + aFilter, + aManifestID + ); + } else { + throw new Error( + "Error in manifest file " + + aURL.spec + + " line " + + lineNo + + ": unknown test type " + + items[0] + ); + } + } +} + +// Read all available data from an input stream and return it +// as a string. +function getStreamContent(inputStream) { + var streamBuf = ""; + var sis = Cc["@mozilla.org/scriptableinputstream;1"].createInstance( + Ci.nsIScriptableInputStream + ); + sis.init(inputStream); + + var available; + while ((available = sis.available()) != 0) { + streamBuf += sis.read(available); + } + + return streamBuf; +} + +// Build the sandbox for fails-if(), etc., condition evaluation. +function BuildConditionSandbox(aURL) { + var sandbox = new Cu.Sandbox(aURL.spec); + sandbox.isDebugBuild = g.debug.isDebugBuild; + sandbox.isCoverageBuild = g.isCoverageBuild; + + sandbox.xulRuntime = Cu.cloneInto( + { + widgetToolkit: Services.appinfo.widgetToolkit, + OS: Services.appinfo.OS, + XPCOMABI: Services.appinfo.XPCOMABI, + }, + sandbox + ); + + sandbox.smallScreen = false; + if ( + g.containingWindow.innerWidth < 800 || + g.containingWindow.innerHeight < 1000 + ) { + sandbox.smallScreen = true; + } + + var gfxInfo = + NS_GFXINFO_CONTRACTID in Cc && + Cc[NS_GFXINFO_CONTRACTID].getService(Ci.nsIGfxInfo); + let readGfxInfo = function (obj, key) { + if (g.contentGfxInfo && key in g.contentGfxInfo) { + return g.contentGfxInfo[key]; + } + return obj[key]; + }; + + try { + sandbox.d2d = readGfxInfo(gfxInfo, "D2DEnabled"); + sandbox.dwrite = readGfxInfo(gfxInfo, "DWriteEnabled"); + sandbox.embeddedInFirefoxReality = readGfxInfo( + gfxInfo, + "EmbeddedInFirefoxReality" + ); + } catch (e) { + sandbox.d2d = false; + sandbox.dwrite = false; + sandbox.embeddedInFirefoxReality = false; + } + + var canvasBackend = readGfxInfo(gfxInfo, "AzureCanvasBackend"); + var contentBackend = readGfxInfo(gfxInfo, "AzureContentBackend"); + + sandbox.gpuProcess = gfxInfo.usingGPUProcess; + sandbox.azureCairo = canvasBackend == "cairo"; + sandbox.azureSkia = canvasBackend == "skia"; + sandbox.skiaContent = contentBackend == "skia"; + sandbox.azureSkiaGL = false; + // true if we are using the same Azure backend for rendering canvas and content + sandbox.contentSameGfxBackendAsCanvas = + contentBackend == canvasBackend || + (contentBackend == "none" && canvasBackend == "cairo"); + + try { + var windowProtocol = readGfxInfo(gfxInfo, "windowProtocol"); + sandbox.wayland = windowProtocol == "wayland"; + } catch (e) { + sandbox.wayland = false; + } + + sandbox.remoteCanvas = + Services.prefs.getBoolPref("gfx.canvas.remote") && + sandbox.d2d && + sandbox.gpuProcess; + + sandbox.layersGPUAccelerated = g.windowUtils.layerManagerType != "Basic"; + sandbox.d3d11 = g.windowUtils.layerManagerType == "Direct3D 11"; + sandbox.d3d9 = g.windowUtils.layerManagerType == "Direct3D 9"; + sandbox.layersOpenGL = g.windowUtils.layerManagerType == "OpenGL"; + sandbox.swgl = g.windowUtils.layerManagerType.startsWith( + "WebRender (Software" + ); + sandbox.layersOMTC = !!g.windowUtils.layerManagerRemote; + + // Shortcuts for widget toolkits. + sandbox.Android = Services.appinfo.OS == "Android"; + sandbox.cocoaWidget = Services.appinfo.widgetToolkit == "cocoa"; + sandbox.gtkWidget = Services.appinfo.widgetToolkit == "gtk"; + sandbox.qtWidget = Services.appinfo.widgetToolkit == "qt"; + sandbox.winWidget = Services.appinfo.widgetToolkit == "windows"; + + sandbox.is64Bit = Services.appinfo.is64Bit; + + // Use this to annotate reftests that fail in drawSnapshot, but + // the reason hasn't been investigated (or fixed) yet. + sandbox.useDrawSnapshot = g.useDrawSnapshot; + // Use this to annotate reftests that use functionality + // that isn't available to drawSnapshot (like any sort of + // compositor feature such as async scrolling). + sandbox.unsupportedWithDrawSnapshot = g.useDrawSnapshot; + + sandbox.retainedDisplayList = + Services.prefs.getBoolPref("layout.display-list.retain") && + !sandbox.useDrawSnapshot; + + // Needed to specifically test the new and old behavior. This will eventually be removed. + sandbox.retainedDisplayListNew = + sandbox.retainedDisplayList && + Services.prefs.getBoolPref("layout.display-list.retain.sc"); + + // GeckoView is currently uniquely identified by "android + e10s" but + // we might want to make this condition more precise in the future. + sandbox.geckoview = sandbox.Android && g.browserIsRemote; + + // Scrollbars that are semi-transparent. See bug 1169666. + sandbox.transparentScrollbars = Services.appinfo.widgetToolkit == "gtk"; + + if (sandbox.Android) { + sandbox.AndroidVersion = Services.sysinfo.getPropertyAsInt32("version"); + + sandbox.emulator = readGfxInfo(gfxInfo, "adapterDeviceID").includes( + "Android Emulator" + ); + sandbox.device = !sandbox.emulator; + } + + // Some reftests need extra fuzz on the Android 13 Pixel 5 devices. + sandbox.Android13 = sandbox.AndroidVersion == "33"; + + sandbox.MinGW = + sandbox.winWidget && Services.sysinfo.getPropertyAsBool("isMinGW"); + + sandbox.AddressSanitizer = AppConstants.ASAN; + sandbox.ThreadSanitizer = AppConstants.TSAN; + sandbox.webrtc = AppConstants.MOZ_WEBRTC; + sandbox.jxl = AppConstants.MOZ_JXL; + + sandbox.compareRetainedDisplayLists = g.compareRetainedDisplayLists; + + sandbox.release_or_beta = AppConstants.RELEASE_OR_BETA; + + var hh = Cc[NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX + "http"].getService( + Ci.nsIHttpProtocolHandler + ); + var httpProps = [ + "userAgent", + "appName", + "appVersion", + "vendor", + "vendorSub", + "product", + "productSub", + "oscpu", + "language", + "misc", + ]; + sandbox.http = new sandbox.Object(); + httpProps.forEach(x => (sandbox.http[x] = hh[x])); + + // Set OSX to be the Mac OS X version, as an integer, or undefined + // for other platforms. The integer is formed by 100 times the + // major version plus the minor version, so 1006 for 10.6, 1010 for + // 10.10, etc. + var osxmatch = /Mac OS X (\d+).(\d+)$/.exec(hh.oscpu); + sandbox.OSX = osxmatch + ? parseInt(osxmatch[1]) * 100 + parseInt(osxmatch[2]) + : undefined; + + // config specific prefs + sandbox.appleSilicon = Services.prefs.getBoolPref( + "sandbox.apple_silicon", + false + ); + + sandbox.gpuProcessForceEnabled = Services.prefs.getBoolPref( + "layers.gpu-process.force-enabled", + false + ); + + sandbox.prefs = Cu.cloneInto( + { + getBoolPref(p) { + return Services.prefs.getBoolPref(p); + }, + getIntPref(p) { + return Services.prefs.getIntPref(p); + }, + }, + sandbox, + { cloneFunctions: true } + ); + + // Tests shouldn't care about this except for when they need to + // crash the content process + sandbox.browserIsRemote = g.browserIsRemote; + sandbox.browserIsFission = g.browserIsFission; + + try { + sandbox.asyncPan = + g.containingWindow.docShell.asyncPanZoomEnabled && + !sandbox.useDrawSnapshot; + } catch (e) { + sandbox.asyncPan = false; + } + + // Graphics features + sandbox.usesRepeatResampling = sandbox.d2d; + + // Running in a test-verify session? + sandbox.verify = Services.prefs.getBoolPref("reftest.verify", false); + + // Running with a variant enabled? + sandbox.fission = Services.appinfo.fissionAutostart; + sandbox.serviceWorkerE10s = true; + + if (!g.dumpedConditionSandbox) { + g.logger.info( + "Dumping representation of sandbox which can be used for expectation annotations" + ); + for (let entry of Object.entries(Cu.waiveXrays(sandbox)).sort((a, b) => + a[0].localeCompare(b[0]) + )) { + let value = + typeof entry[1] === "object" ? JSON.stringify(entry[1]) : entry[1]; + g.logger.info(` ${entry[0]}: ${value}`); + } + g.dumpedConditionSandbox = true; + } + + return sandbox; +} + +function AddRetainedDisplayListTestPrefs( + aSandbox, + aTestPrefSettings, + aRefPrefSettings +) { + AddPrefSettings( + "test-", + "layout.display-list.retain", + "true", + aSandbox, + aTestPrefSettings, + aRefPrefSettings + ); + AddPrefSettings( + "ref-", + "layout.display-list.retain", + "false", + aSandbox, + aTestPrefSettings, + aRefPrefSettings + ); +} + +function AddPrefSettings( + aWhere, + aPrefName, + aPrefValExpression, + aSandbox, + aTestPrefSettings, + aRefPrefSettings +) { + var prefVal = Cu.evalInSandbox("(" + aPrefValExpression + ")", aSandbox); + var prefType; + var valType = typeof prefVal; + if (valType == "boolean") { + prefType = PREF_BOOLEAN; + } else if (valType == "string") { + prefType = PREF_STRING; + } else if (valType == "number" && parseInt(prefVal) == prefVal) { + prefType = PREF_INTEGER; + } else { + return false; + } + var setting = { name: aPrefName, type: prefType, value: prefVal }; + + if ( + g.compareRetainedDisplayLists && + aPrefName != "layout.display-list.retain" + ) { + // ref-pref() is ignored, test-pref() and pref() are added to both + if (aWhere != "ref-") { + aTestPrefSettings.push(setting); + aRefPrefSettings.push(setting); + } + } else { + if (aWhere != "ref-") { + aTestPrefSettings.push(setting); + } + if (aWhere != "test-") { + aRefPrefSettings.push(setting); + } + } + return true; +} + +function ExtractRange(matches, startIndex) { + return { + min: Number(matches[startIndex]), + max: Number(matches[startIndex + 1]), + }; +} + +function ServeTestBase(aURL, depth) { + var listURL = aURL.QueryInterface(Ci.nsIFileURL); + var directory = listURL.file.parent; + + // Allow serving a tree that's an ancestor of the directory containing + // the files so that they can use resources in ../ (etc.). + var dirPath = "/"; + while (depth > 0) { + dirPath = "/" + directory.leafName + dirPath; + directory = directory.parent; + --depth; + } + + g.count++; + var path = "/" + Date.now() + "/" + g.count; + g.server.registerDirectory(path + "/", directory); + // this one is needed so tests can use example.org urls for cross origin testing + g.server.registerDirectory("/", directory); + + return g.ioService.newURI( + "http://localhost:" + g.httpServerPort + path + dirPath + ); +} + +export function CreateUrls(test) { + let manifestURL = g.ioService.newURI(test.manifest); + + let testbase = manifestURL; + if (test.runHttp) { + testbase = ServeTestBase(manifestURL, test.httpDepth); + } + + let testbasePrincipal = Services.scriptSecurityManager.createContentPrincipal( + testbase, + {} + ); + Services.perms.addFromPrincipal( + testbasePrincipal, + "allowXULXBL", + Services.perms.ALLOW_ACTION + ); + + function FileToURI(file) { + if (file === null) { + return file; + } + + var testURI = g.ioService.newURI(file, null, testbase); + let isChromeOrViewSource = + testURI.scheme == "chrome" || testURI.scheme == "view-source"; + let principal = isChromeOrViewSource + ? Services.scriptSecurityManager.getSystemPrincipal() + : Services.scriptSecurityManager.createContentPrincipal(manifestURL, {}); + Services.scriptSecurityManager.checkLoadURIWithPrincipal( + principal, + testURI, + Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT + ); + return testURI; + } + + let files = [test.url1, test.url2]; + [test.url1, test.url2] = files.map(FileToURI); + + return test; +} + +function TestIdentifier(aUrl, aManifestID) { + // Construct a platform-independent and location-independent test identifier for + // a url; normally the identifier looks like a posix-compliant relative file + // path. + // Test urls may be simple file names, chrome: urls with full paths, about:blank, etc. + if (aUrl.startsWith("about:") || aUrl.startsWith("data:")) { + return aUrl; + } + var pos = aUrl.lastIndexOf("/"); + var url = pos < 0 ? aUrl : aUrl.substring(pos + 1); + return aManifestID + "/" + url; +} + +function AddTestItem(aTest, aFilter, aManifestID) { + if (!aFilter) { + aFilter = [null, [], false]; + } + + var identifier = TestIdentifier(aTest.url1, aManifestID); + if (aTest.url2 !== null) { + identifier = [ + identifier, + aTest.type, + TestIdentifier(aTest.url2, aManifestID), + ]; + } + + var { url1, url2 } = CreateUrls(Object.assign({}, aTest)); + + var globalFilter = aFilter[0]; + var manifestFilter = aFilter[1]; + var invertManifest = aFilter[2]; + if (globalFilter && !globalFilter.test(url1.spec)) { + if (url2 === null) { + return; + } + if (globalFilter && !globalFilter.test(url2.spec)) { + return; + } + } + if (manifestFilter && !(invertManifest ^ manifestFilter.test(url1.spec))) { + if (url2 === null) { + return; + } + if (manifestFilter && !(invertManifest ^ manifestFilter.test(url2.spec))) { + return; + } + } + if ( + g.focusFilterMode == FOCUS_FILTER_NEEDS_FOCUS_TESTS && + !aTest.needsFocus + ) { + return; + } + if ( + g.focusFilterMode == FOCUS_FILTER_NON_NEEDS_FOCUS_TESTS && + aTest.needsFocus + ) { + return; + } + + aTest.identifier = identifier; + g.urls.push(aTest); + // Periodically log progress to avoid no-output timeout on slow platforms. + // No-output timeouts during manifest parsing have been a problem for + // jsreftests on Android/debug. Any logging resets the no-output timer, + // even debug logging which is normally not displayed. + if (g.urls.length % 5000 == 0) { + g.logger.debug(g.urls.length + " tests found..."); + } +} -- cgit v1.2.3