diff --git a/.eslintignore b/.eslintignore index 044c26f480a3..d3c457cad62b 100644 --- a/.eslintignore +++ b/.eslintignore @@ -80,9 +80,8 @@ browser/components/sessionstore/test/unit/data/sessionstore_invalid.js browser/components/enterprisepolicies/schemas/schema.jsm # generated & special files in cld2 browser/components/translation/cld2/** -# Screenshots and Follow-on search are imported as a system add-on and have +# Screenshots is imported as a system add-on and has # their own lint rules currently. -browser/extensions/followonsearch/** browser/extensions/screenshots/** browser/extensions/pdfjs/content/build** browser/extensions/pdfjs/content/web** diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 5e80a101160f..1dadd0585c4e 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1051,7 +1051,7 @@ pref("security.sandbox.content.level", 3); // 2 - "read access triggered by file dialog activity, limited read/write" // "access for Flash functionality" // 3 - "limited read/write access for Flash functionality" -pref("dom.ipc.plugins.sandbox-level.flash", 2); +pref("dom.ipc.plugins.sandbox-level.flash", 1); // Controls the level used on older OS X versions. Is overriden when the // "dom.ipc.plugins.sandbox-level.flash" is set to 0. pref("dom.ipc.plugins.sandbox-level.flash.legacy", 1); @@ -1060,7 +1060,7 @@ pref("dom.ipc.plugins.sandbox-level.flash.max-legacy-os-minor", 10); // Controls the sandbox level used by plugins other than Flash. On Mac, // no other plugins are supported and this pref is only used for test // plugins used in automated tests. -pref("dom.ipc.plugins.sandbox-level.default", 2); +pref("dom.ipc.plugins.sandbox-level.default", 1); #endif #if defined(XP_LINUX) && defined(MOZ_SANDBOX) && defined(MOZ_CONTENT_SANDBOX) diff --git a/browser/base/content/test/performance/browser_startup.js b/browser/base/content/test/performance/browser_startup.js index 9bb6e627a9ac..a7a2156e0498 100644 --- a/browser/base/content/test/performance/browser_startup.js +++ b/browser/base/content/test/performance/browser_startup.js @@ -36,6 +36,7 @@ const startupPhases = { modules: new Set([ "resource://gre/modules/AppConstants.jsm", "resource://gre/modules/ActorManagerParent.jsm", + "resource://gre/modules/CustomElementsListener.jsm", "resource://gre/modules/ExtensionUtils.jsm", "resource://gre/modules/XPCOMUtils.jsm", "resource://gre/modules/Services.jsm", diff --git a/browser/components/extensions/parent/ext-menus.js b/browser/components/extensions/parent/ext-menus.js index 555ce33c6654..7a398bbfe467 100644 --- a/browser/components/extensions/parent/ext-menus.js +++ b/browser/components/extensions/parent/ext-menus.js @@ -580,6 +580,7 @@ MenuItem.prototype = { checked: false, contexts: ["all"], enabled: true, + visible: true, }); }, @@ -708,6 +709,9 @@ MenuItem.prototype = { }, enabledForContext(contextData) { + if (!this.visible) { + return false; + } let contexts = getMenuContexts(contextData); if (!this.contexts.some(n => contexts.has(n))) { return false; diff --git a/browser/components/extensions/schemas/menus.json b/browser/components/extensions/schemas/menus.json index e5176f6f4824..b40b160ac45e 100644 --- a/browser/components/extensions/schemas/menus.json +++ b/browser/components/extensions/schemas/menus.json @@ -197,6 +197,11 @@ "optional": true, "description": "List of contexts this menu item will appear in. Defaults to ['page'] if not specified." }, + "visible": { + "type": "boolean", + "optional": true, + "description": "Whether the item is visible in the menu." + }, "onclick": { "type": "function", "optional": true, @@ -294,6 +299,11 @@ "minItems": 1, "optional": true }, + "visible": { + "type": "boolean", + "optional": true, + "description": "Whether the item is visible in the menu." + }, "onclick": { "type": "function", "optional": "omit-key-if-missing", diff --git a/browser/components/extensions/test/browser/browser-common.ini b/browser/components/extensions/test/browser/browser-common.ini index 0b41b56d4ce5..5eea24e3cabf 100644 --- a/browser/components/extensions/test/browser/browser-common.ini +++ b/browser/components/extensions/test/browser/browser-common.ini @@ -115,6 +115,7 @@ skip-if = (verify && (os == 'linux' || os == 'mac')) [browser_ext_menus_targetElement.js] [browser_ext_menus_targetElement_extension.js] [browser_ext_menus_targetElement_shadow.js] +[browser_ext_menus_visible.js] [browser_ext_omnibox.js] [browser_ext_openPanel.js] skip-if = (verify && !debug && (os == 'linux' || os == 'mac')) diff --git a/browser/components/extensions/test/browser/browser_ext_menus_visible.js b/browser/components/extensions/test/browser/browser_ext_menus_visible.js new file mode 100644 index 000000000000..941830d8e1c9 --- /dev/null +++ b/browser/components/extensions/test/browser/browser_ext_menus_visible.js @@ -0,0 +1,86 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + +const PAGE = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html"; + +add_task(async function visible_false() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE); + + async function background() { + browser.menus.onShown.addListener(info => { + browser.test.assertEq("[]", JSON.stringify(info.menuIds), "Expected no menu items"); + browser.test.sendMessage("done"); + }); + browser.menus.create({ + id: "create-visible-false", + title: "invisible menu item", + visible: false, + }); + browser.menus.create({ + id: "update-without-params", + title: "invisible menu item", + visible: false, + }); + await browser.menus.update("update-without-params", {}); + browser.menus.create({ + id: "update-visible-to-false", + title: "initially visible menu item", + }); + await browser.menus.update("update-visible-to-false", {visible: false}); + browser.test.sendMessage("ready"); + } + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: ["menus"], + }, + background, + }); + + await extension.startup(); + await extension.awaitMessage("ready"); + await openContextMenu(); + await extension.awaitMessage("done"); + await closeContextMenu(); + + await extension.unload(); + + BrowserTestUtils.removeTab(tab); +}); + +add_task(async function visible_true() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE); + + async function background() { + browser.menus.onShown.addListener(info => { + browser.test.assertEq(`["update-to-true"]`, JSON.stringify(info.menuIds), "Expected no menu items"); + browser.test.sendMessage("done"); + }); + browser.menus.create({ + id: "update-to-true", + title: "invisible menu item", + visible: false, + }); + await browser.menus.update("update-to-true", {visible: true}); + browser.test.sendMessage("ready"); + } + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: ["menus"], + }, + background, + }); + + await extension.startup(); + await extension.awaitMessage("ready"); + await openContextMenu(); + await extension.awaitMessage("done"); + await closeContextMenu(); + + await extension.unload(); + + BrowserTestUtils.removeTab(tab); +}); diff --git a/browser/components/search/test/browser_searchEngine_behaviors.js b/browser/components/search/test/browser_searchEngine_behaviors.js index 51d07093c26f..9ac960186571 100644 --- a/browser/components/search/test/browser_searchEngine_behaviors.js +++ b/browser/components/search/test/browser_searchEngine_behaviors.js @@ -103,6 +103,7 @@ async function testSearchEngine(engineDetails) { // Test search URLs (including purposes). let url = engine.getSubmission("foo").uri.spec; Assert.equal(url, base + engineDetails.codes.submission, "Check search URL for 'foo'"); + let sb = BrowserSearch.searchBar; let engineTests = [ { @@ -136,12 +137,8 @@ async function testSearchEngine(engineDetails) { name: "search bar search", searchURL: base + engineDetails.codes.submission, run() { - let sb = BrowserSearch.searchBar; sb.focus(); sb.value = "foo"; - registerCleanupFunction(function() { - sb.value = ""; - }); EventUtils.synthesizeKey("KEY_Enter"); } }, @@ -185,5 +182,6 @@ async function testSearchEngine(engineDetails) { } engine.alias = undefined; + sb.value = ""; BrowserTestUtils.removeTab(tab); } diff --git a/browser/extensions/followonsearch/.eslintrc.js b/browser/extensions/followonsearch/.eslintrc.js deleted file mode 100644 index 7086cdb848d6..000000000000 --- a/browser/extensions/followonsearch/.eslintrc.js +++ /dev/null @@ -1,8 +0,0 @@ -"use strict"; - -module.exports = { - "env": { - "browser": true, - "node": false - } -}; diff --git a/browser/extensions/followonsearch/bootstrap.js b/browser/extensions/followonsearch/bootstrap.js deleted file mode 100644 index 276d72e33f5e..000000000000 --- a/browser/extensions/followonsearch/bootstrap.js +++ /dev/null @@ -1,192 +0,0 @@ -/* 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/. */ - -/* global APP_SHUTDOWN:false */ - -"use strict"; - -ChromeUtils.import("resource://gre/modules/Services.jsm"); -ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); -ChromeUtils.import("resource://gre/modules/Timer.jsm"); - -// Preferences this add-on uses. -const kPrefPrefix = "extensions.followonsearch."; -const PREF_LOGGING = `${kPrefPrefix}logging`; - -const kExtensionID = "followonsearch@mozilla.com"; -const kSaveTelemetryMsg = `${kExtensionID}:save-telemetry`; -const kShutdownMsg = `${kExtensionID}:shutdown`; - -const frameScript = `chrome://followonsearch/content/followonsearch-fs.js?q=${Math.random()}`; - -const validSearchTypes = [ - // A search is a follow-on search from an SAP. - "follow-on", - // The search is a "search access point". - "sap", -]; - -var gLoggingEnabled = false; -var gTelemetryActivated = false; - -/** - * Logs a message to the console if logging is enabled. - * - * @param {String} message The message to log. - */ -function log(message) { - if (gLoggingEnabled) { - console.log("Follow-On Search", message); - } -} - -/** - * Handles receiving a message from the content process to save telemetry. - * - * @param {Object} message The message received. - */ -function handleSaveTelemetryMsg(message) { - if (message.name != kSaveTelemetryMsg) { - throw new Error(`Unexpected message received: ${message.name}`); - } - - let info = message.data; - - if (!validSearchTypes.includes(info.type)) { - throw new Error("Unexpected type!"); - } - - log(info); - - let histogram = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS"); - let payload = `${info.sap}.${info.type}:unknown:${info.code}`; - if (info.extra) { - payload += `:${info.extra}` - } - histogram.add(payload); -} - -/** - * Activates recording of telemetry if it isn't already activated. - */ -function activateTelemetry() { - if (gTelemetryActivated) { - return; - } - - gTelemetryActivated = true; - - Services.mm.addMessageListener(kSaveTelemetryMsg, handleSaveTelemetryMsg); - Services.mm.loadFrameScript(frameScript, true); -} - -/** - * Deactivites recording of telemetry if it isn't already deactivated. - */ -function deactivateTelemetry() { - if (!gTelemetryActivated) { - return; - } - - Services.mm.removeMessageListener(kSaveTelemetryMsg, handleSaveTelemetryMsg); - Services.mm.removeDelayedFrameScript(frameScript); - Services.mm.broadcastAsyncMessage(kShutdownMsg); - - gTelemetryActivated = false; -} - -/** - * cohortManager is used to decide which users to enable the add-on for. - */ -var cohortManager = { - // Indicates whether the telemetry should be enabled. - enableForUser: false, - - // Records if we've already run init. - _definedThisSession: false, - - /** - * Initialises the manager, working out if telemetry should be enabled - * for the user. - */ - init() { - if (this._definedThisSession) { - return; - } - - this._definedThisSession = true; - this.enableForUser = false; - - try { - let distId = Services.prefs.getCharPref("distribution.id", ""); - if (distId) { - log("It is a distribution, not setting up nor enabling telemetry."); - return; - } - } catch (e) {} - - log("Enabling telemetry for user"); - this.enableForUser = true; - }, -}; - -/** - * Called when the add-on is installed. - * - * @param {Object} data Data about the add-on. - * @param {Number} reason Indicates why the extension is being installed. - */ -function install(data, reason) { - // Nothing specifically to do, startup will set everything up for us. -} - -/** - * Called when the add-on is uninstalled. - * - * @param {Object} data Data about the add-on. - * @param {Number} reason Indicates why the extension is being uninstalled. - */ -function uninstall(data, reason) { - // Nothing specifically to do, shutdown does what we need. -} - -/** - * Called when the add-on starts up. - * - * @param {Object} data Data about the add-on. - * @param {Number} reason Indicates why the extension is being started. - */ -function startup(data, reason) { - try { - gLoggingEnabled = Services.prefs.getBoolPref(PREF_LOGGING, false); - } catch (e) { - // Needed until Firefox 54 - } - - cohortManager.init(); - - if (cohortManager.enableForUser) { - // Workaround for bug 1202125 - // We need to delay our loading so that when we are upgraded, - // our new script doesn't get the shutdown message. - setTimeout(() => { - activateTelemetry(); - }, 1000); - } -} - -/** - * Called when the add-on shuts down. - * - * @param {Object} data Data about the add-on. - * @param {Number} reason Indicates why the extension is being shut down. - */ -function shutdown(data, reason) { - // If we're shutting down, skip the cleanup to save time. - if (reason === APP_SHUTDOWN) { - return; - } - - deactivateTelemetry(); -} diff --git a/browser/extensions/followonsearch/content/followonsearch-fs.js b/browser/extensions/followonsearch/content/followonsearch-fs.js deleted file mode 100644 index aaba382d0c86..000000000000 --- a/browser/extensions/followonsearch/content/followonsearch-fs.js +++ /dev/null @@ -1,308 +0,0 @@ -/* 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/. */ - -/* eslint-env mozilla/frame-script */ - -"use strict"; - -ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); -XPCOMUtils.defineLazyGlobalGetters(this, ["URLSearchParams"]); - -const kExtensionID = "followonsearch@mozilla.com"; -const kSaveTelemetryMsg = `${kExtensionID}:save-telemetry`; -const kShutdownMsg = `${kExtensionID}:shutdown`; -const kLastSearchQueueDepth = 10; - -/** - * A map of search domains with their expected codes. - */ -let searchDomains = [{ - "domains": [ "search.yahoo.co.jp" ], - "search": "p", - "followOnSearch": "ai", - "prefix": ["fr"], - "codes": ["mozff"], - "sap": "yahoo", -}, { - "domains": [ "www.bing.com" ], - "search": "q", - "prefix": ["pc"], - "reportPrefix": "form", - "codes": ["MOZI", "MOZD", "MZSL01", "MZSL02", "MZSL03", "MOZ2"], - "sap": "bing", -}, { - // The Google domains. - "domains": [ - "www.google.com", "www.google.ac", "www.google.ad", "www.google.ae", - "www.google.com.af", "www.google.com.ag", "www.google.com.ai", - "www.google.al", "www.google.am", "www.google.co.ao", "www.google.com.ar", - "www.google.as", "www.google.at", "www.google.com.au", "www.google.az", - "www.google.ba", "www.google.com.bd", "www.google.be", "www.google.bf", - "www.google.bg", "www.google.com.bh", "www.google.bi", "www.google.bj", - "www.google.com.bn", "www.google.com.bo", "www.google.com.br", - "www.google.bs", "www.google.bt", "www.google.co.bw", "www.google.by", - "www.google.com.bz", "www.google.ca", "www.google.com.kh", "www.google.cc", - "www.google.cd", "www.google.cf", "www.google.cat", "www.google.cg", - "www.google.ch", "www.google.ci", "www.google.co.ck", "www.google.cl", - "www.google.cm", "www.google.cn", "www.google.com.co", "www.google.co.cr", - "www.google.com.cu", "www.google.cv", "www.google.cx", "www.google.com.cy", - "www.google.cz", "www.google.de", "www.google.dj", "www.google.dk", - "www.google.dm", "www.google.com.do", "www.google.dz", "www.google.com.ec", - "www.google.ee", "www.google.com.eg", "www.google.es", "www.google.com.et", - "www.google.eu", "www.google.fi", "www.google.com.fj", "www.google.fm", - "www.google.fr", "www.google.ga", "www.google.ge", "www.google.gf", - "www.google.gg", "www.google.com.gh", "www.google.com.gi", "www.google.gl", - "www.google.gm", "www.google.gp", "www.google.gr", "www.google.com.gt", - "www.google.gy", "www.google.com.hk", "www.google.hn", "www.google.hr", - "www.google.ht", "www.google.hu", "www.google.co.id", "www.google.iq", - "www.google.ie", "www.google.co.il", "www.google.im", "www.google.co.in", - "www.google.io", "www.google.is", "www.google.it", "www.google.je", - "www.google.com.jm", "www.google.jo", "www.google.co.jp", "www.google.co.ke", - "www.google.ki", "www.google.kg", "www.google.co.kr", "www.google.com.kw", - "www.google.kz", "www.google.la", "www.google.com.lb", "www.google.com.lc", - "www.google.li", "www.google.lk", "www.google.co.ls", "www.google.lt", - "www.google.lu", "www.google.lv", "www.google.com.ly", "www.google.co.ma", - "www.google.md", "www.google.me", "www.google.mg", "www.google.mk", - "www.google.ml", "www.google.com.mm", "www.google.mn", "www.google.ms", - "www.google.com.mt", "www.google.mu", "www.google.mv", "www.google.mw", - "www.google.com.mx", "www.google.com.my", "www.google.co.mz", - "www.google.com.na", "www.google.ne", "www.google.nf", "www.google.com.ng", - "www.google.com.ni", "www.google.nl", "www.google.no", "www.google.com.np", - "www.google.nr", "www.google.nu", "www.google.co.nz", "www.google.com.om", - "www.google.com.pk", "www.google.com.pa", "www.google.com.pe", - "www.google.com.ph", "www.google.pl", "www.google.com.pg", "www.google.pn", - "www.google.com.pr", "www.google.ps", "www.google.pt", "www.google.com.py", - "www.google.com.qa", "www.google.ro", "www.google.rs", "www.google.ru", - "www.google.rw", "www.google.com.sa", "www.google.com.sb", "www.google.sc", - "www.google.se", "www.google.com.sg", "www.google.sh", "www.google.si", - "www.google.sk", "www.google.com.sl", "www.google.sn", "www.google.sm", - "www.google.so", "www.google.st", "www.google.sr", "www.google.com.sv", - "www.google.td", "www.google.tg", "www.google.co.th", "www.google.com.tj", - "www.google.tk", "www.google.tl", "www.google.tm", "www.google.to", - "www.google.tn", "www.google.com.tr", "www.google.tt", "www.google.com.tw", - "www.google.co.tz", "www.google.com.ua", "www.google.co.ug", - "www.google.co.uk", "www.google.us", "www.google.com.uy", "www.google.co.uz", - "www.google.com.vc", "www.google.co.ve", "www.google.vg", "www.google.co.vi", - "www.google.com.vn", "www.google.vu", "www.google.ws", "www.google.co.za", - "www.google.co.zm", "www.google.co.zw", - ], - "search": "q", - "prefix": ["client"], - "followOnSearch": "oq", - "codes": ["firefox-b-ab", "firefox-b", "firefox-b-1-ab", "firefox-b-1"], - "sap": "google", -}, { - // This is intended only for tests. - "domains": [ "mochi.test" ], - "search": "m", - "prefix": ["mt"], - "followOnSearch": "mtfo", - "reportPrefix": "form", - "codes": ["TEST"], - "sap": "mochitest" -}]; - -function getSearchDomainCodes(host) { - for (let domainInfo of searchDomains) { - if (domainInfo.domains.includes(host)) { - return domainInfo; - } - } - return null; -} - -/** - * Used for debugging to log messages. - * - * @param {String} message The message to log. - */ -function log(message) { - // console.log(message); -} - -// Hack to handle the most common reload/back/forward case. -// If gLastSearchQueue includes the current URL, ignore the search. -// This also prevents us from handling reloads with hashes twice -let gLastSearchQueue = []; -gLastSearchQueue.push = function(...args) { - if (this.length >= kLastSearchQueueDepth) { - this.shift(); - } - return Array.prototype.push.apply(this, args); -}; - -// Track if we are in the middle of a Google session -// that started from Firefox -let searchingGoogle = false; - -/** - * Since most codes are in the URL, we can handle them via - * a progress listener. - */ -var webProgressListener = { - QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]), - onLocationChange(aWebProgress, aRequest, aLocation, aFlags) - { - if (aWebProgress.DOMWindow && (aWebProgress.DOMWindow != content)) { - return; - } - try { - if (!aWebProgress.isTopLevel || - // Not a URL - (!aLocation.schemeIs("http") && !aLocation.schemeIs("https")) || - // Doesn't have a query string or a ref - (!aLocation.query && !aLocation.ref)) { - searchingGoogle = false; - return; - } - if (gLastSearchQueue.includes(aLocation.spec)) { - // If it's a recent search, just return. We - // don't reset searchingGoogle though because - // we might still be doing that. - return; - } - let domainInfo = getSearchDomainCodes(aLocation.host); - if (!domainInfo) { - searchingGoogle = false; - return; - } - - let queries = new URLSearchParams(aLocation.query); - // Yahoo has switched to Unified search so we can get - // different codes on the same domain. Hack for now - // to allow two different prefixes for codes - let code = queries.get(domainInfo.prefix[0]); - if (!code && domainInfo.prefix.length > 1) { - code = queries.get(domainInfo.prefix[1]); - } - // Special case Google so we can track searches - // without codes from the browser. - if (domainInfo.sap == "google") { - if (aLocation.filePath == "/search") { - gLastSearchQueue.push(aLocation.spec); - // Our engine currently sends oe and ie - no one else does - if (queries.get("oe") && queries.get("ie")) { - sendSaveTelemetryMsg(code ? code : "none", code, "sap"); - searchingGoogle = true; - } else { - // The tbm value is the specific type of search (Books, Images, News, etc). - // These are referred to as vertical searches. - let tbm = queries.get("tbm"); - if (searchingGoogle) { - sendSaveTelemetryMsg(code ? code : "none", code, "follow-on", tbm ? `vertical-${tbm}` : null); - } else if (code) { - // Trying to do the right thing for back button to existing entries - sendSaveTelemetryMsg(code, domainInfo.sap, "follow-on", tbm ? `vertical-${tbm}` : null); - } - } - } - // Special case all Google. Otherwise our code can - // show up in maps - return; - } - searchingGoogle = false; - if (queries.get(domainInfo.search)) { - if (domainInfo.codes.includes(code)) { - if (domainInfo.reportPrefix && - queries.get(domainInfo.reportPrefix)) { - code = queries.get(domainInfo.reportPrefix); - } - if (queries.get(domainInfo.followOnSearch)) { - log(`${aLocation.host} search with code ${code} - Follow on`); - sendSaveTelemetryMsg(code, domainInfo.sap, "follow-on"); - } else { - log(`${aLocation.host} search with code ${code} - First search via Firefox`); - sendSaveTelemetryMsg(code, domainInfo.sap, "sap"); - } - gLastSearchQueue.push(aLocation.spec); - } - } - } catch (e) { - console.error(e); - } - }, -}; - -/** - * Parses a cookie string into separate parts. - * - * @param {String} cookieString The string to parse. - * @param {Object} [params] An optional object to append the parameters to. - * @return {Object} An object containing the query keys and values. - */ -function parseCookies(cookieString, params = {}) { - var cookies = cookieString.split(/;\s*/); - - for (var i in cookies) { - var kvp = cookies[i].split(/=(.+)/); - params[kvp[0]] = kvp[1]; - } - - return params; -} - -/** - * Page load listener to handle loads www.bing.com only. - * We have to use a page load listener because we need - * to check cookies. - * @param {Object} event The page load event. - */ -function onPageLoad(event) { - var doc = event.target; - var win = doc.defaultView; - if (win != win.top) { - return; - } - var uri = doc.documentURIObject; - if (!(uri instanceof Ci.nsIStandardURL) || - (!uri.schemeIs("http") && !uri.schemeIs("https")) || - uri.host != "www.bing.com" || - !doc.location.search || - gLastSearchQueue.includes(uri.spec)) { - return; - } - var queries = new URLSearchParams(doc.location.search.toLowerCase()); - // For Bing, QBRE form code is used for all follow-on search - if (queries.get("form") != "qbre") { - return; - } - if (parseCookies(doc.cookie).SRCHS == "PC=MOZI") { - log(`${uri.host} search with code MOZI - Follow on`); - sendSaveTelemetryMsg("MOZI", "bing", "follow-on"); - gLastSearchQueue.push(uri.spec); - } -} - -/** - * Sends a message to the process that added this script to tell it to save - * telemetry. - * - * @param {String} code The codes used for the search engine. - * @param {String} sap The SAP code. - * @param {String} type The type of search (sap/follow-on). - * @param {String} extra Any additional parameters (Optional) - */ -function sendSaveTelemetryMsg(code, sap, type, extra) { - sendAsyncMessage(kSaveTelemetryMsg, { - code, - sap, - type, - extra, - }); -} - -addEventListener("DOMContentLoaded", onPageLoad, false); -docShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebProgress) - .addProgressListener(webProgressListener, Ci.nsIWebProgress.NOTIFY_LOCATION); - -let gDisabled = false; - -addMessageListener(kShutdownMsg, () => { - if (!gDisabled) { - removeEventListener("DOMContentLoaded", onPageLoad, false); - docShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebProgress) - .removeProgressListener(webProgressListener); - gDisabled = true; - } -}); diff --git a/browser/extensions/followonsearch/install.rdf b/browser/extensions/followonsearch/install.rdf deleted file mode 100644 index 971f8ed63889..000000000000 --- a/browser/extensions/followonsearch/install.rdf +++ /dev/null @@ -1,22 +0,0 @@ - - - - - followonsearch@mozilla.com - Follow-on Search Telemetry - 0.9.7 - 2 - true - true - - - {ec8030f7-c20a-464f-9b0e-13a3a9e97384} - 52.0 - 66.* - - - - diff --git a/browser/extensions/followonsearch/jar.mn b/browser/extensions/followonsearch/jar.mn deleted file mode 100644 index 8bad68630202..000000000000 --- a/browser/extensions/followonsearch/jar.mn +++ /dev/null @@ -1,7 +0,0 @@ -# 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/. - -[features/followonsearch@mozilla.com] chrome.jar: -% content followonsearch %content/ - content/ (content/*) diff --git a/browser/extensions/followonsearch/moz.build b/browser/extensions/followonsearch/moz.build deleted file mode 100644 index 4a95c67135c1..000000000000 --- a/browser/extensions/followonsearch/moz.build +++ /dev/null @@ -1,17 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -with Files("**"): - BUG_COMPONENT = ("Firefox", "Search") - -FINAL_TARGET_FILES.features['followonsearch@mozilla.com'] += [ - 'bootstrap.js', - 'install.rdf', -] - -BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini'] - -JAR_MANIFESTS += ['jar.mn'] diff --git a/browser/extensions/followonsearch/test/browser/.eslintrc.js b/browser/extensions/followonsearch/test/browser/.eslintrc.js deleted file mode 100644 index 71818fe6506a..000000000000 --- a/browser/extensions/followonsearch/test/browser/.eslintrc.js +++ /dev/null @@ -1,7 +0,0 @@ -"use strict"; - -module.exports = { - "extends": [ - "plugin:mozilla/browser-test", - ], -}; diff --git a/browser/extensions/followonsearch/test/browser/browser.ini b/browser/extensions/followonsearch/test/browser/browser.ini deleted file mode 100644 index 434191379e92..000000000000 --- a/browser/extensions/followonsearch/test/browser/browser.ini +++ /dev/null @@ -1,7 +0,0 @@ -[DEFAULT] - -[browser_followOnTelemetry.js] -support-files = - test.html - test2.html - testEngine.xml diff --git a/browser/extensions/followonsearch/test/browser/browser_followOnTelemetry.js b/browser/extensions/followonsearch/test/browser/browser_followOnTelemetry.js deleted file mode 100644 index f610f4d99c37..000000000000 --- a/browser/extensions/followonsearch/test/browser/browser_followOnTelemetry.js +++ /dev/null @@ -1,66 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -ChromeUtils.defineModuleGetter(this, "SearchTestUtils", - "resource://testing-common/SearchTestUtils.jsm"); - -SearchTestUtils.init(Assert, registerCleanupFunction); - -const BASE_URL = "http://mochi.test:8888/browser/browser/extensions/followonsearch/test/browser/"; -const TEST_ENGINE_BASENAME = "testEngine.xml"; - -add_task(async function test_followOnSearchTelemetry() { - let engine = await SearchTestUtils.promiseNewSearchEngine( - getRootDirectory(gTestPath) + TEST_ENGINE_BASENAME, - registerCleanupFunction); - let oldCurrentEngine = Services.search.currentEngine; - Services.search.currentEngine = engine; - - let histogram = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS"); - histogram.clear(); - - registerCleanupFunction(() => Services.search.currentEngine = oldCurrentEngine); - - await BrowserTestUtils.withNewTab({gBrowser}, async browser => { - // Open the initial search page via entering a search on the URL bar. - let loadPromise = BrowserTestUtils.waitForLocationChange(gBrowser, - `${BASE_URL}test.html?searchm=test&mt=TEST`); - - gURLBar.focus(); - EventUtils.sendString("test"); - EventUtils.sendKey("return"); - - await loadPromise; - - // Perform a follow-on search, selecting the form in the page. - loadPromise = BrowserTestUtils.waitForLocationChange(gBrowser, - `${BASE_URL}test2.html?mtfo=followonsearchtest&mt=TEST&m=test`); - - await ContentTask.spawn(browser, null, function() { - content.document.getElementById("submit").click(); - }); - - await loadPromise; - - let snapshot; - - // We have to wait for the snapshot to come in, as there's async functionality - // in the extension. - await TestUtils.waitForCondition(() => { - snapshot = histogram.snapshot(); - return "mochitest.follow-on:unknown:TEST" in snapshot; - }); - Assert.ok("mochitest.follow-on:unknown:TEST" in snapshot, - "Histogram should have an entry for the follow-on search."); - Assert.deepEqual(snapshot["mochitest.follow-on:unknown:TEST"], { - counts: [ 1, 0, 0 ], - histogram_type: 4, - max: 2, - min: 1, - ranges: [ 0, 1, 2 ], - sum: 1, - }, "Histogram should have the correct snapshot data"); - }); -}); diff --git a/browser/extensions/followonsearch/test/browser/test.html b/browser/extensions/followonsearch/test/browser/test.html deleted file mode 100644 index e71568e1511b..000000000000 --- a/browser/extensions/followonsearch/test/browser/test.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - Follow-on Search Test - - -
- - - - -
- - diff --git a/browser/extensions/followonsearch/test/browser/test2.html b/browser/extensions/followonsearch/test/browser/test2.html deleted file mode 100644 index 1c0987b7aa2e..000000000000 --- a/browser/extensions/followonsearch/test/browser/test2.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - Follow-on Search Test Final Page - - - diff --git a/browser/extensions/followonsearch/test/browser/testEngine.xml b/browser/extensions/followonsearch/test/browser/testEngine.xml deleted file mode 100644 index b3c4e5ed1767..000000000000 --- a/browser/extensions/followonsearch/test/browser/testEngine.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - Mochitest - Mochitest Engine - UTF-8 - data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC - - - - - diff --git a/build/moz.configure/rust.configure b/build/moz.configure/rust.configure index 5bb6b8715646..566351c406bb 100644 --- a/build/moz.configure/rust.configure +++ b/build/moz.configure/rust.configure @@ -289,6 +289,28 @@ cbindgen = check_prog('CBINDGEN', add_rustup_path('cbindgen'), paths=toolchain_s when=depends(build_project) (lambda build_project: build_project != 'js')) + +@depends_if(cbindgen) +@checking('cbindgen version') +@imports(_from='textwrap', _import='dedent') +def cbindgen_version(cbindgen): + cbindgen_min_version = Version('0.6.1') + + # cbindgen x.y.z + version = Version(check_cmd_output(cbindgen, '--version').strip().split(" ")[1]) + + if version < cbindgen_min_version: + die(dedent('''\ + cbindgen version {} is too old. At least version {} is required. + + Please update using 'cargo install cbindgen --force' or running + './mach bootstrap', after removing the existing executable located at + {}. + '''.format(version, cbindgen_min_version, cbindgen))) + + return version + + # Bindgen can use rustfmt to format Rust file, but it's not required. js_option(env='RUSTFMT', nargs=1, help='Path to the rustfmt program') diff --git a/dom/media/VideoUtils.cpp b/dom/media/VideoUtils.cpp index 8c1a6aeb4dd5..4a1363b91114 100644 --- a/dom/media/VideoUtils.cpp +++ b/dom/media/VideoUtils.cpp @@ -747,10 +747,12 @@ CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters( Maybe maybeWidth = aContainerType.ExtendedType().GetWidth(); if (maybeWidth && *maybeWidth > 0) { videoInfo->mImage.width = *maybeWidth; + videoInfo->mDisplay.width = *maybeWidth; } Maybe maybeHeight = aContainerType.ExtendedType().GetHeight(); if (maybeHeight && *maybeHeight > 0) { videoInfo->mImage.height = *maybeHeight; + videoInfo->mDisplay.height = *maybeHeight; } } else if (trackInfo->GetAsAudioInfo()) { AudioInfo* audioInfo = trackInfo->GetAsAudioInfo(); diff --git a/dom/media/platforms/android/RemoteDataDecoder.cpp b/dom/media/platforms/android/RemoteDataDecoder.cpp index 87604370bf6f..c938d39984f8 100644 --- a/dom/media/platforms/android/RemoteDataDecoder.cpp +++ b/dom/media/platforms/android/RemoteDataDecoder.cpp @@ -208,6 +208,8 @@ public: } mIsCodecSupportAdaptivePlayback = mJavaDecoder->IsAdaptivePlaybackSupported(); + mIsHardwareAccelerated = + mJavaDecoder->IsHardwareAccelerated(); return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__); } @@ -272,12 +274,19 @@ public: return true; } + bool IsHardwareAccelerated(nsACString& aFailureReason) const override + { + return mIsHardwareAccelerated; + } + private: const VideoInfo mConfig; GeckoSurface::GlobalRef mSurface; AndroidSurfaceTextureHandle mSurfaceHandle; // Only accessed on reader's task queue. bool mIsCodecSupportAdaptivePlayback = false; + // Can be accessed on any thread, but only written on during init. + bool mIsHardwareAccelerated = false; // Accessed on mTaskQueue, reader's TaskQueue and Java callback tread. // SimpleMap however is thread-safe, so it's okay to do so. SimpleMap mInputInfos; @@ -457,8 +466,8 @@ RemoteDataDecoder::CreateVideoDecoder(const CreateDecoderParams& aParams, MediaFormat::LocalRef format; NS_ENSURE_SUCCESS( MediaFormat::CreateVideoFormat(TranslateMimeType(config.mMimeType), - config.mDisplay.width, - config.mDisplay.height, + config.mImage.width, + config.mImage.height, &format), nullptr); diff --git a/layout/painting/nsCSSRendering.cpp b/layout/painting/nsCSSRendering.cpp index 4fe6db006fa6..76c358027676 100644 --- a/layout/painting/nsCSSRendering.cpp +++ b/layout/painting/nsCSSRendering.cpp @@ -2530,6 +2530,43 @@ DrawBackgroundColor(nsCSSRendering::ImageLayerClipState& aClipState, aCtx->Restore(); } +static Maybe +CalcScrollbarColor(nsIFrame* aFrame, StyleComplexColor nsStyleUI::* aColor) +{ + ComputedStyle* scrollbarStyle = nsLayoutUtils::StyleForScrollbar(aFrame); + auto color = scrollbarStyle->StyleUI()->*aColor; + if (color.IsAuto()) { + return Nothing(); + } + return Some(color.CalcColor(scrollbarStyle)); +} + +static nscolor +GetBackgroundColor(nsIFrame* aFrame, ComputedStyle* aComputedStyle) +{ + Maybe overrideColor = Nothing(); + switch (aComputedStyle->StyleDisplay()->mAppearance) { + case StyleAppearance::ScrollbarthumbVertical: + case StyleAppearance::ScrollbarthumbHorizontal: + overrideColor = + CalcScrollbarColor(aFrame, &nsStyleUI::mScrollbarFaceColor); + break; + case StyleAppearance::ScrollbarVertical: + case StyleAppearance::ScrollbarHorizontal: + case StyleAppearance::Scrollcorner: + overrideColor = + CalcScrollbarColor(aFrame, &nsStyleUI::mScrollbarTrackColor); + break; + default: + break; + } + if (overrideColor.isSome()) { + return *overrideColor; + } + return aComputedStyle-> + GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor); +} + nscolor nsCSSRendering::DetermineBackgroundColor(nsPresContext* aPresContext, ComputedStyle* aComputedStyle, @@ -2551,8 +2588,7 @@ nsCSSRendering::DetermineBackgroundColor(nsPresContext* aPresContext, const nsStyleBackground *bg = aComputedStyle->StyleBackground(); nscolor bgColor; if (aDrawBackgroundColor) { - bgColor = aComputedStyle-> - GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor); + bgColor = GetBackgroundColor(aFrame, aComputedStyle); if (NS_GET_A(bgColor) == 0) { aDrawBackgroundColor = false; } diff --git a/layout/xul/nsBox.cpp b/layout/xul/nsBox.cpp index e66ad54cbfeb..c2abe2ab6176 100644 --- a/layout/xul/nsBox.cpp +++ b/layout/xul/nsBox.cpp @@ -522,6 +522,23 @@ nsIFrame::AddXULPrefSize(nsIFrame* aBox, nsSize& aSize, bool &aWidthSet, bool &a return (aWidthSet && aHeightSet); } +// This returns the scrollbar width we want to use when either native +// theme is disabled, or the native theme claims that it doesn't support +// scrollbar. +static nscoord +GetScrollbarWidthNoTheme(nsIFrame* aBox) +{ + ComputedStyle* scrollbarStyle = nsLayoutUtils::StyleForScrollbar(aBox); + switch (scrollbarStyle->StyleUIReset()->mScrollbarWidth) { + default: + case StyleScrollbarWidth::Auto: + return 16 * AppUnitsPerCSSPixel(); + case StyleScrollbarWidth::Thin: + return 8 * AppUnitsPerCSSPixel(); + case StyleScrollbarWidth::None: + return 0; + } +} bool nsIFrame::AddXULMinSize(nsBoxLayoutState& aState, nsIFrame* aBox, nsSize& aSize, @@ -548,6 +565,19 @@ nsIFrame::AddXULMinSize(nsBoxLayoutState& aState, nsIFrame* aBox, nsSize& aSize, aSize.height = aState.PresContext()->DevPixelsToAppUnits(size.height); aHeightSet = true; } + } else { + switch (display->mAppearance) { + case StyleAppearance::ScrollbarVertical: + aSize.width = GetScrollbarWidthNoTheme(aBox); + aWidthSet = true; + break; + case StyleAppearance::ScrollbarHorizontal: + aSize.height = GetScrollbarWidthNoTheme(aBox); + aHeightSet = true; + break; + default: + break; + } } } diff --git a/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/media/ICodec.aidl b/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/media/ICodec.aidl index d48eb47d0a57..3433542efa9b 100644 --- a/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/media/ICodec.aidl +++ b/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/media/ICodec.aidl @@ -15,6 +15,7 @@ interface ICodec { void setCallbacks(in ICodecCallbacks callbacks); boolean configure(in FormatParam format, in GeckoSurface surface, in int flags, in String drmStubId); boolean isAdaptivePlaybackSupported(); + boolean isHardwareAccelerated(); boolean isTunneledPlaybackSupported(); void start(); void stop(); diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java index 8c97b4e68087..143a746e56b5 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java @@ -1046,16 +1046,6 @@ public class GeckoAppShell return sScreenDepth; } - @WrapForJNI(calledFrom = "gecko") - private static synchronized void setScreenDepthOverride(int aScreenDepth) { - if (sScreenDepth != 0) { - Log.e(LOGTAG, "Tried to override screen depth after it's already been set"); - throw new IllegalStateException(); - } - - sScreenDepth = aScreenDepth; - } - @WrapForJNI(calledFrom = "gecko") private static void performHapticFeedback(boolean aIsLongPress) { // Don't perform haptic feedback if a vibration is currently playing, diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/Codec.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/Codec.java index 92b1164f7935..8e9d551e7896 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/Codec.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/Codec.java @@ -350,6 +350,7 @@ import org.mozilla.gecko.gfx.GeckoSurface; private SamplePool mSamplePool; // Values will be updated after configure called. private volatile boolean mIsAdaptivePlaybackSupported = false; + private volatile boolean mIsHardwareAccelerated = false; private boolean mIsTunneledPlaybackSupported = false; public synchronized void setCallbacks(ICodecCallbacks callbacks) throws RemoteException { @@ -399,6 +400,7 @@ import org.mozilla.gecko.gfx.GeckoSurface; Log.w(LOGTAG, "unable to configure " + name + ". Try next."); continue; } + mIsHardwareAccelerated = !name.startsWith("OMX.google."); mCodec = codec; mInputProcessor = new InputProcessor(); final boolean renderToSurface = surface != null; @@ -477,6 +479,11 @@ import org.mozilla.gecko.gfx.GeckoSurface; return mIsAdaptivePlaybackSupported; } + @Override + public synchronized boolean isHardwareAccelerated() { + return mIsHardwareAccelerated; + } + @Override public synchronized boolean isTunneledPlaybackSupported() { return mIsTunneledPlaybackSupported; diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/CodecProxy.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/CodecProxy.java index f5be498c8149..173862fee3ed 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/CodecProxy.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/CodecProxy.java @@ -191,6 +191,21 @@ public final class CodecProxy { } } + @WrapForJNI + public synchronized boolean isHardwareAccelerated() + { + if (mRemote == null) { + Log.e(LOGTAG, "cannot check isHardwareAccelerated with an ended codec"); + return false; + } + try { + return mRemote.isHardwareAccelerated(); + } catch (RemoteException e) { + e.printStackTrace(); + return false; + } + } + @WrapForJNI public synchronized boolean isTunneledPlaybackSupported() { diff --git a/netwerk/base/BackgroundFileSaver.cpp b/netwerk/base/BackgroundFileSaver.cpp index 92e1a03efeb6..a48913ba67d3 100644 --- a/netwerk/base/BackgroundFileSaver.cpp +++ b/netwerk/base/BackgroundFileSaver.cpp @@ -490,10 +490,16 @@ BackgroundFileSaver::ProcessStateChange() NS_ENSURE_SUCCESS(rv, rv); } - // Now we can update the actual target file name. - mActualTarget = renamedTarget; - mActualTargetKeepPartial = renamedTargetKeepPartial; + // We should not only update the mActualTarget with renameTarget when + // they point to the different files. + // In this way, if mActualTarget and renamedTarget point to the same file + // with different addresses, "CheckCompletion()" will return false forever. } + + // Update mActualTarget with renameTarget, + // even if they point to the same file. + mActualTarget = renamedTarget; + mActualTargetKeepPartial = renamedTargetKeepPartial; } // Notify if the target file name actually changed. diff --git a/taskcluster/ci/test/raptor.yml b/taskcluster/ci/test/raptor.yml index 4a0607a5fbb3..629cde615a3a 100644 --- a/taskcluster/ci/test/raptor.yml +++ b/taskcluster/ci/test/raptor.yml @@ -1,6 +1,7 @@ job-defaults: max-run-time: 1800 suite: raptor + workdir: /home/cltbld tier: by-test-platform: windows10-64-ccov/.*: 3 diff --git a/taskcluster/scripts/misc/build-cbindgen.sh b/taskcluster/scripts/misc/build-cbindgen.sh index 9588fed6252b..3bfcc84993ab 100755 --- a/taskcluster/scripts/misc/build-cbindgen.sh +++ b/taskcluster/scripts/misc/build-cbindgen.sh @@ -1,6 +1,8 @@ #!/bin/bash set -x -e -v +# If you update this, make sure to update the minimum version in rust.configure +# as well. CBINDGEN_VERSION=v0.6.1 TARGET="$1" diff --git a/taskcluster/taskgraph/decision.py b/taskcluster/taskgraph/decision.py index de54070ea602..c6208a08ecab 100644 --- a/taskcluster/taskgraph/decision.py +++ b/taskcluster/taskgraph/decision.py @@ -19,6 +19,8 @@ from .taskgraph import TaskGraph from .try_option_syntax import parse_message from .actions import render_actions_json from taskgraph.util.partials import populate_release_history +from taskgraph.util.yaml import load_yaml + logger = logging.getLogger(__name__) @@ -320,8 +322,7 @@ def write_artifact(filename, data): def read_artifact(filename): path = os.path.join(ARTIFACTS_DIR, filename) if filename.endswith('.yml'): - with open(path, 'r') as f: - return yaml.load(f) + return load_yaml(path, filename) elif filename.endswith('.json'): with open(path, 'r') as f: return json.load(f) diff --git a/taskcluster/taskgraph/transforms/beetmover_geckoview.py b/taskcluster/taskgraph/transforms/beetmover_geckoview.py index 518f9c5d95b2..99e41292cb31 100644 --- a/taskcluster/taskgraph/transforms/beetmover_geckoview.py +++ b/taskcluster/taskgraph/transforms/beetmover_geckoview.py @@ -69,7 +69,7 @@ def make_task_description(config, jobs): 'treeherder', {}).get('machine', {}).get('platform', '') treeherder.setdefault('platform', '{}/opt'.format(dep_th_platform)) - treeherder.setdefault('tier', 3) + treeherder.setdefault('tier', 2) treeherder.setdefault('kind', 'build') label = job['label'] description = ( diff --git a/taskcluster/taskgraph/transforms/job/mozharness_test.py b/taskcluster/taskgraph/transforms/job/mozharness_test.py index 28b9f1521e1d..37d74b856f70 100644 --- a/taskcluster/taskgraph/transforms/job/mozharness_test.py +++ b/taskcluster/taskgraph/transforms/job/mozharness_test.py @@ -337,7 +337,8 @@ def mozharness_test_on_native_engine(config, job, taskdesc): if test['max-run-time']: worker['max-run-time'] = test['max-run-time'] - worker['env'] = env = { + env = worker.setdefault('env', {}) + env.update({ 'GECKO_HEAD_REPOSITORY': config.params['head_repository'], 'GECKO_HEAD_REV': config.params['head_rev'], 'MOZHARNESS_CONFIG': ' '.join(mozharness['config']), @@ -351,7 +352,7 @@ def mozharness_test_on_native_engine(config, job, taskdesc): "MOZ_HIDE_RESULTS_TABLE": '1', "MOZ_NODE_PATH": "/usr/local/bin/node", 'MOZ_AUTOMATION': '1', - } + }) # talos tests don't need Xvfb if is_talos: env['NEED_XVFB'] = 'false' diff --git a/taskcluster/taskgraph/transforms/tests.py b/taskcluster/taskgraph/transforms/tests.py index 21ede56f39fc..544a67bd012d 100644 --- a/taskcluster/taskgraph/transforms/tests.py +++ b/taskcluster/taskgraph/transforms/tests.py @@ -146,6 +146,9 @@ test_description_schema = Schema({ 'test-platform', basestring), + # base work directory used to set up the task. + Optional('workdir'): basestring, + # the name by which this test suite is addressed in try syntax; defaults to # the test-name. This will translate to the `unittest_try_name` or # `talos_try_name` attribute. @@ -1097,6 +1100,9 @@ def make_job_description(config, tests): run['using'] = 'mozharness-test' run['test'] = test + if 'workdir' in test: + run['workdir'] = test.pop('workdir') + jobdesc['worker-type'] = test.pop('worker-type') if test.get('fetches'): jobdesc['fetches'] = test.pop('fetches') diff --git a/testing/mozharness/mozharness/mozilla/fetches.py b/testing/mozharness/mozharness/mozilla/fetches.py new file mode 100644 index 000000000000..15090858f58e --- /dev/null +++ b/testing/mozharness/mozharness/mozilla/fetches.py @@ -0,0 +1,59 @@ +# 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 os +from distutils.spawn import find_executable + +import mozfile + +ARTIFACT_URL = 'https://queue.taskcluster.net/v1/task/{task}/artifacts/{artifact}' + + +class FetchesMixin(object): + """Utility class to download artifacts via `MOZ_FETCHES` and the + `fetch-content` script.""" + + @property + def fetch_script(self): + if getattr(self, '_fetch_script', None): + return self._fetch_script + + self._fetch_script = find_executable('fetch-content') + if not self._fetch_script and 'GECKO_PATH' in os.environ: + self._fetch_script = os.path.join(os.environ['GECKO_PATH'], + 'taskcluster', 'script', 'misc', 'fetch-content') + return self._fetch_script + + def fetch_content(self): + if not os.environ.get('MOZ_FETCHES'): + self.warning('no fetches to download') + return + + fetches = os.environ['MOZ_FETCHES'].split() + + if not self.fetch_script or not os.path.isfile(self.fetch_script): + self.warning("fetch-content script not found, downloading manually") + self._download_fetches(fetches) + return + + cmd = [self.fetch_script, 'task-artifacts'] + fetches + self.run_command(cmd, env=os.environ, throw_exception=True) + + def _download_fetches(self, fetches): + # TODO: make sure fetch-content script is available everywhere + # so this isn't needed + for word in fetches: + artifact, task = word.split('@', 1) + extdir = os.environ['MOZ_FETCHES_DIR'] + + if '>' in artifact: + artifact, subdir = artifact.rsplit('>', 1) + extdir = os.path.join(extdir, subdir) + + url = ARTIFACT_URL.format(artifact=artifact, task=task) + self.download_file(url) + + filename = os.path.basename(artifact) + mozfile.extract(filename, extdir) + os.remove(filename) diff --git a/testing/mozharness/mozharness/mozilla/testing/codecoverage.py b/testing/mozharness/mozharness/mozilla/testing/codecoverage.py index 5ac405fc1894..3370ab8bb4a0 100644 --- a/testing/mozharness/mozharness/mozilla/testing/codecoverage.py +++ b/testing/mozharness/mozharness/mozilla/testing/codecoverage.py @@ -8,7 +8,6 @@ import os import posixpath import shutil import sys -import tarfile import tempfile import zipfile import uuid @@ -144,31 +143,14 @@ class CodeCoverageMixin(SingleTestMixin): self.java_coverage_output_path = os.path.join(tempfile.mkdtemp(), 'junit-coverage.ec') - def _download_grcov(self): - fetches_dir = os.environ.get('MOZ_FETCHES_DIR') - if fetches_dir and os.path.isfile(os.path.join(fetches_dir, 'grcov')): - self.grcov_dir = fetches_dir - else: - # Create the grcov directory, then download it. - # TODO: use the fetch-content script to download artifacts. - self.grcov_dir = tempfile.mkdtemp() - ARTIFACT_URL = 'https://queue.taskcluster.net/v1/task/{task}/artifacts/{artifact}' - for word in os.getenv('MOZ_FETCHES').split(): - artifact, task = word.split('@', 1) - filename = os.path.basename(artifact) - url = ARTIFACT_URL.format(artifact=artifact, task=task) - self.download_file(url, parent_dir=self.grcov_dir) - - with tarfile.open(os.path.join(self.grcov_dir, filename), 'r') as tar: - tar.extractall(self.grcov_dir) - os.remove(os.path.join(self.grcov_dir, filename)) - @PostScriptAction('download-and-extract') def setup_coverage_tools(self, action, success=None): if not self.code_coverage_enabled and not self.java_code_coverage_enabled: return - self._download_grcov() + self.grcov_dir = os.environ['MOZ_FETCHES_DIR'] + if not os.path.isfile(os.path.join(self.grcov_dir, 'grcov')): + self.fetch_content() if self.code_coverage_enabled: self._setup_cpp_js_coverage_tools() diff --git a/testing/mozharness/mozharness/mozilla/testing/per_test_base.py b/testing/mozharness/mozharness/mozilla/testing/per_test_base.py index 2fa9fb8c8eb4..fb82beac1012 100644 --- a/testing/mozharness/mozharness/mozilla/testing/per_test_base.py +++ b/testing/mozharness/mozharness/mozilla/testing/per_test_base.py @@ -13,8 +13,10 @@ import sys import mozinfo from manifestparser import TestManifest +from mozharness.mozilla.fetches import FetchesMixin -class SingleTestMixin(object): + +class SingleTestMixin(FetchesMixin): """Utility functions for per-test testing like test verification and per-test coverage.""" def __init__(self): diff --git a/testing/mozharness/mozharness/mozilla/testing/raptor.py b/testing/mozharness/mozharness/mozilla/testing/raptor.py index 0cec719c8765..09b7009890f6 100644 --- a/testing/mozharness/mozharness/mozilla/testing/raptor.py +++ b/testing/mozharness/mozharness/mozilla/testing/raptor.py @@ -299,6 +299,8 @@ class Raptor(TestingMixin, MercurialScript, CodeCoverageMixin): # clobber defined in BaseScript def download_and_extract(self, extract_dirs=None, suite_categories=None): + if 'MOZ_FETCHES' in os.environ: + self.fetch_content() return super(Raptor, self).download_and_extract( suite_categories=['common', 'raptor'] ) diff --git a/testing/mozharness/mozharness/mozilla/testing/testbase.py b/testing/mozharness/mozharness/mozilla/testing/testbase.py index 9bb888c0f227..127597d15e67 100755 --- a/testing/mozharness/mozharness/mozilla/testing/testbase.py +++ b/testing/mozharness/mozharness/mozilla/testing/testbase.py @@ -20,6 +20,7 @@ from mozharness.base.python import ( virtualenv_config_options, ) from mozharness.mozilla.automation import AutomationMixin, TBPL_WARNING +from mozharness.mozilla.fetches import FetchesMixin from mozharness.mozilla.structuredlog import StructuredOutputParser from mozharness.mozilla.testing.unittest import DesktopUnittestOutputParser from mozharness.mozilla.testing.try_tools import TryToolsMixin, try_config_options @@ -102,7 +103,7 @@ testing_config_options = [ # TestingMixin {{{1 class TestingMixin(VirtualenvMixin, AutomationMixin, ResourceMonitoringMixin, - TooltoolMixin, TryToolsMixin, VerifyToolsMixin): + TooltoolMixin, TryToolsMixin, VerifyToolsMixin, FetchesMixin): """ The steps to identify + download the proper bits for [browser] unit tests and Talos. diff --git a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm index 9e589323bd7c..c97e362518fe 100644 --- a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm +++ b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm @@ -11,6 +11,9 @@ ChromeUtils.import("resource://gre/modules/ActorManagerParent.jsm"); ChromeUtils.import("resource://gre/modules/ExtensionUtils.jsm"); ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); +// Windowless browsers can create documents that rely on XUL Custom Elements: +ChromeUtils.import("resource://gre/modules/CustomElementsListener.jsm", null); + ChromeUtils.defineModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm"); ChromeUtils.defineModuleGetter(this, "AddonTestUtils", diff --git a/toolkit/components/processsingleton/CustomElementsListener.jsm b/toolkit/components/processsingleton/CustomElementsListener.jsm new file mode 100644 index 000000000000..812907692343 --- /dev/null +++ b/toolkit/components/processsingleton/CustomElementsListener.jsm @@ -0,0 +1,22 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* 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/. */ + +ChromeUtils.import("resource://gre/modules/Services.jsm"); + +// Set up Custom Elements for XUL and XHTML documents before anything else +// happens. Anything loaded here should be considered part of core XUL functionality. +// Any window-specific elements can be registered via