diff --git a/.cron.yml b/.cron.yml index 1b9d04bc6bc0..bab57e07da36 100644 --- a/.cron.yml +++ b/.cron.yml @@ -31,6 +31,16 @@ jobs: - date when: [] # never (hook only) + - name: nightly-desktop-win64 + job: + type: decision-task + treeherder-symbol: Nd-Win64 + triggered-by: nightly + target-tasks-method: nightly_win64 + run-on-projects: + - date + when: [] # never (hook only) + - name: nightly-android job: type: decision-task diff --git a/browser/base/content/aboutDialog-appUpdater.js b/browser/base/content/aboutDialog-appUpdater.js index 3f6dba61258e..3ce4bf8fa49a 100644 --- a/browser/base/content/aboutDialog-appUpdater.js +++ b/browser/base/content/aboutDialog-appUpdater.js @@ -2,7 +2,8 @@ * 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/. */ -// Note: this file is included in aboutDialog.xul if MOZ_UPDATER is defined. +// Note: this file is included in aboutDialog.xul and preferences/advanced.xul +// if MOZ_UPDATER is defined. /* import-globals-from aboutDialog.js */ diff --git a/browser/base/content/moz.build b/browser/base/content/moz.build index 07777a26b320..b9b7a5ba7b59 100644 --- a/browser/base/content/moz.build +++ b/browser/base/content/moz.build @@ -29,7 +29,7 @@ with Files("sync/**"): BUG_COMPONENT = ("Firefox", "Sync") with Files("test/alerts/**"): - BUG_COMPONENT = ("Toolkit", "Notification and Alerts") + BUG_COMPONENT = ("Toolkit", "Notifications and Alerts") with Files("test/appUpdate/**"): BUG_COMPONENT = ("Toolkit", "Application Update") diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 50295c671c9f..635b47e0911d 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -215,15 +215,15 @@ nsContextMenu.prototype = { initNavigationItems: function CM_initNavigationItems() { var shouldShow = !(this.isContentSelected || this.onLink || this.onImage || this.onCanvas || this.onVideo || this.onAudio || - this.onTextInput || this.onSocial); + this.onTextInput) && this.inTabBrowser; this.showItem("context-navigation", shouldShow); this.showItem("context-sep-navigation", shouldShow); let stopped = XULBrowserWindow.stopCommand.getAttribute("disabled") == "true"; let stopReloadItem = ""; - if (shouldShow || this.onSocial) { - stopReloadItem = (stopped || this.onSocial) ? "reload" : "stop"; + if (shouldShow || !this.inTabBrowser) { + stopReloadItem = (stopped || !this.inTabBrowser) ? "reload" : "stop"; } this.showItem("context-reload", stopReloadItem == "reload"); @@ -290,9 +290,12 @@ nsContextMenu.prototype = { this.onImage || this.onCanvas || this.onVideo || this.onAudio || this.onLink || this.onTextInput); - var showInspect = !this.onSocial && gPrefService.getBoolPref("devtools.inspector.enabled"); + var showInspect = this.inTabBrowser && gPrefService.getBoolPref("devtools.inspector.enabled"); this.showItem("context-viewsource", shouldShow); this.showItem("context-viewinfo", shouldShow); + // The page info is broken for WebExtension popups, as the browser is + // destroyed when the popup is closed. + this.setItemAttr("context-viewinfo", "disabled", this.webExtBrowserType === "popup"); this.showItem("inspect-separator", showInspect); this.showItem("context-inspect", showInspect); @@ -341,6 +344,9 @@ nsContextMenu.prototype = { .disabled = !this.hasBGImage; this.showItem("context-viewimageinfo", this.onImage); + // The image info popup is broken for WebExtension popups, since the browser + // is destroyed when the popup is closed. + this.setItemAttr("context-viewimageinfo", "disabled", this.webExtBrowserType === "popup"); this.showItem("context-viewimagedesc", this.onImage && this.imageDescURL !== ""); }, @@ -350,11 +356,12 @@ nsContextMenu.prototype = { this.showItem(bookmarkPage, !(this.isContentSelected || this.onTextInput || this.onLink || this.onImage || this.onVideo || this.onAudio || this.onSocial || - this.onCanvas)); + this.onCanvas || this.inWebExtBrowser)); bookmarkPage.setAttribute("tooltiptext", bookmarkPage.getAttribute("buttontooltiptext")); this.showItem("context-bookmarklink", (this.onLink && !this.onMailtoLink && - !this.onSocial) || this.onPlainTextLink); + !this.onSocial && !this.onMozExtLink) || + this.onPlainTextLink); this.showItem("context-keywordfield", this.onTextInput && this.onKeywordField); this.showItem("frame", this.inFrame); @@ -398,13 +405,14 @@ nsContextMenu.prototype = { let shareEnabled = shareButton && !shareButton.disabled && !this.onSocial; let pageShare = shareEnabled && !(this.isContentSelected || this.onTextInput || this.onLink || this.onImage || - this.onVideo || this.onAudio || this.onCanvas); + this.onVideo || this.onAudio || this.onCanvas || + this.inWebExtBrowser); this.showItem("context-sharepage", pageShare); this.showItem("context-shareselect", shareEnabled && this.isContentSelected); - this.showItem("context-sharelink", shareEnabled && (this.onLink || this.onPlainTextLink) && !this.onMailtoLink); + this.showItem("context-sharelink", shareEnabled && (this.onLink || this.onPlainTextLink) && !this.onMailtoLink && !this.onMozExtLink); this.showItem("context-shareimage", shareEnabled && this.onImage); this.showItem("context-sharevideo", shareEnabled && this.onVideo); - this.setItemAttr("context-sharevideo", "disabled", !this.mediaURL || this.mediaURL.startsWith("blob:")); + this.setItemAttr("context-sharevideo", "disabled", !this.mediaURL || this.mediaURL.startsWith("blob:") || this.mediaURL.startsWith("moz-extension:")); }, initSpellingItems() { @@ -677,6 +685,10 @@ nsContextMenu.prototype = { this.onCTPPlugin = false; this.canSpellCheck = false; this.onPassword = false; + this.webExtBrowserType = ""; + this.inWebExtBrowser = false; + this.inTabBrowser = true; + this.onMozExtLink = false; if (this.isRemote) { this.selectionInfo = gContextMenuContentData.selectionInfo; @@ -713,6 +725,10 @@ nsContextMenu.prototype = { this.frameOuterWindowID = WebNavigationFrames.getFrameId(ownerDoc.defaultView); } this.onSocial = !!this.browser.getAttribute("origin"); + this.webExtBrowserType = this.browser.getAttribute("webextension-view-type"); + this.inWebExtBrowser = !!this.webExtBrowserType; + this.inTabBrowser = this.browser.ownerGlobal.gBrowser ? + !!this.browser.ownerGlobal.gBrowser.getTabForBrowser(this.browser) : false; // Check if we are in a synthetic document (stand alone image, video, etc.). this.inSyntheticDoc = ownerDoc.mozSyntheticDocument; @@ -869,6 +885,7 @@ nsContextMenu.prototype = { this.linkTextStr = this.getLinkText(); this.linkProtocol = this.getLinkProtocol(); this.onMailtoLink = (this.linkProtocol == "mailto"); + this.onMozExtLink = (this.linkProtocol == "moz-extension"); this.onSaveableLink = this.isLinkSaveable( this.link ); this.linkHasNoReferrer = BrowserUtils.linkHasNoReferrer(elem); try { @@ -1033,8 +1050,11 @@ nsContextMenu.prototype = { } if (!this.isRemote) { - params.frameOuterWindowID = WebNavigationFrames.getFrameId(this.target.ownerGlobal); + // Propagate the frameOuterWindowID value saved when + // the context menu has been opened. + params.frameOuterWindowID = this.frameOuterWindowID; } + // If we want to change userContextId, we must be sure that we don't // propagate the referrer. if ("userContextId" in params && @@ -1911,7 +1931,7 @@ nsContextMenu.prototype = { _getTelemetryPageContextInfo() { let rv = []; for (let k of ["isContentSelected", "onLink", "onImage", "onCanvas", "onVideo", "onAudio", - "onTextInput", "onSocial"]) { + "onTextInput", "onSocial", "inWebExtBrowser", "inTabBrowser"]) { if (this[k]) { rv.push(k.replace(/^(?:is|on)(.)/, (match, firstLetter) => firstLetter.toLowerCase())); } diff --git a/browser/base/content/test/contextMenu/.eslintrc.js b/browser/base/content/test/contextMenu/.eslintrc.js new file mode 100644 index 000000000000..b1c842d8a6db --- /dev/null +++ b/browser/base/content/test/contextMenu/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "plugin:mozilla/browser-test" + ] +}; diff --git a/browser/base/content/test/contextMenu/browser.ini b/browser/base/content/test/contextMenu/browser.ini new file mode 100644 index 000000000000..00d0748108e2 --- /dev/null +++ b/browser/base/content/test/contextMenu/browser.ini @@ -0,0 +1,6 @@ +[DEFAULT] +support-files = + !/browser/base/content/test/general/contextmenu_common.js + subtst_contextmenu_webext.html + +[browser_contextmenu_mozextension.js] diff --git a/browser/base/content/test/contextMenu/browser_contextmenu_mozextension.js b/browser/base/content/test/contextMenu/browser_contextmenu_mozextension.js new file mode 100644 index 000000000000..e6c9da97921a --- /dev/null +++ b/browser/base/content/test/contextMenu/browser_contextmenu_mozextension.js @@ -0,0 +1,82 @@ +"use strict"; + +var { SocialService } = Cu.import("resource:///modules/SocialService.jsm", {}); + +let contextMenu; +let hasPocket = Services.prefs.getBoolPref("extensions.pocket.enabled"); +let hasContainers = Services.prefs.getBoolPref("privacy.userContext.enabled"); + +// A social share provider +let manifest = { + name: "provider 1", + origin: "https://example.com", + iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png", + shareURL: "https://example.com/browser/browser/base/content/test/social/share.html" +}; + +add_task(function* test_setup() { + const example_base = "http://example.com/browser/browser/base/content/test/contextMenu/"; + const url = example_base + "subtst_contextmenu_webext.html"; + yield BrowserTestUtils.openNewForegroundTab(gBrowser, url); + + const chrome_base = "chrome://mochitests/content/browser/browser/base/content/test/general/"; + const contextmenu_common = chrome_base + "contextmenu_common.js"; + /* import-globals-from ../general/contextmenu_common.js */ + Services.scriptloader.loadSubScript(contextmenu_common, this); + + // Enable social sharing functions in the browser, so the context menu item is shown. + CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_NAVBAR); + + yield new Promise((resolve) => SocialService.addProvider(manifest, resolve)); + ok(SocialShare.shareButton && !SocialShare.shareButton.disabled, "Sharing is enabled"); +}); + +add_task(function* test_link() { + // gets hidden for this case. + yield test_contextmenu("#link", + ["context-openlinkintab", true, + ...(hasContainers ? ["context-openlinkinusercontext-menu", true] : []), + // We need a blank entry here because the containers submenu is + // dynamically generated with no ids. + ...(hasContainers ? ["", null] : []), + "context-openlink", true, + "context-openlinkprivate", true, + "---", null, + "context-savelink", true, + "context-copylink", true, + "context-searchselect", true]); +}); + +add_task(function* test_video() { + yield test_contextmenu("#video", + ["context-media-play", null, + "context-media-mute", null, + "context-media-playbackrate", null, + ["context-media-playbackrate-050x", null, + "context-media-playbackrate-100x", null, + "context-media-playbackrate-125x", null, + "context-media-playbackrate-150x", null, + "context-media-playbackrate-200x", null], null, + "context-media-loop", null, + "context-media-showcontrols", null, + "context-video-fullscreen", null, + "---", null, + "context-viewvideo", null, + "context-copyvideourl", null, + "---", null, + "context-savevideo", null, + "context-sharevideo", false, + "context-video-saveimage", null, + "context-sendvideo", null, + "context-castvideo", null, + [], null + ]); +}); + +add_task(function* test_cleanup() { + lastElementSelector = null; + yield BrowserTestUtils.removeTab(gBrowser.selectedTab); + yield new Promise((resolve) => { + return SocialService.disableProvider(manifest.origin, resolve); + }); +}); diff --git a/browser/base/content/test/contextMenu/subtst_contextmenu_webext.html b/browser/base/content/test/contextMenu/subtst_contextmenu_webext.html new file mode 100644 index 000000000000..ac3b5415ddaf --- /dev/null +++ b/browser/base/content/test/contextMenu/subtst_contextmenu_webext.html @@ -0,0 +1,12 @@ + + + + + Subtest for browser context menu + + + Browser context menu subtest. + Link to an extension resource + + + diff --git a/browser/base/content/test/forms/browser.ini b/browser/base/content/test/forms/browser.ini index 0bb272919530..b9b35903dcc8 100644 --- a/browser/base/content/test/forms/browser.ini +++ b/browser/base/content/test/forms/browser.ini @@ -6,3 +6,4 @@ support-files = skip-if = os == "linux" # Bug 1329991 - test fails intermittently on Linux builds [browser_selectpopup_colors.js] skip-if = os == "linux" # Bug 1329991 - test fails intermittently on Linux builds +[browser_selectpopup_searchfocus.js] diff --git a/browser/base/content/test/forms/browser_selectpopup_searchfocus.js b/browser/base/content/test/forms/browser_selectpopup_searchfocus.js new file mode 100644 index 000000000000..ca4f5cb7a182 --- /dev/null +++ b/browser/base/content/test/forms/browser_selectpopup_searchfocus.js @@ -0,0 +1,42 @@ +let SELECT = + ""; + +add_task(function* setup() { + yield SpecialPowers.pushPrefEnv({ + "set": [ + ["dom.select_popup_in_parent.enabled", true], + ["dom.forms.selectSearch", true] + ] + }); +}); + +add_task(function* test_focus_on_search_shouldnt_close_popup() { + const pageUrl = "data:text/html," + escape(SELECT); + let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl); + + let menulist = document.getElementById("ContentSelectDropdown"); + let selectPopup = menulist.menupopup; + + let popupShownPromise = BrowserTestUtils.waitForEvent(selectPopup, "popupshown"); + yield BrowserTestUtils.synthesizeMouseAtCenter("#one", { type: "mousedown" }, gBrowser.selectedBrowser); + yield popupShownPromise; + + let searchInput = selectPopup.querySelector("textbox[type='search']"); + searchInput.scrollIntoView(); + let searchFocused = BrowserTestUtils.waitForEvent(searchInput, "focus"); + yield EventUtils.synthesizeMouseAtCenter(searchInput, {}, window); + yield searchFocused; + + is(selectPopup.state, "open", "select popup should still be open after clicking on the search field"); + + yield hideSelectPopup(selectPopup, "escape"); + yield BrowserTestUtils.removeTab(tab); +}); + diff --git a/browser/base/content/test/static/browser_all_files_referenced.js b/browser/base/content/test/static/browser_all_files_referenced.js index a7266bcdc209..a309406b9564 100644 --- a/browser/base/content/test/static/browser_all_files_referenced.js +++ b/browser/base/content/test/static/browser_all_files_referenced.js @@ -235,8 +235,6 @@ var whitelist = new Set([ {file: "resource://gre/modules/Manifest.jsm"}, // Bug 1351089 {file: "resource://gre/modules/PresentationDeviceInfoManager.jsm"}, - // Bug 1351091 - {file: "resource://gre/modules/Profiler.jsm"}, // Bug 1351658 {file: "resource://gre/modules/PropertyListUtils.jsm", platforms: ["linux", "win"]}, // Bug 1351097 diff --git a/browser/base/content/test/tabs/browser.ini b/browser/base/content/test/tabs/browser.ini index ef575a3c033f..958d7b1c5c84 100644 --- a/browser/base/content/test/tabs/browser.ini +++ b/browser/base/content/test/tabs/browser.ini @@ -1,9 +1,11 @@ [DEFAULT] support-files = dummy_page.html + test_bug1358314.html [browser_abandonment_telemetry.js] [browser_allow_process_switches_despite_related_browser.js] +[browser_contextmenu_openlink_after_tabnavigated.js] [browser_tabCloseProbes.js] [browser_tabSpinnerProbe.js] skip-if = !e10s # Tab spinner is e10s only. diff --git a/browser/base/content/test/tabs/browser_contextmenu_openlink_after_tabnavigated.js b/browser/base/content/test/tabs/browser_contextmenu_openlink_after_tabnavigated.js new file mode 100644 index 000000000000..5a1225709d45 --- /dev/null +++ b/browser/base/content/test/tabs/browser_contextmenu_openlink_after_tabnavigated.js @@ -0,0 +1,43 @@ +"use strict"; + +const example_base = "http://example.com/browser/browser/base/content/test/tabs/"; + +add_task(function* test_contextmenu_openlink_after_tabnavigated() { + let url = example_base + "test_bug1358314.html"; + + const tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, url); + + const contextMenu = document.getElementById("contentAreaContextMenu"); + let awaitPopupShown = BrowserTestUtils.waitForEvent(contextMenu, "popupshown"); + yield BrowserTestUtils.synthesizeMouse("a", 0, 0, { + type: "contextmenu", + button: 2, + }, gBrowser.selectedBrowser); + yield awaitPopupShown; + info("Popup Shown"); + + info("Navigate the tab with the opened context menu"); + gBrowser.selectedBrowser.loadURI("about:blank"); + yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + + let awaitNewTabOpen = BrowserTestUtils.waitForNewTab(gBrowser, "http://example.com/"); + + info("Click the 'open link in new tab' menu item"); + let openLinkMenuItem = contextMenu.querySelector("#context-openlinkintab"); + openLinkMenuItem.click(); + + info("Wait for the new tab to be opened"); + const newTab = yield awaitNewTabOpen; + + // Close the contextMenu popup if it has not been closed yet. + contextMenu.hidePopup(); + + yield BrowserTestUtils.browserLoaded(newTab.linkedBrowser); + const newTabURL = yield ContentTask.spawn(newTab.linkedBrowser, null, function* () { + return content.location.href; + }); + is(newTabURL, "http://example.com/", "Got the expected URL loaded in the new tab"); + + yield BrowserTestUtils.removeTab(newTab); + yield BrowserTestUtils.removeTab(tab); +}); diff --git a/browser/base/content/test/tabs/test_bug1358314.html b/browser/base/content/test/tabs/test_bug1358314.html new file mode 100644 index 000000000000..9aa2019752cf --- /dev/null +++ b/browser/base/content/test/tabs/test_bug1358314.html @@ -0,0 +1,10 @@ + + + + + + +

Test page

+ Link + + diff --git a/browser/base/moz.build b/browser/base/moz.build index b321ea5b3872..4a865deec3cd 100644 --- a/browser/base/moz.build +++ b/browser/base/moz.build @@ -17,6 +17,7 @@ MOCHITEST_CHROME_MANIFESTS += [ BROWSER_CHROME_MANIFESTS += [ 'content/test/alerts/browser.ini', 'content/test/captivePortal/browser.ini', + 'content/test/contextMenu/browser.ini', 'content/test/forms/browser.ini', 'content/test/general/browser.ini', 'content/test/newtab/browser.ini', diff --git a/browser/components/extensions/ExtensionPopups.jsm b/browser/components/extensions/ExtensionPopups.jsm index 113ae4d2c34c..deb141ec3859 100644 --- a/browser/components/extensions/ExtensionPopups.jsm +++ b/browser/components/extensions/ExtensionPopups.jsm @@ -233,6 +233,7 @@ class BasePopup { browser.setAttribute("class", "webextension-popup-browser"); browser.setAttribute("webextension-view-type", "popup"); browser.setAttribute("tooltip", "aHTMLTooltip"); + browser.setAttribute("contextmenu", "contentAreaContextMenu"); if (this.extension.remote) { browser.setAttribute("remote", "true"); @@ -286,6 +287,9 @@ class BasePopup { setupBrowser(browser); let mm = browser.messageManager; + // Sets the context information for context menus. + mm.loadFrameScript("chrome://browser/content/content.js", true); + mm.loadFrameScript( "chrome://extensions/content/ext-browser-content.js", false); diff --git a/browser/components/extensions/ext-browserAction.js b/browser/components/extensions/ext-browserAction.js index 8d96512441b7..4aab80cde761 100644 --- a/browser/components/extensions/ext-browserAction.js +++ b/browser/components/extensions/ext-browserAction.js @@ -321,7 +321,7 @@ this.browserAction = class extends ExtensionAPI { if (pendingPopup) { if (pendingPopup.window === window && pendingPopup.popupURL === popupURL) { - if (!this.blockParser) { + if (!blockParser) { pendingPopup.unblockParser(); } diff --git a/browser/components/extensions/test/browser/browser-common.ini b/browser/components/extensions/test/browser/browser-common.ini index d757c45fd8f6..f37e202db06b 100644 --- a/browser/components/extensions/test/browser/browser-common.ini +++ b/browser/components/extensions/test/browser/browser-common.ini @@ -31,6 +31,7 @@ support-files = [browser_ext_browserAction_area.js] [browser_ext_browserAction_context.js] +[browser_ext_browserAction_contextMenu.js] [browser_ext_browserAction_disabled.js] [browser_ext_browserAction_pageAction_icon.js] [browser_ext_browserAction_pageAction_icon_permissions.js] @@ -73,6 +74,7 @@ skip-if = debug || asan # Bug 1354681 [browser_ext_optionsPage_browser_style.js] [browser_ext_optionsPage_privileges.js] [browser_ext_pageAction_context.js] +[browser_ext_pageAction_contextMenu.js] [browser_ext_pageAction_popup.js] [browser_ext_pageAction_popup_resize.js] [browser_ext_pageAction_simple.js] @@ -93,6 +95,7 @@ skip-if = debug || asan # Bug 1354681 [browser_ext_sessions_restore.js] [browser_ext_sidebarAction.js] [browser_ext_sidebarAction_context.js] +[browser_ext_sidebarAction_contextMenu.js] [browser_ext_sidebarAction_tabs.js] [browser_ext_sidebarAction_windows.js] [browser_ext_simple.js] diff --git a/browser/components/extensions/test/browser/browser_ext_browserAction_contextMenu.js b/browser/components/extensions/test/browser/browser_ext_browserAction_contextMenu.js new file mode 100644 index 000000000000..1b4ddbcb94f5 --- /dev/null +++ b/browser/components/extensions/test/browser/browser_ext_browserAction_contextMenu.js @@ -0,0 +1,106 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +let extData = { + manifest: { + "permissions": ["contextMenus"], + "browser_action": { + "default_popup": "popup.html", + }, + }, + useAddonManager: "temporary", + + files: { + "popup.html": ` + + + + + + A Test Popup + + + `, + }, + + background: function() { + browser.contextMenus.create({ + id: "clickme-page", + title: "Click me!", + contexts: ["all"], + }); + }, +}; + +let contextMenuItems = { + "context-navigation": "hidden", + "context-sep-navigation": "hidden", + "context-viewsource": "", + "context-viewinfo": "disabled", + "inspect-separator": "hidden", + "context-inspect": "hidden", + "context-bookmarkpage": "hidden", + "context-sharepage": "hidden", +}; + +add_task(function* browseraction_popup_contextmenu() { + let extension = ExtensionTestUtils.loadExtension(extData); + yield extension.startup(); + + yield clickBrowserAction(extension, window); + + let contentAreaContextMenu = yield openContextMenuInPopup(extension); + let item = contentAreaContextMenu.getElementsByAttribute("label", "Click me!"); + is(item.length, 1, "contextMenu item for page was found"); + yield closeContextMenu(contentAreaContextMenu); + + yield extension.unload(); +}); + +add_task(function* browseraction_popup_contextmenu_hidden_items() { + let extension = ExtensionTestUtils.loadExtension(extData); + yield extension.startup(); + + yield clickBrowserAction(extension); + + let contentAreaContextMenu = yield openContextMenuInPopup(extension, "#text"); + + let item, state; + for (const itemID in contextMenuItems) { + item = contentAreaContextMenu.querySelector(`#${itemID}`); + state = contextMenuItems[itemID]; + + if (state !== "") { + ok(item[state], `${itemID} is ${state}`); + + if (state !== "hidden") { + ok(!item.hidden, `Disabled ${itemID} is not hidden`); + } + } else { + ok(!item.hidden, `${itemID} is not hidden`); + ok(!item.disabled, `${itemID} is not disabled`); + } + } + + yield closeContextMenu(contentAreaContextMenu); + + yield extension.unload(); +}); + +add_task(function* browseraction_popup_image_contextmenu() { + let extension = ExtensionTestUtils.loadExtension(extData); + yield extension.startup(); + + yield clickBrowserAction(extension); + + let contentAreaContextMenu = yield openContextMenuInPopup(extension, "#testimg"); + + let item = contentAreaContextMenu.querySelector("#context-viewimageinfo"); + ok(!item.hidden); + ok(item.disabled); + + yield closeContextMenu(contentAreaContextMenu); + + yield extension.unload(); +}); diff --git a/browser/components/extensions/test/browser/browser_ext_pageAction_contextMenu.js b/browser/components/extensions/test/browser/browser_ext_pageAction_contextMenu.js new file mode 100644 index 000000000000..aff1c795baa7 --- /dev/null +++ b/browser/components/extensions/test/browser/browser_ext_pageAction_contextMenu.js @@ -0,0 +1,116 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +let extData = { + manifest: { + "permissions": ["contextMenus"], + "page_action": { + "default_popup": "popup.html", + }, + }, + useAddonManager: "temporary", + + files: { + "popup.html": ` + + + + + + A Test Popup + + + `, + }, + + background: function() { + browser.contextMenus.create({ + id: "clickme-page", + title: "Click me!", + contexts: ["all"], + }); + browser.tabs.query({active: true, currentWindow: true}, tabs => { + const tabId = tabs[0].id; + + browser.pageAction.show(tabId).then(() => { + browser.test.sendMessage("action-shown"); + }); + }); + }, +}; + +let contextMenuItems = { + "context-navigation": "hidden", + "context-sep-navigation": "hidden", + "context-viewsource": "", + "context-viewinfo": "disabled", + "inspect-separator": "hidden", + "context-inspect": "hidden", + "context-bookmarkpage": "hidden", + "context-sharepage": "hidden", +}; + +add_task(function* pageaction_popup_contextmenu() { + let extension = ExtensionTestUtils.loadExtension(extData); + yield extension.startup(); + yield extension.awaitMessage("action-shown"); + + yield clickPageAction(extension, window); + + let contentAreaContextMenu = yield openContextMenuInPopup(extension); + let item = contentAreaContextMenu.getElementsByAttribute("label", "Click me!"); + is(item.length, 1, "contextMenu item for page was found"); + yield closeContextMenu(contentAreaContextMenu); + + yield extension.unload(); +}); + +add_task(function* pageaction_popup_contextmenu_hidden_items() { + let extension = ExtensionTestUtils.loadExtension(extData); + yield extension.startup(); + yield extension.awaitMessage("action-shown"); + + yield clickPageAction(extension, window); + + let contentAreaContextMenu = yield openContextMenuInPopup(extension, "#text"); + + let item, state; + for (const itemID in contextMenuItems) { + item = contentAreaContextMenu.querySelector(`#${itemID}`); + state = contextMenuItems[itemID]; + + if (state !== "") { + ok(item[state], `${itemID} is ${state}`); + + if (state !== "hidden") { + ok(!item.hidden, `Disabled ${itemID} is not hidden`); + } + } else { + ok(!item.hidden, `${itemID} is not hidden`); + ok(!item.disabled, `${itemID} is not disabled`); + } + } + + yield closeContextMenu(contentAreaContextMenu); + + yield extension.unload(); +}); + +add_task(function* pageaction_popup_image_contextmenu() { + let extension = ExtensionTestUtils.loadExtension(extData); + yield extension.startup(); + yield extension.awaitMessage("action-shown"); + + yield clickPageAction(extension, window); + + let contentAreaContextMenu = yield openContextMenuInPopup(extension, "#testimg"); + + let item = contentAreaContextMenu.querySelector("#context-viewimageinfo"); + ok(!item.hidden); + ok(item.disabled); + + yield closeContextMenu(contentAreaContextMenu); + + yield extension.unload(); +}); diff --git a/browser/components/extensions/test/browser/browser_ext_sidebarAction.js b/browser/components/extensions/test/browser/browser_ext_sidebarAction.js index 4eed082037cd..5aea4d96823d 100644 --- a/browser/components/extensions/test/browser/browser_ext_sidebarAction.js +++ b/browser/components/extensions/test/browser/browser_ext_sidebarAction.js @@ -4,7 +4,6 @@ let extData = { manifest: { - "permissions": ["contextMenus"], "sidebar_action": { "default_panel": "sidebar.html", }, @@ -31,12 +30,6 @@ let extData = { }, background: function() { - browser.contextMenus.create({ - id: "clickme-page", - title: "Click me!", - contexts: ["all"], - }); - browser.test.onMessage.addListener(msg => { if (msg === "set-panel") { browser.sidebarAction.setPanel({panel: ""}).then(() => { @@ -103,20 +96,6 @@ add_task(function* sidebar_empty_panel() { yield extension.unload(); }); -add_task(function* sidebar_contextmenu() { - let extension = ExtensionTestUtils.loadExtension(extData); - yield extension.startup(); - // Test sidebar is opened on install - yield extension.awaitMessage("sidebar"); - - let contentAreaContextMenu = yield openContextMenuInSidebar(); - let item = contentAreaContextMenu.getElementsByAttribute("label", "Click me!"); - is(item.length, 1, "contextMenu item for page was found"); - yield closeContextMenu(contentAreaContextMenu); - - yield extension.unload(); -}); - add_task(function* cleanup() { // This is set on initial sidebar install. Services.prefs.clearUserPref("extensions.sidebar-button.shown"); diff --git a/browser/components/extensions/test/browser/browser_ext_sidebarAction_contextMenu.js b/browser/components/extensions/test/browser/browser_ext_sidebarAction_contextMenu.js new file mode 100644 index 000000000000..49a226a57c69 --- /dev/null +++ b/browser/components/extensions/test/browser/browser_ext_sidebarAction_contextMenu.js @@ -0,0 +1,119 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +let extData = { + manifest: { + "permissions": ["contextMenus"], + "sidebar_action": { + "default_panel": "sidebar.html", + }, + }, + useAddonManager: "temporary", + + files: { + "sidebar.html": ` + + + + + + + A Test Sidebar + + + `, + + "sidebar.js": function() { + window.onload = () => { + browser.test.sendMessage("sidebar"); + }; + }, + }, + + background: function() { + browser.contextMenus.create({ + id: "clickme-page", + title: "Click me!", + contexts: ["all"], + }); + }, +}; + +let contextMenuItems = { + "context-navigation": "hidden", + "context-sep-navigation": "hidden", + "context-viewsource": "", + "context-viewinfo": "", + "inspect-separator": "hidden", + "context-inspect": "hidden", + "context-bookmarkpage": "hidden", + "context-sharepage": "hidden", +}; + +add_task(function* sidebar_contextmenu() { + let extension = ExtensionTestUtils.loadExtension(extData); + yield extension.startup(); + // Test sidebar is opened on install + yield extension.awaitMessage("sidebar"); + + let contentAreaContextMenu = yield openContextMenuInSidebar(); + let item = contentAreaContextMenu.getElementsByAttribute("label", "Click me!"); + is(item.length, 1, "contextMenu item for page was found"); + yield closeContextMenu(contentAreaContextMenu); + + yield extension.unload(); +}); + + +add_task(function* sidebar_contextmenu_hidden_items() { + let extension = ExtensionTestUtils.loadExtension(extData); + yield extension.startup(); + // Test sidebar is opened on install + yield extension.awaitMessage("sidebar"); + + let contentAreaContextMenu = yield openContextMenuInSidebar("#text"); + + let item, state; + for (const itemID in contextMenuItems) { + item = contentAreaContextMenu.querySelector(`#${itemID}`); + state = contextMenuItems[itemID]; + + if (state !== "") { + ok(item[state], `${itemID} is ${state}`); + + if (state !== "hidden") { + ok(!item.hidden, `Disabled ${itemID} is not hidden`); + } + } else { + ok(!item.hidden, `${itemID} is not hidden`); + ok(!item.disabled, `${itemID} is not disabled`); + } + } + + yield closeContextMenu(contentAreaContextMenu); + + yield extension.unload(); +}); + +add_task(function* sidebar_image_contextmenu() { + let extension = ExtensionTestUtils.loadExtension(extData); + yield extension.startup(); + // Test sidebar is opened on install + yield extension.awaitMessage("sidebar"); + + let contentAreaContextMenu = yield openContextMenuInSidebar("#testimg"); + + let item = contentAreaContextMenu.querySelector("#context-viewimageinfo"); + ok(!item.hidden); + ok(!item.disabled); + + yield closeContextMenu(contentAreaContextMenu); + + yield extension.unload(); +}); + +add_task(function* cleanup() { + // This is set on initial sidebar install. + Services.prefs.clearUserPref("extensions.sidebar-button.shown"); +}); diff --git a/browser/components/extensions/test/browser/head.js b/browser/components/extensions/test/browser/head.js index 75560660b7c4..8625c6cd79ec 100644 --- a/browser/components/extensions/test/browser/head.js +++ b/browser/components/extensions/test/browser/head.js @@ -8,7 +8,8 @@ * getBrowserActionPopup getPageActionPopup * closeBrowserAction closePageAction * promisePopupShown promisePopupHidden - * openContextMenu closeContextMenu openContextMenuInSidebar + * openContextMenu closeContextMenu + * openContextMenuInSidebar openContextMenuInPopup * openExtensionContextMenu closeExtensionContextMenu * openActionContextMenu openSubmenu closeActionContextMenu * openTabContextMenu closeTabContextMenu @@ -232,6 +233,16 @@ function closeBrowserAction(extension, win = window) { return Promise.resolve(); } +async function openContextMenuInPopup(extension, selector = "body") { + let contentAreaContextMenu = document.getElementById("contentAreaContextMenu"); + let browser = await awaitExtensionPanel(extension); + let popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown"); + await BrowserTestUtils.synthesizeMouseAtCenter(selector, {type: "mousedown", button: 2}, browser); + await BrowserTestUtils.synthesizeMouseAtCenter(selector, {type: "contextmenu"}, browser); + await popupShownPromise; + return contentAreaContextMenu; +} + async function openContextMenuInSidebar(selector = "body") { let contentAreaContextMenu = SidebarUI.browser.contentDocument.getElementById("contentAreaContextMenu"); let browser = SidebarUI.browser.contentDocument.getElementById("webext-panels-browser"); diff --git a/browser/components/extensions/test/mochitest/mochitest.ini b/browser/components/extensions/test/mochitest/mochitest.ini index 39290db613ef..f4fe07931480 100644 --- a/browser/components/extensions/test/mochitest/mochitest.ini +++ b/browser/components/extensions/test/mochitest/mochitest.ini @@ -1,6 +1,7 @@ [DEFAULT] support-files = ../../../../../toolkit/components/extensions/test/mochitest/test_ext_all_apis.js + ../../../../../toolkit/components/extensions/test/mochitest/file_sample.html tags = webextensions [test_ext_all_apis.html] diff --git a/browser/components/preferences/in-content/advanced.js b/browser/components/preferences/in-content/advanced.js index c4f72088ef93..e575db2acca8 100644 --- a/browser/components/preferences/in-content/advanced.js +++ b/browser/components/preferences/in-content/advanced.js @@ -3,6 +3,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ /* import-globals-from preferences.js */ +/* import-globals-from ../../../base/content/aboutDialog-appUpdater.js */ // Load DownloadUtils module for convertByteUnits Components.utils.import("resource://gre/modules/DownloadUtils.jsm"); @@ -20,7 +21,56 @@ var gAdvancedPane = { this._inited = true; + let version = AppConstants.MOZ_APP_VERSION_DISPLAY; + + // Include the build ID if this is an "a#" (nightly) build + if (/a\d+$/.test(version)) { + let buildID = Services.appinfo.appBuildID; + let year = buildID.slice(0, 4); + let month = buildID.slice(4, 6); + let day = buildID.slice(6, 8); + version += ` (${year}-${month}-${day})`; + } + + // Append "(32-bit)" or "(64-bit)" build architecture to the version number: + let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); + let archResource = Services.appinfo.is64Bit + ? "aboutDialog.architecture.sixtyFourBit" + : "aboutDialog.architecture.thirtyTwoBit"; + let arch = bundle.GetStringFromName(archResource); + version += ` (${arch})`; + + document.getElementById("version").textContent = version; + + // Show a release notes link if we have a URL. + let relNotesLink = document.getElementById("releasenotes"); + let relNotesPrefType = Services.prefs.getPrefType("app.releaseNotesURL"); + if (relNotesPrefType != Services.prefs.PREF_INVALID) { + let relNotesURL = Services.urlFormatter.formatURLPref("app.releaseNotesURL"); + if (relNotesURL != "about:blank") { + relNotesLink.href = relNotesURL; + relNotesLink.hidden = false; + } + } + + let distroId = Services.prefs.getCharPref("distribution.id", ""); + if (distroId) { + let distroVersion = Services.prefs.getCharPref("distribution.version"); + + let distroIdField = document.getElementById("distributionId"); + distroIdField.value = distroId + " - " + distroVersion; + distroIdField.hidden = false; + + let distroAbout = Services.prefs.getStringPref("distribution.about", ""); + if (distroAbout) { + let distroField = document.getElementById("distribution"); + distroField.value = distroAbout; + distroField.hidden = false; + } + } + if (AppConstants.MOZ_UPDATER) { + gAppUpdater = new appUpdater(); let onUnload = () => { window.removeEventListener("unload", onUnload); Services.prefs.removeObserver("app.update.", this); diff --git a/browser/components/preferences/in-content/advanced.xul b/browser/components/preferences/in-content/advanced.xul index 97dd5cb0c29a..d760676307ae 100644 --- a/browser/components/preferences/in-content/advanced.xul +++ b/browser/components/preferences/in-content/advanced.xul @@ -4,6 +4,10 @@ +#ifdef MOZ_UPDATER + - - diff --git a/dom/media/test/crashtests/crashtests.list b/dom/media/test/crashtests/crashtests.list index f194139482ce..a8f02261bf9c 100644 --- a/dom/media/test/crashtests/crashtests.list +++ b/dom/media/test/crashtests/crashtests.list @@ -81,8 +81,6 @@ load 1157994.html load 1158427.html load 1185176.html load 1185192.html -load 1223670.html -load 1228484.html load 1304948.html load 1319486.html load 1291702.html diff --git a/dom/media/tests/mochitest/head.js b/dom/media/tests/mochitest/head.js index 14220ebc8a54..6da68247e5a6 100644 --- a/dom/media/tests/mochitest/head.js +++ b/dom/media/tests/mochitest/head.js @@ -908,55 +908,94 @@ AudioStreamHelper.prototype = { } } -function VideoStreamHelper() { - this._helper = new CaptureStreamTestHelper2D(50,50); - this._canvas = this._helper.createAndAppendElement('canvas', 'source_canvas'); - // Make sure this is initted - this._helper.drawColor(this._canvas, this._helper.green); - this._stream = this._canvas.captureStream(10); -} +class VideoFrameEmitter { + constructor(color1, color2) { + this._helper = new CaptureStreamTestHelper2D(50,50); + this._canvas = this._helper.createAndAppendElement('canvas', 'source_canvas'); + this._color1 = color1 ? color1 : this._helper.green; + this._color2 = color2 ? color2 : this._helper.red; + // Make sure this is initted + this._helper.drawColor(this._canvas, this._color1); + this._stream = this._canvas.captureStream(); + this._started = false; + } -VideoStreamHelper.prototype = { - stream: function() { + stream() { return this._stream; - }, + } - startCapturingFrames: function() { - var i = 0; - var helper = this; - return setInterval(function() { + start() { + if (this._started) { + return; + } + + let i = 0; + this._started = true; + this._intervalId = setInterval(() => { try { - helper._helper.drawColor(helper._canvas, - i ? helper._helper.green : helper._helper.red); + this._helper.drawColor(this._canvas, i ? this._color1: this._color2); i = 1 - i; - helper._stream.requestFrame(); } catch (e) { // ignore; stream might have shut down, and we don't bother clearing // the setInterval. } }, 500); - }, + } - waitForFrames: function(canvas, timeout_value) { - var intervalId = this.startCapturingFrames(); - timeout_value = timeout_value || 8000; + stop() { + if (this._started) { + clearInterval(this._intervalId); + this._started = false; + } + } +} - return addFinallyToPromise(timeout( - Promise.all([ - this._helper.waitForPixelColor(canvas, this._helper.green, 128, - canvas.id + " should become green"), - this._helper.waitForPixelColor(canvas, this._helper.red, 128, - canvas.id + " should become red") - ]), - timeout_value, - "Timed out waiting for frames")).finally(() => clearInterval(intervalId)); - }, +class VideoStreamHelper { + constructor() { + this._helper = new CaptureStreamTestHelper2D(50,50); + } - verifyNoFrames: function(canvas) { - return this.waitForFrames(canvas).then( - () => ok(false, "Color should not change"), - () => ok(true, "Color should not change") - ); + checkHasFrame(video, offsetX, offsetY, threshold) { + const h = this._helper; + return h.waitForPixel(video, offsetX, offsetY, px => { + let result = h.isOpaquePixelNot(px, h.black, threshold); + info("Checking that we have a frame, got [" + + Array.slice(px) + "]. Ref=[" + + Array.slice(h.black.data) + "]. Threshold=" + threshold + + ". Pass=" + result); + return result; + }); + } + + async checkVideoPlaying(video, offsetX, offsetY, threshold) { + const h = this._helper; + await this.checkHasFrame(video, offsetX, offsetY, threshold); + let startPixel = { data: h.getPixel(video, offsetX, offsetY) + , name: "startcolor" + }; + return h.waitForPixel(video, offsetX, offsetY, px => { + let result = h.isPixelNot(px, startPixel, threshold) + info("Checking playing, [" + + Array.slice(px) + "] vs [" + Array.slice(startPixel.data) + + "]. Threshold=" + threshold + " Pass=" + result); + return result; + }); + } + + async checkVideoPaused(video, offsetX, offsetY, threshold, timeout) { + const h = this._helper; + await this.checkHasFrame(video, offsetX, offsetY, threshold); + let startPixel = { data: h.getPixel(video, offsetX, offsetY) + , name: "startcolor" + }; + const changed = await h.waitForPixel(video, offsetX, offsetY, px => { + let result = h.isOpaquePixelNot(px, startPixel, threshold); + info("Checking paused, [" + + Array.slice(px) + "] vs [" + Array.slice(startPixel.data) + + "]. Threshold=" + threshold + " Pass=" + result); + return result; + }, timeout); + ok(!changed, "Frame shouldn't change within " + timeout / 1000 + " seconds."); } } diff --git a/dom/media/tests/mochitest/pc.js b/dom/media/tests/mochitest/pc.js index d473c91ec8ee..cb1e756717e4 100644 --- a/dom/media/tests/mochitest/pc.js +++ b/dom/media/tests/mochitest/pc.js @@ -1004,13 +1004,13 @@ PeerConnectionWrapper.prototype = { return Promise.all(constraintsList.map(constraints => { return getUserMedia(constraints).then(stream => { if (constraints.audio) { - stream.getAudioTracks().map(track => { + stream.getAudioTracks().forEach(track => { info(this + " gUM local stream " + stream.id + " with audio track " + track.id); }); } if (constraints.video) { - stream.getVideoTracks().map(track => { + stream.getVideoTracks().forEach(track => { info(this + " gUM local stream " + stream.id + " with video track " + track.id); }); diff --git a/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_audio.html b/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_audio.html index 6d99f2e11aa9..8e1dab466b75 100644 --- a/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_audio.html +++ b/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_audio.html @@ -2,7 +2,6 @@ -
diff --git a/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_tracks.html b/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_tracks.html
index 646cc15db6e6..335537d3f447 100644
--- a/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_tracks.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_tracks.html
@@ -2,7 +2,6 @@
 
 
   
-  
 
 
 
diff --git a/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_video.html b/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_video.html
index a1097094eb54..5ab62a04ddd3 100644
--- a/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_video.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_video.html
@@ -3,7 +3,6 @@
 
   
   
-  
 
 
 
@@ -24,43 +23,11 @@ const offsetX = 20;
 const offsetY = 20;
 const threshold = 16;
 const pausedTimeout = 1000;
-const h = new CaptureStreamTestHelper2D(50, 50);
-
-var checkHasFrame = video => h.waitForPixel(video, offsetX, offsetY, px => {
-  let result = h.isOpaquePixelNot(px, h.black, threshold);
-  info("Checking that we have a frame, got [" +
-       Array.slice(px) + "]. Pass=" + result);
-  return result;
-});
-
-var checkVideoPlaying = video => checkHasFrame(video)
-  .then(() => {
-    let startPixel = { data: h.getPixel(video, offsetX, offsetY)
-                     , name: "startcolor"
-                     };
-    return h.waitForPixel(video, offsetX, offsetY, px => {
-      let result = h.isPixelNot(px, startPixel, threshold)
-      info("Checking playing, [" + Array.slice(px) + "] vs [" +
-           Array.slice(startPixel.data) + "]. Pass=" + result);
-      return result;
-    });
-  });
-
-var checkVideoPaused = video => checkHasFrame(video)
-  .then(() => {
-    let startPixel = { data: h.getPixel(video, offsetX, offsetY)
-                     , name: "startcolor"
-                     };
-    return h.waitForPixel(video, offsetX, offsetY, px => {
-      let result = h.isOpaquePixelNot(px, startPixel, threshold);
-      info("Checking paused, [" + Array.slice(px) + "] vs [" +
-           Array.slice(startPixel.data) + "]. Pass=" + result);
-      return result;
-    }, pausedTimeout);
-  }).then(result => ok(!result, "Frame shouldn't change within " + pausedTimeout / 1000 + " seconds."));
+let h;
 
 runTest(() => getUserMedia({video: true, fake: true})
   .then(stream => {
+    h = new VideoStreamHelper();
     gUMVideoElement =
       createMediaElement("video", "gUMVideo");
     gUMVideoElement.srcObject = stream;
@@ -80,43 +47,45 @@ runTest(() => getUserMedia({video: true, fake: true})
     let osc = createOscillatorStream(new AudioContext(), 1000);
     captureStreamElement.srcObject.addTrack(osc.getTracks()[0]);
 
-    return checkVideoPlaying(captureStreamElement);
+    return h.checkVideoPlaying(captureStreamElement, 10, 10, 16);
   })
   .then(() => {
     info("Video flowing. Pausing.");
     gUMVideoElement.pause();
 
-    return checkVideoPaused(captureStreamElement);
+    return h.checkVideoPaused(captureStreamElement, 10, 10, 16, pausedTimeout);
   })
   .then(() => {
     info("Video stopped flowing. Playing.");
     gUMVideoElement.play();
 
-    return checkVideoPlaying(captureStreamElement);
+    return h.checkVideoPlaying(captureStreamElement, 10, 10, 16);
   })
   .then(() => {
     info("Video flowing. Removing source.");
     var stream = gUMVideoElement.srcObject;
     gUMVideoElement.srcObject = null;
 
-    return checkVideoPaused(captureStreamElement).then(() => stream);
+    return h.checkVideoPaused(captureStreamElement, 10, 10, 16, pausedTimeout)
+        .then(() => stream);
   })
   .then(stream => {
     info("Video stopped flowing. Setting source.");
     gUMVideoElement.srcObject = stream;
-    return checkVideoPlaying(captureStreamElement);
+    return h.checkVideoPlaying(captureStreamElement, 10, 10, 16);
   })
   .then(() => {
     info("Video flowing. Changing source by track manipulation. Remove first.");
     var track = gUMVideoElement.srcObject.getTracks()[0];
     gUMVideoElement.srcObject.removeTrack(track);
-    return checkVideoPaused(captureStreamElement).then(() => track);
+    return h.checkVideoPaused(captureStreamElement, 10, 10, 16, pausedTimeout)
+        .then(() => track);
   })
   .then(track => {
     info("Video paused. Changing source by track manipulation. Add first.");
     gUMVideoElement.srcObject.addTrack(track);
     gUMVideoElement.play();
-    return checkVideoPlaying(captureStreamElement);
+    return h.checkVideoPlaying(captureStreamElement, 10, 10, 16);
   })
   .then(() => {
     gUMVideoElement.srcObject.getTracks().forEach(t => t.stop());
diff --git a/dom/media/tests/mochitest/test_getUserMedia_scarySources.html b/dom/media/tests/mochitest/test_getUserMedia_scarySources.html
index 3dc912455386..279f18a4f8c7 100644
--- a/dom/media/tests/mochitest/test_getUserMedia_scarySources.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_scarySources.html
@@ -1,7 +1,6 @@
 
 
 
-  
   
 
 
diff --git a/dom/media/tests/mochitest/test_peerConnection_addSecondAudioStream.html b/dom/media/tests/mochitest/test_peerConnection_addSecondAudioStream.html
index 73b28f1af624..81dec37b3320 100644
--- a/dom/media/tests/mochitest/test_peerConnection_addSecondAudioStream.html
+++ b/dom/media/tests/mochitest/test_peerConnection_addSecondAudioStream.html
@@ -11,9 +11,8 @@
     title: "Renegotiation: add second audio stream"
   });
 
-  var test;
   runNetworkTest(function (options) {
-    test = new PeerConnectionTest(options);
+    const test = new PeerConnectionTest(options);
     addRenegotiation(test.chain,
       [
         function PC_LOCAL_ADD_SECOND_STREAM(test) {
@@ -21,10 +20,22 @@
                                    [{audio: true}]);
           return test.pcLocal.getAllUserMedia([{audio: true}]);
         },
+      ],
+      [
+        function PC_REMOTE_CHECK_ADDED_TRACK(test) {
+          // We test both tracks to avoid an ordering problem
+          is(test.pcRemote._pc.getReceivers().length, 2,
+             "pcRemote should have two receivers");
+          return Promise.all(test.pcRemote._pc.getReceivers().map(r => {
+            const analyser = new AudioStreamAnalyser(
+                new AudioContext(), new MediaStream([r.track]));
+            const freq = analyser.binIndexForFrequency(TEST_AUDIO_FREQ);
+            return analyser.waitForAnalysisSuccess(arr => arr[freq] > 200);
+          }));
+        },
       ]
     );
 
-    // TODO(bug 1093835): figure out how to verify if media flows through the new stream
     test.setMediaConstraints([{audio: true}], [{audio: true}]);
     test.run();
   });
diff --git a/dom/media/tests/mochitest/test_peerConnection_addSecondAudioStreamNoBundle.html b/dom/media/tests/mochitest/test_peerConnection_addSecondAudioStreamNoBundle.html
index cf9736e8761d..32e53b1202f5 100644
--- a/dom/media/tests/mochitest/test_peerConnection_addSecondAudioStreamNoBundle.html
+++ b/dom/media/tests/mochitest/test_peerConnection_addSecondAudioStreamNoBundle.html
@@ -11,11 +11,9 @@
     title: "Renegotiation: add second audio stream, no bundle"
   });
 
-  var test;
-  runNetworkTest(function (options) {
-    options = options || { };
+  runNetworkTest(function (options = {}) {
     options.bundle = false;
-    test = new PeerConnectionTest(options);
+    const test = new PeerConnectionTest(options);
     addRenegotiation(test.chain,
       [
         function PC_LOCAL_ADD_SECOND_STREAM(test) {
@@ -29,6 +27,19 @@
         function PC_REMOTE_EXPECT_ICE_CHECKING(test) {
           test.pcRemote.expectIceChecking();
         },
+      ],
+      [
+        function PC_REMOTE_CHECK_ADDED_TRACK(test) {
+          // We test both tracks to avoid an ordering problem
+          is(test.pcRemote._pc.getReceivers().length, 2,
+             "pcRemote should have two receivers");
+          return Promise.all(test.pcRemote._pc.getReceivers().map(r => {
+            const analyser = new AudioStreamAnalyser(
+                new AudioContext(), new MediaStream([r.track]));
+            const freq = analyser.binIndexForFrequency(TEST_AUDIO_FREQ);
+            return analyser.waitForAnalysisSuccess(arr => arr[freq] > 200);
+          }));
+        },
       ]
     );
 
diff --git a/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStream.html b/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStream.html
index ebe7d46b1725..245cde5a064d 100644
--- a/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStream.html
+++ b/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStream.html
@@ -2,6 +2,7 @@
 
 
   
+  
 
 
 
@@ -11,21 +12,30 @@
     title: "Renegotiation: add second video stream"
   });
 
-  var test;
   runNetworkTest(function (options) {
-    test = new PeerConnectionTest(options);
+    const test = new PeerConnectionTest(options);
     addRenegotiation(test.chain,
       [
         function PC_LOCAL_ADD_SECOND_STREAM(test) {
           test.setMediaConstraints([{video: true}, {video: true}],
                                    [{video: true}]);
-          return test.pcLocal.getAllUserMedia([{video: true}]);
+          // Use fake:true here since the native fake device on linux doesn't
+          // change color as needed by checkVideoPlaying() below.
+          return test.pcLocal.getAllUserMedia([{video: true, fake: true}]);
+        },
+      ],
+      [
+        function PC_REMOTE_CHECK_VIDEO_FLOW(test) {
+          const h = new VideoStreamHelper();
+          is(test.pcRemote.remoteMediaElements.length, 2,
+             "Should have two remote media elements after renegotiation");
+          return Promise.all(test.pcRemote.remoteMediaElements.map(video =>
+            h.checkVideoPlaying(video, 10, 10, 16)));
         },
       ]
     );
 
-    // TODO(bug 1093835): figure out how to verify if media flows through the new stream
-    test.setMediaConstraints([{video: true}], [{video: true}]);
+    test.setMediaConstraints([{video: true, fake: true}], [{video: true}]);
     test.run();
   });
 
diff --git a/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStreamNoBundle.html b/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStreamNoBundle.html
index 64dc97fc71bf..53206778969a 100644
--- a/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStreamNoBundle.html
+++ b/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStreamNoBundle.html
@@ -2,6 +2,7 @@
 
 
   
+  
 
 
 
@@ -11,11 +12,9 @@
     title: "Renegotiation: add second video stream, no bundle"
   });
 
-  var test;
-  runNetworkTest(function (options) {
-    options = options || { };
+  runNetworkTest(function (options = {}) {
     options.bundle = false;
-    test = new PeerConnectionTest(options);
+    const test = new PeerConnectionTest(options);
     addRenegotiation(test.chain,
       [
         function PC_LOCAL_ADD_SECOND_STREAM(test) {
@@ -24,16 +23,26 @@
           // Since this is a NoBundle variant, adding a track will cause us to
           // go back to checking.
           test.pcLocal.expectIceChecking();
-          return test.pcLocal.getAllUserMedia([{video: true}]);
+          // Use fake:true here since the native fake device on linux doesn't
+          // change color as needed by checkVideoPlaying() below.
+          return test.pcLocal.getAllUserMedia([{video: true, fake: true}]);
         },
         function PC_REMOTE_EXPECT_ICE_CHECKING(test) {
           test.pcRemote.expectIceChecking();
         },
+      ],
+      [
+        function PC_REMOTE_CHECK_VIDEO_FLOW(test) {
+          const h = new VideoStreamHelper();
+          is(test.pcRemote.remoteMediaElements.length, 2,
+             "Should have two remote media elements after renegotiation");
+          return Promise.all(test.pcRemote.remoteMediaElements.map(video =>
+            h.checkVideoPlaying(video, 10, 10, 16)));
+        },
       ]
     );
 
-    // TODO(bug 1093835): figure out how to verify if media flows through the new stream
-    test.setMediaConstraints([{video: true}], [{video: true}]);
+    test.setMediaConstraints([{video: true, fake: true}], [{video: true}]);
     test.run();
   });
 
diff --git a/dom/media/tests/mochitest/test_peerConnection_close.html b/dom/media/tests/mochitest/test_peerConnection_close.html
index 42a523fb398a..628d4833dc9d 100644
--- a/dom/media/tests/mochitest/test_peerConnection_close.html
+++ b/dom/media/tests/mochitest/test_peerConnection_close.html
@@ -1,7 +1,6 @@
 
 
 
-  
   
 
 
diff --git a/dom/media/tests/mochitest/test_peerConnection_removeAudioTrack.html b/dom/media/tests/mochitest/test_peerConnection_removeAudioTrack.html
index dfb5c5b4cc3f..119369eef9e1 100644
--- a/dom/media/tests/mochitest/test_peerConnection_removeAudioTrack.html
+++ b/dom/media/tests/mochitest/test_peerConnection_removeAudioTrack.html
@@ -11,20 +11,42 @@
     title: "Renegotiation: remove audio track"
   });
 
-  var test;
   runNetworkTest(function (options) {
-    test = new PeerConnectionTest(options);
+    const test = new PeerConnectionTest(options);
+    let receivedTrack, analyser, freq;
     addRenegotiation(test.chain,
       [
+        function PC_REMOTE_SETUP_ANALYSER(test) {
+          is(test.pcRemote._pc.getReceivers().length, 1,
+             "pcRemote should have one receiver before renegotiation");
+
+          receivedTrack = test.pcRemote._pc.getReceivers()[0].track;
+          is(receivedTrack.readyState, "live",
+             "The received track should be live");
+
+          analyser = new AudioStreamAnalyser(
+              new AudioContext(), new MediaStream([receivedTrack]));
+          freq = analyser.binIndexForFrequency(TEST_AUDIO_FREQ);
+
+          return analyser.waitForAnalysisSuccess(arr => arr[freq] > 200);
+        },
         function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
           test.setOfferOptions({ offerToReceiveAudio: true });
           return test.pcLocal.removeSender(0);
         },
+      ],
+      [
+        function PC_REMOTE_CHECK_FLOW_STOPPED(test) {
+          is(test.pcRemote._pc.getReceivers().length, 0,
+             "pcRemote should have no more receivers");
+          is(receivedTrack.readyState, "ended",
+             "The received track should have ended");
+
+          return analyser.waitForAnalysisSuccess(arr => arr[freq] < 50);
+        },
       ]
     );
 
-    // TODO(bug 1093835): figure out how to verify that media stopped flowing from pcLocal
-
     test.setMediaConstraints([{audio: true}], [{audio: true}]);
     test.run();
   });
diff --git a/dom/media/tests/mochitest/test_peerConnection_removeThenAddAudioTrack.html b/dom/media/tests/mochitest/test_peerConnection_removeThenAddAudioTrack.html
index 097cbcc86c09..3e1fab2855c7 100644
--- a/dom/media/tests/mochitest/test_peerConnection_removeThenAddAudioTrack.html
+++ b/dom/media/tests/mochitest/test_peerConnection_removeThenAddAudioTrack.html
@@ -11,11 +11,16 @@
     title: "Renegotiation: remove then add audio track"
   });
 
-  var test;
   runNetworkTest(function (options) {
-    test = new PeerConnectionTest(options);
+    const test = new PeerConnectionTest(options);
+    let originalTrack;
     addRenegotiation(test.chain,
       [
+        function PC_REMOTE_FIND_RECEIVER(test) {
+          is(test.pcRemote._pc.getReceivers().length, 1,
+             "pcRemote should have one receiver");
+          originalTrack = test.pcRemote._pc.getReceivers()[0].track;
+        },
         function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
           return test.pcLocal.removeSender(0);
         },
@@ -26,10 +31,22 @@
           test.pcLocal.disableRtpCountChecking = true;
           return test.pcLocal.getAllUserMedia([{audio: true}]);
         },
+      ],
+      [
+        function PC_REMOTE_CHECK_ADDED_TRACK(test) {
+          is(test.pcRemote._pc.getReceivers().length, 1,
+              "pcRemote should still have one receiver");
+          const track = test.pcRemote._pc.getReceivers()[0].track;
+          isnot(originalTrack.id, track.id, "Receiver should have changed");
+
+          const analyser = new AudioStreamAnalyser(
+              new AudioContext(), new MediaStream([track]));
+          const freq = analyser.binIndexForFrequency(TEST_AUDIO_FREQ);
+          return analyser.waitForAnalysisSuccess(arr => arr[freq] > 200);
+        },
       ]
     );
 
-    // TODO(bug 1093835): figure out how to verify if media flows through the new stream
     test.setMediaConstraints([{audio: true}], [{audio: true}]);
     test.run();
   });
diff --git a/dom/media/tests/mochitest/test_peerConnection_removeThenAddAudioTrackNoBundle.html b/dom/media/tests/mochitest/test_peerConnection_removeThenAddAudioTrackNoBundle.html
index 6d814bcae496..a0634b4006a4 100644
--- a/dom/media/tests/mochitest/test_peerConnection_removeThenAddAudioTrackNoBundle.html
+++ b/dom/media/tests/mochitest/test_peerConnection_removeThenAddAudioTrackNoBundle.html
@@ -11,11 +11,16 @@
     title: "Renegotiation: remove then add audio track"
   });
 
-  var test;
   runNetworkTest(function (options) {
-    test = new PeerConnectionTest(options);
+    const test = new PeerConnectionTest(options);
+    let originalTrack;
     addRenegotiation(test.chain,
       [
+        function PC_REMOTE_FIND_RECEIVER(test) {
+          is(test.pcRemote._pc.getReceivers().length, 1,
+             "pcRemote should have one receiver");
+          originalTrack = test.pcRemote._pc.getReceivers()[0].track;
+        },
         function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
           // The new track's pipeline will start with a packet count of
           // 0, but the remote side will keep its old pipeline and packet
@@ -26,13 +31,25 @@
         function PC_LOCAL_ADD_AUDIO_TRACK(test) {
           return test.pcLocal.getAllUserMedia([{audio: true}]);
         },
+      ],
+      [
+        function PC_REMOTE_CHECK_ADDED_TRACK(test) {
+          is(test.pcRemote._pc.getReceivers().length, 1,
+              "pcRemote should still have one receiver");
+          const track = test.pcRemote._pc.getReceivers()[0].track;
+          isnot(originalTrack.id, track.id, "Receiver should have changed");
+
+          const analyser = new AudioStreamAnalyser(
+              new AudioContext(), new MediaStream([track]));
+          const freq = analyser.binIndexForFrequency(TEST_AUDIO_FREQ);
+          return analyser.waitForAnalysisSuccess(arr => arr[freq] > 200);
+        },
       ]
     );
 
     test.chain.insertAfterEach('PC_LOCAL_CREATE_OFFER',
-                              PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER);
+                               PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER);
 
-    // TODO(bug 1093835): figure out how to verify if media flows through the new stream
     test.setMediaConstraints([{audio: true}], [{audio: true}]);
     test.run();
   });
diff --git a/dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrack.html b/dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrack.html
index 7335266ea523..5e7c0863e2f5 100644
--- a/dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrack.html
+++ b/dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrack.html
@@ -2,6 +2,7 @@
 
 
   
+  
 
 
 
@@ -11,25 +12,47 @@
     title: "Renegotiation: remove then add video track"
   });
 
-  var test;
   runNetworkTest(function (options) {
-    test = new PeerConnectionTest(options);
+    const test = new PeerConnectionTest(options);
+    const helper = new VideoStreamHelper();
+    var originalTrack;
     addRenegotiation(test.chain,
       [
-        function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
+        function PC_REMOTE_FIND_RECEIVER(test) {
+          is(test.pcRemote._pc.getReceivers().length, 1,
+             "pcRemote should have one receiver");
+          originalTrack = test.pcRemote._pc.getReceivers()[0].track;
+        },
+        function PC_LOCAL_REMOVE_VIDEO_TRACK(test) {
           // The new track's pipeline will start with a packet count of
           // 0, but the remote side will keep its old pipeline and packet
           // count.
           test.pcLocal.disableRtpCountChecking = true;
           return test.pcLocal.removeSender(0);
         },
-        function PC_LOCAL_ADD_AUDIO_TRACK(test) {
-          return test.pcLocal.getAllUserMedia([{video: true}]);
+        function PC_LOCAL_ADD_VIDEO_TRACK(test) {
+          // Use fake:true here since the native fake device on linux doesn't
+          // change color as needed by checkVideoPlaying() below.
+          return test.pcLocal.getAllUserMedia([{video: true, fake: true}]);
+        },
+      ],
+      [
+        function PC_REMOTE_CHECK_ADDED_TRACK(test) {
+          is(test.pcRemote._pc.getReceivers().length, 1,
+              "pcRemote should still have one receiver");
+          const track = test.pcRemote._pc.getReceivers()[0].track;
+          isnot(originalTrack.id, track.id, "Receiver should have changed");
+
+          const vOriginal = test.pcRemote.remoteMediaElements.find(
+              elem => elem.id.includes(originalTrack.id));
+          const vAdded = test.pcRemote.remoteMediaElements.find(
+              elem => elem.id.includes(track.id));
+          ok(vOriginal.ended, "Original video element should have ended");
+          return helper.checkVideoPlaying(vAdded, 10, 10, 16);
         },
       ]
     );
 
-    // TODO(bug 1093835): figure out how to verify if media flows through the new stream
     test.setMediaConstraints([{video: true}], [{video: true}]);
     test.run();
   });
diff --git a/dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrackNoBundle.html b/dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrackNoBundle.html
index 40f037683b91..b8be63c629b8 100644
--- a/dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrackNoBundle.html
+++ b/dom/media/tests/mochitest/test_peerConnection_removeThenAddVideoTrackNoBundle.html
@@ -2,6 +2,7 @@
 
 
   
+  
 
 
 
@@ -11,28 +12,50 @@
     title: "Renegotiation: remove then add video track, no bundle"
   });
 
-  var test;
   runNetworkTest(function (options) {
-    test = new PeerConnectionTest(options);
+    const test = new PeerConnectionTest(options);
+    const helper = new VideoStreamHelper();
+    var originalTrack;
     addRenegotiation(test.chain,
       [
-        function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
+        function PC_REMOTE_FIND_RECEIVER(test) {
+          is(test.pcRemote._pc.getReceivers().length, 1,
+             "pcRemote should have one receiver");
+          originalTrack = test.pcRemote._pc.getReceivers()[0].track;
+        },
+        function PC_LOCAL_REMOVE_VIDEO_TRACK(test) {
           // The new track's pipeline will start with a packet count of
           // 0, but the remote side will keep its old pipeline and packet
           // count.
           test.pcLocal.disableRtpCountChecking = true;
           return test.pcLocal.removeSender(0);
         },
-        function PC_LOCAL_ADD_AUDIO_TRACK(test) {
-          return test.pcLocal.getAllUserMedia([{video: true}]);
+        function PC_LOCAL_ADD_VIDEO_TRACK(test) {
+          // Use fake:true here since the native fake device on linux doesn't
+          // change color as needed by checkVideoPlaying() below.
+          return test.pcLocal.getAllUserMedia([{video: true, fake: true}]);
+        },
+      ],
+      [
+        function PC_REMOTE_CHECK_ADDED_TRACK(test) {
+          is(test.pcRemote._pc.getReceivers().length, 1,
+              "pcRemote should still have one receiver");
+          const track = test.pcRemote._pc.getReceivers()[0].track;
+          isnot(originalTrack.id, track.id, "Receiver should have changed");
+
+          const vOriginal = test.pcRemote.remoteMediaElements.find(
+              elem => elem.id.includes(originalTrack.id));
+          const vAdded = test.pcRemote.remoteMediaElements.find(
+              elem => elem.id.includes(track.id));
+          ok(vOriginal.ended, "Original video element should have ended");
+          return helper.checkVideoPlaying(vAdded, 10, 10, 16);
         },
       ]
     );
 
     test.chain.insertAfterEach('PC_LOCAL_CREATE_OFFER',
-                              PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER);
+                               PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER);
 
-    // TODO(bug 1093835): figure out how to verify if media flows through the new stream
     test.setMediaConstraints([{video: true}], [{video: true}]);
     test.run();
   });
diff --git a/dom/media/tests/mochitest/test_peerConnection_removeVideoTrack.html b/dom/media/tests/mochitest/test_peerConnection_removeVideoTrack.html
index 88fff9531faf..9364752d7944 100644
--- a/dom/media/tests/mochitest/test_peerConnection_removeVideoTrack.html
+++ b/dom/media/tests/mochitest/test_peerConnection_removeVideoTrack.html
@@ -11,21 +11,41 @@
     title: "Renegotiation: remove video track"
   });
 
-  var test;
   runNetworkTest(function (options) {
-    test = new PeerConnectionTest(options);
+    const test = new PeerConnectionTest(options);
+    let receivedTrack, element;
     addRenegotiation(test.chain,
       [
+        function PC_REMOTE_SETUP_HELPER(test) {
+          is(test.pcRemote._pc.getReceivers().length, 1,
+             "pcRemote should have one receiver before renegotiation");
+
+          receivedTrack = test.pcRemote._pc.getReceivers()[0].track;
+          is(receivedTrack.readyState, "live",
+             "The received track should be live");
+
+          element = createMediaElement("video", "pcRemoteReceivedVideo");
+          element.srcObject = new MediaStream([receivedTrack]);
+          return haveEvent(element, "loadeddata");
+        },
         function PC_LOCAL_REMOVE_VIDEO_TRACK(test) {
           test.setOfferOptions({ offerToReceiveVideo: true });
           test.setMediaConstraints([], [{video: true}]);
           return test.pcLocal.removeSender(0);
         },
+      ],
+      [
+        function PC_REMOTE_CHECK_FLOW_STOPPED(test) {
+          is(test.pcRemote._pc.getReceivers().length, 0,
+             "pcRemote should have no more receivers");
+          is(receivedTrack.readyState, "ended",
+             "The received track should have ended");
+          is(element.ended, true,
+             "Element playing the removed track should have ended");
+        },
       ]
     );
 
-    // TODO(bug 1093835): figure out how to verify that media stopped flowing from pcLocal
-
     test.setMediaConstraints([{video: true}], [{video: true}]);
     test.run();
   });
diff --git a/dom/media/tests/mochitest/test_peerConnection_replaceVideoThenRenegotiate.html b/dom/media/tests/mochitest/test_peerConnection_replaceVideoThenRenegotiate.html
index 5e36d7a5e02c..e58a0ab7d1d9 100644
--- a/dom/media/tests/mochitest/test_peerConnection_replaceVideoThenRenegotiate.html
+++ b/dom/media/tests/mochitest/test_peerConnection_replaceVideoThenRenegotiate.html
@@ -2,6 +2,7 @@
 
 
   
+  
 
 
 
@@ -11,33 +12,74 @@
     title: "Renegotiation: replaceTrack followed by adding a second video stream"
   });
 
-  var test;
   runNetworkTest(function (options) {
-    test = new PeerConnectionTest(options);
+    const test = new PeerConnectionTest(options);
     test.setMediaConstraints([{video:true}], [{video:true}]);
+    const helper = new VideoStreamHelper();
+    const emitter1 = new VideoFrameEmitter(CaptureStreamTestHelper.prototype.red,
+                                           CaptureStreamTestHelper.prototype.green);
+    const emitter2 = new VideoFrameEmitter(CaptureStreamTestHelper.prototype.blue,
+                                           CaptureStreamTestHelper.prototype.grey);
+    test.chain.replace("PC_LOCAL_GUM", [
+      function PC_LOCAL_ADDTRACK(test) {
+        test.pcLocal.attachLocalStream(emitter1.stream());
+        emitter1.start();
+      },
+    ]);
     addRenegotiation(test.chain,
       [
         function PC_LOCAL_REPLACE_VIDEO_TRACK_THEN_ADD_SECOND_STREAM(test) {
-          var oldstream = test.pcLocal._pc.getLocalStreams()[0];
-          var oldtrack = oldstream.getVideoTracks()[0];
-          var sender = test.pcLocal._pc.getSenders()[0];
-          return navigator.mediaDevices.getUserMedia({video:true})
-            .then(newstream => {
-              var newtrack = newstream.getVideoTracks()[0];
-              return test.pcLocal.senderReplaceTrack(0, newtrack, newstream.id);
-            })
+          emitter1.stop();
+          emitter2.start();
+          const newstream = emitter2.stream();
+          const newtrack = newstream.getVideoTracks()[0];
+          return test.pcLocal.senderReplaceTrack(0, newtrack, newstream.id)
             .then(() => {
               test.setMediaConstraints([{video: true}, {video: true}],
                                        [{video: true}]);
-              return test.pcLocal.getAllUserMedia([{video: true}]);
+              // Use fake:true here since the native fake device on linux
+              // doesn't change color as needed by checkVideoPlaying() below.
+              return test.pcLocal.getAllUserMedia([{video: true, fake: true}]);
             });
         },
+      ],
+      [
+        function PC_REMOTE_CHECK_ORIGINAL_TRACK_ENDED(test) {
+          const vremote = test.pcRemote.remoteMediaElements.find(
+              elem => elem.id.includes(emitter1.stream().getTracks()[0].id));
+          if (!vremote) {
+            return Promise.reject(new Error("Couldn't find video element"));
+          }
+          ok(vremote.ended, "Original track should have ended after renegotiation");
+        },
+        function PC_REMOTE_CHECK_REPLACED_TRACK_FLOW(test) {
+          const vremote = test.pcRemote.remoteMediaElements.find(
+              elem => elem.id.includes(test.pcLocal._pc.getSenders()[0].track.id));
+          if (!vremote) {
+            return Promise.reject(new Error("Couldn't find video element"));
+          }
+          return addFinallyToPromise(helper.checkVideoPlaying(vremote, 10, 10, 16))
+            .finally(() => emitter2.stop())
+            .then(() => {
+              const px = helper._helper.getPixel(vremote, 10, 10);
+              const isBlue = helper._helper.isPixel(
+                  px, CaptureStreamTestHelper.prototype.blue, 5);
+              const isGrey = helper._helper.isPixel(
+                  px, CaptureStreamTestHelper.prototype.grey, 5);
+              ok(isBlue || isGrey, "replaced track should be blue or grey");
+            });
+        },
+        function PC_REMOTE_CHECK_ADDED_TRACK_FLOW(test) {
+          const vremote = test.pcRemote.remoteMediaElements.find(
+              elem => elem.id.includes(test.pcLocal._pc.getSenders()[1].track.id));
+          if (!vremote) {
+            return Promise.reject(new Error("Couldn't find video element"));
+          }
+          return helper.checkVideoPlaying(vremote, 10, 10, 16);
+        },
       ]
     );
 
-    // TODO(bug 1093835):
-    // figure out how to verify if media flows through the new stream
-    // figure out how to verify that media stopped flowing from old stream
     test.run();
   });
 
diff --git a/dom/media/tests/mochitest/test_peerConnection_simulcastAnswer.html b/dom/media/tests/mochitest/test_peerConnection_simulcastAnswer.html
index c75c22b22b1a..bd13c86b6db1 100644
--- a/dom/media/tests/mochitest/test_peerConnection_simulcastAnswer.html
+++ b/dom/media/tests/mochitest/test_peerConnection_simulcastAnswer.html
@@ -13,21 +13,20 @@
     visible: true
   });
 
-  var test;
-  var pushPrefs = (...p) => SpecialPowers.pushPrefEnv({set: p});
+  const pushPrefs = (...p) => SpecialPowers.pushPrefEnv({set: p});
 
   function addRIDExtension(pc, extensionId) {
-    var receivers = pc._pc.getReceivers();
+    const receivers = pc._pc.getReceivers();
     is(receivers.length, 1, "We have exactly one RTP receiver");
-    var receiver = receivers[0];
+    const receiver = receivers[0];
 
     SpecialPowers.wrap(pc._pc).mozAddRIDExtension(receiver, extensionId);
   }
 
   function selectRecvRID(pc, rid) {
-    var receivers = pc._pc.getReceivers();
+    const receivers = pc._pc.getReceivers();
     is(receivers.length, 1, "We have exactly one RTP receiver");
-    var receiver = receivers[0];
+    const receiver = receivers[0];
 
     SpecialPowers.wrap(pc._pc).mozAddRIDFilter(receiver, rid);
   }
@@ -38,23 +37,24 @@
               // the 80Kbps+overhead needed for the two simulcast streams.
               // 100Kbps was apparently too low.
               ['media.peerconnection.video.min_bitrate_estimate', 180*1000]).then(() => {
-      var helper;
+      let emitter, helper;
 
       test = new PeerConnectionTest({bundle: false});
       test.setMediaConstraints([{video: true}], [{video: true}]);
 
       test.chain.replace("PC_REMOTE_GUM", [
         function PC_REMOTE_CANVAS_CAPTURESTREAM(test) {
+          emitter = new VideoFrameEmitter();
           helper = new VideoStreamHelper();
-          test.pcRemote.attachLocalStream(helper.stream());
+          test.pcRemote.attachLocalStream(emitter.stream());
         }
       ]);
 
       test.chain.insertAfter('PC_REMOTE_GET_OFFER', [
         function PC_REMOTE_SET_RIDS(test) {
-          var senders = test.pcRemote._pc.getSenders();
+          const senders = test.pcRemote._pc.getSenders();
           is(senders.length, 1, "We have exactly one RTP sender");
-          var sender = senders[0];
+          const sender = senders[0];
           ok(sender.track, "Sender has a track");
 
           return sender.setParameters({
@@ -88,7 +88,7 @@
       // has been created.
       test.chain.insertAfter('PC_LOCAL_SET_REMOTE_DESCRIPTION',[
         function PC_LOCAL_SET_RTP_FIRST_RID(test) {
-          var extmap_id = test._local_offer.sdp.match(
+          const extmap_id = test._local_offer.sdp.match(
               "a=extmap:([0-9+])/recvonly urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id");
           ok(extmap_id, "Local offer has extmap id for simulcast: " + extmap_id[1]);
           // Cause pcLocal to filter out everything but RID "bar", only
@@ -99,14 +99,16 @@
       ]);
 
       test.chain.append([
-        function PC_LOCAL_WAIT_FOR_FRAMES() {
-          var vremote = test.pcLocal.remoteMediaElements[0];
+        async function PC_LOCAL_WAIT_FOR_FRAMES() {
+          const vremote = test.pcLocal.remoteMediaElements[0];
           ok(vremote, "Should have remote video element for pcLocal");
-          return helper.waitForFrames(vremote);
+          emitter.start();
+          await helper.checkVideoPlaying(vremote, 10, 10, 16);
+          emitter.stop();
         },
         function PC_LOCAL_CHECK_SIZE_1() {
-          var vlocal = test.pcRemote.localMediaElements[0];
-          var vremote = test.pcLocal.remoteMediaElements[0];
+          const vlocal = test.pcRemote.localMediaElements[0];
+          const vremote = test.pcLocal.remoteMediaElements[0];
           ok(vlocal, "Should have local video element for pcRemote");
           ok(vremote, "Should have remote video element for pcLocal");
           ok(vlocal.videoWidth > 0, "source width is positive");
@@ -122,21 +124,25 @@
         function PC_LOCAL_WAIT_FOR_SECOND_MEDIA_FLOW(test) {
           return test.pcLocal.waitForMediaFlow();
         },
-        function PC_LOCAL_WAIT_FOR_FRAMES_2() {
-          var vremote = test.pcLocal.remoteMediaElements[0];
+        async function PC_LOCAL_WAIT_FOR_FRAMES_2() {
+          const vremote = test.pcLocal.remoteMediaElements[0];
           ok(vremote, "Should have remote video element for pcLocal");
-          return helper.waitForFrames(vremote);
+          emitter.start();
+          await helper.checkVideoPlaying(vremote, 10, 10, 16);
+          emitter.stop();
         },
         // For some reason, even though we're getting a 25x25 stream, sometimes
         // the resolution isn't updated on the video element on the first frame.
-        function PC_LOCAL_WAIT_FOR_FRAMES_3() {
-          var vremote = test.pcLocal.remoteMediaElements[0];
+        async function PC_LOCAL_WAIT_FOR_FRAMES_3() {
+          const vremote = test.pcLocal.remoteMediaElements[0];
           ok(vremote, "Should have remote video element for pcLocal");
-          return helper.waitForFrames(vremote);
+          emitter.start();
+          await helper.checkVideoPlaying(vremote, 10, 10, 16);
+          emitter.stop();
         },
         function PC_LOCAL_CHECK_SIZE_2() {
-          var vlocal = test.pcRemote.localMediaElements[0];
-          var vremote = test.pcLocal.remoteMediaElements[0];
+          const vlocal = test.pcRemote.localMediaElements[0];
+          const vremote = test.pcLocal.remoteMediaElements[0];
           ok(vlocal, "Should have local video element for pcRemote");
           ok(vremote, "Should have remote video element for pcLocal");
           ok(vlocal.videoWidth > 0, "source width is positive");
diff --git a/dom/media/tests/mochitest/test_peerConnection_simulcastOffer.html b/dom/media/tests/mochitest/test_peerConnection_simulcastOffer.html
index ebee917c3ae7..97a02c47a1a4 100644
--- a/dom/media/tests/mochitest/test_peerConnection_simulcastOffer.html
+++ b/dom/media/tests/mochitest/test_peerConnection_simulcastOffer.html
@@ -13,21 +13,20 @@
     visible: true
   });
 
-  var test;
-  var pushPrefs = (...p) => SpecialPowers.pushPrefEnv({set: p});
+  const pushPrefs = (...p) => SpecialPowers.pushPrefEnv({set: p});
 
   function addRIDExtension(pc, extensionId) {
-    var receivers = pc._pc.getReceivers();
+    const receivers = pc._pc.getReceivers();
     is(receivers.length, 1, "We have exactly one RTP receiver");
-    var receiver = receivers[0];
+    const receiver = receivers[0];
 
     SpecialPowers.wrap(pc._pc).mozAddRIDExtension(receiver, extensionId);
   }
 
   function selectRecvRID(pc, rid) {
-    var receivers = pc._pc.getReceivers();
+    const receivers = pc._pc.getReceivers();
     is(receivers.length, 1, "We have exactly one RTP receiver");
-    var receiver = receivers[0];
+    const receiver = receivers[0];
 
     SpecialPowers.wrap(pc._pc).mozAddRIDFilter(receiver, rid);
   }
@@ -38,23 +37,24 @@
               // the 80Kbps+overhead needed for the two simulcast streams.
               // 100Kbps was apparently too low.
               ['media.peerconnection.video.min_bitrate_estimate', 180*1000]).then(() => {
-      var helper;
+      let emitter, helper;
 
-      test = new PeerConnectionTest({bundle: false});
+      const test = new PeerConnectionTest({bundle: false});
       test.setMediaConstraints([{video: true}], []);
 
       test.chain.replace("PC_LOCAL_GUM", [
         function PC_LOCAL_CANVAS_CAPTURESTREAM(test) {
+          emitter = new VideoFrameEmitter();
           helper = new VideoStreamHelper();
-          test.pcLocal.attachLocalStream(helper.stream());
+          test.pcLocal.attachLocalStream(emitter.stream());
         }
       ]);
 
       test.chain.insertBefore('PC_LOCAL_CREATE_OFFER', [
         function PC_LOCAL_SET_RIDS(test) {
-          var senders = test.pcLocal._pc.getSenders();
+          const senders = test.pcLocal._pc.getSenders();
           is(senders.length, 1, "We have exactly one RTP sender");
-          var sender = senders[0];
+          const sender = senders[0];
           ok(sender.track, "Sender has a track");
 
           return sender.setParameters({
@@ -80,7 +80,7 @@
       // has been created.
       test.chain.insertAfter('PC_REMOTE_SET_LOCAL_DESCRIPTION',[
         function PC_REMOTE_SET_RTP_FIRST_RID(test) {
-          var extmap_id = test.originalOffer.sdp.match(
+          const extmap_id = test.originalOffer.sdp.match(
               "a=extmap:([0-9+])/sendonly urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id");
           ok(extmap_id, "Original offer has extmap id for simulcast: " + extmap_id[1]);
           // Cause pcRemote to filter out everything but RID "foo", only
@@ -91,14 +91,16 @@
       ]);
 
       test.chain.append([
-        function PC_REMOTE_WAIT_FOR_FRAMES() {
-          var vremote = test.pcRemote.remoteMediaElements[0];
+        async function PC_REMOTE_WAIT_FOR_FRAMES() {
+          const vremote = test.pcRemote.remoteMediaElements[0];
           ok(vremote, "Should have remote video element for pcRemote");
-          return helper.waitForFrames(vremote);
+          emitter.start();
+          await helper.checkVideoPlaying(vremote, 10, 10, 16);
+          emitter.stop();
         },
         function PC_REMOTE_CHECK_SIZE_1() {
-          var vlocal = test.pcLocal.localMediaElements[0];
-          var vremote = test.pcRemote.remoteMediaElements[0];
+          const vlocal = test.pcLocal.localMediaElements[0];
+          const vremote = test.pcRemote.remoteMediaElements[0];
           ok(vlocal, "Should have local video element for pcLocal");
           ok(vremote, "Should have remote video element for pcRemote");
           ok(vlocal.videoWidth > 0, "source width is positive");
@@ -114,21 +116,25 @@
         function PC_REMOTE_WAIT_FOR_SECOND_MEDIA_FLOW(test) {
           return test.pcRemote.waitForMediaFlow();
         },
-        function PC_REMOTE_WAIT_FOR_FRAMES_2() {
-          var vremote = test.pcRemote.remoteMediaElements[0];
+        async function PC_REMOTE_WAIT_FOR_FRAMES_2() {
+          const vremote = test.pcRemote.remoteMediaElements[0];
           ok(vremote, "Should have remote video element for pcRemote");
-          return helper.waitForFrames(vremote);
+          emitter.start();
+          await helper.checkVideoPlaying(vremote, 10, 10, 16);
+          emitter.stop();
         },
         // For some reason, even though we're getting a 25x25 stream, sometimes
         // the resolution isn't updated on the video element on the first frame.
-        function PC_REMOTE_WAIT_FOR_FRAMES_3() {
-          var vremote = test.pcRemote.remoteMediaElements[0];
+        async function PC_REMOTE_WAIT_FOR_FRAMES_3() {
+          const vremote = test.pcRemote.remoteMediaElements[0];
           ok(vremote, "Should have remote video element for pcRemote");
-          return helper.waitForFrames(vremote);
+          emitter.start();
+          await helper.checkVideoPlaying(vremote, 10, 10, 16);
+          emitter.stop();
         },
         function PC_REMOTE_CHECK_SIZE_2() {
-          var vlocal = test.pcLocal.localMediaElements[0];
-          var vremote = test.pcRemote.remoteMediaElements[0];
+          const vlocal = test.pcLocal.localMediaElements[0];
+          const vremote = test.pcRemote.remoteMediaElements[0];
           ok(vlocal, "Should have local video element for pcLocal");
           ok(vremote, "Should have remote video element for pcRemote");
           ok(vlocal.videoWidth > 0, "source width is positive");
diff --git a/dom/media/tests/mochitest/test_peerConnection_videoRenegotiationInactiveAnswer.html b/dom/media/tests/mochitest/test_peerConnection_videoRenegotiationInactiveAnswer.html
index fb77c332f208..f399d5e38384 100644
--- a/dom/media/tests/mochitest/test_peerConnection_videoRenegotiationInactiveAnswer.html
+++ b/dom/media/tests/mochitest/test_peerConnection_videoRenegotiationInactiveAnswer.html
@@ -15,14 +15,14 @@
 
   var test;
   runNetworkTest(function (options) {
-    var helper;
+    const emitter = new VideoFrameEmitter();
+    const helper = new VideoStreamHelper();
 
     test = new PeerConnectionTest(options);
 
     test.chain.replace("PC_LOCAL_GUM", [
       function PC_LOCAL_CANVAS_CAPTURESTREAM(test) {
-        helper = new VideoStreamHelper();
-        test.pcLocal.attachLocalStream(helper.stream());
+        test.pcLocal.attachLocalStream(emitter.stream());
       }
     ]);
 
@@ -30,7 +30,9 @@
       function PC_REMOTE_WAIT_FOR_FRAMES() {
         var vremote = test.pcRemote.remoteMediaElements[0];
         ok(vremote, "Should have remote video element for pcRemote");
-        return helper.waitForFrames(vremote);
+        emitter.start();
+        return addFinallyToPromise(helper.checkVideoPlaying(vremote, 10, 10, 16))
+            .finally(() => emitter.stop());
       }
     ]);
 
@@ -47,7 +49,9 @@
       function PC_REMOTE_ENSURE_NO_FRAMES() {
         var vremote = test.pcRemote.remoteMediaElements[0];
         ok(vremote, "Should have remote video element for pcRemote");
-        return helper.verifyNoFrames(vremote);
+        emitter.start();
+        return addFinallyToPromise(helper.checkVideoPaused(vremote, 10, 10, 16, 5000))
+            .finally(() => emitter.stop());
       },
     ]);
 
@@ -60,7 +64,9 @@
       function PC_REMOTE_WAIT_FOR_FRAMES_2() {
         var vremote = test.pcRemote.remoteMediaElements[0];
         ok(vremote, "Should have remote video element for pcRemote");
-        return helper.waitForFrames(vremote);
+        emitter.start();
+        return addFinallyToPromise(helper.checkVideoPlaying(vremote, 10, 10, 16))
+            .finally(() => emitter.stop());
       }
     ]);
 
diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp
index 31a825f257f1..b1ef14fb532d 100644
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -197,16 +197,6 @@ AudioContext::WrapObject(JSContext* aCx, JS::Handle aGivenProto)
 /* static */ already_AddRefed
 AudioContext::Constructor(const GlobalObject& aGlobal,
                           ErrorResult& aRv)
-{
-  return AudioContext::Constructor(aGlobal,
-                                   AudioChannelService::GetDefaultAudioChannel(),
-                                   aRv);
-}
-
-/* static */ already_AddRefed
-AudioContext::Constructor(const GlobalObject& aGlobal,
-                          AudioChannel aChannel,
-                          ErrorResult& aRv)
 {
   nsCOMPtr window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window) {
@@ -214,7 +204,9 @@ AudioContext::Constructor(const GlobalObject& aGlobal,
     return nullptr;
   }
 
-  RefPtr object = new AudioContext(window, false, aChannel);
+  RefPtr object =
+    new AudioContext(window, false,
+                     AudioChannelService::GetDefaultAudioChannel());
   aRv = object->Init();
   if (NS_WARN_IF(aRv.Failed())) {
      return nullptr;
diff --git a/dom/media/webaudio/AudioContext.h b/dom/media/webaudio/AudioContext.h
index 64d2e3577905..be927461e634 100644
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -154,12 +154,6 @@ public:
   static already_AddRefed
   Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
 
-  // Constructor for regular AudioContext. A default audio channel is needed.
-  static already_AddRefed
-  Constructor(const GlobalObject& aGlobal,
-              AudioChannel aChannel,
-              ErrorResult& aRv);
-
   // Constructor for offline AudioContext
   static already_AddRefed
   Constructor(const GlobalObject& aGlobal,
diff --git a/dom/media/webm/WebMBufferedParser.cpp b/dom/media/webm/WebMBufferedParser.cpp
index 9f25cb1be4b3..0f7bc61cdb48 100644
--- a/dom/media/webm/WebMBufferedParser.cpp
+++ b/dom/media/webm/WebMBufferedParser.cpp
@@ -449,7 +449,7 @@ void WebMBufferedState::UpdateIndex(const MediaByteRangeSet& aRanges, MediaResou
     while (length > 0) {
       static const uint32_t BLOCK_SIZE = 1048576;
       uint32_t block = std::min(length, BLOCK_SIZE);
-      RefPtr bytes = aResource->MediaReadAt(offset, block);
+      RefPtr bytes = aResource->CachedReadAt(offset, block);
       if (!bytes) {
         break;
       }
diff --git a/dom/media/webm/WebMDemuxer.h b/dom/media/webm/WebMDemuxer.h
index d9f030155d3d..406cf9db14ed 100644
--- a/dom/media/webm/WebMDemuxer.h
+++ b/dom/media/webm/WebMDemuxer.h
@@ -8,9 +8,13 @@
 
 #include "nsTArray.h"
 #include "MediaDataDemuxer.h"
+#include "MediaResource.h"
 #include "NesteggPacketHolder.h"
 #include "mozilla/Move.h"
 
+#include 
+#include 
+
 typedef struct nestegg nestegg;
 
 namespace mozilla {
diff --git a/dom/webidl/AudioContext.webidl b/dom/webidl/AudioContext.webidl
index 72e3aabb87da..8d564d54d8d6 100644
--- a/dom/webidl/AudioContext.webidl
+++ b/dom/webidl/AudioContext.webidl
@@ -11,7 +11,6 @@
  */
 
 [Constructor,
- Constructor(AudioChannel audioChannelType),
  Pref="dom.webaudio.enabled"]
 interface AudioContext : BaseAudioContext {
 
@@ -33,4 +32,4 @@ interface AudioContext : BaseAudioContext {
 
     [NewObject, Throws]
     MediaStreamAudioDestinationNode createMediaStreamDestination();
-};
\ No newline at end of file
+};
diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build
index 8b1c8b535cda..7e679e0d0d12 100644
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -98,7 +98,7 @@ with Files("DynamicsCompressorNode.webidl"):
     BUG_COMPONENT = ("Core", "Web Audio")
 
 with Files("DesktopNotification.webidl"):
-    BUG_COMPONENT = ("Toolkit", "Notification and Alerts")
+    BUG_COMPONENT = ("Toolkit", "Notifications and Alerts")
 
 with Files("FakePluginTagInit.webidl"):
     BUG_COMPONENT = ("Core", "Plug-ins")
diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h
index 496b0797ecae..73cd98a13996 100644
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -26,6 +26,7 @@
 // outparams using the &-operator. But it will have to do as there's no easy
 // solution.
 #include "mozilla/RefPtr.h"
+#include "mozilla/ServoUtils.h"
 #include "mozilla/WeakPtr.h"
 
 #include "mozilla/DebugOnly.h"
@@ -62,6 +63,23 @@ typedef struct CGContext *CGContextRef;
 
 namespace mozilla {
 
+namespace gfx {
+class UnscaledFont;
+}
+
+template<>
+struct WeakPtrTraits
+{
+  static void AssertSafeToAccessFromNonOwningThread()
+  {
+    // We want to allow UnscaledFont objects that were created on the main
+    // thread to be accessed from other threads if the Servo font metrics
+    // mutex is locked, and for objects created on Servo style worker threads
+    // to be accessed later back on the main thread.
+    AssertIsMainThreadOrServoFontMetricsLocked();
+  }
+};
+
 namespace gfx {
 
 class ScaledFont;
diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp
index 72c94d870c2b..c5d71e2979a6 100644
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -881,6 +881,13 @@ TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
         gfxCriticalError() << "Attempt to move a texture to different compositor backend.";
         return false;
       }
+      if (ShadowLayerForwarder* forwarder = aForwarder->AsLayerForwarder()) {
+        // Do the DOM labeling.
+        if (nsIEventTarget* target = forwarder->GetEventTarget()) {
+          forwarder->GetCompositorBridgeChild()->ReplaceEventTargetForActor(
+            mActor, target);
+        }
+      }
       mActor->mCompositableForwarder = aForwarder;
     }
     return true;
@@ -895,12 +902,20 @@ TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
   // Try external image id allocation.
   mExternalImageId = aForwarder->GetTextureForwarder()->GetNextExternalImageId();
 
+  nsIEventTarget* target = nullptr;
+  // Get the layers id if the forwarder is a ShadowLayerForwarder.
+  if (ShadowLayerForwarder* forwarder = aForwarder->AsLayerForwarder()) {
+    target = forwarder->GetEventTarget();
+  }
+
   PTextureChild* actor = aForwarder->GetTextureForwarder()->CreateTexture(
     desc,
     aForwarder->GetCompositorBackendType(),
     GetFlags(),
     mSerial,
-    mExternalImageId);
+    mExternalImageId,
+    target);
+
   if (!actor) {
     gfxCriticalNote << static_cast(desc.type()) << ", "
                     << static_cast(aForwarder->GetCompositorBackendType()) << ", "
diff --git a/gfx/layers/ipc/CompositableForwarder.h b/gfx/layers/ipc/CompositableForwarder.h
index d2fa1d6a4e3c..447a882ffb1e 100644
--- a/gfx/layers/ipc/CompositableForwarder.h
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -116,6 +116,8 @@ public:
 
   static uint32_t GetMaxFileDescriptorsPerMessage();
 
+  virtual ShadowLayerForwarder* AsLayerForwarder() { return nullptr; }
+
 protected:
   nsTArray > mTexturesToRemove;
   nsTArray> mCompositableClientsToRemove;
diff --git a/gfx/layers/ipc/CompositorBridgeChild.cpp b/gfx/layers/ipc/CompositorBridgeChild.cpp
index aeb581fdd5e3..a7e4cf0484a8 100644
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -19,6 +19,7 @@
 #include "mozilla/layers/APZCTreeManagerChild.h"
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "mozilla/layers/PLayerTransactionChild.h"
+#include "mozilla/layers/PTextureChild.h"
 #include "mozilla/layers/TextureClient.h"// for TextureClient
 #include "mozilla/layers/TextureClientPool.h"// for TextureClientPool
 #include "mozilla/layers/WebRenderBridgeChild.h"
@@ -336,6 +337,17 @@ CompositorBridgeChild::AllocPLayerTransactionChild(const nsTArray
 {
   LayerTransactionChild* c = new LayerTransactionChild(aId);
   c->AddIPDLReference();
+
+  TabChild* tabChild = TabChild::GetFrom(c->GetId());
+
+  // Do the DOM Labeling.
+  if (tabChild) {
+    nsCOMPtr target =
+      tabChild->TabGroup()->EventTargetFor(TaskCategory::Other);
+    SetEventTargetForActor(c, target);
+    MOZ_ASSERT(c->GetActorEventTarget());
+  }
+
   return c;
 }
 
@@ -1051,15 +1063,24 @@ CompositorBridgeChild::GetTileLockAllocator()
   return mSectionAllocator;
 }
 
-
 PTextureChild*
 CompositorBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
                                      LayersBackend aLayersBackend,
                                      TextureFlags aFlags,
                                      uint64_t aSerial,
-                                     wr::MaybeExternalImageId& aExternalImageId)
+                                     wr::MaybeExternalImageId& aExternalImageId,
+                                     nsIEventTarget* aTarget)
 {
-  return PCompositorBridgeChild::SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, 0 /* FIXME? */, aSerial, aExternalImageId);
+  PTextureChild* textureChild = AllocPTextureChild(
+    aSharedData, aLayersBackend, aFlags, 0 /* FIXME */, aSerial, aExternalImageId);
+
+  // Do the DOM labeling.
+  if (aTarget) {
+    SetEventTargetForActor(textureChild, aTarget);
+  }
+
+  return SendPTextureConstructor(
+    textureChild, aSharedData, aLayersBackend, aFlags, 0 /* FIXME? */, aSerial, aExternalImageId);
 }
 
 bool
diff --git a/gfx/layers/ipc/CompositorBridgeChild.h b/gfx/layers/ipc/CompositorBridgeChild.h
index fccd14a3e2a1..84a8d518fc62 100644
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -134,7 +134,8 @@ public:
                                        LayersBackend aLayersBackend,
                                        TextureFlags aFlags,
                                        uint64_t aSerial,
-                                       wr::MaybeExternalImageId& aExternalImageId) override;
+                                       wr::MaybeExternalImageId& aExternalImageId,
+                                       nsIEventTarget* aTarget) override;
 
   virtual void HandleFatalError(const char* aName, const char* aMsg) const override;
 
diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp
index 365793b88db6..ade05fb76773 100644
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -1046,7 +1046,8 @@ ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
                                 LayersBackend aLayersBackend,
                                 TextureFlags aFlags,
                                 uint64_t aSerial,
-                                wr::MaybeExternalImageId& aExternalImageId)
+                                wr::MaybeExternalImageId& aExternalImageId,
+                                nsIEventTarget* aTarget)
 {
   MOZ_ASSERT(CanSend());
   return SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, aSerial, aExternalImageId);
diff --git a/gfx/layers/ipc/ImageBridgeChild.h b/gfx/layers/ipc/ImageBridgeChild.h
index 124d6be2c3da..0f925775362c 100644
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -328,11 +328,13 @@ public:
    */
   virtual bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
 
-  virtual PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData,
-                                       LayersBackend aLayersBackend,
-                                       TextureFlags aFlags,
-                                       uint64_t aSerial,
-                                       wr::MaybeExternalImageId& aExternalImageId) override;
+  virtual PTextureChild* CreateTexture(
+    const SurfaceDescriptor& aSharedData,
+    LayersBackend aLayersBackend,
+    TextureFlags aFlags,
+    uint64_t aSerial,
+    wr::MaybeExternalImageId& aExternalImageId,
+    nsIEventTarget* aTarget = nullptr) override;
 
   virtual bool IsSameProcess() const override;
 
diff --git a/gfx/layers/ipc/ShadowLayers.h b/gfx/layers/ipc/ShadowLayers.h
index 4c2bfe58006b..038831334ee6 100644
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -395,6 +395,8 @@ public:
     return mPaintTiming;
   }
 
+  ShadowLayerForwarder* AsLayerForwarder() override { return this; }
+
   // Returns true if aSurface wraps a Shmem.
   static bool IsShmem(SurfaceDescriptor* aSurface);
 
@@ -412,6 +414,11 @@ public:
   LayersIPCActor* GetLayersIPCActor() override { return this; }
 
   ActiveResourceTracker& GetActiveResourceTracker() { return *mActiveResourceTracker.get(); }
+
+  CompositorBridgeChild* GetCompositorBridgeChild();
+
+  nsIEventTarget* GetEventTarget() { return mEventTarget; };
+
 protected:
   virtual ~ShadowLayerForwarder();
 
@@ -427,8 +434,6 @@ protected:
 
   bool InWorkerThread();
 
-  CompositorBridgeChild* GetCompositorBridgeChild();
-
   RefPtr mShadowManager;
   RefPtr mCompositorBridgeChild;
 
diff --git a/gfx/layers/ipc/TextureForwarder.h b/gfx/layers/ipc/TextureForwarder.h
index 6ae4c5969b50..f34cff43951f 100644
--- a/gfx/layers/ipc/TextureForwarder.h
+++ b/gfx/layers/ipc/TextureForwarder.h
@@ -72,7 +72,8 @@ public:
     LayersBackend aLayersBackend,
     TextureFlags aFlags,
     uint64_t aSerial,
-    wr::MaybeExternalImageId& aExternalImageId) = 0;
+    wr::MaybeExternalImageId& aExternalImageId,
+    nsIEventTarget* aTarget = nullptr) = 0;
 };
 
 } // namespace layers
diff --git a/gfx/layers/ipc/VideoBridgeChild.cpp b/gfx/layers/ipc/VideoBridgeChild.cpp
index 1818a168bc18..3ba740c34b92 100644
--- a/gfx/layers/ipc/VideoBridgeChild.cpp
+++ b/gfx/layers/ipc/VideoBridgeChild.cpp
@@ -108,7 +108,8 @@ VideoBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
                                 LayersBackend aLayersBackend,
                                 TextureFlags aFlags,
                                 uint64_t aSerial,
-                                wr::MaybeExternalImageId& aExternalImageId)
+                                wr::MaybeExternalImageId& aExternalImageId,
+                                nsIEventTarget* aTarget)
 {
   MOZ_ASSERT(CanSend());
   return SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, aSerial);
diff --git a/gfx/layers/ipc/VideoBridgeChild.h b/gfx/layers/ipc/VideoBridgeChild.h
index 19f8bdbca580..8284c3558048 100644
--- a/gfx/layers/ipc/VideoBridgeChild.h
+++ b/gfx/layers/ipc/VideoBridgeChild.h
@@ -49,7 +49,8 @@ public:
                                LayersBackend aLayersBackend,
                                TextureFlags aFlags,
                                uint64_t aSerial,
-                               wr::MaybeExternalImageId& aExternalImageId) override;
+                               wr::MaybeExternalImageId& aExternalImageId,
+                               nsIEventTarget* aTarget = nullptr) override;
 
   // ClientIPCAllocator
   base::ProcessId GetParentPid() const override { return OtherPid(); }
diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp
index 23e1ce78197c..8469d7172d35 100644
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -1968,6 +1968,7 @@ gfxFontGroup::FamilyFace::CheckState(bool& aSkipDrawing)
         gfxUserFontEntry* ufe = static_cast(fe);
         gfxUserFontEntry::UserFontLoadState state = ufe->LoadState();
         switch (state) {
+            case gfxUserFontEntry::STATUS_LOAD_PENDING:
             case gfxUserFontEntry::STATUS_LOADING:
                 SetLoading(true);
                 break;
diff --git a/gfx/thebes/gfxUserFontSet.cpp b/gfx/thebes/gfxUserFontSet.cpp
index 7074f55404b6..0933def8bf0e 100644
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -21,6 +21,8 @@
 #include "mozilla/Telemetry.h"
 #include "mozilla/gfx/2D.h"
 #include "gfxPlatformFontList.h"
+#include "mozilla/ServoStyleSet.h"
+#include "mozilla/PostTraversalTask.h"
 
 #include "opentype-sanitiser.h"
 #include "ots-memory-stream.h"
@@ -113,7 +115,7 @@ gfxUserFontEntry::gfxUserFontEntry(gfxUserFontSet* aFontSet,
              uint8_t aStyle,
              const nsTArray& aFeatureSettings,
              uint32_t aLanguageOverride,
-             gfxSparseBitSet* aUnicodeRanges,
+             gfxCharacterMap* aUnicodeRanges,
              uint8_t aFontDisplay)
     : gfxFontEntry(NS_LITERAL_STRING("userfont")),
       mUserFontLoadState(STATUS_NOT_LOADED),
@@ -133,14 +135,15 @@ gfxUserFontEntry::gfxUserFontEntry(gfxUserFontSet* aFontSet,
     mStyle = aStyle;
     mFeatureSettings.AppendElements(aFeatureSettings);
     mLanguageOverride = aLanguageOverride;
-
-    if (aUnicodeRanges) {
-        mCharacterMap = new gfxCharacterMap(*aUnicodeRanges);
-    }
+    mCharacterMap = aUnicodeRanges;
 }
 
 gfxUserFontEntry::~gfxUserFontEntry()
 {
+    // Assert that we don't drop any gfxUserFontEntry objects during a Servo
+    // traversal, since PostTraversalTask objects can hold raw pointers to
+    // gfxUserFontEntry objects.
+    MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
 }
 
 bool
@@ -150,7 +153,7 @@ gfxUserFontEntry::Matches(const nsTArray& aFontFaceSrcList,
                           uint8_t aStyle,
                           const nsTArray& aFeatureSettings,
                           uint32_t aLanguageOverride,
-                          gfxSparseBitSet* aUnicodeRanges,
+                          gfxCharacterMap* aUnicodeRanges,
                           uint8_t aFontDisplay)
 {
     return mWeight == aWeight &&
@@ -429,11 +432,10 @@ CopyWOFFMetadata(const uint8_t* aFontData,
 void
 gfxUserFontEntry::LoadNextSrc()
 {
-    uint32_t numSrc = mSrcList.Length();
-
-    NS_ASSERTION(mSrcIndex < numSrc,
+    NS_ASSERTION(mSrcIndex < mSrcList.Length(),
                  "already at the end of the src list for user font");
     NS_ASSERTION((mUserFontLoadState == STATUS_NOT_LOADED ||
+                  mUserFontLoadState == STATUS_LOAD_PENDING ||
                   mUserFontLoadState == STATUS_LOADING) &&
                  mFontDataLoadingState < LOADING_FAILED,
                  "attempting to load a font that has either completed or failed");
@@ -449,6 +451,23 @@ gfxUserFontEntry::LoadNextSrc()
         mSrcIndex++;
     }
 
+    DoLoadNextSrc(false);
+}
+
+void
+gfxUserFontEntry::ContinueLoad()
+{
+    MOZ_ASSERT(mUserFontLoadState == STATUS_LOAD_PENDING);
+    MOZ_ASSERT(mSrcList[mSrcIndex].mSourceType == gfxFontFaceSrc::eSourceType_URL);
+
+    DoLoadNextSrc(true);
+}
+
+void
+gfxUserFontEntry::DoLoadNextSrc(bool aForceAsync)
+{
+    uint32_t numSrc = mSrcList.Length();
+
     // load each src entry in turn, until a local face is found
     // or a download begins successfully
     while (mSrcIndex < numSrc) {
@@ -504,6 +523,12 @@ gfxUserFontEntry::LoadNextSrc()
             if (gfxPlatform::GetPlatform()->IsFontFormatSupported(currSrc.mURI,
                     currSrc.mFormatFlags)) {
 
+                if (ServoStyleSet* set = ServoStyleSet::Current()) {
+                    set->AppendTask(PostTraversalTask::LoadFontEntry(this));
+                    SetLoadState(STATUS_LOAD_PENDING);
+                    return;
+                }
+
                 nsIPrincipal* principal = nullptr;
                 bool bypassCache;
                 nsresult rv = mFontSet->CheckFontLoad(&currSrc, &principal,
@@ -537,9 +562,11 @@ gfxUserFontEntry::LoadNextSrc()
                     mPrincipal = principal;
 
                     bool loadDoesntSpin = false;
-                    rv = NS_URIChainHasFlags(currSrc.mURI,
-                           nsIProtocolHandler::URI_SYNC_LOAD_IS_OK,
-                           &loadDoesntSpin);
+                    if (!aForceAsync) {
+                        rv = NS_URIChainHasFlags(currSrc.mURI,
+                               nsIProtocolHandler::URI_SYNC_LOAD_IS_OK,
+                               &loadDoesntSpin);
+                    }
 
                     if (NS_SUCCEEDED(rv) && loadDoesntSpin) {
                         uint8_t* buffer = nullptr;
@@ -644,6 +671,7 @@ bool
 gfxUserFontEntry::LoadPlatformFont(const uint8_t* aFontData, uint32_t& aLength)
 {
     NS_ASSERTION((mUserFontLoadState == STATUS_NOT_LOADED ||
+                  mUserFontLoadState == STATUS_LOAD_PENDING ||
                   mUserFontLoadState == STATUS_LOADING) &&
                  mFontDataLoadingState < LOADING_FAILED,
                  "attempting to load a font that has either completed or failed");
@@ -881,7 +909,7 @@ gfxUserFontSet::FindOrCreateUserFontEntry(
                                uint8_t aStyle,
                                const nsTArray& aFeatureSettings,
                                uint32_t aLanguageOverride,
-                               gfxSparseBitSet* aUnicodeRanges,
+                               gfxCharacterMap* aUnicodeRanges,
                                uint8_t aFontDisplay)
 {
     RefPtr entry;
@@ -919,7 +947,7 @@ gfxUserFontSet::CreateUserFontEntry(
                                uint8_t aStyle,
                                const nsTArray& aFeatureSettings,
                                uint32_t aLanguageOverride,
-                               gfxSparseBitSet* aUnicodeRanges,
+                               gfxCharacterMap* aUnicodeRanges,
                                uint8_t aFontDisplay)
 {
 
@@ -939,7 +967,7 @@ gfxUserFontSet::FindExistingUserFontEntry(
                                uint8_t aStyle,
                                const nsTArray& aFeatureSettings,
                                uint32_t aLanguageOverride,
-                               gfxSparseBitSet* aUnicodeRanges,
+                               gfxCharacterMap* aUnicodeRanges,
                                uint8_t aFontDisplay)
 {
     MOZ_ASSERT(aWeight != 0,
diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h
index d008e39d7da3..93ee3086bb74 100644
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -17,6 +17,9 @@
 #include "mozilla/net/ReferrerPolicy.h"
 #include "gfxFontConstants.h"
 
+namespace mozilla {
+class PostTraversalTask;
+} // namespace mozilla
 class nsFontFaceLoader;
 
 //#define DEBUG_USERFONT_CACHE
@@ -175,7 +178,7 @@ class gfxUserFontSet {
 
 public:
 
-    NS_INLINE_DECL_REFCOUNTING(gfxUserFontSet)
+    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxUserFontSet)
 
     gfxUserFontSet();
 
@@ -215,7 +218,7 @@ public:
                               uint8_t aStyle,
                               const nsTArray& aFeatureSettings,
                               uint32_t aLanguageOverride,
-                              gfxSparseBitSet* aUnicodeRanges,
+                              gfxCharacterMap* aUnicodeRanges,
                               uint8_t aFontDisplay) = 0;
 
     // creates a font face for the specified family, or returns an existing
@@ -228,7 +231,7 @@ public:
                                uint8_t aStyle,
                                const nsTArray& aFeatureSettings,
                                uint32_t aLanguageOverride,
-                               gfxSparseBitSet* aUnicodeRanges,
+                               gfxCharacterMap* aUnicodeRanges,
                                uint8_t aFontDisplay);
 
     // add in a font face for which we have the gfxUserFontEntry already
@@ -521,7 +524,7 @@ protected:
                                    uint8_t aStyle,
                                    const nsTArray& aFeatureSettings,
                                    uint32_t aLanguageOverride,
-                                   gfxSparseBitSet* aUnicodeRanges,
+                                   gfxCharacterMap* aUnicodeRanges,
                                    uint8_t aFontDisplay);
 
     // creates a new gfxUserFontFamily in mFontFamilies, or returns an existing
@@ -548,6 +551,7 @@ protected:
 // acts a placeholder until the real font is downloaded
 
 class gfxUserFontEntry : public gfxFontEntry {
+    friend class mozilla::PostTraversalTask;
     friend class gfxUserFontSet;
     friend class nsUserFontSet;
     friend class nsFontFaceLoader;
@@ -556,6 +560,7 @@ class gfxUserFontEntry : public gfxFontEntry {
 public:
     enum UserFontLoadState {
         STATUS_NOT_LOADED = 0,
+        STATUS_LOAD_PENDING,
         STATUS_LOADING,
         STATUS_LOADED,
         STATUS_FAILED
@@ -568,7 +573,7 @@ public:
                      uint8_t aStyle,
                      const nsTArray& aFeatureSettings,
                      uint32_t aLanguageOverride,
-                     gfxSparseBitSet* aUnicodeRanges,
+                     gfxCharacterMap* aUnicodeRanges,
                      uint8_t aFontDisplay);
 
     virtual ~gfxUserFontEntry();
@@ -580,7 +585,7 @@ public:
                  uint8_t aStyle,
                  const nsTArray& aFeatureSettings,
                  uint32_t aLanguageOverride,
-                 gfxSparseBitSet* aUnicodeRanges,
+                 gfxCharacterMap* aUnicodeRanges,
                  uint8_t aFontDisplay);
 
     virtual gfxFont* CreateFontInstance(const gfxFontStyle* aFontStyle,
@@ -593,7 +598,8 @@ public:
 
     // whether to wait before using fallback font or not
     bool WaitForUserFont() const {
-        return mUserFontLoadState == STATUS_LOADING &&
+        return (mUserFontLoadState == STATUS_LOAD_PENDING ||
+                mUserFontLoadState == STATUS_LOADING) &&
                mFontDataLoadingState < LOADING_SLOWLY;
     }
 
@@ -633,6 +639,8 @@ protected:
 
     // attempt to load the next resource in the src list.
     void LoadNextSrc();
+    void ContinueLoad();
+    void DoLoadNextSrc(bool aForceAsync);
 
     // change the load state
     virtual void SetLoadState(UserFontLoadState aLoadState);
diff --git a/gfx/vr/ipc/VRManagerChild.cpp b/gfx/vr/ipc/VRManagerChild.cpp
index 9c4396786b81..98fa680d9583 100644
--- a/gfx/vr/ipc/VRManagerChild.cpp
+++ b/gfx/vr/ipc/VRManagerChild.cpp
@@ -353,7 +353,8 @@ VRManagerChild::CreateTexture(const SurfaceDescriptor& aSharedData,
                               LayersBackend aLayersBackend,
                               TextureFlags aFlags,
                               uint64_t aSerial,
-                              wr::MaybeExternalImageId& aExternalImageId)
+                              wr::MaybeExternalImageId& aExternalImageId,
+                              nsIEventTarget* aTarget)
 {
   return SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, aSerial);
 }
diff --git a/gfx/vr/ipc/VRManagerChild.h b/gfx/vr/ipc/VRManagerChild.h
index c1feaff2fc86..2ce05a4d128f 100644
--- a/gfx/vr/ipc/VRManagerChild.h
+++ b/gfx/vr/ipc/VRManagerChild.h
@@ -64,11 +64,13 @@ public:
 
   static bool IsCreated();
 
-  virtual PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData,
-                                       layers::LayersBackend aLayersBackend,
-                                       TextureFlags aFlags,
-                                       uint64_t aSerial,
-                                       wr::MaybeExternalImageId& aExternalImageId) override;
+  virtual PTextureChild* CreateTexture(
+    const SurfaceDescriptor& aSharedData,
+    layers::LayersBackend aLayersBackend,
+    TextureFlags aFlags,
+    uint64_t aSerial,
+    wr::MaybeExternalImageId& aExternalImageId,
+    nsIEventTarget* aTarget = nullptr) override;
   virtual void CancelWaitForRecycle(uint64_t aTextureId) override;
 
   PVRLayerChild* CreateVRLayer(uint32_t aDisplayID,
diff --git a/ipc/chromium/src/base/id_map.h b/ipc/chromium/src/base/id_map.h
index f3f78c4ec797..2540a0eae091 100644
--- a/ipc/chromium/src/base/id_map.h
+++ b/ipc/chromium/src/base/id_map.h
@@ -77,6 +77,11 @@ class IDMap {
     }
   }
 
+  void ReplaceWithID(const T& data, int32_t id) {
+    DCHECK(data_.find(id) != data_.end()) << "item doesn't exist";
+    data_[id] = data;
+  }
+
   bool IsEmpty() const {
     return data_.empty();
   }
diff --git a/ipc/glue/ProtocolUtils.cpp b/ipc/glue/ProtocolUtils.cpp
index 42f822d8711a..1d6559bf9201 100644
--- a/ipc/glue/ProtocolUtils.cpp
+++ b/ipc/glue/ProtocolUtils.cpp
@@ -546,6 +546,15 @@ IProtocol::SetEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarge
   SetEventTargetForActorInternal(aActor, aEventTarget);
 }
 
+void
+IProtocol::ReplaceEventTargetForActor(IProtocol* aActor,
+                                      nsIEventTarget* aEventTarget)
+{
+  // Ensure the actor has been registered.
+  MOZ_ASSERT(aActor->Manager());
+  ReplaceEventTargetForActorInternal(aActor, aEventTarget);
+}
+
 void
 IProtocol::SetEventTargetForActorInternal(IProtocol* aActor,
                                           nsIEventTarget* aEventTarget)
@@ -553,6 +562,13 @@ IProtocol::SetEventTargetForActorInternal(IProtocol* aActor,
   Manager()->SetEventTargetForActorInternal(aActor, aEventTarget);
 }
 
+void
+IProtocol::ReplaceEventTargetForActorInternal(IProtocol* aActor,
+                                              nsIEventTarget* aEventTarget)
+{
+  Manager()->ReplaceEventTargetForActorInternal(aActor, aEventTarget);
+}
+
 nsIEventTarget*
 IProtocol::GetActorEventTarget()
 {
@@ -876,5 +892,21 @@ IToplevelProtocol::SetEventTargetForActorInternal(IProtocol* aActor,
   mEventTargetMap.AddWithID(aEventTarget, id);
 }
 
+void
+IToplevelProtocol::ReplaceEventTargetForActorInternal(
+  IProtocol* aActor,
+  nsIEventTarget* aEventTarget)
+{
+  // The EventTarget of a ToplevelProtocol shall never be set.
+  MOZ_RELEASE_ASSERT(aActor != this);
+
+  int32_t id = aActor->Id();
+  // The ID of the actor should have existed.
+  MOZ_RELEASE_ASSERT(id!= kNullActorId && id!= kFreedActorId);
+
+  MutexAutoLock lock(mEventTargetMutex);
+  mEventTargetMap.ReplaceWithID(aEventTarget, id);
+}
+
 } // namespace ipc
 } // namespace mozilla
diff --git a/ipc/glue/ProtocolUtils.h b/ipc/glue/ProtocolUtils.h
index 81185748fad3..8f02d85c8179 100644
--- a/ipc/glue/ProtocolUtils.h
+++ b/ipc/glue/ProtocolUtils.h
@@ -191,6 +191,12 @@ public:
     // aActor.
     void SetEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget);
 
+    // Replace the event target for the messages of aActor. There must not be
+    // any messages of aActor in the task queue, or we might run into some
+    // unexpected behavior.
+    void ReplaceEventTargetForActor(IProtocol* aActor,
+                                    nsIEventTarget* aEventTarget);
+
     // Returns the event target set by SetEventTargetForActor() if available.
     virtual nsIEventTarget* GetActorEventTarget();
 
@@ -202,6 +208,9 @@ protected:
     void SetIPCChannel(MessageChannel* aChannel) { mChannel = aChannel; }
 
     virtual void SetEventTargetForActorInternal(IProtocol* aActor, nsIEventTarget* aEventTarget);
+    virtual void ReplaceEventTargetForActorInternal(
+      IProtocol* aActor,
+      nsIEventTarget* aEventTarget);
 
     virtual already_AddRefed
     GetActorEventTargetInternal(IProtocol* aActor);
@@ -389,6 +398,9 @@ protected:
     GetSpecificMessageEventTarget(const Message& aMsg) { return nullptr; }
 
     virtual void SetEventTargetForActorInternal(IProtocol* aActor, nsIEventTarget* aEventTarget);
+    virtual void ReplaceEventTargetForActorInternal(
+      IProtocol* aActor,
+      nsIEventTarget* aEventTarget);
 
     virtual already_AddRefed
     GetActorEventTargetInternal(IProtocol* aActor);
diff --git a/js/src/devtools/rootAnalysis/analyzeHeapWrites.js b/js/src/devtools/rootAnalysis/analyzeHeapWrites.js
index b4c9e2d5c4b8..90edc82ec4a8 100644
--- a/js/src/devtools/rootAnalysis/analyzeHeapWrites.js
+++ b/js/src/devtools/rootAnalysis/analyzeHeapWrites.js
@@ -325,7 +325,8 @@ function ignoreCallEdge(entry, callee)
     }
 
     // We manually lock here
-    if ("Gecko_nsFont_InitSystem" == name)
+    if (name == "Gecko_nsFont_InitSystem" ||
+        name == "Gecko_GetFontMetrics")
     {
         return true;
     }
@@ -375,6 +376,7 @@ function ignoreContents(entry)
         "Gecko_AnimationAppendKeyframe",
         "Gecko_NewStyleQuoteValues",
         "Gecko_NewCSSValueSharedList",
+        "Gecko_NewGridTemplateAreasValue",
         /nsCSSValue::SetCalcValue/,
         /CSSValueSerializeCalcOps::Append/,
         "Gecko_CSSValue_SetFunction",
diff --git a/layout/reftests/bidi/reftest.list b/layout/reftests/bidi/reftest.list
index e4cd18f5e3a3..f558ed3962e8 100644
--- a/layout/reftests/bidi/reftest.list
+++ b/layout/reftests/bidi/reftest.list
@@ -37,7 +37,7 @@ random-if(cocoaWidget) == mirroring-02.html mirroring-02-ref.html
 == unicode-bidi-anonymous-001.html unicode-bidi-anonymous-001-ref.html
 == unicode-bidi-anonymous-002.html unicode-bidi-anonymous-002-ref.html
 == unicode-bidi-isolate-basic.html unicode-bidi-isolate-basic-ref.html
-fails-if(stylo) == unicode-bidi-isolate-aharon.html unicode-bidi-isolate-aharon-ref.html
+== unicode-bidi-isolate-aharon.html unicode-bidi-isolate-aharon-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia,73,1) fuzzy-if(skiaContent,104,32) == unicode-bidi-plaintext.html unicode-bidi-plaintext-ref.html
 fails-if(stylo) == unicode-bidi-plaintext-textarea-1.html unicode-bidi-plaintext-textarea-ref.html
 fails-if(stylo) == unicode-bidi-plaintext-textarea-2.html unicode-bidi-plaintext-textarea-ref.html
@@ -81,7 +81,7 @@ fuzzy-if(skiaContent,1,1100) fails-if(stylo) == 267459-2.html 267459-2-ref.html
 random-if(winWidget) == 305643-1.html 305643-1-ref.html # depends on windows version, see bug 590101
 == 332655-1.html 332655-1-ref.html
 == 332655-2.html 332655-2-ref.html
-fails-if(stylo) == 381279-1.html 381279-1-ref.html
+== 381279-1.html 381279-1-ref.html
 == 386339.html 386339-ref.html
 == 409375.html 409375-ref.html
 == 413542-1.html 413542-1-ref.html
@@ -97,7 +97,7 @@ fails-if(stylo) == 413928-2.html 413928-2-ref.html
 == 503269-1.html 503269-1-ref.html
 == 503957-1.html 503957-1-ref.html
 == 525740-1.html 525740-1-ref.html
-fails-if(stylo) == 536963-1.html 536963-1-ref.html
+== 536963-1.html 536963-1-ref.html
 == 562169-1.html 562169-1-ref.html
 fails-if(stylo) == 562169-1a.html 562169-1-ref.html
 == 562169-2.html 562169-2-ref.html
diff --git a/layout/reftests/border-radius/reftest.list b/layout/reftests/border-radius/reftest.list
index 9842052eacec..d89e2ee69a12 100644
--- a/layout/reftests/border-radius/reftest.list
+++ b/layout/reftests/border-radius/reftest.list
@@ -14,7 +14,7 @@
 != outline-square.html outline-ellips.html
 != outline-circle.html outline-ellips.html
 == border-value-interpret.html border-value-interpret-ref.html
-fails-if(stylo) != curved-borders-all-styles.html about:blank # no way to generate reference for dotted/dashed/inset/outset
+!= curved-borders-all-styles.html about:blank # no way to generate reference for dotted/dashed/inset/outset
 # ridge/groove borders
 
 # percent units
diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list
index 13f0d4249cc4..a54a985d4c42 100644
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -447,9 +447,9 @@ fails-if(stylo) == 335628-1.html 335628-1-ref.html
 fails-if(stylo) == 336147-1.html 336147-1-ref.html
 == 336153-1.html 336153-1-ref.html
 != 338251-p.html about:blank
-fails-if(stylo) == 338251-p-oh.html 338251-p-oh-ref.html
+== 338251-p-oh.html 338251-p-oh-ref.html
 != 338251-pre.html about:blank
-fails-if(stylo) == 338251-pre-oh.html 338251-pre-oh-ref.html
+== 338251-pre-oh.html 338251-pre-oh-ref.html
 fuzzy-if(skiaContent,2,3) == 339289-1.html 339289-1-ref.html
 == 341043-1a.html 341043-1-ref.html
 != 341043-1b.html 341043-1-ref.html
@@ -465,7 +465,7 @@ fuzzy-if(skiaContent,4,2) fails-if(stylo) == 346774-1a.html 346774-1-ref.html
 fuzzy-if(skiaContent,4,2) fails-if(stylo) == 346774-1b.html 346774-1-ref.html
 fuzzy-if(skiaContent,4,2) fails-if(stylo) == 346774-1c.html 346774-1-ref.html
 == 347348-1.xhtml 347348-1-ref.xhtml
-fails-if(stylo) == 347496-1.xhtml 347496-1-ref.xhtml
+== 347496-1.xhtml 347496-1-ref.xhtml
 == 347912-1.html 347912-1-ref.html
 fails-if(stylo) == 348049-1.xhtml 348049-1-ref.xhtml
 fails-if(stylo) == 348516-1.html 348516-1-ref.html
@@ -549,8 +549,8 @@ fuzzy-if(skiaContent,2,4) == 362594-2c.html 362594-2-standards-ref.html
 == 363370-1.html 363370-1-ref.html
 == 363402-1.html 363402-1-ref.html
 == 363637-1.html 363637-1-ref.html
-skip-if(Android) fails-if(stylo) == 363706-1.html 363706-1-ref.html
-fails-if(stylo) != 363706-1.html about:blank
+skip-if(Android) == 363706-1.html 363706-1-ref.html
+!= 363706-1.html about:blank
 fails-if(stylo) == 363728-1.html 363728-1-ref.html
 == 363728-2.html 363728-2-ref.html
 fuzzy-if(skiaContent||Android,4,11) fails-if(stylo) == 363858-1.html 363858-1-ref.html
@@ -641,7 +641,7 @@ fails-if(stylo) == 370422-1.html 370422-1-ref.html
 == 370629-2.html 370629-2-ref.html
 == 370692-1.xhtml 370692-1-ref.xhtml
 == 371041-1.html 371041-1-ref.html
-fails-if(stylo) == 371043-1.html 371043-1-ref.html
+== 371043-1.html 371043-1-ref.html
 == 371354-1.html 371354-1-ref.html
 == 371483-1.html about:blank # assertion test
 fails-if(Android&&!asyncPan) == 371561-1.html 371561-1-ref.html
@@ -786,8 +786,8 @@ skip-if(!winWidget) == 391045.html 391045-ref.html # windows-specific Uniscribe
 == 391140-1.html 391140-1-ref.html
 == 391412-1a.html 391412-1-ref.html
 == 391412-1b.html 391412-1-ref.html
-fails-if(stylo) == 391909-1.html 391909-1-ref.html
-skip-if(Android) fails-if(stylo) == 391979.html 391979-ref.html
+== 391909-1.html 391909-1-ref.html
+skip-if(Android) == 391979.html 391979-ref.html
 fails-if(stylo) == 391994-1.html 391994-1-ref.html
 == 392047.html 392047-ref.html
 fails-if(stylo) == 392435-1.html 392435-1-ref.html
@@ -821,7 +821,7 @@ fails-if(stylo) == 395130-2.html 395130-2-ref.html
 fuzzy-if(Android,5,283) == 397428-1.html 397428-1-ref.html
 == 397844-1.xhtml 397844-1-ref.xhtml
 == 398092-1.html 398092-1-ref.html
-fails-if(stylo) == 398101-1.html 398101-1-ref.html
+== 398101-1.html 398101-1-ref.html
 == 398144-1.html 398144-1-ref.html
 fuzzy-if(skiaContent,2,21) == 398682-1.html 398682-1-ref.html
 == 398797-1a.html 398797-1-ref.html
@@ -1195,7 +1195,7 @@ test-pref(dom.use_xbl_scopes_for_remote_xul,true) fails-if(stylo) != 449149-1b.h
 == 455105-2.html 455105-ref.html
 == 455171-5.html 455171-5-ref.html
 == 455280-1.xhtml 455280-1-ref.xhtml
-fails-if(stylo) == 455826-1.html 455826-1-ref.html
+== 455826-1.html 455826-1-ref.html
 fails-if(cocoaWidget) fails-if(Android) == 456147.xul 456147-ref.html # bug 458047
 fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) == 456219-1a.html 456219-1-ref.html # bug 1128229
 fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) == 456219-1b.html 456219-1-ref.html # bug 1128229
@@ -1244,7 +1244,7 @@ fuzzy-if(skiaContent,1,12000) == 461512-1.html 461512-1-ref.html
 fails-if(stylo) == 467084-1.html 467084-1-ref.html
 fails-if(stylo) == 467084-2.html 467084-2-ref.html
 == 467444-1.html 467444-1-ref.html
-fails-if(stylo) == 467460-1.html 467460-1-ref.html
+== 467460-1.html 467460-1-ref.html
 == 468473-1.xul 468473-1-ref.xul
 fails-if(stylo) == 468546-1.xhtml 468546-1-ref.xhtml
 == 471356-1.html 471356-1-ref.html
diff --git a/layout/reftests/columns/reftest.list b/layout/reftests/columns/reftest.list
index 3362dc3a5ede..091d2c535730 100644
--- a/layout/reftests/columns/reftest.list
+++ b/layout/reftests/columns/reftest.list
@@ -29,8 +29,8 @@ HTTP(..) == columnfill-auto-3.html columnfill-auto-2-ref.html
 == columnfill-overflow.html columnfill-overflow-ref.html
 == margin-collapsing-bug616722-1.html margin-collapsing-bug616722-1-ref.html
 == margin-collapsing-bug616722-2.html margin-collapsing-bug616722-2-ref.html
-fails-if(stylo) == column-balancing-nested-000.html column-balancing-nested-000-ref.html
-fails-if(stylo) == column-balancing-nested-001.html column-balancing-nested-001-ref.html
+== column-balancing-nested-000.html column-balancing-nested-000-ref.html
+== column-balancing-nested-001.html column-balancing-nested-001-ref.html
 == columnrule-overflow.html columnrule-overflow-ref.html
 == columns-table-caption-000.html columns-table-caption-000-ref.html
 == positioning-transforms-bug1112501.html positioning-transforms-bug1112501-ref.html
diff --git a/layout/reftests/css-grid/reftest.list b/layout/reftests/css-grid/reftest.list
index 44150f839762..0db89922e777 100644
--- a/layout/reftests/css-grid/reftest.list
+++ b/layout/reftests/css-grid/reftest.list
@@ -3,7 +3,7 @@ default-preferences pref(layout.css.grid.enabled,true)
 fails-if(!stylo) == grid-whitespace-handling-1a.xhtml grid-whitespace-handling-1-ref.xhtml
 fails-if(!stylo) skip-if(stylo) == grid-whitespace-handling-1b.xhtml grid-whitespace-handling-1-ref.xhtml
 == grid-whitespace-handling-2.xhtml  grid-whitespace-handling-2-ref.xhtml
-fails-if(stylo) == grid-placement-definite-001.html grid-placement-definite-001-ref.html
+== grid-placement-definite-001.html grid-placement-definite-001-ref.html
 fails-if(stylo) == grid-placement-definite-002.html grid-placement-definite-002-ref.html
 fails-if(stylo) == grid-placement-definite-003.html grid-placement-definite-003-ref.html
 fails-if(stylo) == grid-placement-negative-lines-001.html grid-placement-negative-lines-001-ref.html
@@ -39,7 +39,7 @@ skip-if(Android) fails-if(stylo) == grid-placement-definite-implicit-001.html gr
 fails-if(stylo) == grid-placement-definite-implicit-002.html grid-placement-definite-implicit-002-ref.html
 skip-if(Android) fuzzy-if(winWidget,1,32) fails-if(stylo) == grid-placement-auto-implicit-001.html grid-placement-auto-implicit-001-ref.html
 == grid-placement-abspos-implicit-001.html grid-placement-abspos-implicit-001-ref.html
-fails-if(stylo) == rtl-grid-placement-definite-001.html rtl-grid-placement-definite-001-ref.html
+== rtl-grid-placement-definite-001.html rtl-grid-placement-definite-001-ref.html
 fails-if(stylo) == rtl-grid-placement-auto-row-sparse-001.html rtl-grid-placement-auto-row-sparse-001-ref.html
 fails-if(stylo) == vlr-grid-placement-auto-row-sparse-001.html vlr-grid-placement-auto-row-sparse-001-ref.html
 fails-if(stylo) == vrl-grid-placement-auto-row-sparse-001.html vrl-grid-placement-auto-row-sparse-001-ref.html
diff --git a/layout/reftests/forms/fieldset/reftest.list b/layout/reftests/forms/fieldset/reftest.list
index fa327df71a5d..cd89f019501f 100644
--- a/layout/reftests/forms/fieldset/reftest.list
+++ b/layout/reftests/forms/fieldset/reftest.list
@@ -12,7 +12,7 @@ fuzzy-if(winWidget&&!layersGPUAccelerated,140,276) == positioned-container-1.htm
 == relpos-legend-4.html relpos-legend-4-ref.html
 == sticky-legend-1.html sticky-legend-1-ref.html
 fuzzy-if(skiaContent,1,40768) == abs-pos-child-sizing.html abs-pos-child-sizing-ref.html
-fails-if(stylo) == overflow-hidden.html overflow-hidden-ref.html
+== overflow-hidden.html overflow-hidden-ref.html
 == legend-rtl.html legend-rtl-ref.html
 fails-if(stylo) == fieldset-grid-001.html fieldset-grid-001-ref.html
 fails-if(stylo) == fieldset-flexbox-001.html fieldset-flexbox-001-ref.html
diff --git a/layout/reftests/mathml/reftest.list b/layout/reftests/mathml/reftest.list
index 22db56953f12..44838d52e533 100644
--- a/layout/reftests/mathml/reftest.list
+++ b/layout/reftests/mathml/reftest.list
@@ -3,8 +3,8 @@
 random-if(gtkWidget) == dir-3.html dir-3-ref.html # bug 1309426
 == dir-4.html dir-4-ref.html
 == dir-5.html dir-5-ref.html
-fails-if(stylo) == dir-6.html dir-6-ref.html
-fails-if(stylo) == dir-6a.html dir-6a-ref.html
+== dir-6.html dir-6-ref.html
+== dir-6a.html dir-6a-ref.html
 == dir-7.html dir-7-ref.html
 fails-if(!stylo) == dir-8.html dir-8-ref.html
 fails-if(!stylo) == dir-9.html dir-9-ref.html # Bug 787215
@@ -41,7 +41,7 @@ random-if(smallScreen&&Android) fuzzy(255,200) == mirror-op-1.html mirror-op-1-r
 == mfenced-7.html mfenced-7-ref.html
 != mfenced-8.html mfenced-8-ref.html
 == mfenced-9.html mfenced-9-ref.html
-fails-if(stylo) == mfenced-10.html mfenced-10-ref.html
+== mfenced-10.html mfenced-10-ref.html
 fails-if(gtkWidget&&!stylo) == mfenced-11.html mfenced-11-ref.html # bug 670592, bug 1328771
 fails-if(gtkWidget&&!stylo) == mfenced-12.html mfenced-12-ref.html # bug 670592, bug 1328771
 == mi-mathvariant-1.xhtml mi-mathvariant-1-ref.xhtml
@@ -87,14 +87,14 @@ fails-if(!stylo) == stretchy-mover-2a.html stretchy-mover-2-ref.html
 == stretchy-largeop-1.html stretchy-largeop-1-ref.html
 == stretchy-largeop-2.html stretchy-largeop-2-ref.html
 == stretchy-largeop-3.html stretchy-largeop-3-ref.html
-fails-if(stylo) == table-width-1.xhtml table-width-1-ref.xhtml
+== table-width-1.xhtml table-width-1-ref.xhtml
 == table-width-2.html table-width-2-ref.html
 == table-width-3.html table-width-3-ref.html
 == table-width-4.html table-width-4-ref.html
 == underbar-width-1.xhtml underbar-width-1-ref.xhtml
 == mathml-type-supported.xhtml mathml-type-supported-ref.xml
-fails-if(stylo) == mtable-align-negative-rownumber.html mtable-align-negative-rownumber-ref.html
-fails-if(stylo) == mtable-align-negative-rownumber-2.html mtable-align-negative-rownumber-2-ref.html
+== mtable-align-negative-rownumber.html mtable-align-negative-rownumber-ref.html
+== mtable-align-negative-rownumber-2.html mtable-align-negative-rownumber-2-ref.html
 != embellished-op-1-1.html embellished-op-1-1-ref.html
 != embellished-op-1-2.html embellished-op-1-2-ref.html
 != embellished-op-1-3.html embellished-op-1-3-ref.html
@@ -127,7 +127,7 @@ fails-if(gtkWidget&&!stylo) random-if(winWidget) == semantics-1.xhtml semantics-
 != mathbackground-3.xml mathbackground-3-ref.xml
 == mathbackground-4.xml mathbackground-4-ref.xml
 == mstyle-1.xhtml mstyle-1-ref.xhtml
-fails-if(stylo) == mstyle-2.xhtml mstyle-2-ref.xhtml
+== mstyle-2.xhtml mstyle-2-ref.xhtml
 == mstyle-3.xhtml mstyle-3-ref.xhtml
 == mstyle-4.xhtml mstyle-4-ref.xhtml
 == mstyle-5.xhtml mstyle-5-ref.xhtml # Bug 787215
@@ -163,26 +163,26 @@ random-if(gtkWidget) == mpadded-9.html mpadded-9-ref.html # bug 1309430
 != link-1.xhtml link-ref.xhtml
 == munderover-empty-scripts.html munderover-empty-scripts-ref.html
 == positive-namedspace.html positive-namedspace-ref.html
-fails-if(stylo) == mtable-align-whitespace.html mtable-align-whitespace-ref.html
+== mtable-align-whitespace.html mtable-align-whitespace-ref.html
 == mtable-width.html mtable-width-ref.html
-fails-if(stylo) == mtable-rowlines-single-mtable-dynamic.html mtable-rowlines-single-ref.html
-fails-if(stylo) == mtable-rowlines-multi-mtable-dynamic.html mtable-rowlines-multi-ref.html
-fails-if(stylo) == mtable-rowalign-single-mtr.html mtable-rowalign-single-ref.html
-fails-if(stylo) == mtable-rowalign-single-mtr-dynamic.html mtable-rowalign-single-ref.html
-fails-if(stylo) == mtable-rowalign-single-mtable.html mtable-rowalign-single-ref.html
-fails-if(stylo) == mtable-rowalign-single-mtable-dynamic.html mtable-rowalign-single-ref.html
-fails-if(stylo) == mtable-rowalign-multi-mtable.html mtable-rowalign-multi-ref.html
-fails-if(stylo) == mtable-rowalign-multi-mtable-dynamic.html mtable-rowalign-multi-ref.html
-fails-if(stylo) == mtable-columnlines-single-mtable-dynamic.html mtable-columnlines-single-ref.html
-fails-if(stylo) == mtable-columnlines-multi-mtable-dynamic.html mtable-columnlines-multi-ref.html
-fails-if(stylo) == mtable-columnalign-single-mtr.html mtable-columnalign-single-ref.html
-fails-if(stylo) == mtable-columnalign-single-mtr-dynamic.html mtable-columnalign-single-ref.html
-fails-if(stylo) == mtable-columnalign-single-mtable.html mtable-columnalign-single-ref.html
-fails-if(stylo) == mtable-columnalign-single-mtable-dynamic.html mtable-columnalign-single-ref.html
-fails-if(stylo) == mtable-columnalign-multi-mtr.html mtable-columnalign-multi-ref.html
-fails-if(stylo) == mtable-columnalign-multi-mtr-dynamic.html mtable-columnalign-multi-ref.html
-fails-if(stylo) == mtable-columnalign-multi-mtable.html mtable-columnalign-multi-ref.html
-fails-if(stylo) == mtable-columnalign-multi-mtable-dynamic.html mtable-columnalign-multi-ref.html
+== mtable-rowlines-single-mtable-dynamic.html mtable-rowlines-single-ref.html
+== mtable-rowlines-multi-mtable-dynamic.html mtable-rowlines-multi-ref.html
+== mtable-rowalign-single-mtr.html mtable-rowalign-single-ref.html
+== mtable-rowalign-single-mtr-dynamic.html mtable-rowalign-single-ref.html
+== mtable-rowalign-single-mtable.html mtable-rowalign-single-ref.html
+== mtable-rowalign-single-mtable-dynamic.html mtable-rowalign-single-ref.html
+== mtable-rowalign-multi-mtable.html mtable-rowalign-multi-ref.html
+== mtable-rowalign-multi-mtable-dynamic.html mtable-rowalign-multi-ref.html
+== mtable-columnlines-single-mtable-dynamic.html mtable-columnlines-single-ref.html
+== mtable-columnlines-multi-mtable-dynamic.html mtable-columnlines-multi-ref.html
+== mtable-columnalign-single-mtr.html mtable-columnalign-single-ref.html
+== mtable-columnalign-single-mtr-dynamic.html mtable-columnalign-single-ref.html
+== mtable-columnalign-single-mtable.html mtable-columnalign-single-ref.html
+== mtable-columnalign-single-mtable-dynamic.html mtable-columnalign-single-ref.html
+== mtable-columnalign-multi-mtr.html mtable-columnalign-multi-ref.html
+== mtable-columnalign-multi-mtr-dynamic.html mtable-columnalign-multi-ref.html
+== mtable-columnalign-multi-mtable.html mtable-columnalign-multi-ref.html
+== mtable-columnalign-multi-mtable-dynamic.html mtable-columnalign-multi-ref.html
 == maction-selection.html maction-selection-ref.html
 == maction-dynamic-embellished-op.html maction-dynamic-embellished-op-ref.html
 == maction-dynamic-1.html maction-dynamic-1-ref.html # bug 773482
@@ -306,28 +306,28 @@ fails-if(stylo) == mathscript-2.html mathscript-2-ref.html
 == mo-movablelimits-dynamic.html mo-movablelimits-dynamic-ref.html
 == munderover-accent-dynamic.html munderover-accent-dynamic-ref.html
 == munderover-accentunder-dynamic.html munderover-accentunder-dynamic-ref.html
-fails-if(stylo) == columnlines-1a.html columnlines-1-ref.html
-fails-if(stylo) != columnlines-1b.html columnlines-1-ref.html
-fails-if(stylo) != columnlines-1c.html columnlines-1-ref.html
+== columnlines-1a.html columnlines-1-ref.html
+!= columnlines-1b.html columnlines-1-ref.html
+!= columnlines-1c.html columnlines-1-ref.html
 == columnlines-2a.html columnlines-2-ref.html
 == columnlines-2b.html columnlines-2-ref.html
 != columnlines-3-1.html columnlines-3-1-ref.html
 == columnlines-3-2.html columnlines-3-2-ref.html
-fails-if(stylo) == rowlines-1a.html rowlines-1-ref.html
-fails-if(stylo) != rowlines-1b.html rowlines-1-ref.html
-fails-if(stylo) != rowlines-1c.html rowlines-1-ref.html
-fails-if(stylo) == rowlines-2a.html rowlines-2-ref.html
-fails-if(stylo) == rowlines-2b.html rowlines-2-ref.html
+== rowlines-1a.html rowlines-1-ref.html
+!= rowlines-1b.html rowlines-1-ref.html
+!= rowlines-1c.html rowlines-1-ref.html
+== rowlines-2a.html rowlines-2-ref.html
+== rowlines-2b.html rowlines-2-ref.html
 != rowlines-3-1.html rowlines-3-1-ref.html
 random-if(gtkWidget) == rowlines-3-2.html rowlines-3-2-ref.html # bug 1309426
-fails-if(stylo) == tablespacing-1.html tablespacing-1-ref.html
+== tablespacing-1.html tablespacing-1-ref.html
 == tablespacing-2.html tablespacing-2-ref.html
 == tablespacing-3.html tablespacing-3-ref.html
 == tablespacing-4.html tablespacing-4-ref.html
-fails-if(stylo) == tablespacing-5.html tablespacing-5-ref.html
-fails-if(stylo) == tablespacing-5a.html tablespacing-5a-ref.html
-fails-if(stylo) == tablespacing-6.html tablespacing-6-ref.html
-fails-if(stylo) == tablespacing-7.html tablespacing-7-ref.html
+== tablespacing-5.html tablespacing-5-ref.html
+== tablespacing-5a.html tablespacing-5a-ref.html
+== tablespacing-6.html tablespacing-6-ref.html
+== tablespacing-7.html tablespacing-7-ref.html
 != tablespacing-8a.html tablespacing-8-ref.html
 != tablespacing-8b.html tablespacing-8-ref.html
 != op-dict-1.html op-dict-1-ref.html
diff --git a/layout/reftests/svg/svg-integration/clip-path/reftest.list b/layout/reftests/svg/svg-integration/clip-path/reftest.list
index 0d6ffde392c5..e69eca1136a0 100644
--- a/layout/reftests/svg/svg-integration/clip-path/reftest.list
+++ b/layout/reftests/svg/svg-integration/clip-path/reftest.list
@@ -16,7 +16,7 @@ default-preferences pref(layout.css.clip-path-shapes.enabled,true)
 == clip-path-polygon-010.html clip-path-stripes-001-ref.html
 == clip-path-polygon-011.html clip-path-stripes-001-ref.html
 == clip-path-polygon-012.html clip-path-stripes-001-ref.html
-fails-if(stylo) == clip-path-polygon-013.html clip-path-stripes-003-ref.html
+== clip-path-polygon-013.html clip-path-stripes-003-ref.html
 
 == clip-path-circle-001.html clip-path-circle-001-ref.html
 == clip-path-circle-002.html clip-path-circle-001-ref.html
@@ -56,4 +56,4 @@ fails-if(stylo) == clip-path-polygon-013.html clip-path-stripes-003-ref.html
 fuzzy(64,146) == clip-path-inset-002a.html clip-path-inset-002-ref.html
 fuzzy(64,146) == clip-path-inset-002b.html clip-path-inset-002-ref.html
 fuzzy(64,146) == clip-path-inset-002c.html clip-path-inset-002-ref.html
-fuzzy(64,340) == clip-path-inset-003.html clip-path-inset-003-ref.html
\ No newline at end of file
+fuzzy(64,340) == clip-path-inset-003.html clip-path-inset-003-ref.html
diff --git a/layout/reftests/text-overflow/reftest.list b/layout/reftests/text-overflow/reftest.list
index 1a17f176a68f..f8a20344428a 100644
--- a/layout/reftests/text-overflow/reftest.list
+++ b/layout/reftests/text-overflow/reftest.list
@@ -1,14 +1,14 @@
 == ellipsis-font-fallback.html ellipsis-font-fallback-ref.html
 == line-clipping.html line-clipping-ref.html
 fuzzy-if(Android,16,244) HTTP(..) == marker-basic.html marker-basic-ref.html  # Bug 1128229
-fails-if(stylo) HTTP(..) == marker-string.html marker-string-ref.html
+HTTP(..) == marker-string.html marker-string-ref.html
 skip-if(Android) HTTP(..) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing
 skip-if(!gtkWidget) fuzzy-if(gtkWidget,2,289) HTTP(..) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing
 fuzzy-if(Android,24,4000) fuzzy-if(cocoaWidget,1,40) fuzzy-if(asyncPan&&!layersGPUAccelerated,140,1836) HTTP(..) == scroll-rounding.html scroll-rounding-ref.html # bug 760264
 fuzzy(2,453) fuzzy-if(skiaContent,9,2100) fails-if(gtkWidget) HTTP(..) == anonymous-block.html anonymous-block-ref.html # gtkWidget:bug 1309103
 HTTP(..) == false-marker-overlap.html false-marker-overlap-ref.html
 HTTP(..) == visibility-hidden.html visibility-hidden-ref.html
-fuzzy-if(asyncPan&&!layersGPUAccelerated,102,1724) fuzzy-if(gtkWidget,10,8) fails-if(stylo) HTTP(..) == block-padding.html block-padding-ref.html
+fuzzy-if(asyncPan&&!layersGPUAccelerated,102,1724) fuzzy-if(gtkWidget,10,8) HTTP(..) == block-padding.html block-padding-ref.html
 HTTP(..) == quirks-decorations.html quirks-decorations-ref.html
 HTTP(..) == quirks-line-height.html quirks-line-height-ref.html
 HTTP(..) == standards-decorations.html standards-decorations-ref.html
@@ -22,16 +22,16 @@ HTTP(..) == table-cell.html table-cell-ref.html
 fuzzy-if(gtkWidget,10,32) fails-if(stylo) HTTP(..) == two-value-syntax.html two-value-syntax-ref.html
 fails-if(stylo) HTTP(..) == single-value.html single-value-ref.html
 fuzzy-if(gtkWidget,10,2) HTTP(..) == atomic-under-marker.html atomic-under-marker-ref.html
-fuzzy(1,2616) skip-if(Android) fuzzy-if(asyncPan&&!layersGPUAccelerated,102,12352) fails-if(gtkWidget) HTTP(..) == xulscroll.html xulscroll-ref.html # gtkWidget:bug 1309107, bug 1328771
+fuzzy(1,2616) skip-if(Android) fuzzy-if(asyncPan&&!layersGPUAccelerated,102,12352) fails-if(gtkWidget&&!stylo) HTTP(..) == xulscroll.html xulscroll-ref.html # gtkWidget:bug 1309107, bug 1328771
 HTTP(..) == combobox-zoom.html combobox-zoom-ref.html
 == dynamic-change-1.html dynamic-change-1-ref.html
 == float-edges-1-ref.html float-edges-1-ref.html
 
 # The vertical-text pref setting can be removed after bug 1138384 lands
-fails-if(stylo) == vertical-decorations-1.html vertical-decorations-1-ref.html
-fails-if(stylo) == vertical-decorations-2.html vertical-decorations-2-ref.html
-fails-if(stylo) != vertical-decorations-1.html vertical-decorations-1-2-notref.html
-fails-if(stylo) != vertical-decorations-2.html vertical-decorations-1-2-notref.html
+== vertical-decorations-1.html vertical-decorations-1-ref.html
+== vertical-decorations-2.html vertical-decorations-2-ref.html
+!= vertical-decorations-1.html vertical-decorations-1-2-notref.html
+!= vertical-decorations-2.html vertical-decorations-1-2-notref.html
 == vertical-decorations-3.html vertical-decorations-3-ref.html
 == vertical-decorations-4.html vertical-decorations-4-ref.html
 != vertical-decorations-3.html vertical-decorations-3-4-notref.html
diff --git a/layout/reftests/text/reftest.list b/layout/reftests/text/reftest.list
index 6a47e651ff8d..286eb1f31b1e 100644
--- a/layout/reftests/text/reftest.list
+++ b/layout/reftests/text/reftest.list
@@ -11,7 +11,7 @@ random-if(!cocoaWidget) == font-size-adjust-02.html font-size-adjust-02-ref.html
 # in the "obvious" way, but it is unclear what the behavior should really be;
 # see bug #366138 for some (inconclusive) discussion
 # == font-size-adjust-03.html font-size-adjust-03-ref.html
-fails-if(stylo) == justification-1.html justification-1-ref.html
+== justification-1.html justification-1-ref.html
 == justification-2a.html justification-2-ref.html
 == justification-2b.html justification-2-ref.html
 == justification-2c.html justification-2-ref.html
@@ -34,7 +34,7 @@ fuzzy-if(Android,255,147) == pre-line-1.html pre-line-1-ref.html
 == pre-line-3.html pre-line-3-ref.html
 == pre-line-4.html pre-line-4-ref.html
 == pre-space-1.html pre-space-1-ref.html
-fails-if(stylo) == pre-wrap-1.html pre-wrap-1-ref.html
+== pre-wrap-1.html pre-wrap-1-ref.html
 == soft-hyphens-1a.html soft-hyphens-1-ref.html
 == soft-hyphens-1b.html soft-hyphens-1-ref.html
 == soft-hyphens-1c.html soft-hyphens-1-ref.html
@@ -122,7 +122,7 @@ HTTP(..) == wordbreak-7a.html wordbreak-7a-ref.html
 fails-if(!stylo) HTTP(..) == wordbreak-7b.html wordbreak-7b-ref.html # bug 479829
 == wordbreak-8.html wordbreak-8-ref.html
 pref(gfx.font_rendering.graphite.enabled,true) HTTP(..) == wordbreak-9.html wordbreak-9-ref.html
-fails-if(stylo) == wordbreak-dynamic-1.html wordbreak-dynamic-1-ref.html
+== wordbreak-dynamic-1.html wordbreak-dynamic-1-ref.html
 fails-if(stylo) == wordwrap-01.html wordwrap-01-ref.html
 fails-if(stylo) HTTP(..) == wordwrap-02.html wordwrap-02-ref.html
 fuzzy-if(gtkWidget,1,177) fuzzy-if(skiaContent,1,50) fails-if(stylo) HTTP(..) == wordwrap-03.html wordwrap-03-ref.html # Fuzzy on Linux because the native textbox gradient is painted in a slightly different position depending on the invalid area.
@@ -317,9 +317,9 @@ fails-if(stylo) == auto-hyphenation-pl-1.html auto-hyphenation-pl-1-ref.html
 
 == auto-hyphenation-transformed-1.html auto-hyphenation-transformed-1-ref.html
 
-fails-if(stylo) == hyphenation-control-1.html hyphenation-control-1-ref.html
-fails-if(stylo) == hyphenation-control-2.html hyphenation-control-2-ref.html
-fails-if(stylo) == hyphenation-control-3.html hyphenation-control-3-ref.html
+== hyphenation-control-1.html hyphenation-control-1-ref.html
+== hyphenation-control-2.html hyphenation-control-2-ref.html
+== hyphenation-control-3.html hyphenation-control-3-ref.html
 
 # osx-font-smoothing - with and without subpixel AA, only under OSX
 fails-if(!cocoaWidget&&!stylo) != osx-font-smoothing.html osx-font-smoothing-ref.html
diff --git a/layout/reftests/usercss/reftest.list b/layout/reftests/usercss/reftest.list
index 656da58f6cb4..1c0cf56fb5d5 100644
--- a/layout/reftests/usercss/reftest.list
+++ b/layout/reftests/usercss/reftest.list
@@ -1 +1,3 @@
-skip-if(stylo) == usercss.html usercss-ref.html
+== usercss.html usercss-ref.html
+== usercss-xbl.html usercss-ref.html
+fails-if(stylo) == usercss-moz-document.html usercss-moz-document-ref.html # bug 1355408
diff --git a/layout/reftests/usercss/usercss-moz-document-ref.html b/layout/reftests/usercss/usercss-moz-document-ref.html
new file mode 100644
index 000000000000..c33062ea9dfe
--- /dev/null
+++ b/layout/reftests/usercss/usercss-moz-document-ref.html
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+

@-moz-document rules should be applied.

+

@-moz-document rules should not be applied.

+ + diff --git a/layout/reftests/usercss/usercss-moz-document.html b/layout/reftests/usercss/usercss-moz-document.html new file mode 100644 index 000000000000..c57c6db02dba --- /dev/null +++ b/layout/reftests/usercss/usercss-moz-document.html @@ -0,0 +1,17 @@ + + + + + + +

@-moz-document rules should be applied.

+

@-moz-document rules should not be applied.

+ + diff --git a/layout/reftests/usercss/usercss-ref.html b/layout/reftests/usercss/usercss-ref.html index 3512a8e34611..50a51ce8bca7 100644 --- a/layout/reftests/usercss/usercss-ref.html +++ b/layout/reftests/usercss/usercss-ref.html @@ -5,8 +5,5 @@

This paragraph should have a green background.

-

This paragraph should have a green background, too.

-

@-moz-document rules should be applied.

-

@-moz-document rules should not be applied.

diff --git a/layout/reftests/usercss/usercss-xbl.html b/layout/reftests/usercss/usercss-xbl.html new file mode 100644 index 000000000000..e1d44d9ea76d --- /dev/null +++ b/layout/reftests/usercss/usercss-xbl.html @@ -0,0 +1,13 @@ + + + + + + +

This paragraph should have a green background.

+ + diff --git a/layout/reftests/usercss/usercss.html b/layout/reftests/usercss/usercss.html index bde2bec1458f..363cded74cab 100644 --- a/layout/reftests/usercss/usercss.html +++ b/layout/reftests/usercss/usercss.html @@ -1,19 +1,13 @@ - +

This paragraph should have a green background.

-

This paragraph should have a green background, too.

-

@-moz-document rules should be applied.

-

@-moz-document rules should not be applied.

diff --git a/layout/reftests/w3c-css/failures.list b/layout/reftests/w3c-css/failures.list index 957f2c5f0bb9..2771dc4378cb 100644 --- a/layout/reftests/w3c-css/failures.list +++ b/layout/reftests/w3c-css/failures.list @@ -25,7 +25,7 @@ fails-if(!stylo) needs-focus selectors-4/focus-within-shadow-001.html #### CSS Values 3 #################################################### # Fuzzy -fuzzy-if(OSX,40,6) fails-if(stylo) css-values-3/ch-unit-001.html +fuzzy-if(OSX,40,6) css-values-3/ch-unit-001.html # Bug 435426 fails-if(!stylo) css-values-3/attr-*.html diff --git a/layout/reftests/w3c-css/received/reftest.list b/layout/reftests/w3c-css/received/reftest.list index 5b4824cad4f1..39eba0f984b9 100644 --- a/layout/reftests/w3c-css/received/reftest.list +++ b/layout/reftests/w3c-css/received/reftest.list @@ -223,7 +223,7 @@ fails == css-values-3/calc-in-media-queries-001.html css-values-3/reference/all- fails == css-values-3/calc-in-media-queries-002.html css-values-3/reference/all-green.html == css-values-3/calc-invalid-range-clamping.html css-values-3/reference/200-200-green.html == css-values-3/calc-parenthesis-stack.html css-values-3/reference/all-green.html -fuzzy-if(OSX,40,6) fails-if(stylo) == css-values-3/ch-unit-001.html css-values-3/reference/ch-unit-001-ref.html +fuzzy-if(OSX,40,6) == css-values-3/ch-unit-001.html css-values-3/reference/ch-unit-001-ref.html == css-values-3/initial-background-color.html css-values-3/reference/all-green.html == css-values-3/vh-calc-support-pct.html css-values-3/reference/all-green.html == css-values-3/vh-calc-support.html css-values-3/reference/all-green.html diff --git a/layout/reftests/w3c-css/submitted/text3/reftest.list b/layout/reftests/w3c-css/submitted/text3/reftest.list index 9fd79953562d..0ba99ad97e1d 100644 --- a/layout/reftests/w3c-css/submitted/text3/reftest.list +++ b/layout/reftests/w3c-css/submitted/text3/reftest.list @@ -12,7 +12,7 @@ pref(layout.css.text-justify.enabled,true) == text-justify-distribute-001.html t == text-word-spacing-001.html text-word-spacing-ref.html -fails-if(stylo) == hyphenation-control-1.html hyphenation-control-1-ref.html +== hyphenation-control-1.html hyphenation-control-1-ref.html == segment-break-transformation-removable-1.html segment-break-transformation-removable-ref.html == segment-break-transformation-removable-2.html segment-break-transformation-removable-ref.html diff --git a/layout/style/FontFace.cpp b/layout/style/FontFace.cpp index 4095c65d54fa..76d26910bb62 100644 --- a/layout/style/FontFace.cpp +++ b/layout/style/FontFace.cpp @@ -12,6 +12,8 @@ #include "mozilla/dom/TypedArray.h" #include "mozilla/dom/UnionTypes.h" #include "mozilla/CycleCollectedJSContext.h" +#include "mozilla/ServoStyleSet.h" +#include "mozilla/ServoUtils.h" #include "nsCSSFontFaceRule.h" #include "nsCSSParser.h" #include "nsIDocument.h" @@ -106,12 +108,17 @@ FontFace::FontFace(nsISupports* aParent, FontFaceSet* aFontFaceSet) , mSourceBuffer(nullptr) , mSourceBufferLength(0) , mFontFaceSet(aFontFaceSet) + , mUnicodeRangeDirty(true) , mInFontFaceSet(false) { } FontFace::~FontFace() { + // Assert that we don't drop any FontFace objects during a Servo traversal, + // since PostTraversalTask objects can hold raw pointers to FontFaces. + MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal()); + SetUserFontEntry(nullptr); if (mSourceBuffer) { @@ -131,6 +138,7 @@ LoadStateToStatus(gfxUserFontEntry::UserFontLoadState aLoadState) switch (aLoadState) { case gfxUserFontEntry::UserFontLoadState::STATUS_NOT_LOADED: return FontFaceLoadStatus::Unloaded; + case gfxUserFontEntry::UserFontLoadState::STATUS_LOAD_PENDING: case gfxUserFontEntry::UserFontLoadState::STATUS_LOADING: return FontFaceLoadStatus::Loading; case gfxUserFontEntry::UserFontLoadState::STATUS_LOADED: @@ -357,6 +365,8 @@ FontFace::Status() Promise* FontFace::Load(ErrorResult& aRv) { + MOZ_ASSERT(NS_IsMainThread()); + mFontFaceSet->FlushUserFontSet(); EnsurePromise(); @@ -414,6 +424,8 @@ FontFace::DoLoad() Promise* FontFace::GetLoaded(ErrorResult& aRv) { + MOZ_ASSERT(NS_IsMainThread()); + mFontFaceSet->FlushUserFontSet(); EnsurePromise(); @@ -429,6 +441,8 @@ FontFace::GetLoaded(ErrorResult& aRv) void FontFace::SetStatus(FontFaceLoadStatus aStatus) { + AssertIsMainThreadOrServoFontMetricsLocked(); + if (mStatus == aStatus) { return; } @@ -454,7 +468,7 @@ FontFace::SetStatus(FontFaceLoadStatus aStatus) if (mStatus == FontFaceLoadStatus::Loaded) { if (mLoaded) { - mLoaded->MaybeResolve(this); + DoResolve(); } } else if (mStatus == FontFaceLoadStatus::Error) { if (mSourceType == eSourceType_Buffer) { @@ -465,6 +479,34 @@ FontFace::SetStatus(FontFaceLoadStatus aStatus) } } +void +FontFace::DoResolve() +{ + AssertIsMainThreadOrServoFontMetricsLocked(); + + if (ServoStyleSet* ss = ServoStyleSet::Current()) { + // See comments in Gecko_GetFontMetrics. + ss->AppendTask(PostTraversalTask::ResolveFontFaceLoadedPromise(this)); + return; + } + + mLoaded->MaybeResolve(this); +} + +void +FontFace::DoReject(nsresult aResult) +{ + AssertIsMainThreadOrServoFontMetricsLocked(); + + if (ServoStyleSet* ss = ServoStyleSet::Current()) { + // See comments in Gecko_GetFontMetrics. + ss->AppendTask(PostTraversalTask::RejectFontFaceLoadedPromise(this, aResult)); + return; + } + + mLoaded->MaybeReject(aResult); +} + bool FontFace::ParseDescriptor(nsCSSFontDesc aDescID, const nsAString& aString, @@ -510,6 +552,10 @@ FontFace::SetDescriptor(nsCSSFontDesc aFontDesc, mDescriptors->Get(aFontDesc) = parsedValue; + if (aFontDesc == eCSSFontDesc_UnicodeRange) { + mUnicodeRangeDirty = true; + } + // XXX Setting descriptors doesn't actually have any effect on FontFace // objects that have started loading or have already been loaded. } @@ -732,8 +778,10 @@ FontFace::RemoveFontFaceSet(FontFaceSet* aFontFaceSet) void FontFace::Reject(nsresult aResult) { + AssertIsMainThreadOrServoFontMetricsLocked(); + if (mLoaded) { - mLoaded->MaybeReject(aResult); + DoReject(aResult); } else if (mLoadedRejection == NS_OK) { mLoadedRejection = aResult; } @@ -742,6 +790,8 @@ FontFace::Reject(nsresult aResult) void FontFace::EnsurePromise() { + MOZ_ASSERT(NS_IsMainThread()); + if (mLoaded) { return; } @@ -763,6 +813,35 @@ FontFace::EnsurePromise() } } +gfxCharacterMap* +FontFace::GetUnicodeRangeAsCharacterMap() +{ + if (!mUnicodeRangeDirty) { + return mUnicodeRange; + } + + nsCSSValue val; + GetDesc(eCSSFontDesc_UnicodeRange, val); + + if (val.GetUnit() == eCSSUnit_Array) { + mUnicodeRange = new gfxCharacterMap(); + const nsCSSValue::Array& sources = *val.GetArrayValue(); + MOZ_ASSERT(sources.Count() % 2 == 0, + "odd number of entries in a unicode-range: array"); + + for (uint32_t i = 0; i < sources.Count(); i += 2) { + uint32_t min = sources[i].GetIntValue(); + uint32_t max = sources[i+1].GetIntValue(); + mUnicodeRange->SetRange(min, max); + } + } else { + mUnicodeRange = nullptr; + } + + mUnicodeRangeDirty = false; + return mUnicodeRange; +} + // -- FontFace::Entry -------------------------------------------------------- /* virtual */ void diff --git a/layout/style/FontFace.h b/layout/style/FontFace.h index 29171a6da672..69e76c9b848a 100644 --- a/layout/style/FontFace.h +++ b/layout/style/FontFace.h @@ -18,6 +18,7 @@ class nsCSSFontFaceRule; namespace mozilla { struct CSSFontFaceDescriptors; +class PostTraversalTask; namespace dom { class FontFaceBufferSource; struct FontFaceDescriptors; @@ -33,6 +34,7 @@ namespace dom { class FontFace final : public nsISupports, public nsWrapperCache { + friend class mozilla::PostTraversalTask; friend class mozilla::dom::FontFaceBufferSource; friend class Entry; @@ -48,7 +50,7 @@ public: uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges, + gfxCharacterMap* aUnicodeRanges, uint8_t aFontDisplay) : gfxUserFontEntry(aFontSet, aFontFaceSrcList, aWeight, aStretch, aStyle, aFeatureSettings, aLanguageOverride, @@ -128,6 +130,11 @@ public: */ bool GetData(uint8_t*& aBuffer, uint32_t& aLength); + /** + * Returns the value of the unicode-range descriptor as a gfxCharacterMap. + */ + gfxCharacterMap* GetUnicodeRangeAsCharacterMap(); + // Web IDL static already_AddRefed Constructor(const GlobalObject& aGlobal, @@ -207,6 +214,9 @@ private: // reject mLoaded based on mStatus and mLoadedRejection. void EnsurePromise(); + void DoResolve(); + void DoReject(nsresult aResult); + nsCOMPtr mParent; // A Promise that is fulfilled once the font represented by this FontFace is @@ -251,6 +261,10 @@ private: // the descriptors stored in mRule. nsAutoPtr mDescriptors; + // The value of the unicode-range descriptor as a gfxCharacterMap. Valid + // only when mUnicodeRangeDirty is false. + RefPtr mUnicodeRange; + // The primary FontFaceSet this FontFace is associated with, // regardless of whether it is currently "in" the set. RefPtr mFontFaceSet; @@ -259,6 +273,10 @@ private: // appears in. nsTArray> mOtherFontFaceSets; + // Whether mUnicodeRange needs to be rebuilt before being returned from + // GetUnicodeRangeAsCharacterMap. + bool mUnicodeRangeDirty; + // Whether this FontFace appears in mFontFaceSet. bool mInFontFaceSet; }; diff --git a/layout/style/FontFaceSet.cpp b/layout/style/FontFaceSet.cpp index 4c46839c121b..c0e93c87ead2 100644 --- a/layout/style/FontFaceSet.cpp +++ b/layout/style/FontFaceSet.cpp @@ -17,6 +17,8 @@ #include "mozilla/AsyncEventDispatcher.h" #include "mozilla/Logging.h" #include "mozilla/Preferences.h" +#include "mozilla/ServoStyleSet.h" +#include "mozilla/ServoUtils.h" #include "mozilla/SizePrintfMacros.h" #include "mozilla/Sprintf.h" #include "mozilla/Telemetry.h" @@ -128,6 +130,10 @@ FontFaceSet::FontFaceSet(nsPIDOMWindowInner* aWindow, nsIDocument* aDocument) FontFaceSet::~FontFaceSet() { + // Assert that we don't drop any FontFaceSet objects during a Servo traversal, + // since PostTraversalTask objects can hold raw pointers to FontFaceSets. + MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal()); + Disconnect(); for (auto it = mLoaders.Iter(); !it.Done(); it.Next()) { it.Get()->GetKey()->Cancel(); @@ -380,6 +386,8 @@ FontFaceSet::Check(const nsAString& aFont, Promise* FontFaceSet::GetReady(ErrorResult& aRv) { + MOZ_ASSERT(NS_IsMainThread()); + if (!mReady) { nsCOMPtr global = GetParentObject(); mReady = Promise::Create(global, aRv); @@ -1050,21 +1058,7 @@ FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsAString& aFamilyName, } // set up unicode-range - nsAutoPtr unicodeRanges; - aFontFace->GetDesc(eCSSFontDesc_UnicodeRange, val); - unit = val.GetUnit(); - if (unit == eCSSUnit_Array) { - unicodeRanges = new gfxCharacterMap(); - const nsCSSValue::Array& sources = *val.GetArrayValue(); - MOZ_ASSERT(sources.Count() % 2 == 0, - "odd number of entries in a unicode-range: array"); - - for (uint32_t i = 0; i < sources.Count(); i += 2) { - uint32_t min = sources[i].GetIntValue(); - uint32_t max = sources[i+1].GetIntValue(); - unicodeRanges->SetRange(min, max); - } - } + gfxCharacterMap* unicodeRanges = aFontFace->GetUnicodeRangeAsCharacterMap(); // set up src array nsTArray srcArray; @@ -1462,6 +1456,8 @@ FontFaceSet::GetPrivateBrowsing() void FontFaceSet::OnFontFaceStatusChanged(FontFace* aFontFace) { + AssertIsMainThreadOrServoFontMetricsLocked(); + MOZ_ASSERT(HasAvailableFontFace(aFontFace)); mHasLoadingFontFacesIsDirty = true; @@ -1480,14 +1476,33 @@ FontFaceSet::OnFontFaceStatusChanged(FontFace* aFontFace) // and call CheckLoadingFinished() after the reflow has been queued. if (!mDelayedLoadCheck) { mDelayedLoadCheck = true; - nsCOMPtr checkTask = - NewRunnableMethod(this, &FontFaceSet::CheckLoadingFinishedAfterDelay); - mDocument->Dispatch("FontFaceSet::CheckLoadingFinishedAfterDelay", - TaskCategory::Other, checkTask.forget()); + DispatchCheckLoadingFinishedAfterDelay(); } } } +void +FontFaceSet::DispatchCheckLoadingFinishedAfterDelay() +{ + AssertIsMainThreadOrServoFontMetricsLocked(); + + if (ServoStyleSet* set = ServoStyleSet::Current()) { + // See comments in Gecko_GetFontMetrics. + // + // We can't just dispatch the runnable below if we're not on the main + // thread, since it needs to take a strong reference to the FontFaceSet, + // and being a DOM object, FontFaceSet doesn't support thread-safe + // refcounting. + set->AppendTask(PostTraversalTask::DispatchFontFaceSetCheckLoadingFinishedAfterDelay(this)); + return; + } + + nsCOMPtr checkTask = + NewRunnableMethod(this, &FontFaceSet::CheckLoadingFinishedAfterDelay); + mDocument->Dispatch("FontFaceSet::CheckLoadingFinishedAfterDelay", + TaskCategory::Other, checkTask.forget()); +} + void FontFaceSet::DidRefresh() { @@ -1504,6 +1519,8 @@ FontFaceSet::CheckLoadingFinishedAfterDelay() void FontFaceSet::CheckLoadingStarted() { + AssertIsMainThreadOrServoFontMetricsLocked(); + if (!HasLoadingFontFaces()) { return; } @@ -1515,6 +1532,27 @@ FontFaceSet::CheckLoadingStarted() } mStatus = FontFaceSetLoadStatus::Loading; + DispatchLoadingEventAndReplaceReadyPromise(); +} + +void +FontFaceSet::DispatchLoadingEventAndReplaceReadyPromise() +{ + AssertIsMainThreadOrServoFontMetricsLocked(); + + if (ServoStyleSet* set = ServoStyleSet::Current()) { + // See comments in Gecko_GetFontMetrics. + // + // We can't just dispatch the runnable below if we're not on the main + // thread, since it needs to take a strong reference to the FontFaceSet, + // and being a DOM object, FontFaceSet doesn't support thread-safe + // refcounting. (Also, the Promise object creation must be done on + // the main thread.) + set->AppendTask( + PostTraversalTask::DispatchLoadingEventAndReplaceReadyPromise(this)); + return; + } + (new AsyncEventDispatcher(this, NS_LITERAL_STRING("loading"), false))->PostDOMEvent(); @@ -1594,6 +1632,8 @@ FontFaceSet::MightHavePendingFontLoads() void FontFaceSet::CheckLoadingFinished() { + MOZ_ASSERT(NS_IsMainThread()); + if (mDelayedLoadCheck) { // Wait until the runnable posted in OnFontFaceStatusChanged calls us. return; @@ -1839,7 +1879,7 @@ FontFaceSet::UserFontSet::CreateUserFontEntry( uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges, + gfxCharacterMap* aUnicodeRanges, uint8_t aFontDisplay) { RefPtr entry = diff --git a/layout/style/FontFaceSet.h b/layout/style/FontFaceSet.h index 1350b38ddf96..bef4f1e3c1d4 100644 --- a/layout/style/FontFaceSet.h +++ b/layout/style/FontFaceSet.h @@ -20,6 +20,7 @@ class nsIPrincipal; class nsPIDOMWindowInner; namespace mozilla { +class PostTraversalTask; namespace css { class FontFamilyListRefCnt; } // namespace css @@ -36,6 +37,7 @@ class FontFaceSet final : public DOMEventTargetHelper , public nsIDOMEventListener , public nsICSSLoaderObserver { + friend class mozilla::PostTraversalTask; friend class UserFontSet; public: @@ -92,7 +94,7 @@ public: uint8_t aStyle, const nsTArray& aFeatureSettings, uint32_t aLanguageOverride, - gfxSparseBitSet* aUnicodeRanges, + gfxCharacterMap* aUnicodeRanges, uint8_t aFontDisplay) override; private: @@ -303,6 +305,9 @@ private: nsTArray& aFontFaces, mozilla::ErrorResult& aRv); + void DispatchLoadingEventAndReplaceReadyPromise(); + void DispatchCheckLoadingFinishedAfterDelay(); + TimeStamp GetNavigationStartTimeStamp(); RefPtr mUserFontSet; diff --git a/layout/style/PostTraversalTask.cpp b/layout/style/PostTraversalTask.cpp new file mode 100644 index 000000000000..2638ecc7d3d1 --- /dev/null +++ b/layout/style/PostTraversalTask.cpp @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "PostTraversalTask.h" + +#include "mozilla/dom/FontFace.h" +#include "mozilla/dom/FontFaceSet.h" +#include "gfxUserFontSet.h" + +namespace mozilla { + +using namespace dom; + +void +PostTraversalTask::Run() +{ + switch (mType) { + case Type::ResolveFontFaceLoadedPromise: + static_cast(mTarget)->DoResolve(); + break; + + case Type::RejectFontFaceLoadedPromise: + static_cast(mTarget)->DoReject(mResult); + break; + + case Type::DispatchLoadingEventAndReplaceReadyPromise: + static_cast(mTarget)-> + DispatchLoadingEventAndReplaceReadyPromise(); + break; + + case Type::DispatchFontFaceSetCheckLoadingFinishedAfterDelay: + static_cast(mTarget)-> + DispatchCheckLoadingFinishedAfterDelay(); + break; + + case Type::LoadFontEntry: + static_cast(mTarget)->ContinueLoad(); + break; + } +} + +} // namespace mozilla diff --git a/layout/style/PostTraversalTask.h b/layout/style/PostTraversalTask.h new file mode 100644 index 000000000000..539cec489fc3 --- /dev/null +++ b/layout/style/PostTraversalTask.h @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_PostTraversalTask_h +#define mozilla_PostTraversalTask_h + +/* a task to be performed immediately after a Servo traversal */ + +namespace mozilla { +namespace dom { +class FontFace; +class FontFaceSet; +} // namespace dom +} // namespace mozilla +class gfxUserFontEntry; + +namespace mozilla { + +/** + * A PostTraversalTask is a task to be performed immediately after a Servo + * traversal. There are just a few tasks we need to perform, so we use this + * class rather than Runnables, to avoid virtual calls and some allocations. + * + * A PostTraversalTask is only safe to run immediately after the Servo + * traversal, since it can hold raw pointers to DOM objects. + */ +class PostTraversalTask +{ +public: + static PostTraversalTask ResolveFontFaceLoadedPromise(dom::FontFace* aFontFace) + { + auto task = PostTraversalTask(Type::ResolveFontFaceLoadedPromise); + task.mTarget = aFontFace; + return task; + } + + static PostTraversalTask RejectFontFaceLoadedPromise(dom::FontFace* aFontFace, + nsresult aResult) + { + auto task = PostTraversalTask(Type::ResolveFontFaceLoadedPromise); + task.mTarget = aFontFace; + task.mResult = aResult; + return task; + } + + static PostTraversalTask DispatchLoadingEventAndReplaceReadyPromise( + dom::FontFaceSet* aFontFaceSet) + { + auto task = + PostTraversalTask(Type::DispatchLoadingEventAndReplaceReadyPromise); + task.mTarget = aFontFaceSet; + return task; + } + + static PostTraversalTask DispatchFontFaceSetCheckLoadingFinishedAfterDelay( + dom::FontFaceSet* aFontFaceSet) + { + auto task = + PostTraversalTask(Type::DispatchFontFaceSetCheckLoadingFinishedAfterDelay); + task.mTarget = aFontFaceSet; + return task; + } + + static PostTraversalTask LoadFontEntry(gfxUserFontEntry* aFontEntry) + { + auto task = PostTraversalTask(Type::LoadFontEntry); + task.mTarget = aFontEntry; + return task; + } + + void Run(); + +private: + // For any new raw pointer type that we need to store in a PostTraversalTask, + // please add an assertion that class' destructor that we are not in a Servo + // traversal, to protect against the possibility of having dangling pointers. + enum class Type + { + // mTarget (FontFace*) + ResolveFontFaceLoadedPromise, + + // mTarget (FontFace*) + // mResult + RejectFontFaceLoadedPromise, + + // mTarget (FontFaceSet*) + DispatchLoadingEventAndReplaceReadyPromise, + + // mTarget (FontFaceSet*) + DispatchFontFaceSetCheckLoadingFinishedAfterDelay, + + // mTarget (gfxUserFontEntry*) + LoadFontEntry, + }; + + explicit PostTraversalTask(Type aType) + : mType(aType) + , mTarget(nullptr) + , mResult(NS_OK) + { + } + + Type mType; + void* mTarget; + nsresult mResult; +}; + +} // namespace mozilla + +#endif // mozilla_PostTraversalTask_h diff --git a/layout/style/ServoBindings.cpp b/layout/style/ServoBindings.cpp index e83fdbb6b04a..c511e561e7b9 100644 --- a/layout/style/ServoBindings.cpp +++ b/layout/style/ServoBindings.cpp @@ -1328,6 +1328,18 @@ Gecko_CopyStyleGridTemplateValues(nsStyleGridTemplate* aGridTemplate, *aGridTemplate = *aOther; } +mozilla::css::GridTemplateAreasValue* +Gecko_NewGridTemplateAreasValue(uint32_t aAreas, uint32_t aTemplates, uint32_t aColumns) +{ + RefPtr value = new mozilla::css::GridTemplateAreasValue; + value->mNamedAreas.SetLength(aAreas); + value->mTemplates.SetLength(aTemplates); + value->mNColumns = aColumns; + return value.forget().take(); +} + +NS_IMPL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::GridTemplateAreasValue, GridTemplateAreasValue); + void Gecko_ClearAndResizeStyleContents(nsStyleContent* aContent, uint32_t aHowMany) { @@ -1821,6 +1833,19 @@ ShutdownServo() Servo_Shutdown(); } +namespace mozilla { + +void +AssertIsMainThreadOrServoFontMetricsLocked() +{ + if (!NS_IsMainThread()) { + MOZ_ASSERT(sServoFontMetricsLock); + sServoFontMetricsLock->AssertCurrentThreadOwns(); + } +} + +} // namespace mozilla + GeckoFontMetrics Gecko_GetFontMetrics(RawGeckoPresContextBorrowed aPresContext, bool aIsVertical, @@ -1828,13 +1853,20 @@ Gecko_GetFontMetrics(RawGeckoPresContextBorrowed aPresContext, nscoord aFontSize, bool aUseUserFontSet) { - // This function is still unsafe due to frobbing DOM and network - // off main thread. We currently disable it in Servo, see bug 1356105 - MOZ_ASSERT(NS_IsMainThread()); MutexAutoLock lock(*sServoFontMetricsLock); GeckoFontMetrics ret; - // Safe because we are locked, and this function is only - // ever called from Servo parallel traversal or the main thread + + // Getting font metrics can require some main thread only work to be + // done, such as work that needs to touch non-threadsafe refcounted + // objects (like the DOM FontFace/FontFaceSet objects), network loads, etc. + // + // To handle this work, font code checks whether we are in a Servo traversal + // and if so, appends PostTraversalTasks to the current ServoStyleSet + // to be performed immediately after the traversal is finished. This + // works well for starting downloadable font loads, since we don't have + // those fonts available to get metrics for anyway. Platform fonts and + // ArrayBuffer-backed FontFace objects are handled synchronously. + nsPresContext* presContext = const_cast(aPresContext); presContext->SetUsesExChUnits(true); RefPtr fm = nsRuleNode::GetMetricsFor(presContext, aIsVertical, diff --git a/layout/style/ServoBindings.h b/layout/style/ServoBindings.h index f41b9be65e6c..97c1358d4efa 100644 --- a/layout/style/ServoBindings.h +++ b/layout/style/ServoBindings.h @@ -334,6 +334,11 @@ void Gecko_ClearPODTArray(void* array, size_t elem_size, size_t elem_align); void Gecko_CopyStyleGridTemplateValues(nsStyleGridTemplate* grid_template, const nsStyleGridTemplate* other); +mozilla::css::GridTemplateAreasValue* Gecko_NewGridTemplateAreasValue(uint32_t areas, + uint32_t templates, + uint32_t columns); +NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::GridTemplateAreasValue, GridTemplateAreasValue); + // Clear the mContents, mCounterIncrements, or mCounterResets field in nsStyleContent. This is // needed to run the destructors, otherwise we'd leak the images, strings, and whatnot. void Gecko_ClearAndResizeStyleContents(nsStyleContent* content, diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp index 6b7f8cbf4d05..e1f8284eafc5 100644 --- a/layout/style/ServoStyleSet.cpp +++ b/layout/style/ServoStyleSet.cpp @@ -295,8 +295,7 @@ ServoStyleSet::PrepareAndTraverseSubtree(RawGeckoElementBorrowed aRoot, // is necessary to avoid a data race when updating the cache. mozilla::Unused << aRoot->OwnerDoc()->GetRootElement(); - MOZ_ASSERT(!sInServoTraversal); - sInServoTraversal = true; + AutoSetInServoTraversal guard(this); bool isInitial = !aRoot->HasServoData(); bool forReconstruct = @@ -338,7 +337,6 @@ ServoStyleSet::PrepareAndTraverseSubtree(RawGeckoElementBorrowed aRoot, } } - sInServoTraversal = false; return postTraversalRequired; } @@ -983,8 +981,8 @@ already_AddRefed ServoStyleSet::ResolveStyleLazily(Element* aElement, nsIAtom* aPseudoTag) { mPresContext->EffectCompositor()->PreTraverse(aElement, aPseudoTag); - MOZ_ASSERT(!sInServoTraversal); - sInServoTraversal = true; + + AutoSetInServoTraversal guard(this); /** * NB: This is needed because we process animations and transitions on the @@ -1023,8 +1021,6 @@ ServoStyleSet::ResolveStyleLazily(Element* aElement, nsIAtom* aPseudoTag) mRawSet.get()).Consume(); } - sInServoTraversal = false; - return computedValues.forget(); } @@ -1110,4 +1106,21 @@ ServoStyleSet::RemoveSheetOfType(SheetType aType, return 0; } -bool ServoStyleSet::sInServoTraversal = false; +void +ServoStyleSet::RunPostTraversalTasks() +{ + MOZ_ASSERT(!IsInServoTraversal()); + + if (mPostTraversalTasks.IsEmpty()) { + return; + } + + nsTArray tasks; + tasks.SwapElements(mPostTraversalTasks); + + for (auto& task : tasks) { + task.Run(); + } +} + +ServoStyleSet* ServoStyleSet::sInServoTraversal = nullptr; diff --git a/layout/style/ServoStyleSet.h b/layout/style/ServoStyleSet.h index cff75f8ba6f3..18822f0e304e 100644 --- a/layout/style/ServoStyleSet.h +++ b/layout/style/ServoStyleSet.h @@ -9,8 +9,10 @@ #include "mozilla/EnumeratedArray.h" #include "mozilla/EventStates.h" +#include "mozilla/PostTraversalTask.h" #include "mozilla/ServoBindingTypes.h" #include "mozilla/ServoElementSnapshot.h" +#include "mozilla/ServoUtils.h" #include "mozilla/StyleSheetInlines.h" #include "mozilla/SheetType.h" #include "mozilla/UniquePtr.h" @@ -85,6 +87,11 @@ public: return sInServoTraversal; } + static ServoStyleSet* Current() + { + return sInServoTraversal; + } + ServoStyleSet(); ~ServoStyleSet(); @@ -308,7 +315,44 @@ public: ComputeAnimationValue(RawServoDeclarationBlock* aDeclaration, const ServoComputedValuesWithParent& aComputedValues); + void AppendTask(PostTraversalTask aTask) + { + MOZ_ASSERT(IsInServoTraversal()); + + // We currently only use PostTraversalTasks while the Servo font metrics + // mutex is locked. If we need to use them in other situations during + // a traversal, we should assert that we've taken appropriate + // synchronization measures. + AssertIsMainThreadOrServoFontMetricsLocked(); + + mPostTraversalTasks.AppendElement(aTask); + } + private: + // On construction, sets sInServoTraversal to the given ServoStyleSet. + // On destruction, clears sInServoTraversal and calls RunPostTraversalTasks. + class MOZ_STACK_CLASS AutoSetInServoTraversal + { + public: + explicit AutoSetInServoTraversal(ServoStyleSet* aSet) + : mSet(aSet) + { + MOZ_ASSERT(!sInServoTraversal); + MOZ_ASSERT(aSet); + sInServoTraversal = aSet; + } + + ~AutoSetInServoTraversal() + { + MOZ_ASSERT(sInServoTraversal); + sInServoTraversal = nullptr; + mSet->RunPostTraversalTasks(); + } + + private: + ServoStyleSet* mSet; + }; + already_AddRefed GetContext(already_AddRefed, nsStyleContext* aParentContext, nsIAtom* aPseudoTag, @@ -356,6 +400,8 @@ private: already_AddRefed ResolveStyleLazily(dom::Element* aElement, nsIAtom* aPseudoTag); + void RunPostTraversalTasks(); + uint32_t FindSheetOfType(SheetType aType, ServoStyleSheet* aSheet); @@ -399,7 +445,13 @@ private: nsCSSAnonBoxes::NonInheriting::_Count, RefPtr> mNonInheritingStyleContexts; - static bool sInServoTraversal; + // Tasks to perform after a traversal, back on the main thread. + // + // These are similar to Servo's SequentialTasks, except that they are + // posted by C++ code running on style worker threads. + nsTArray mPostTraversalTasks; + + static ServoStyleSet* sInServoTraversal; }; } // namespace mozilla diff --git a/layout/style/ServoUtils.h b/layout/style/ServoUtils.h index 65cd544bbccd..cfc41ba95723 100644 --- a/layout/style/ServoUtils.h +++ b/layout/style/ServoUtils.h @@ -11,6 +11,13 @@ #include "mozilla/TypeTraits.h" +namespace mozilla { + +// Defined in ServoBindings.cpp. +void AssertIsMainThreadOrServoFontMetricsLocked(); + +} // namespace mozilla + #ifdef MOZ_STYLO # define MOZ_DECL_STYLO_CHECK_METHODS \ bool IsGecko() const { return !IsServo(); } \ diff --git a/layout/style/moz.build b/layout/style/moz.build index 9557a46dde19..ec913c0500d1 100644 --- a/layout/style/moz.build +++ b/layout/style/moz.build @@ -93,6 +93,7 @@ EXPORTS.mozilla += [ 'HandleRefPtr.h', 'IncrementalClearCOMRuleArray.h', 'LayerAnimationInfo.h', + 'PostTraversalTask.h', 'PreloadedStyleSheet.h', 'RuleNodeCacheConditions.h', 'RuleProcessorCache.h', @@ -219,6 +220,7 @@ UNIFIED_SOURCES += [ 'nsStyleTransformMatrix.cpp', 'nsStyleUtil.cpp', 'nsTransitionManager.cpp', + 'PostTraversalTask.cpp', 'PreloadedStyleSheet.cpp', 'RuleNodeCacheConditions.cpp', 'RuleProcessorCache.cpp', diff --git a/layout/style/nsCSSRules.cpp b/layout/style/nsCSSRules.cpp index f012ff995f18..ad7e618dbba2 100644 --- a/layout/style/nsCSSRules.cpp +++ b/layout/style/nsCSSRules.cpp @@ -1081,6 +1081,9 @@ nsCSSFontFaceStyleDecl::SetProperty(const nsAString & propertyName, const nsAString & value, const nsAString & priority) { + // FIXME(heycam): If we are changing unicode-range, then a FontFace object + // representing this rule must have its mUnicodeRange value invalidated. + return NS_ERROR_NOT_IMPLEMENTED; // bug 443978 } @@ -1296,6 +1299,9 @@ nsCSSFontFaceRule::SetDesc(nsCSSFontDesc aDescID, nsCSSValue const & aValue) // FIXME: handle dynamic changes + // FIXME(heycam): If we are changing unicode-range, then a FontFace object + // representing this rule must have its mUnicodeRange value invalidated. + mDecl.mDescriptors.Get(aDescID) = aValue; } diff --git a/layout/style/nsCSSValue.h b/layout/style/nsCSSValue.h index bd68b1bed0cf..daecbf4753f9 100644 --- a/layout/style/nsCSSValue.h +++ b/layout/style/nsCSSValue.h @@ -277,7 +277,7 @@ struct GridTemplateAreasValue final { return !(*this == aOther); } - NS_INLINE_DECL_REFCOUNTING(GridTemplateAreasValue) + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GridTemplateAreasValue) size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; diff --git a/layout/style/nsLayoutStylesheetCache.cpp b/layout/style/nsLayoutStylesheetCache.cpp index f891529c430e..5951db3d7b53 100644 --- a/layout/style/nsLayoutStylesheetCache.cpp +++ b/layout/style/nsLayoutStylesheetCache.cpp @@ -256,16 +256,22 @@ nsLayoutStylesheetCache::Shutdown() { gCSSLoader_Gecko = nullptr; gCSSLoader_Servo = nullptr; + MOZ_ASSERT(!gStyleCache_Gecko || !gUserContentSheetURL_Gecko, + "Got the URL but never used by Gecko?"); + MOZ_ASSERT(!gStyleCache_Servo || !gUserContentSheetURL_Servo, + "Got the URL but never used by Servo?"); gStyleCache_Gecko = nullptr; gStyleCache_Servo = nullptr; - gUserContentSheetURL = nullptr; + gUserContentSheetURL_Gecko = nullptr; + gUserContentSheetURL_Servo = nullptr; } void nsLayoutStylesheetCache::SetUserContentCSSURL(nsIURI* aURI) { MOZ_ASSERT(XRE_IsContentProcess(), "Only used in content processes."); - gUserContentSheetURL = aURI; + gUserContentSheetURL_Gecko = aURI; + gUserContentSheetURL_Servo = aURI; } MOZ_DEFINE_MALLOC_SIZE_OF(LayoutStylesheetCacheMallocSizeOf) @@ -351,10 +357,13 @@ nsLayoutStylesheetCache::nsLayoutStylesheetCache(StyleBackendType aType) XULSheet(); } - if (gUserContentSheetURL) { + auto& userContentSheetURL = aType == StyleBackendType::Gecko ? + gUserContentSheetURL_Gecko : + gUserContentSheetURL_Servo; + if (userContentSheetURL) { MOZ_ASSERT(XRE_IsContentProcess(), "Only used in content processes."); - LoadSheet(gUserContentSheetURL, &mUserContentSheet, eUserSheetFeatures, eLogToConsole); - gUserContentSheetURL = nullptr; + LoadSheet(userContentSheetURL, &mUserContentSheet, eUserSheetFeatures, eLogToConsole); + userContentSheetURL = nullptr; } // The remaining sheets are created on-demand do to their use being rarer @@ -1008,4 +1017,7 @@ mozilla::StaticRefPtr nsLayoutStylesheetCache::gCSSLoader_Servo; mozilla::StaticRefPtr -nsLayoutStylesheetCache::gUserContentSheetURL; +nsLayoutStylesheetCache::gUserContentSheetURL_Gecko; + +mozilla::StaticRefPtr +nsLayoutStylesheetCache::gUserContentSheetURL_Servo; diff --git a/layout/style/nsLayoutStylesheetCache.h b/layout/style/nsLayoutStylesheetCache.h index 48391cc7a164..08f76536152b 100644 --- a/layout/style/nsLayoutStylesheetCache.h +++ b/layout/style/nsLayoutStylesheetCache.h @@ -109,7 +109,8 @@ private: static mozilla::StaticRefPtr gStyleCache_Servo; static mozilla::StaticRefPtr gCSSLoader_Gecko; static mozilla::StaticRefPtr gCSSLoader_Servo; - static mozilla::StaticRefPtr gUserContentSheetURL; + static mozilla::StaticRefPtr gUserContentSheetURL_Gecko; + static mozilla::StaticRefPtr gUserContentSheetURL_Servo; mozilla::StyleBackendType mBackendType; RefPtr mChromePreferenceSheet; RefPtr mContentEditableSheet; diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 568ba3026281..b1afd272db3c 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -3234,141 +3234,6 @@ nsRuleNode::CalcFontPointSize(int32_t aHTMLSize, int32_t aBasePointSize, return (nscoord)1; } - -//------------------------------------------------------------------------------ -// -//------------------------------------------------------------------------------ - -/* static */ nscoord -nsRuleNode::FindNextSmallerFontSize(nscoord aFontSize, int32_t aBasePointSize, - nsPresContext* aPresContext, - nsFontSizeType aFontSizeType) -{ - int32_t index; - int32_t indexMin; - int32_t indexMax; - float relativePosition; - nscoord smallerSize; - nscoord indexFontSize = aFontSize; // XXX initialize to quell a spurious gcc3.2 warning - nscoord smallestIndexFontSize; - nscoord largestIndexFontSize; - nscoord smallerIndexFontSize; - nscoord largerIndexFontSize; - - nscoord onePx = nsPresContext::CSSPixelsToAppUnits(1); - - if (aFontSizeType == eFontSize_HTML) { - indexMin = 1; - indexMax = 7; - } else { - indexMin = 0; - indexMax = 6; - } - - smallestIndexFontSize = CalcFontPointSize(indexMin, aBasePointSize, aPresContext, aFontSizeType); - largestIndexFontSize = CalcFontPointSize(indexMax, aBasePointSize, aPresContext, aFontSizeType); - if (aFontSize > smallestIndexFontSize) { - if (aFontSize < NSToCoordRound(float(largestIndexFontSize) * 1.5)) { // smaller will be in HTML table - // find largest index smaller than current - for (index = indexMax; index >= indexMin; index--) { - indexFontSize = CalcFontPointSize(index, aBasePointSize, aPresContext, aFontSizeType); - if (indexFontSize < aFontSize) - break; - } - // set up points beyond table for interpolation purposes - if (indexFontSize == smallestIndexFontSize) { - smallerIndexFontSize = indexFontSize - onePx; - largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType); - } else if (indexFontSize == largestIndexFontSize) { - smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType); - largerIndexFontSize = NSToCoordRound(float(largestIndexFontSize) * 1.5); - } else { - smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType); - largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType); - } - // compute the relative position of the parent size between the two closest indexed sizes - relativePosition = float(aFontSize - indexFontSize) / float(largerIndexFontSize - indexFontSize); - // set the new size to have the same relative position between the next smallest two indexed sizes - smallerSize = smallerIndexFontSize + NSToCoordRound(relativePosition * (indexFontSize - smallerIndexFontSize)); - } - else { // larger than HTML table, drop by 33% - smallerSize = NSToCoordRound(float(aFontSize) / 1.5); - } - } - else { // smaller than HTML table, drop by 1px - smallerSize = std::max(aFontSize - onePx, onePx); - } - return smallerSize; -} - -//------------------------------------------------------------------------------ -// -//------------------------------------------------------------------------------ - -/* static */ nscoord -nsRuleNode::FindNextLargerFontSize(nscoord aFontSize, int32_t aBasePointSize, - nsPresContext* aPresContext, - nsFontSizeType aFontSizeType) -{ - int32_t index; - int32_t indexMin; - int32_t indexMax; - float relativePosition; - nscoord adjustment; - nscoord largerSize; - nscoord indexFontSize = aFontSize; // XXX initialize to quell a spurious gcc3.2 warning - nscoord smallestIndexFontSize; - nscoord largestIndexFontSize; - nscoord smallerIndexFontSize; - nscoord largerIndexFontSize; - - nscoord onePx = nsPresContext::CSSPixelsToAppUnits(1); - - if (aFontSizeType == eFontSize_HTML) { - indexMin = 1; - indexMax = 7; - } else { - indexMin = 0; - indexMax = 6; - } - - smallestIndexFontSize = CalcFontPointSize(indexMin, aBasePointSize, aPresContext, aFontSizeType); - largestIndexFontSize = CalcFontPointSize(indexMax, aBasePointSize, aPresContext, aFontSizeType); - if (aFontSize > (smallestIndexFontSize - onePx)) { - if (aFontSize < largestIndexFontSize) { // larger will be in HTML table - // find smallest index larger than current - for (index = indexMin; index <= indexMax; index++) { - indexFontSize = CalcFontPointSize(index, aBasePointSize, aPresContext, aFontSizeType); - if (indexFontSize > aFontSize) - break; - } - // set up points beyond table for interpolation purposes - if (indexFontSize == smallestIndexFontSize) { - smallerIndexFontSize = indexFontSize - onePx; - largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType); - } else if (indexFontSize == largestIndexFontSize) { - smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType); - largerIndexFontSize = NSCoordSaturatingMultiply(largestIndexFontSize, 1.5); - } else { - smallerIndexFontSize = CalcFontPointSize(index-1, aBasePointSize, aPresContext, aFontSizeType); - largerIndexFontSize = CalcFontPointSize(index+1, aBasePointSize, aPresContext, aFontSizeType); - } - // compute the relative position of the parent size between the two closest indexed sizes - relativePosition = float(aFontSize - smallerIndexFontSize) / float(indexFontSize - smallerIndexFontSize); - // set the new size to have the same relative position between the next largest two indexed sizes - adjustment = NSCoordSaturatingNonnegativeMultiply(largerIndexFontSize - indexFontSize, relativePosition); - largerSize = NSCoordSaturatingAdd(indexFontSize, adjustment); - } - else { // larger than HTML table, increase by 50% - largerSize = NSCoordSaturatingMultiply(aFontSize, 1.5); - } - } - else { // smaller than HTML table, increase by 1px - largerSize = NSCoordSaturatingAdd(aFontSize, onePx); - } - return largerSize; -} - struct SetFontSizeCalcOps : public css::BasicCoordCalcOps, public css::FloatCoeffsAlreadyNormalizedOps { @@ -3477,20 +3342,10 @@ nsRuleNode::SetFontSize(nsPresContext* aPresContext, parentSize = nsStyleFont::UnZoomText(aPresContext, parentSize); } - if (NS_STYLE_FONT_SIZE_LARGER == value) { - *aSize = FindNextLargerFontSize(parentSize, - baseSize, aPresContext, eFontSize_CSS); + float factor = (NS_STYLE_FONT_SIZE_LARGER == value) ? 1.2f : (1.0f / 1.2f); + + *aSize = parentSize * factor; - NS_ASSERTION(*aSize >= parentSize, - "FindNextLargerFontSize failed"); - } - else { - *aSize = FindNextSmallerFontSize(parentSize, - baseSize, aPresContext, eFontSize_CSS); - NS_ASSERTION(*aSize < parentSize || - parentSize <= nsPresContext::CSSPixelsToAppUnits(1), - "FindNextSmallerFontSize failed"); - } } else { NS_NOTREACHED("unexpected value"); } diff --git a/layout/style/test/stylo-failures.md b/layout/style/test/stylo-failures.md index 893cf67a8139..b536b824d543 100644 --- a/layout/style/test/stylo-failures.md +++ b/layout/style/test/stylo-failures.md @@ -156,8 +156,6 @@ to mochitest command. * ... `-moz-min-content` [6] * ... `-moz-fit-content` [6] * ... `-moz-available` [4] - * several prefixed values in cursor property bug 1356072 - * test_value_storage.html `cursor` [4] * -webkit-{flex,inline-flex} for display servo/servo#15400 * test_webkit_flex_display.html [4] * Unsupported values diff --git a/media/libcubeb/cubeb-pulse-rs/README_MOZILLA b/media/libcubeb/cubeb-pulse-rs/README_MOZILLA index a4dd3f0d0c35..af1887687f78 100644 --- a/media/libcubeb/cubeb-pulse-rs/README_MOZILLA +++ b/media/libcubeb/cubeb-pulse-rs/README_MOZILLA @@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system. The cubeb-pulse-rs git repository is: https://github.com/djg/cubeb-pulse-rs.git -The git commit ID used was faa1dcf3a061144c1f7edee76f23691eabd1f436 (2017-04-20 11:23:09 +1000) +The git commit ID used was dbcd7f96aea8d249a4b78f9a7597768c9dff22eb (2017-04-25 11:42:10 +1000) diff --git a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/errors.rs b/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/errors.rs deleted file mode 100644 index a6e084f3d7d4..000000000000 --- a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/errors.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub const OK: i32 = 0; -pub const ERROR: i32 = -1; -pub const ERROR_INVALID_FORMAT: i32 = -2; -pub const ERROR_INVALID_PARAMETER: i32 = -3; -pub const ERROR_NOT_SUPPORTED: i32 = -4; -pub const ERROR_DEVICE_UNAVAILABLE: i32 = -5; diff --git a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs b/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs index 13a1306fc56c..e717e7043b8f 100644 --- a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs +++ b/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs @@ -487,7 +487,7 @@ fn bindgen_test_layout_cubeb_device_info() { #[test] fn bindgen_test_layout_cubeb_device_collection() { assert_eq!(::std::mem::size_of::(), - 16usize, + 8usize, concat!("Size of: ", stringify!(DeviceCollection))); assert_eq!(::std::mem::align_of::(), 8usize, @@ -506,15 +506,3 @@ fn bindgen_test_layout_cubeb_device_collection() { stringify!(device))); } - -#[test] -fn test_normal_logging() { - log!("This is log at normal level"); - log!("This is {} at normal level", "log with param"); -} - -#[test] -fn test_verbose_logging() { - logv!("This is a log at verbose level"); - logv!("This is {} at verbose level", "log with param"); -} diff --git a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/internal.rs b/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/internal.rs deleted file mode 100644 index 8a3315671073..000000000000 --- a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/internal.rs +++ /dev/null @@ -1,34 +0,0 @@ -use libc::c_void; -use *; - -#[repr(C)] -#[derive(Clone,Copy,Debug)] -pub struct LayoutMap { - pub name: *const i8, - pub channels: u32, - pub layout: ChannelLayout -} - -#[repr(C)] -pub struct Ops { - pub init: Option i32>, - pub get_backend_id: Option *const i8>, - pub get_max_channel_count: Option i32>, - pub get_min_latency: Option i32>, - pub get_preferred_sample_rate: Option i32>, - pub get_preferred_channel_layout: Option i32>, - pub enumerate_devices: Option i32>, - pub destroy: Option, - pub stream_init: Option i32>, - pub stream_destroy: Option, - pub stream_start: Option i32>, - pub stream_stop: Option i32>, - pub stream_get_position: Option i32>, - pub stream_get_latency: Option i32>, - pub stream_set_volume: Option i32>, - pub stream_set_panning: Option i32>, - pub stream_get_current_device: Option i32>, - pub stream_device_destroy: Option i32>, - pub stream_register_device_changed_callback: Option i32>, - pub register_device_collection_changed: Option i32> -} diff --git a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/log.rs b/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/log.rs index da955edcd85a..9ae5b0e00721 100644 --- a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/log.rs +++ b/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/log.rs @@ -53,6 +53,10 @@ extern "C" { pub static g_cubeb_log_callback: LogCallback; } +pub fn log_enabled() -> bool { + unsafe { g_cubeb_log_level != LogLevel::Disabled } +} + #[test] fn test_normal_logging() { log!("This is log at normal level"); @@ -64,3 +68,8 @@ fn test_verbose_logging() { logv!("This is a log at verbose level"); logv!("Formatted log %d", 1); } + +#[test] +fn test_logging_disabled_by_default() { + assert!(!log_enabled()); +} diff --git a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/types/device_fmt.rs b/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/types/device_fmt.rs deleted file mode 100644 index 8ebcce53ae1d..000000000000 --- a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/types/device_fmt.rs +++ /dev/null @@ -1,89 +0,0 @@ -use std::ops; - -#[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct DeviceFmt(u32); - -const DEVICE_FMT_S16LE: u32 = 0x0010; -const DEVICE_FMT_S16BE: u32 = 0x0020; -const DEVICE_FMT_F32LE: u32 = 0x1000; -const DEVICE_FMT_F32BE: u32 = 0x2000; -const DEVICE_FMT_S16_MASK: u32 = DEVICE_FMT_S16LE | DEVICE_FMT_S16BE; -const DEVICE_FMT_F32_MASK: u32 = DEVICE_FMT_F32LE | DEVICE_FMT_F32BE; -const DEVICE_FMT_ALL: u32 = DEVICE_FMT_S16_MASK | DEVICE_FMT_F32_MASK; - - -impl DeviceFmt { - pub fn empty() -> Self { DeviceFmt(0) } - - #[inline] pub fn s16le() -> Self { DeviceFmt(DEVICE_FMT_S16LE) } - #[inline] pub fn s16be() -> Self { DeviceFmt(DEVICE_FMT_S16BE) } - #[inline] pub fn f32le() -> Self { DeviceFmt(DEVICE_FMT_F32LE) } - #[inline] pub fn f32be() -> Self { DeviceFmt(DEVICE_FMT_F32BE) } - #[inline] pub fn all() -> Self { DeviceFmt(DEVICE_FMT_ALL) } - - #[inline] pub fn s16ne() -> Self { - if cfg!(target_endian = "little") { - DeviceFmt::s16le() - } else { - DeviceFmt::s16be() - } - } - - #[inline] pub fn f32ne() -> Self { - if cfg!(target_endian = "little") { - DeviceFmt::f32le() - } else { - DeviceFmt::f32be() - } - } - - #[inline] pub fn contains(&self, other: Self) -> bool { (*self & other) == other } - #[inline] pub fn insert(&mut self, other: Self) { self.0 |= other.0; } - #[inline] pub fn remove(&mut self, other: Self) { self.0 &= !other.0; } -} - -impl ops::BitOr for DeviceFmt { - type Output = DeviceFmt; - - #[inline] - fn bitor(self, other: Self) -> Self { - DeviceFmt(self.0 | other.0) - } -} - -impl ops::BitXor for DeviceFmt { - type Output = DeviceFmt; - - #[inline] - fn bitxor(self, other: Self) -> Self { - DeviceFmt(self.0 ^ other.0) - } -} - -impl ops::BitAnd for DeviceFmt { - type Output = DeviceFmt; - - #[inline] - fn bitand(self, other: Self) -> Self { - DeviceFmt(self.0 & other.0) - } -} - -impl ops::Sub for DeviceFmt { - type Output = DeviceFmt; - - #[inline] - fn sub(self, other: Self) -> Self { - DeviceFmt(self.0 & !other.0) - } -} - -impl ops::Not for DeviceFmt { - type Output = DeviceFmt; - - #[inline] - fn not(self) -> Self { - DeviceFmt(!self.0 & DEVICE_FMT_ALL) - } -} diff --git a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/types/device_pref.rs b/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/types/device_pref.rs deleted file mode 100644 index be30ed7fe6d0..000000000000 --- a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/types/device_pref.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::ops; - -#[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct DevicePref(u32); - -const DEVICE_PREF_MULTIMEDIA: u32 = 0x1; -const DEVICE_PREF_VOICE: u32 = 0x2; -const DEVICE_PREF_NOTIFICATION: u32 = 0x4; -const DEVICE_PREF_ALL: u32 = 0xF; - -impl DevicePref { - pub fn none() -> Self { DevicePref(0) } - - #[inline] pub fn multimedia() -> Self { DevicePref(DEVICE_PREF_MULTIMEDIA) } - #[inline] pub fn voice() -> Self { DevicePref(DEVICE_PREF_VOICE) } - #[inline] pub fn notification() -> Self { DevicePref(DEVICE_PREF_NOTIFICATION) } - #[inline] pub fn all() -> Self { DevicePref(DEVICE_PREF_ALL) } - - #[inline] pub fn contains(&self, other: Self) -> bool { (*self & other) == other } - #[inline] pub fn insert(&mut self, other: Self) { self.0 |= other.0; } - #[inline] pub fn remove(&mut self, other: Self) { self.0 &= !other.0; } -} - -impl ops::BitOr for DevicePref { - type Output = DevicePref; - - #[inline] - fn bitor(self, other: Self) -> Self { - DevicePref(self.0 | other.0) - } -} - -impl ops::BitXor for DevicePref { - type Output = DevicePref; - - #[inline] - fn bitxor(self, other: Self) -> Self { - DevicePref(self.0 ^ other.0) - } -} - -impl ops::BitAnd for DevicePref { - type Output = DevicePref; - - #[inline] - fn bitand(self, other: Self) -> Self { - DevicePref(self.0 & other.0) - } -} - -impl ops::Sub for DevicePref { - type Output = DevicePref; - - #[inline] - fn sub(self, other: Self) -> Self { - DevicePref(self.0 & !other.0) - } -} - -impl ops::Not for DevicePref { - type Output = DevicePref; - - #[inline] - fn not(self) -> Self { - DevicePref(!self.0 & DEVICE_PREF_ALL) - } -} diff --git a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/types/device_type.rs b/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/types/device_type.rs deleted file mode 100644 index 614d260a50e6..000000000000 --- a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/types/device_type.rs +++ /dev/null @@ -1,70 +0,0 @@ -use std::ops; - -#[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct DeviceType(u32); - -const DEVICE_TYPE_UNKNOWN: u32 = 0b00; -const DEVICE_TYPE_INPUT:u32 = 0b01; -const DEVICE_TYPE_OUTPUT: u32 = 0b10; -const DEVICE_TYPE_ALL: u32 = 0b11; - -impl DeviceType { - pub fn unknown() -> Self { DeviceType(DEVICE_TYPE_UNKNOWN) } - - #[inline] pub fn input() -> Self { DeviceType(DEVICE_TYPE_INPUT) } - #[inline] pub fn output() -> Self { DeviceType(DEVICE_TYPE_OUTPUT) } - #[inline] pub fn all() -> Self { DeviceType(DEVICE_TYPE_ALL) } - - #[inline] pub fn is_input(&self) -> bool { self.contains(DeviceType::input()) } - #[inline] pub fn is_output(&self) -> bool { self.contains(DeviceType::output()) } - - #[inline] pub fn contains(&self, other: Self) -> bool { (*self & other) == other } - #[inline] pub fn insert(&mut self, other: Self) { self.0 |= other.0; } - #[inline] pub fn remove(&mut self, other: Self) { self.0 &= !other.0; } -} - -impl ops::BitOr for DeviceType { - type Output = DeviceType; - - #[inline] - fn bitor(self, other: Self) -> Self { - DeviceType(self.0 | other.0) - } -} - -impl ops::BitXor for DeviceType { - type Output = DeviceType; - - #[inline] - fn bitxor(self, other: Self) -> Self { - DeviceType(self.0 ^ other.0) - } -} - -impl ops::BitAnd for DeviceType { - type Output = DeviceType; - - #[inline] - fn bitand(self, other: Self) -> Self { - DeviceType(self.0 & other.0) - } -} - -impl ops::Sub for DeviceType { - type Output = DeviceType; - - #[inline] - fn sub(self, other: Self) -> Self { - DeviceType(self.0 & !other.0) - } -} - -impl ops::Not for DeviceType { - type Output = DeviceType; - - #[inline] - fn not(self) -> Self { - DeviceType(!self.0 & DEVICE_TYPE_ALL) - } -} diff --git a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/types/mod.rs b/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/types/mod.rs deleted file mode 100644 index ba97122a591e..000000000000 --- a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/types/mod.rs +++ /dev/null @@ -1,323 +0,0 @@ -use libc::c_void; - -mod device_pref; -mod device_fmt; -mod device_type; - -pub use self::device_pref::*; -pub use self::device_fmt::*; -pub use self::device_type::*; - -/// Opaque handle to cubeb context. -pub enum Context {} - -/// Opaque handle to cubeb stream. -pub enum Stream {} - -#[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum SampleFormat { - Signed16LE = 0, - Signed16BE = 1, - Float32LE = 2, - Float32BE = 3, -} - -#[cfg(target_endian = "little")] -pub const SAMPLE_S16NE: SampleFormat = SampleFormat::Signed16LE; -#[cfg(target_endian = "little")] -pub const SAMPLE_FLOAT32NE: SampleFormat = SampleFormat::Float32LE; -#[cfg(target_endian = "big")] -pub const SAMPLE_S16NE: SampleFormat = SampleFormat::Signed16BE; -#[cfg(target_endian = "big")] -pub const SAMPLE_FLOAT32NE: SampleFormat = SampleFormat::Float32BE; - -pub type DeviceId = *const c_void; - -#[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum ChannelLayout { - Undefined = 0, - DualMono = 1, - DualMonoLfe = 2, - Mono = 3, - MonoLfe = 4, - Stereo = 5, - StereoLfe = 6, - Layout3F = 7, - Layout3FLfe = 8, - Layout2F1 = 9, - Layout2F1Lfe = 10, - Layout3F1 = 11, - Layout3F1Lfe = 12, - Layout2F2 = 13, - Layout2F2Lfe = 14, - Layout3F2 = 15, - Layout3F2Lfe = 16, - Layout3F3RLfe = 17, - Layout3F4Lfe = 18, - Max = 19, -} - -#[repr(C)] -#[derive(Copy, Clone, Debug)] -pub struct StreamParams { - pub format: SampleFormat, - pub rate: u32, - pub channels: u32, - pub layout: ChannelLayout, -} - -#[repr(C)] -#[derive(Copy, Clone, Debug)] -pub struct Device { - pub output_name: *mut i8, - pub input_name: *mut i8, -} - -impl Default for Device { - fn default() -> Self { - Device { - output_name: 0 as *mut _, - input_name: 0 as *mut _, - } - } -} - -#[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum State { - Started = 0, - Stopped = 1, - Drained = 2, - Error = 3, -} - -#[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum DeviceState { - Disabled = 0, - Unplugged = 1, - Enabled = 2, -} - -#[repr(C)] -#[derive(Copy, Clone, Debug)] -pub struct DeviceInfo { - pub devid: DeviceId, - pub device_id: *const i8, - pub friendly_name: *const i8, - pub group_id: *const i8, - pub vendor_name: *const i8, - pub devtype: DeviceType, - pub state: DeviceState, - pub preferred: DevicePref, - pub format: DeviceFmt, - pub default_format: DeviceFmt, - pub max_channels: u32, - pub default_rate: u32, - pub max_rate: u32, - pub min_rate: u32, - pub latency_lo: u32, - pub latency_hi: u32, -} - -#[repr(C)] -#[derive(Copy, Clone, Debug)] -pub struct DeviceCollection { - /// Device count in collection. - pub count: u32, - /// Array of pointers to device info. - pub device: [*const DeviceInfo; 0], -} - -pub type DataCallback = Option i64>; -pub type StateCallback = Option; -pub type DeviceChangedCallback = Option; -pub type DeviceCollectionChangedCallback = Option; -pub type LogCallback = Option; - -#[test] -fn bindgen_test_layout_stream_params() { - assert_eq!(::std::mem::size_of::(), - 16usize, - concat!("Size of: ", stringify!(StreamParams))); - assert_eq!(::std::mem::align_of::(), - 4usize, - concat!("Alignment of ", stringify!(StreamParams))); - assert_eq!(unsafe { &(*(0 as *const StreamParams)).format as *const _ as usize }, - 0usize, - concat!("Alignment of field: ", - stringify!(StreamParams), - "::", - stringify!(format))); - assert_eq!(unsafe { &(*(0 as *const StreamParams)).rate as *const _ as usize }, - 4usize, - concat!("Alignment of field: ", - stringify!(StreamParams), - "::", - stringify!(rate))); - assert_eq!(unsafe { &(*(0 as *const StreamParams)).channels as *const _ as usize }, - 8usize, - concat!("Alignment of field: ", - stringify!(StreamParams), - "::", - stringify!(channels))); - assert_eq!(unsafe { &(*(0 as *const StreamParams)).layout as *const _ as usize }, - 12usize, - concat!("Alignment of field: ", - stringify!(StreamParams), - "::", - stringify!(layout))); -} - -#[test] -fn bindgen_test_layout_cubeb_device() { - assert_eq!(::std::mem::size_of::(), - 16usize, - concat!("Size of: ", stringify!(Device))); - assert_eq!(::std::mem::align_of::(), - 8usize, - concat!("Alignment of ", stringify!(Device))); - assert_eq!(unsafe { &(*(0 as *const Device)).output_name as *const _ as usize }, - 0usize, - concat!("Alignment of field: ", - stringify!(Device), - "::", - stringify!(output_name))); - assert_eq!(unsafe { &(*(0 as *const Device)).input_name as *const _ as usize }, - 8usize, - concat!("Alignment of field: ", - stringify!(Device), - "::", - stringify!(input_name))); -} - -#[test] -fn bindgen_test_layout_cubeb_device_info() { - assert_eq!(::std::mem::size_of::(), - 88usize, - concat!("Size of: ", stringify!(DeviceInfo))); - assert_eq!(::std::mem::align_of::(), - 8usize, - concat!("Alignment of ", stringify!(DeviceInfo))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).devid as *const _ as usize }, - 0usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(devid))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).device_id as *const _ as usize }, - 8usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(device_id))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).friendly_name as *const _ as usize }, - 16usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(friendly_name))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).group_id as *const _ as usize }, - 24usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(group_id))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).vendor_name as *const _ as usize }, - 32usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(vendor_name))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).devtype as *const _ as usize }, - 40usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(type_))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).state as *const _ as usize }, - 44usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(state))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).preferred as *const _ as usize }, - 48usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(preferred))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).format as *const _ as usize }, - 52usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(format))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).default_format as *const _ as usize }, - 56usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(default_format))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).max_channels as *const _ as usize }, - 60usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(max_channels))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).default_rate as *const _ as usize }, - 64usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(default_rate))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).max_rate as *const _ as usize }, - 68usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(max_rate))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).min_rate as *const _ as usize }, - 72usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(min_rate))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).latency_lo as *const _ as usize }, - 76usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(latency_lo))); - assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).latency_hi as *const _ as usize }, - 80usize, - concat!("Alignment of field: ", - stringify!(DeviceInfo), - "::", - stringify!(latency_hi))); -} - -#[test] -fn bindgen_test_layout_cubeb_device_collection() { - assert_eq!(::std::mem::size_of::(), - 8usize, - concat!("Size of: ", stringify!(DeviceCollection))); - assert_eq!(::std::mem::align_of::(), - 8usize, - concat!("Alignment of ", stringify!(DeviceCollection))); - assert_eq!(unsafe { &(*(0 as *const DeviceCollection)).count as *const _ as usize }, - 0usize, - concat!("Alignment of field: ", - stringify!(DeviceCollection), - "::", - stringify!(count))); - assert_eq!(unsafe { &(*(0 as *const DeviceCollection)).device as *const _ as usize }, - 8usize, - concat!("Alignment of field: ", - stringify!(DeviceCollection), - "::", - stringify!(device))); - -} diff --git a/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs b/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs index 982f9546663b..ed87b0ae56cb 100644 --- a/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs +++ b/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs @@ -694,7 +694,7 @@ unsafe extern "C" fn pulse_subscribe_callback(_ctx: *mut pa_context, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_SINK => { - if cubeb::g_cubeb_log_level != cubeb::LogLevel::Disabled { + if cubeb::log_enabled() { if (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE && (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE { log!("Removing sink index %d", index); diff --git a/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs b/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs index 96a9fd2d8c2e..0aa3861189c9 100644 --- a/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs +++ b/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs @@ -190,7 +190,7 @@ impl<'ctx> Stream<'ctx> { return Err(cubeb::ERROR); } - if cubeb::g_cubeb_log_level != cubeb::LogLevel::Disabled { + if cubeb::log_enabled() { if output_stream_params.is_some() { let output_att = *pa_stream_get_buffer_attr(stm.output_stream); log!("Output buffer attributes maxlength %u, tlength %u, \ diff --git a/mfbt/WeakPtr.h b/mfbt/WeakPtr.h index ef0c19f4ef0c..f8bc65b6f58b 100644 --- a/mfbt/WeakPtr.h +++ b/mfbt/WeakPtr.h @@ -112,8 +112,11 @@ _empty = !p; \ } while (false) #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \ - MOZ_DIAGNOSTIC_ASSERT(_empty || _owningThread == std::this_thread::get_id(), \ - "WeakPtr used on multiple threads") + do { \ + if (!(_empty || _owningThread == std::this_thread::get_id())) { \ + WeakPtrTraits::AssertSafeToAccessFromNonOwningThread(); \ + } \ + } while (false) #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \ (that)->AssertThreadSafety(); @@ -140,6 +143,15 @@ template class SupportsWeakPtr; #define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T) #endif +template +struct WeakPtrTraits +{ + static void AssertSafeToAccessFromNonOwningThread() + { + MOZ_DIAGNOSTIC_ASSERT(false, "WeakPtr accessed from multiple threads"); + } +}; + namespace detail { // This can live beyond the lifetime of the class derived from diff --git a/mobile/android/components/extensions/test/mochitest/mochitest.ini b/mobile/android/components/extensions/test/mochitest/mochitest.ini index 4cd7c22b66c1..7cc03c5bb0e4 100644 --- a/mobile/android/components/extensions/test/mochitest/mochitest.ini +++ b/mobile/android/components/extensions/test/mochitest/mochitest.ini @@ -1,6 +1,7 @@ [DEFAULT] support-files = ../../../../../../toolkit/components/extensions/test/mochitest/test_ext_all_apis.js + ../../../../../../toolkit/components/extensions/test/mochitest/file_sample.html ../../../../../../toolkit/components/extensions/test/mochitest/chrome_cleanup_script.js context.html context_tabs_onUpdated_iframe.html diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/HardwareCodecCapabilityUtils.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/HardwareCodecCapabilityUtils.java index 1d9ea5827d70..dbfda195dfec 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/HardwareCodecCapabilityUtils.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/HardwareCodecCapabilityUtils.java @@ -15,6 +15,8 @@ import android.media.MediaCodecList; import android.os.Build; import android.util.Log; +import java.util.Locale; + public final class HardwareCodecCapabilityUtils { private static final String LOGTAG = "GeckoHardwareCodecCapabilityUtils"; @@ -37,6 +39,11 @@ public final class HardwareCodecCapabilityUtils { CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar, COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m }; + private static final String[] adaptivePlaybackBlacklist = + { + "GT-I9300", // S3 (I9300 / I9300I) + "SCH-I535" // S3 + }; @WrapForJNI public static boolean findDecoderCodecInfoForMimeType(String aMimeType) { @@ -64,21 +71,45 @@ public final class HardwareCodecCapabilityUtils { @WrapForJNI public static boolean checkSupportsAdaptivePlayback(MediaCodec aCodec, String aMimeType) { - // isFeatureSupported supported on API level >= 19. - if (!(Build.VERSION.SDK_INT >= 19)) { - return false; - } - - try { - MediaCodecInfo info = aCodec.getCodecInfo(); - MediaCodecInfo.CodecCapabilities capabilities = info.getCapabilitiesForType(aMimeType); - return capabilities != null && - capabilities.isFeatureSupported( - MediaCodecInfo.CodecCapabilities.FEATURE_AdaptivePlayback); - } catch (IllegalArgumentException e) { - Log.e(LOGTAG, "Retrieve codec information failed", e); - } + // isFeatureSupported supported on API level >= 19. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT || + isAdaptivePlaybackBlacklisted(aMimeType)) { return false; + } + + try { + MediaCodecInfo info = aCodec.getCodecInfo(); + MediaCodecInfo.CodecCapabilities capabilities = info.getCapabilitiesForType(aMimeType); + return capabilities != null && + capabilities.isFeatureSupported( + MediaCodecInfo.CodecCapabilities.FEATURE_AdaptivePlayback); + } catch (IllegalArgumentException e) { + Log.e(LOGTAG, "Retrieve codec information failed", e); + } + return false; + } + + // See Bug1360626 and + // https://codereview.chromium.org/1869103002 for details. + private static boolean isAdaptivePlaybackBlacklisted(String aMimeType) { + if (!aMimeType.equals("video/avc") && !aMimeType.equals("video/avc1")) { + return false; + } + + if (!Build.VERSION.RELEASE.equals("4.4.2")) { + return false; + } + + if (!Build.MANUFACTURER.toLowerCase(Locale.getDefault()).equals("samsung")) { + return false; + } + + for (String model : adaptivePlaybackBlacklist) { + if (Build.MODEL.startsWith(model)) { + return true; + } + } + return false; } public static boolean getHWEncoderCapability() { diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index f7b772ebdbfb..c51b8f0724c4 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -296,11 +296,11 @@ pref("media.dormant-on-pause-timeout-ms", 5000); pref("media.cache_size", 512000); // When a network connection is suspended, don't resume it until the // amount of buffered data falls below this threshold (in seconds). -pref("media.cache_resume_threshold", 999999); +pref("media.cache_resume_threshold", 30); // Stop reading ahead when our buffered data is this many seconds ahead // of the current playback position. This limit can stop us from using arbitrary // amounts of network bandwidth prefetching huge videos. -pref("media.cache_readahead_limit", 999999); +pref("media.cache_readahead_limit", 60); // Master HTML5 media volume scale. pref("media.volume_scale", "1.0"); diff --git a/netwerk/base/CaptivePortalService.cpp b/netwerk/base/CaptivePortalService.cpp index a026b591210e..f97fb41d7e65 100644 --- a/netwerk/base/CaptivePortalService.cpp +++ b/netwerk/base/CaptivePortalService.cpp @@ -85,6 +85,13 @@ CaptivePortalService::RearmTimer() mTimer->Cancel(); } + // If we have successfully determined the state, and we have never detected + // a captive portal, we don't need to keep polling, but will rely on events + // to trigger detection. + if (mState == NOT_CAPTIVE) { + return NS_OK; + } + if (!mTimer) { mTimer = do_CreateInstance(NS_TIMER_CONTRACTID); } diff --git a/parser/htmlparser/tests/reftest/reftest.list b/parser/htmlparser/tests/reftest/reftest.list index db6ccd315baa..a549c9481d78 100644 --- a/parser/htmlparser/tests/reftest/reftest.list +++ b/parser/htmlparser/tests/reftest/reftest.list @@ -1,5 +1,5 @@ == bug535530-1.html bug535530-1-ref.html -fails-if(stylo) == view-source:bug535530-2.html bug535530-2-ref.html +== view-source:bug535530-2.html bug535530-2-ref.html == bug566280-1.html bug566280-1-ref.html == bug569229-1.xml bug569229-1-ref.xml == bug577418-1.html bug577418-1-ref.html @@ -8,19 +8,19 @@ fuzzy-if(skiaContent,2,5) == bug582940-1.html bug582940-1-ref.html == bug592656-1.html bug592656-1-ref.html fuzzy-if(skiaContent,1,5) == bug599320-1.html bug599320-1-ref.html fuzzy-if(skiaContent,2,5) == bug608373-1.html bug608373-1-ref.html -fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia,73,1) fails-if(stylo) == view-source:bug482921-1.html bug482921-1-ref.html -fails-if(stylo) == view-source:bug482921-2.xhtml bug482921-2-ref.html +fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia,73,1) == view-source:bug482921-1.html bug482921-1-ref.html +== view-source:bug482921-2.xhtml bug482921-2-ref.html fuzzy-if(skiaContent,2,5) == bug659763-1.html bug659763-1-ref.html fuzzy-if(skiaContent,1,5) == bug659763-2.html bug659763-2-ref.html fuzzy-if(skiaContent,1,5) == bug659763-3.html bug659763-3-ref.html fuzzy-if(skiaContent,2,3) == bug659763-4.html bug659763-4-ref.html fuzzy-if(skiaContent,1,5) == bug659763-5.html bug659763-5-ref.html fuzzy-if(skiaContent,1,5) == bug659763-6.html bug659763-6-ref.html -fails-if(stylo) == view-source:bug673094-1.html view-source:bug673094-1-ref.html +== view-source:bug673094-1.html view-source:bug673094-1-ref.html == bug696651-1.html bug696651-1-ref.html == bug696651-2.html bug696651-2-ref.html -fails-if(stylo) == view-source:bug700260-1.html view-source:bug700260-1-ref.html -fails-if(stylo) == view-source:bug704667-1.html bug704667-1-ref.html -fails-if(stylo) == view-source:bug731234-1.html bug731234-1-ref.html +== view-source:bug700260-1.html view-source:bug700260-1-ref.html +== view-source:bug704667-1.html bug704667-1-ref.html +== view-source:bug731234-1.html bug731234-1-ref.html == bug820508-1.html bug820508-1-ref.html -fails-if(stylo) == view-source:bug910588-1.html bug910588-1-ref.html +== view-source:bug910588-1.html bug910588-1-ref.html diff --git a/security/manager/ssl/SSLServerCertVerification.cpp b/security/manager/ssl/SSLServerCertVerification.cpp index 7f4e4971a625..c23234276d51 100644 --- a/security/manager/ssl/SSLServerCertVerification.cpp +++ b/security/manager/ssl/SSLServerCertVerification.cpp @@ -110,7 +110,6 @@ #include "cert.h" #include "mozilla/Assertions.h" #include "mozilla/Casting.h" -#include "mozilla/Mutex.h" #include "mozilla/RefPtr.h" #include "mozilla/Telemetry.h" #include "mozilla/UniquePtr.h" @@ -150,14 +149,6 @@ namespace { // do not use a nsCOMPtr to avoid static initializer/destructor nsIThreadPool* gCertVerificationThreadPool = nullptr; -// We avoid using a mutex for the success case to avoid lock-related -// performance issues. However, we do use a lock in the error case to simplify -// the code, since performance in the error case is not important. -Mutex* gSSLVerificationTelemetryMutex = nullptr; - -// We add a mutex to serialize PKCS11 database operations -Mutex* gSSLVerificationPK11Mutex = nullptr; - } // unnamed namespace // Called when the socket transport thread starts, to initialize the SSL cert @@ -173,8 +164,6 @@ Mutex* gSSLVerificationPK11Mutex = nullptr; void InitializeSSLServerCertVerificationThreads() { - gSSLVerificationTelemetryMutex = new Mutex("SSLVerificationTelemetryMutex"); - gSSLVerificationPK11Mutex = new Mutex("SSLVerificationPK11Mutex"); // TODO: tuning, make parameters preferences // XXX: instantiate nsThreadPool directly, to make this more bulletproof. // Currently, the nsThreadPool.h header isn't exported for us to do so. @@ -207,14 +196,6 @@ void StopSSLServerCertVerificationThreads() gCertVerificationThreadPool->Shutdown(); NS_RELEASE(gCertVerificationThreadPool); } - if (gSSLVerificationTelemetryMutex) { - delete gSSLVerificationTelemetryMutex; - gSSLVerificationTelemetryMutex = nullptr; - } - if (gSSLVerificationPK11Mutex) { - delete gSSLVerificationPK11Mutex; - gSSLVerificationPK11Mutex = nullptr; - } } namespace { @@ -1609,11 +1590,10 @@ SSLServerCertVerificationJob::Run() // Note: the interval is not calculated once as PR_GetError MUST be called // before any other function call error = PR_GetError(); - { - TimeStamp now = TimeStamp::Now(); - MutexAutoLock telemetryMutex(*gSSLVerificationTelemetryMutex); - Telemetry::AccumulateTimeDelta(failureTelemetry, mJobStartTime, now); - } + + TimeStamp now = TimeStamp::Now(); + Telemetry::AccumulateTimeDelta(failureTelemetry, mJobStartTime, now); + if (error != 0) { RefPtr runnable( CreateCertErrorRunnable(*mCertVerifier, error, mInfoObject, mCert, @@ -1871,9 +1851,7 @@ SSLServerCertVerificationResult::Run() if (mTelemetryID != Telemetry::HistogramCount) { Telemetry::Accumulate(mTelemetryID, mTelemetryValue); } - // XXX: This cast will be removed by the next patch - ((nsNSSSocketInfo*) mInfoObject.get()) - ->SetCertVerificationResult(mErrorCode, mErrorMessageType); + mInfoObject->SetCertVerificationResult(mErrorCode, mErrorMessageType); return NS_OK; } diff --git a/services/sync/tps/extensions/tps/resource/tps.jsm b/services/sync/tps/extensions/tps/resource/tps.jsm index 5e2ae78641f6..faab2704f6e2 100644 --- a/services/sync/tps/extensions/tps/resource/tps.jsm +++ b/services/sync/tps/extensions/tps/resource/tps.jsm @@ -624,7 +624,7 @@ var TPS = { item.decrypt(collectionKey); items.push(item.cleartext); }; - collection.get(); + Async.promiseSpinningly(collection.get()); return items; }; let serverRecordDumpStr; diff --git a/servo/Cargo.lock b/servo/Cargo.lock index 96e0f655b125..3e2763875103 100644 --- a/servo/Cargo.lock +++ b/servo/Cargo.lock @@ -141,7 +141,7 @@ dependencies = [ [[package]] name = "base64" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -200,6 +200,11 @@ name = "bitflags" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitflags" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bitreader" version = "0.3.0" @@ -1192,7 +1197,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.9 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1695,7 +1700,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "net" version = "0.0.1" dependencies = [ - "base64 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "brotli 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "cookie 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "devtools_traits 0.0.1", @@ -1712,7 +1717,7 @@ dependencies = [ "mime_guess 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "net_traits 0.0.1", - "openssl 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)", "parse-hosts 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "profile_traits 0.0.1", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1911,10 +1916,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2259,7 +2264,7 @@ dependencies = [ "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "audio-video-metadata 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "base64 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "bluetooth_traits 0.0.1", "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2568,7 +2573,7 @@ dependencies = [ "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.9 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3172,7 +3177,7 @@ dependencies = [ name = "webdriver_server" version = "0.0.1" dependencies = [ - "base64 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "cookie 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3194,7 +3199,7 @@ dependencies = [ [[package]] name = "webrender" version = "0.36.0" -source = "git+https://github.com/servo/webrender#e44a079266a181ddaae2fd27298cec1094b54b7e" +source = "git+https://github.com/servo/webrender#c661afa3193b4d00c15509537a8d8fc33aa0c274" dependencies = [ "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.0.0-alpha6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3223,7 +3228,7 @@ dependencies = [ [[package]] name = "webrender_traits" version = "0.36.0" -source = "git+https://github.com/servo/webrender#e44a079266a181ddaae2fd27298cec1094b54b7e" +source = "git+https://github.com/servo/webrender#c661afa3193b4d00c15509537a8d8fc33aa0c274" dependencies = [ "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.0.0-alpha6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3354,13 +3359,14 @@ dependencies = [ "checksum azure 0.15.0 (git+https://github.com/servo/rust-azure)" = "" "checksum backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f551bc2ddd53aea015d453ef0b635af89444afa5ed2405dd0b2062ad5d600d80" "checksum backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d192fd129132fbc97497c1f2ec2c2c5174e376b95f535199ef4fe0a293d33842" -"checksum base64 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9892882c3bd89ed02dec391c128984c772b663a29700c32b5de0b33861cdf2bd" +"checksum base64 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "979d348dc50dfcd050a87df408ec61f01a0a27ee9b4ebdc6085baba8275b2c7f" "checksum binary-space-partition 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "df65281d9b2b5c332f5bfbd9bb5e5f2e62f627c259cf9dc9cd10fecb758be33d" "checksum bincode 1.0.0-alpha6 (registry+https://github.com/rust-lang/crates.io-index)" = "fb0cdeac1c5d567fdb487ae5853c024e4acf1ea85ba6a6552fe084e0805fea5d" "checksum bindgen 0.22.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88f9d9abd7964621201c558021ff4f39b7b4d571a9a56a88844da9971e2344ce" "checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c" "checksum bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5b97c2c8e8bbb4251754f559df8af22fb264853c7d009084a576cdf12565089d" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" "checksum bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80b13e2ab064ff3aa0bdbf1eff533f9822dc37899821f5f98c67f263eab51707" "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" "checksum blurdroid 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4a86fbb3818e7f850410e026bfac7742fe86cbf4acf49f5752936b32d1f7eb8" @@ -3493,7 +3499,7 @@ dependencies = [ "checksum ogg 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "013b78ceb7fb82555a2f8a95d8e40866fe64a5d15b83c51b3e1fdd40cd903ed3" "checksum ogg_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1753e64956b3afd900f788bf6d2e9d0986df39168be86f4b47ec2058d0c2f7" "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842" -"checksum openssl 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8aa0eb7aad44f0da6f7dda13ddb4559d91a0f40cfab150b1f76ad5b39ec523f" +"checksum openssl 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)" = "241bcf67b1bb8d19da97360a925730bdf5b6176d434ab8ded55b4ca632346e3a" "checksum openssl-sys 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e5e0fd64cb2fa018ed2e7b2c8d9649114fe5da957c9a67432957f01e5dcc82e9" "checksum ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da12c96037889ae0be29dd2bdd260e5a62a7df24e6466d5a15bb8131c1c200a8" "checksum osmesa-src 12.0.1 (git+https://github.com/servo/osmesa-src)" = "" diff --git a/servo/components/gfx/display_list/mod.rs b/servo/components/gfx/display_list/mod.rs index 77a64553c29f..f2aea7a97df8 100644 --- a/servo/components/gfx/display_list/mod.rs +++ b/servo/components/gfx/display_list/mod.rs @@ -86,7 +86,7 @@ impl DisplayList { scroll_offsets, result); } - &DisplayItem::PushScrollRoot(ref item) => { + &DisplayItem::DefineClip(ref item) => { let mut point = *translated_point; DisplayList::scroll_root(&item.scroll_root, &mut point, @@ -149,7 +149,7 @@ impl DisplayList { scroll_offsets, result); } - &DisplayItem::PushScrollRoot(ref item) => { + &DisplayItem::DefineClip(ref item) => { let mut point = *translated_point; DisplayList::scroll_root(&item.scroll_root, &mut point, @@ -160,7 +160,7 @@ impl DisplayList { scroll_offsets, result); } - &DisplayItem::PopStackingContext(_) | &DisplayItem::PopScrollRoot(_) => return, + &DisplayItem::PopStackingContext(_) => return, _ => { if let Some(meta) = item.hit_test(*translated_point) { result.push(meta); @@ -510,8 +510,8 @@ pub struct ScrollRoot { } impl ScrollRoot { - pub fn to_push(&self, pipeline_id: PipelineId) -> DisplayItem { - DisplayItem::PushScrollRoot(box PushScrollRootItem { + pub fn to_define_item(&self, pipeline_id: PipelineId) -> DisplayItem { + DisplayItem::DefineClip(box DefineClipItem { base: BaseDisplayItem::empty(pipeline_id), scroll_root: self.clone(), }) @@ -534,8 +534,7 @@ pub enum DisplayItem { Iframe(Box), PushStackingContext(Box), PopStackingContext(Box), - PushScrollRoot(Box), - PopScrollRoot(Box), + DefineClip(Box), } /// Information common to all display items. @@ -1123,7 +1122,7 @@ pub struct PopStackingContextItem { /// Starts a group of items inside a particular scroll root. #[derive(Clone, HeapSizeOf, Deserialize, Serialize)] -pub struct PushScrollRootItem { +pub struct DefineClipItem { /// Fields common to all display items. pub base: BaseDisplayItem, @@ -1159,8 +1158,7 @@ impl DisplayItem { DisplayItem::Iframe(ref iframe) => &iframe.base, DisplayItem::PushStackingContext(ref stacking_context) => &stacking_context.base, DisplayItem::PopStackingContext(ref item) => &item.base, - DisplayItem::PushScrollRoot(ref item) => &item.base, - DisplayItem::PopScrollRoot(ref base) => &base, + DisplayItem::DefineClip(ref item) => &item.base, } } @@ -1246,12 +1244,8 @@ impl fmt::Debug for DisplayItem { return write!(f, "PopStackingContext({:?}", item.stacking_context_id); } - if let DisplayItem::PushScrollRoot(ref item) = *self { - return write!(f, "PushScrollRoot({:?}", item.scroll_root); - } - - if let DisplayItem::PopScrollRoot(_) = *self { - return write!(f, "PopScrollRoot"); + if let DisplayItem::DefineClip(ref item) = *self { + return write!(f, "DefineClip({:?}", item.scroll_root); } write!(f, "{} @ {:?} {:?}", @@ -1277,8 +1271,7 @@ impl fmt::Debug for DisplayItem { DisplayItem::Iframe(_) => "Iframe".to_owned(), DisplayItem::PushStackingContext(_) | DisplayItem::PopStackingContext(_) | - DisplayItem::PushScrollRoot(_) | - DisplayItem::PopScrollRoot(_) => "".to_owned(), + DisplayItem::DefineClip(_) => "".to_owned(), }, self.bounds(), self.base().clip diff --git a/servo/components/layout/display_list_builder.rs b/servo/components/layout/display_list_builder.rs index 878b1220336e..d91050176a92 100644 --- a/servo/components/layout/display_list_builder.rs +++ b/servo/components/layout/display_list_builder.rs @@ -289,12 +289,12 @@ impl<'a> DisplayListBuildState<'a> { let pipeline_id = self.layout_context.id; if stacking_context.context_type != StackingContextType::Real { - list.extend(info.scroll_roots.into_iter().map(|root| root.to_push(pipeline_id))); + list.extend(info.scroll_roots.into_iter().map(|root| root.to_define_item(pipeline_id))); self.to_display_list_for_items(list, child_items, info.children); } else { let (push_item, pop_item) = stacking_context.to_display_list_items(pipeline_id); list.push(push_item); - list.extend(info.scroll_roots.into_iter().map(|root| root.to_push(pipeline_id))); + list.extend(info.scroll_roots.into_iter().map(|root| root.to_define_item(pipeline_id))); self.to_display_list_for_items(list, child_items, info.children); list.push(pop_item); } diff --git a/servo/components/layout/webrender_helpers.rs b/servo/components/layout/webrender_helpers.rs index aceebd8a19d0..eca0837d6a80 100644 --- a/servo/components/layout/webrender_helpers.rs +++ b/servo/components/layout/webrender_helpers.rs @@ -449,7 +449,7 @@ impl WebRenderDisplayItemConverter for DisplayItem { stacking_context.filters.to_filter_ops()); } DisplayItem::PopStackingContext(_) => builder.pop_stacking_context(), - DisplayItem::PushScrollRoot(ref item) => { + DisplayItem::DefineClip(ref item) => { builder.push_clip_id(item.scroll_root.parent_id); let our_id = item.scroll_root.id; @@ -460,7 +460,6 @@ impl WebRenderDisplayItemConverter for DisplayItem { builder.pop_clip_id(); } - DisplayItem::PopScrollRoot(_) => {} //builder.pop_scroll_layer(), } } } diff --git a/servo/components/net/Cargo.toml b/servo/components/net/Cargo.toml index 47f412f28fab..e241d55f908c 100644 --- a/servo/components/net/Cargo.toml +++ b/servo/components/net/Cargo.toml @@ -10,7 +10,7 @@ name = "net" path = "lib.rs" [dependencies] -base64 = "0.4.1" +base64 = "0.4.2" brotli = "1.0.6" cookie = "0.6" devtools_traits = {path = "../devtools_traits"} diff --git a/servo/components/script/Cargo.toml b/servo/components/script/Cargo.toml index 76facbdc2ec4..1266e7065823 100644 --- a/servo/components/script/Cargo.toml +++ b/servo/components/script/Cargo.toml @@ -28,7 +28,7 @@ angle = {git = "https://github.com/servo/angle", branch = "servo"} app_units = "0.4" audio-video-metadata = "0.1.2" atomic_refcell = "0.1" -base64 = "0.4.1" +base64 = "0.4.2" bitflags = "0.7" bluetooth_traits = {path = "../bluetooth_traits"} byteorder = "1.0" diff --git a/servo/components/script/dom/history.rs b/servo/components/script/dom/history.rs index 537e9cbbb222..5488d02d9bf3 100644 --- a/servo/components/script/dom/history.rs +++ b/servo/components/script/dom/history.rs @@ -6,7 +6,7 @@ use dom::bindings::codegen::Bindings::HistoryBinding; use dom::bindings::codegen::Bindings::HistoryBinding::HistoryMethods; use dom::bindings::codegen::Bindings::LocationBinding::LocationBinding::LocationMethods; use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; -use dom::bindings::error::Fallible; +use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::inheritance::Castable; use dom::bindings::js::{JS, Root}; use dom::bindings::reflector::{Reflector, reflect_dom_object}; @@ -40,27 +40,34 @@ impl History { } impl History { - fn traverse_history(&self, direction: TraversalDirection) { + fn traverse_history(&self, direction: TraversalDirection) -> ErrorResult { + if !self.window.Document().is_fully_active() { + return Err(Error::Security); + } let global_scope = self.window.upcast::(); let pipeline = global_scope.pipeline_id(); let msg = ConstellationMsg::TraverseHistory(Some(pipeline), direction); let _ = global_scope.constellation_chan().send(msg); + Ok(()) } } impl HistoryMethods for History { // https://html.spec.whatwg.org/multipage/#dom-history-length - fn Length(&self) -> u32 { + fn GetLength(&self) -> Fallible { + if !self.window.Document().is_fully_active() { + return Err(Error::Security); + } let global_scope = self.window.upcast::(); let pipeline = global_scope.pipeline_id(); let (sender, recv) = ipc::channel().expect("Failed to create channel to send jsh length."); let msg = ConstellationMsg::JointSessionHistoryLength(pipeline, sender); let _ = global_scope.constellation_chan().send(msg); - recv.recv().unwrap() + Ok(recv.recv().unwrap()) } // https://html.spec.whatwg.org/multipage/#dom-history-go - fn Go(&self, delta: i32) -> Fallible<()> { + fn Go(&self, delta: i32) -> ErrorResult { let direction = if delta > 0 { TraversalDirection::Forward(delta as usize) } else if delta < 0 { @@ -69,17 +76,16 @@ impl HistoryMethods for History { return self.window.Location().Reload(); }; - self.traverse_history(direction); - Ok(()) + self.traverse_history(direction) } // https://html.spec.whatwg.org/multipage/#dom-history-back - fn Back(&self) { - self.traverse_history(TraversalDirection::Back(1)); + fn Back(&self) -> ErrorResult { + self.traverse_history(TraversalDirection::Back(1)) } // https://html.spec.whatwg.org/multipage/#dom-history-forward - fn Forward(&self) { - self.traverse_history(TraversalDirection::Forward(1)); + fn Forward(&self) -> ErrorResult { + self.traverse_history(TraversalDirection::Forward(1)) } } diff --git a/servo/components/script/dom/webidls/History.webidl b/servo/components/script/dom/webidls/History.webidl index 56171470877b..d5b729961824 100644 --- a/servo/components/script/dom/webidls/History.webidl +++ b/servo/components/script/dom/webidls/History.webidl @@ -7,12 +7,20 @@ // https://html.spec.whatwg.org/multipage/#the-history-interface [Exposed=(Window,Worker)] interface History { + [Throws] readonly attribute unsigned long length; + // [Throws] // attribute ScrollRestoration scrollRestoration; + // [Throws] // readonly attribute any state; - [Throws] void go(optional long delta = 0); + [Throws] + void go(optional long delta = 0); + [Throws] void back(); + [Throws] void forward(); + // [Throws] // void pushState(any data, DOMString title, optional USVString? url = null); + // [Throws] // void replaceState(any data, DOMString title, optional USVString? url = null); }; diff --git a/servo/components/style/Cargo.toml b/servo/components/style/Cargo.toml index a7e262ec3229..dbd5e767457b 100644 --- a/servo/components/style/Cargo.toml +++ b/servo/components/style/Cargo.toml @@ -13,7 +13,7 @@ path = "lib.rs" doctest = false [features] -gecko = ["nsstring_vendor", "rayon/unstable", "num_cpus"] +gecko = ["nsstring_vendor", "rayon/unstable", "num_cpus", "style_traits/gecko"] use_bindgen = ["bindgen", "regex"] servo = ["serde/unstable", "serde", "serde_derive", "heapsize", "heapsize_derive", "style_traits/servo", "servo_atoms", "servo_config", "html5ever", diff --git a/servo/components/style/binding_tools/regen_atoms.py b/servo/components/style/binding_tools/regen_atoms.py index b14a30dd0e0c..0950c0d72120 100755 --- a/servo/components/style/binding_tools/regen_atoms.py +++ b/servo/components/style/binding_tools/regen_atoms.py @@ -51,7 +51,7 @@ class CSSPseudoElementsAtomSource: class CSSAnonBoxesAtomSource: - PATTERN = re.compile('^(?:CSS_ANON_BOX|CSS_NON_INHERITING_ANON_BOX)\((.+),\s*"(.*)"\)') + PATTERN = re.compile('^(?:CSS_ANON_BOX|CSS_NON_INHERITING_ANON_BOX)\((.+),\s*"(.*)"(\,|\))') FILE = "include/nsCSSAnonBoxList.h" CLASS = "nsCSSAnonBoxes" TYPE = "nsICSSAnonBoxPseudo" diff --git a/servo/components/style/build_gecko.rs b/servo/components/style/build_gecko.rs index 7b223e4eac4e..85d80fae1d4b 100644 --- a/servo/components/style/build_gecko.rs +++ b/servo/components/style/build_gecko.rs @@ -623,6 +623,7 @@ mod bindings { .whitelisted_function("Servo_.*") .whitelisted_function("Gecko_.*"); let structs_types = [ + "mozilla::css::GridTemplateAreasValue", "mozilla::css::URLValue", "mozilla::Side", "RawGeckoAnimationPropertySegment", diff --git a/servo/components/style/gecko/wrapper.rs b/servo/components/style/gecko/wrapper.rs index f71ef0a6c9c5..a8ed92192afc 100644 --- a/servo/components/style/gecko/wrapper.rs +++ b/servo/components/style/gecko/wrapper.rs @@ -22,7 +22,7 @@ use dom::{self, AnimationRules, DescendantsBit, LayoutIterator, NodeInfo, TEleme use dom::{OpaqueNode, PresentationalHintsSynthetizer}; use element_state::ElementState; use error_reporting::RustLogReporter; -use font_metrics::{FontMetricsProvider, FontMetricsQueryResult}; +use font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult}; use gecko::global_style_data::GLOBAL_STYLE_DATA; use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement}; use gecko::snapshot_helpers; @@ -476,25 +476,22 @@ impl FontMetricsProvider for GeckoFontMetricsProvider { sizes.size_for_generic(font_family) } - fn query(&self, _font: &Font, _font_size: Au, _wm: WritingMode, - _in_media_query: bool, _device: &Device) -> FontMetricsQueryResult { - // Disabled until we can make font metrics thread safe (bug 1356105) - // - // use gecko_bindings::bindings::Gecko_GetFontMetrics; - // let gecko_metrics = unsafe { - // Gecko_GetFontMetrics(&*device.pres_context, - // wm.is_vertical() && !wm.is_sideways(), - // font.gecko(), - // font_size.0, - // // we don't use the user font set in a media query - // !in_media_query) - // }; - // let metrics = FontMetrics { - // x_height: Au(gecko_metrics.mXSize), - // zero_advance_measure: Au(gecko_metrics.mChSize), - // }; - // FontMetricsQueryResult::Available(metrics) - FontMetricsQueryResult::NotAvailable + fn query(&self, font: &Font, font_size: Au, wm: WritingMode, + in_media_query: bool, device: &Device) -> FontMetricsQueryResult { + use gecko_bindings::bindings::Gecko_GetFontMetrics; + let gecko_metrics = unsafe { + Gecko_GetFontMetrics(&*device.pres_context, + wm.is_vertical() && !wm.is_sideways(), + font.gecko(), + font_size.0, + // we don't use the user font set in a media query + !in_media_query) + }; + let metrics = FontMetrics { + x_height: Au(gecko_metrics.mXSize), + zero_advance_measure: Au(gecko_metrics.mChSize), + }; + FontMetricsQueryResult::Available(metrics) } } diff --git a/servo/components/style/gecko_bindings/bindings.rs b/servo/components/style/gecko_bindings/bindings.rs index 4099761c6c3d..026881bf6098 100644 --- a/servo/components/style/gecko_bindings/bindings.rs +++ b/servo/components/style/gecko_bindings/bindings.rs @@ -3,6 +3,7 @@ pub use nsstring::{nsACString, nsAString, nsString}; type nsACString_internal = nsACString; type nsAString_internal = nsAString; +use gecko_bindings::structs::mozilla::css::GridTemplateAreasValue; use gecko_bindings::structs::mozilla::css::URLValue; use gecko_bindings::structs::mozilla::Side; use gecko_bindings::structs::RawGeckoAnimationPropertySegment; @@ -893,6 +894,19 @@ extern "C" { other: *const nsStyleGridTemplate); } +extern "C" { + pub fn Gecko_NewGridTemplateAreasValue(areas: u32, templates: u32, + columns: u32) + -> *mut GridTemplateAreasValue; +} +extern "C" { + pub fn Gecko_AddRefGridTemplateAreasValueArbitraryThread(aPtr: + *mut GridTemplateAreasValue); +} +extern "C" { + pub fn Gecko_ReleaseGridTemplateAreasValueArbitraryThread(aPtr: + *mut GridTemplateAreasValue); +} extern "C" { pub fn Gecko_ClearAndResizeStyleContents(content: *mut nsStyleContent, how_many: u32); diff --git a/servo/components/style/gecko_bindings/sugar/refptr.rs b/servo/components/style/gecko_bindings/sugar/refptr.rs index 9ca1d3dc7b6a..2b3776e70fd6 100644 --- a/servo/components/style/gecko_bindings/sugar/refptr.rs +++ b/servo/components/style/gecko_bindings/sugar/refptr.rs @@ -277,3 +277,6 @@ impl_threadsafe_refcount!(::gecko_bindings::structs::nsCSSValueSharedList, impl_threadsafe_refcount!(::gecko_bindings::structs::mozilla::css::URLValue, Gecko_AddRefCSSURLValueArbitraryThread, Gecko_ReleaseCSSURLValueArbitraryThread); +impl_threadsafe_refcount!(::gecko_bindings::structs::mozilla::css::GridTemplateAreasValue, + Gecko_AddRefGridTemplateAreasValueArbitraryThread, + Gecko_ReleaseGridTemplateAreasValueArbitraryThread); diff --git a/servo/components/style/properties/data.py b/servo/components/style/properties/data.py index 8db09e6fe81c..eb1706e691ee 100644 --- a/servo/components/style/properties/data.py +++ b/servo/components/style/properties/data.py @@ -140,7 +140,7 @@ class Longhand(object): need_clone=False, need_index=False, gecko_ffi_name=None, depend_on_viewport_size=False, allowed_in_keyframe_block=True, complex_color=False, cast_type='u8', has_uncacheable_values=False, logical=False, alias=None, extra_prefixes=None, boxed=False, - flags=None, allowed_in_page_rule=False, allow_quirks=False): + flags=None, allowed_in_page_rule=False, allow_quirks=False, vector=False): self.name = name if not spec: raise TypeError("Spec should be specified for %s" % name) @@ -167,6 +167,7 @@ class Longhand(object): self.flags = flags.split() if flags else [] self.allowed_in_page_rule = arg_to_bool(allowed_in_page_rule) self.allow_quirks = allow_quirks + self.is_vector = vector # https://drafts.csswg.org/css-animations/#keyframes # > The inside of accepts any CSS property diff --git a/servo/components/style/properties/gecko.mako.rs b/servo/components/style/properties/gecko.mako.rs index e99dc303457c..e1a5594f6c0f 100644 --- a/servo/components/style/properties/gecko.mako.rs +++ b/servo/components/style/properties/gecko.mako.rs @@ -1052,7 +1052,8 @@ fn static_assert() { <%self:impl_trait style_struct_name="Position" skip_longhands="${skip_position_longhands} z-index box-sizing order align-content justify-content align-self justify-self align-items - justify-items grid-auto-rows grid-auto-columns grid-auto-flow"> + justify-items grid-auto-rows grid-auto-columns grid-auto-flow + grid-template-areas"> % for side in SIDES: <% impl_split_style_coord("%s" % side.ident, "mOffset", @@ -1228,6 +1229,42 @@ fn static_assert() { } ${impl_simple_copy('grid_auto_flow', 'mGridAutoFlow')} + + pub fn set_grid_template_areas(&mut self, v: longhands::grid_template_areas::computed_value::T) { + use gecko_bindings::bindings::Gecko_NewGridTemplateAreasValue; + use gecko_bindings::sugar::refptr::UniqueRefPtr; + + let v = match v { + Either::First(areas) => areas, + Either::Second(_) => { + unsafe { self.gecko.mGridTemplateAreas.clear() } + return; + }, + }; + + let mut refptr = unsafe { + UniqueRefPtr::from_addrefed( + Gecko_NewGridTemplateAreasValue(v.areas.len() as u32, v.strings.len() as u32, v.width)) + }; + + for (servo, gecko) in v.areas.into_iter().zip(refptr.mNamedAreas.iter_mut()) { + gecko.mName.assign_utf8(&*servo.name); + gecko.mColumnStart = servo.columns.start; + gecko.mColumnEnd = servo.columns.end; + gecko.mRowStart = servo.rows.start; + gecko.mRowEnd = servo.rows.end; + } + + for (servo, gecko) in v.strings.into_iter().zip(refptr.mTemplates.iter_mut()) { + gecko.assign_utf8(&*servo); + } + + unsafe { self.gecko.mGridTemplateAreas.set_move(refptr.get()) } + } + + pub fn copy_grid_template_areas_from(&mut self, other: &Self) { + unsafe { self.gecko.mGridTemplateAreas.set(&other.gecko.mGridTemplateAreas) } + } <% skip_outline_longhands = " ".join("outline-style outline-width".split() + @@ -1697,14 +1734,18 @@ fn static_assert() { <%def name="impl_animation_or_transition_time_value(type, ident, gecko_ffi_name)"> #[allow(non_snake_case)] - pub fn set_${type}_${ident}(&mut self, v: longhands::${type}_${ident}::computed_value::T) { - debug_assert!(!v.0.is_empty()); - let input_len = v.0.len(); + pub fn set_${type}_${ident}(&mut self, v: I) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator + Clone + { + let v = v.into_iter(); + debug_assert!(v.len() != 0); + let input_len = v.len(); unsafe { self.gecko.m${type.capitalize()}s.ensure_len(input_len) }; self.gecko.m${type.capitalize()}${gecko_ffi_name}Count = input_len as u32; - for (i, gecko) in self.gecko.m${type.capitalize()}s.iter_mut().enumerate() { - gecko.m${gecko_ffi_name} = v.0[i % input_len].seconds() * 1000.; + for (gecko, servo) in self.gecko.m${type.capitalize()}s.iter_mut().zip(v.cycle()) { + gecko.m${gecko_ffi_name} = servo.seconds() * 1000.; } } #[allow(non_snake_case)] @@ -1718,14 +1759,18 @@ fn static_assert() { <%def name="impl_animation_or_transition_timing_function(type)"> - pub fn set_${type}_timing_function(&mut self, v: longhands::${type}_timing_function::computed_value::T) { - debug_assert!(!v.0.is_empty()); - let input_len = v.0.len(); + pub fn set_${type}_timing_function(&mut self, v: I) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator + Clone + { + let v = v.into_iter(); + debug_assert!(v.len() != 0); + let input_len = v.len(); unsafe { self.gecko.m${type.capitalize()}s.ensure_len(input_len) }; self.gecko.m${type.capitalize()}TimingFunctionCount = input_len as u32; - for (i, gecko) in self.gecko.m${type.capitalize()}s.iter_mut().enumerate() { - gecko.mTimingFunction = v.0[i % input_len].into(); + for (gecko, servo) in self.gecko.m${type.capitalize()}s.iter_mut().zip(v.cycle()) { + gecko.mTimingFunction = servo.into(); } } ${impl_animation_or_transition_count(type, 'timing_function', 'TimingFunction')} @@ -1766,18 +1811,23 @@ fn static_assert() { <%def name="impl_animation_keyword(ident, gecko_ffi_name, keyword, cast_type='u8')"> #[allow(non_snake_case)] - pub fn set_animation_${ident}(&mut self, v: longhands::animation_${ident}::computed_value::T) { + pub fn set_animation_${ident}(&mut self, v: I) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator + Clone + { use properties::longhands::animation_${ident}::single_value::computed_value::T as Keyword; use gecko_bindings::structs; - debug_assert!(!v.0.is_empty()); - let input_len = v.0.len(); + let v = v.into_iter(); + + debug_assert!(v.len() != 0); + let input_len = v.len(); unsafe { self.gecko.mAnimations.ensure_len(input_len) }; self.gecko.mAnimation${gecko_ffi_name}Count = input_len as u32; - for (i, gecko) in self.gecko.mAnimations.iter_mut().enumerate() { - let result = match v.0[i % input_len] { + for (gecko, servo) in self.gecko.mAnimations.iter_mut().zip(v.cycle()) { + let result = match servo { % for value in keyword.gecko_values(): Keyword::${to_rust_ident(value)} => structs::${keyword.gecko_constant(value)} ${keyword.maybe_cast(cast_type)}, @@ -1970,11 +2020,16 @@ fn static_assert() { ${impl_coord_copy('scroll_snap_points_y', 'mScrollSnapPointsY')} - pub fn set_scroll_snap_coordinate(&mut self, v: longhands::scroll_snap_coordinate::computed_value::T) { - unsafe { self.gecko.mScrollSnapCoordinate.set_len_pod(v.0.len() as u32); } + pub fn set_scroll_snap_coordinate(&mut self, v: I) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator + { + let v = v.into_iter(); + + unsafe { self.gecko.mScrollSnapCoordinate.set_len_pod(v.len() as u32); } for (gecko, servo) in self.gecko.mScrollSnapCoordinate .iter_mut() - .zip(v.0.iter()) { + .zip(v) { gecko.mXPosition = servo.horizontal.0.into(); gecko.mYPosition = servo.vertical.0.into(); } @@ -2165,13 +2220,18 @@ fn static_assert() { self.gecko.mTransitions[index].mDuration.max(0.0) + self.gecko.mTransitions[index].mDelay } - pub fn set_transition_property(&mut self, v: longhands::transition_property::computed_value::T) { + pub fn set_transition_property(&mut self, v: I) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator + { use gecko_bindings::structs::nsCSSPropertyID::eCSSPropertyExtra_no_properties; - if !v.0.is_empty() { - unsafe { self.gecko.mTransitions.ensure_len(v.0.len()) }; - self.gecko.mTransitionPropertyCount = v.0.len() as u32; - for (servo, gecko) in v.0.into_iter().zip(self.gecko.mTransitions.iter_mut()) { + let v = v.into_iter(); + + if v.len() != 0 { + unsafe { self.gecko.mTransitions.ensure_len(v.len()) }; + self.gecko.mTransitionPropertyCount = v.len() as u32; + for (servo, gecko) in v.zip(self.gecko.mTransitions.iter_mut()) { match servo { TransitionProperty::Unsupported(ref atom) => unsafe { Gecko_StyleTransition_SetUnsupportedProperty(gecko, atom.as_ptr()) @@ -2246,12 +2306,17 @@ fn static_assert() { unsafe { bindings::Gecko_StyleAnimationsEquals(&self.gecko.mAnimations, &other.gecko.mAnimations) } } - pub fn set_animation_name(&mut self, v: longhands::animation_name::computed_value::T) { - debug_assert!(!v.0.is_empty()); - unsafe { self.gecko.mAnimations.ensure_len(v.0.len()) }; + pub fn set_animation_name(&mut self, v: I) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator + { - self.gecko.mAnimationNameCount = v.0.len() as u32; - for (servo, gecko) in v.0.into_iter().zip(self.gecko.mAnimations.iter_mut()) { + let v = v.into_iter(); + debug_assert!(v.len() != 0); + unsafe { self.gecko.mAnimations.ensure_len(v.len()) }; + + self.gecko.mAnimationNameCount = v.len() as u32; + for (servo, gecko) in v.zip(self.gecko.mAnimations.iter_mut()) { // TODO This is inefficient. We should fix this in bug 1329169. gecko.mName.assign(match servo.0 { Some(ref name) => name.as_atom().as_slice(), @@ -2294,17 +2359,22 @@ fn static_assert() { ${impl_animation_keyword('play_state', 'PlayState', data.longhands_by_name["animation-play-state"].keyword)} - pub fn set_animation_iteration_count(&mut self, v: longhands::animation_iteration_count::computed_value::T) { + pub fn set_animation_iteration_count(&mut self, v: I) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator + Clone + { use std::f32; use properties::longhands::animation_iteration_count::single_value::SpecifiedValue as AnimationIterationCount; - debug_assert!(!v.0.is_empty()); - let input_len = v.0.len(); + let v = v.into_iter(); + + debug_assert!(v.len() != 0); + let input_len = v.len(); unsafe { self.gecko.mAnimations.ensure_len(input_len) }; self.gecko.mAnimationIterationCountCount = input_len as u32; - for (i, gecko) in self.gecko.mAnimations.iter_mut().enumerate() { - match v.0[i % input_len] { + for (gecko, servo) in self.gecko.mAnimations.iter_mut().zip(v.cycle()) { + match servo { AnimationIterationCount::Number(n) => gecko.mIterationCount = n, AnimationIterationCount::Infinite => gecko.mIterationCount = f32::INFINITY, } @@ -2558,18 +2628,21 @@ fn static_assert() { other.gecko.${image_layers_field}.${field_name}Count; } - pub fn set_${shorthand}_${name}(&mut self, - v: longhands::${shorthand}_${name}::computed_value::T) { + + pub fn set_${shorthand}_${name}(&mut self, v: I) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator + { use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; + let v = v.into_iter(); unsafe { - Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, v.0.len(), + Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, v.len(), LayerType::${shorthand.title()}); } - self.gecko.${image_layers_field}.${field_name}Count = v.0.len() as u32; - for (servo, geckolayer) in v.0.into_iter() - .zip(self.gecko.${image_layers_field}.mLayers.iter_mut()) { + self.gecko.${image_layers_field}.${field_name}Count = v.len() as u32; + for (servo, geckolayer) in v.zip(self.gecko.${image_layers_field}.mLayers.iter_mut()) { geckolayer.${field_name} = { ${caller.body()} }; @@ -2675,17 +2748,23 @@ fn static_assert() { ) } - pub fn set_${shorthand}_position_${orientation[0]}(&mut self, - v: longhands::${shorthand}_position_${orientation[0]}::computed_value::T) { + pub fn set_${shorthand}_position_${orientation[0]}(&mut self, + v: I) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator + { use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; + let v = v.into_iter(); + unsafe { - Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, v.0.len(), + Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, v.len(), LayerType::${shorthand.capitalize()}); } - self.gecko.${image_layers_field}.mPosition${orientation[0].upper()}Count = v.0.len() as u32; - for (servo, geckolayer) in v.0.into_iter().zip(self.gecko.${image_layers_field} + self.gecko.${image_layers_field}.mPosition${orientation[0].upper()}Count = v.len() as u32; + for (servo, geckolayer) in v.zip(self.gecko.${image_layers_field} .mLayers.iter_mut()) { geckolayer.mPosition.m${orientation[0].upper()}Position = servo.0.into(); } @@ -2772,25 +2851,28 @@ fn static_assert() { } #[allow(unused_variables)] - pub fn set_${shorthand}_image(&mut self, - images: longhands::${shorthand}_image::computed_value::T, - cacheable: &mut bool) { + pub fn set_${shorthand}_image(&mut self, images: I, cacheable: &mut bool) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator + { use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; + let images = images.into_iter(); + unsafe { // Prevent leaking of the last elements we did set for image in &mut self.gecko.${image_layers_field}.mLayers { Gecko_SetNullImageValue(&mut image.mImage) } // XXXManishearth clear mSourceURI for masks - Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, images.0.len(), + Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, images.len(), LayerType::${shorthand.title()}); } - self.gecko.${image_layers_field}.mImageCount = images.0.len() as u32; + self.gecko.${image_layers_field}.mImageCount = images.len() as u32; - for (image, geckoimage) in images.0.into_iter().zip(self.gecko.${image_layers_field} - .mLayers.iter_mut()) { + for (image, geckoimage) in images.zip(self.gecko.${image_layers_field} + .mLayers.iter_mut()) { if let Some(image) = image.0 { geckoimage.mImage.set(image, cacheable) } @@ -2986,12 +3068,15 @@ fn static_assert() { <%self:impl_trait style_struct_name="Effects" skip_longhands="box-shadow clip filter"> - pub fn set_box_shadow(&mut self, v: longhands::box_shadow::computed_value::T) { + pub fn set_box_shadow(&mut self, v: I) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator + { + let v = v.into_iter(); - self.gecko.mBoxShadow.replace_with_new(v.0.len() as u32); + self.gecko.mBoxShadow.replace_with_new(v.len() as u32); - for (servo, gecko_shadow) in v.0.into_iter() - .zip(self.gecko.mBoxShadow.iter_mut()) { + for (servo, gecko_shadow) in v.zip(self.gecko.mBoxShadow.iter_mut()) { gecko_shadow.mXOffset = servo.offset_x.0; gecko_shadow.mYOffset = servo.offset_y.0; @@ -3790,12 +3875,16 @@ clip-path ${impl_simple_copy('paint_order', 'mPaintOrder')} - pub fn set_stroke_dasharray(&mut self, v: longhands::stroke_dasharray::computed_value::T) { + pub fn set_stroke_dasharray(&mut self, v: I) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator + { + let v = v.into_iter(); unsafe { - bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut self.gecko, v.0.len() as u32); + bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut self.gecko, v.len() as u32); } - for (mut gecko, servo) in self.gecko.mStrokeDasharray.iter_mut().zip(v.0.into_iter()) { + for (mut gecko, servo) in self.gecko.mStrokeDasharray.iter_mut().zip(v) { match servo { Either::First(number) => gecko.set_value(CoordDataValue::Factor(number)), Either::Second(lop) => gecko.set(lop), @@ -3808,6 +3897,26 @@ clip-path bindings::Gecko_nsStyleSVG_CopyDashArray(&mut self.gecko, &other.gecko); } } + + pub fn clone_stroke_dasharray(&self) -> longhands::stroke_dasharray::computed_value::T { + use smallvec::SmallVec; + use values::computed::LengthOrPercentage; + + let mut vec = SmallVec::new(); + for gecko in self.gecko.mStrokeDasharray.iter() { + match gecko.as_value() { + CoordDataValue::Factor(number) => vec.push(Either::First(number)), + CoordDataValue::Coord(coord) => + vec.push(Either::Second(LengthOrPercentage::Length(Au(coord)))), + CoordDataValue::Percent(p) => + vec.push(Either::Second(LengthOrPercentage::Percentage(p))), + CoordDataValue::Calc(calc) => + vec.push(Either::Second(LengthOrPercentage::Calc(calc.into()))), + _ => unreachable!(), + } + } + longhands::stroke_dasharray::computed_value::T(vec) + } <%self:impl_trait style_struct_name="Color" @@ -3869,6 +3978,11 @@ clip-path Cursor::AllScroll => structs::NS_STYLE_CURSOR_ALL_SCROLL, Cursor::ZoomIn => structs::NS_STYLE_CURSOR_ZOOM_IN, Cursor::ZoomOut => structs::NS_STYLE_CURSOR_ZOOM_OUT, + // note: the following properties are gecko-only. + Cursor::MozGrab => structs::NS_STYLE_CURSOR_GRAB, + Cursor::MozGrabbing => structs::NS_STYLE_CURSOR_GRABBING, + Cursor::MozZoomIn => structs::NS_STYLE_CURSOR_ZOOM_IN, + Cursor::MozZoomOut => structs::NS_STYLE_CURSOR_ZOOM_OUT, } } as u8; diff --git a/servo/components/style/properties/helpers.mako.rs b/servo/components/style/properties/helpers.mako.rs index b69057f916c0..9f89abda8572 100644 --- a/servo/components/style/properties/helpers.mako.rs +++ b/servo/components/style/properties/helpers.mako.rs @@ -74,7 +74,7 @@ <%def name="vector_longhand(name, gecko_only=False, allow_empty=False, delegate_animate=False, space_separated_allowed=False, **kwargs)"> - <%call expr="longhand(name, **kwargs)"> + <%call expr="longhand(name, vector=True, **kwargs)"> % if not gecko_only: use smallvec::SmallVec; use std::fmt; @@ -102,7 +102,9 @@ pub mod computed_value { pub use super::single_value::computed_value as single_value; pub use self::single_value::T as SingleComputedValue; - use smallvec::SmallVec; + use smallvec::{IntoIter, SmallVec}; + use values::computed::ComputedVecIter; + /// The computed value, effectively a list of single values. #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] @@ -129,6 +131,16 @@ } } % endif + + pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>; + + impl IntoIterator for T { + type Item = single_value::T; + type IntoIter = IntoIter<[single_value::T; 1]>; + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } + } } impl ToCss for computed_value::T { @@ -212,12 +224,19 @@ pub use self::single_value::SpecifiedValue as SingleSpecifiedValue; + impl SpecifiedValue { + pub fn compute_iter<'a, 'cx, 'cx_a>(&'a self, context: &'cx Context<'cx_a>) + -> computed_value::Iter<'a, 'cx, 'cx_a> { + computed_value::Iter::new(context, &self.0) + } + } + impl ToComputedValue for SpecifiedValue { type ComputedValue = computed_value::T; #[inline] fn to_computed_value(&self, context: &Context) -> computed_value::T { - computed_value::T(self.0.iter().map(|x| x.to_computed_value(context)).collect()) + computed_value::T(self.compute_iter(context).collect()) } #[inline] fn from_computed_value(computed: &computed_value::T) -> Self { @@ -294,7 +313,10 @@ % if property.logical: let wm = context.style.writing_mode; % endif - <% maybe_wm = ", wm" if property.logical else "" %> + <% + maybe_wm = ", wm" if property.logical else "" + maybe_cacheable = ", cacheable" if property.has_uncacheable_values == "True" else "" + %> match *value { DeclaredValue::Value(ref specified_value) => { % if property.ident in SYSTEM_FONT_LONGHANDS and product == "gecko": @@ -302,19 +324,30 @@ longhands::system_font::resolve_system_font(sf, context); } % endif - let computed = specified_value.to_computed_value(context); - % if property.ident == "font_size": - longhands::font_size::cascade_specified_font_size(context, - specified_value, - computed, - inherited_style.get_font()); + % if property.is_vector: + // In the case of a vector property we want to pass down + // an iterator so that this can be computed without allocation + // + // However, computing requires a context, but the style struct + // being mutated is on the context. We temporarily remove it, + // mutate it, and then put it back. Vector longhands cannot + // touch their own style struct whilst computing, else this will panic. + let mut s = context.mutate_style().take_${data.current_style_struct.name_lower}(); + { + let iter = specified_value.compute_iter(context); + s.set_${property.ident}(iter ${maybe_cacheable}); + } + context.mutate_style().put_${data.current_style_struct.name_lower}(s); % else: - % if property.has_uncacheable_values == "True": - context.mutate_style().mutate_${data.current_style_struct.name_lower}() - .set_${property.ident}(computed, cacheable ${maybe_wm}); + let computed = specified_value.to_computed_value(context); + % if property.ident == "font_size": + longhands::font_size::cascade_specified_font_size(context, + specified_value, + computed, + inherited_style.get_font()); % else: - context.mutate_style().mutate_${data.current_style_struct.name_lower}() - .set_${property.ident}(computed ${maybe_wm}); + context.mutate_style().mutate_${data.current_style_struct.name_lower}() + .set_${property.ident}(computed ${maybe_cacheable} ${maybe_wm}); % endif % endif } diff --git a/servo/components/style/properties/helpers/animated_properties.mako.rs b/servo/components/style/properties/helpers/animated_properties.mako.rs index 1b2e8f456c36..8767f78102fc 100644 --- a/servo/components/style/properties/helpers/animated_properties.mako.rs +++ b/servo/components/style/properties/helpers/animated_properties.mako.rs @@ -621,6 +621,8 @@ pub trait Interpolate: Sized { /// https://drafts.csswg.org/css-transitions/#animtype-repeatable-list pub trait RepeatableListInterpolate: Interpolate {} +impl RepeatableListInterpolate for Either {} + impl Interpolate for SmallVec<[T; 1]> { fn interpolate(&self, other: &Self, progress: f64) -> Result { use num_integer::lcm; diff --git a/servo/components/style/properties/longhand/font.mako.rs b/servo/components/style/properties/longhand/font.mako.rs index 761dd95e025c..230a8839fedf 100644 --- a/servo/components/style/properties/longhand/font.mako.rs +++ b/servo/components/style/properties/longhand/font.mako.rs @@ -741,6 +741,10 @@ ${helpers.single_keyword_system("font-variant-caps", } % endif + /// This is the ratio applied for font-size: larger + /// and smaller by both Firefox and Chrome + const LARGER_FONT_SIZE_RATIO: f32 = 1.2; + impl SpecifiedValue { /// https://html.spec.whatwg.org/multipage/#rules-for-parsing-a-legacy-font-size pub fn from_html_size(size: u8) -> Self { @@ -768,6 +772,10 @@ ${helpers.single_keyword_system("font-variant-caps", return Some(em) } } + } else if let SpecifiedValue::Larger = *self { + return Some(LARGER_FONT_SIZE_RATIO) + } else if let SpecifiedValue::Smaller = *self { + return Some(1. / LARGER_FONT_SIZE_RATIO) } None } @@ -799,11 +807,11 @@ ${helpers.single_keyword_system("font-variant-caps", key.to_computed_value(context).scale_by(fraction) } SpecifiedValue::Smaller => { - FontRelativeLength::Em(0.85) + FontRelativeLength::Em(1. / LARGER_FONT_SIZE_RATIO) .to_computed_value(context, base_size) } SpecifiedValue::Larger => { - FontRelativeLength::Em(1.2) + FontRelativeLength::Em(LARGER_FONT_SIZE_RATIO) .to_computed_value(context, base_size) } @@ -2429,3 +2437,12 @@ ${helpers.single_keyword("-moz-math-variant", } } % endif + +${helpers.single_keyword("-moz-osx-font-smoothing", + "auto grayscale", + gecko_constant_prefix="NS_FONT_SMOOTHING", + gecko_ffi_name="mFont.smoothing", + products="gecko", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/font-smooth)", + animation_value_type="none", + need_clone=True)} diff --git a/servo/components/style/properties/longhand/inherited_svg.mako.rs b/servo/components/style/properties/longhand/inherited_svg.mako.rs index 068c3d127f61..33cda168d501 100644 --- a/servo/components/style/properties/longhand/inherited_svg.mako.rs +++ b/servo/components/style/properties/longhand/inherited_svg.mako.rs @@ -74,20 +74,20 @@ ${helpers.predefined_type( spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth")} ${helpers.single_keyword("stroke-linecap", "butt round square", - products="gecko", animation_value_type="none", + products="gecko", animation_value_type="discrete", spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty")} ${helpers.single_keyword("stroke-linejoin", "miter round bevel", - products="gecko", animation_value_type="none", + products="gecko", animation_value_type="discrete", spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty")} ${helpers.predefined_type("stroke-miterlimit", "Number", "4.0", "parse_at_least_one", products="gecko", - animation_value_type="none", + animation_value_type="ComputedValue", spec="https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty")} ${helpers.predefined_type("stroke-opacity", "Opacity", "1.0", - products="gecko", animation_value_type="none", + products="gecko", animation_value_type="ComputedValue", spec="https://www.w3.org/TR/SVG11/painting.html#StrokeOpacityProperty")} ${helpers.predefined_type("stroke-dasharray", @@ -95,9 +95,10 @@ ${helpers.predefined_type("stroke-dasharray", "Either::First(0.0)", "parse_non_negative", vector="True", + delegate_animate="True", allow_empty="True", products="gecko", - animation_value_type="none", + animation_value_type="ComputedValue", space_separated_allowed="True", spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing")} diff --git a/servo/components/style/properties/longhand/position.mako.rs b/servo/components/style/properties/longhand/position.mako.rs index 757c270bb493..370a538e893c 100644 --- a/servo/components/style/properties/longhand/position.mako.rs +++ b/servo/components/style/properties/longhand/position.mako.rs @@ -406,3 +406,173 @@ ${helpers.predefined_type("object-position", } } + +<%helpers:longhand name="grid-template-areas" + spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-areas" + products="gecko" + animation_value_type="none" + disable_when_testing="True" + boxed="True"> + use cssparser::serialize_string; + use std::collections::HashMap; + use std::fmt; + use std::ops::Range; + use str::HTML_SPACE_CHARACTERS; + use style_traits::ToCss; + use style_traits::values::Css; + use values::HasViewportPercentage; + use values::computed::ComputedValueAsSpecified; + + pub mod computed_value { + pub use super::SpecifiedValue as T; + } + + pub type SpecifiedValue = Either; + + #[inline] + pub fn get_initial_value() -> computed_value::T { + Either::Second(None_) + } + + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + SpecifiedValue::parse(context, input) + } + + #[derive(Clone, PartialEq)] + pub struct TemplateAreas { + pub areas: Box<[NamedArea]>, + pub strings: Box<[Box]>, + pub width: u32, + } + + #[derive(Clone, PartialEq)] + pub struct NamedArea { + pub name: Box, + pub rows: Range, + pub columns: Range, + } + + no_viewport_percentage!(TemplateAreas); + impl ComputedValueAsSpecified for TemplateAreas {} + + impl Parse for TemplateAreas { + fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + let mut strings = vec![]; + while let Ok(string) = input.try(Parser::expect_string) { + strings.push(string.into_owned().into_boxed_str()); + } + if strings.is_empty() { + return Err(()); + } + let mut areas: Vec = vec![]; + let mut width = 0; + { + let mut row = 0u32; + let mut area_indices = HashMap::<(&str), usize>::new(); + for string in &strings { + let mut current_area_index: Option = None; + row += 1; + let mut column = 0u32; + for token in Tokenizer(string) { + column += 1; + let token = if let Some(token) = token? { + token + } else { + if let Some(index) = current_area_index.take() { + if areas[index].columns.end != column { + return Err(()); + } + } + continue; + }; + if let Some(index) = current_area_index { + if &*areas[index].name == token { + if areas[index].rows.start == row { + areas[index].columns.end += 1; + } + continue; + } + if areas[index].columns.end != column { + return Err(()); + } + } + if let Some(index) = area_indices.get(token).cloned() { + if areas[index].columns.start != column || areas[index].rows.end != row { + return Err(()); + } + areas[index].rows.end += 1; + current_area_index = Some(index); + continue; + } + let index = areas.len(); + areas.push(NamedArea { + name: token.to_owned().into_boxed_str(), + columns: column..(column + 1), + rows: row..(row + 1), + }); + assert!(area_indices.insert(token, index).is_none()); + current_area_index = Some(index); + } + if let Some(index) = current_area_index { + if areas[index].columns.end != column + 1 { + assert!(areas[index].rows.start != row); + return Err(()); + } + } + if row == 1 { + width = column; + } else if width != column { + return Err(()); + } + } + } + Ok(TemplateAreas { + areas: areas.into_boxed_slice(), + strings: strings.into_boxed_slice(), + width: width, + }) + } + } + + impl ToCss for TemplateAreas { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + for (i, string) in self.strings.iter().enumerate() { + if i != 0 { + dest.write_str(" ")?; + } + serialize_string(string, dest)?; + } + Ok(()) + } + } + + struct Tokenizer<'a>(&'a str); + + impl<'a> Iterator for Tokenizer<'a> { + type Item = Result, ()>; + + fn next(&mut self) -> Option { + let rest = self.0.trim_left_matches(HTML_SPACE_CHARACTERS); + if rest.is_empty() { + return None; + } + if rest.starts_with('.') { + self.0 = &rest[rest.find(|c| c != '.').unwrap_or(rest.len())..]; + return Some(Ok(None)); + } + if !rest.starts_with(is_name_code_point) { + return Some(Err(())); + } + let token_len = rest.find(|c| !is_name_code_point(c)).unwrap_or(rest.len()); + let token = &rest[..token_len]; + self.0 = &rest[token_len..]; + Some(Ok(Some(token))) + } + } + + fn is_name_code_point(c: char) -> bool { + c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || + c >= '\u{80}' || c == '_' || + c >= '0' && c <= '9' || c == '-' + } + diff --git a/servo/components/style/properties/properties.mako.rs b/servo/components/style/properties/properties.mako.rs index b2a122adcbe6..566263252fb6 100644 --- a/servo/components/style/properties/properties.mako.rs +++ b/servo/components/style/properties/properties.mako.rs @@ -14,7 +14,7 @@ use std::borrow::Cow; use std::collections::HashSet; use std::fmt; use std::ops::Deref; -use stylearc::Arc; +use stylearc::{Arc, UniqueArc}; use app_units::Au; #[cfg(feature = "servo")] use cssparser::{Color as CSSParserColor, RGBA}; @@ -1509,12 +1509,26 @@ pub mod style_structs { % if longhand.logical: ${helpers.logical_setter(name=longhand.name)} % else: - /// Set ${longhand.name}. - #[allow(non_snake_case)] - #[inline] - pub fn set_${longhand.ident}(&mut self, v: longhands::${longhand.ident}::computed_value::T) { - self.${longhand.ident} = v; - } + % if longhand.is_vector: + /// Set ${longhand.name}. + #[allow(non_snake_case)] + #[inline] + pub fn set_${longhand.ident}(&mut self, v: I) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator + { + self.${longhand.ident} = longhands::${longhand.ident}::computed_value + ::T(v.into_iter().collect()); + } + % else: + /// Set ${longhand.name}. + #[allow(non_snake_case)] + #[inline] + pub fn set_${longhand.ident}(&mut self, v: longhands::${longhand.ident}::computed_value::T) { + self.${longhand.ident} = v; + } + % endif /// Set ${longhand.name} from other struct. #[allow(non_snake_case)] #[inline] @@ -2057,7 +2071,9 @@ pub enum StyleStructRef<'a, T: 'a> { /// A borrowed struct from the parent, for example, for inheriting style. Borrowed(&'a Arc), /// An owned struct, that we've already mutated. - Owned(Arc), + Owned(UniqueArc), + /// Temporarily vacated, will panic if accessed + Vacated, } impl<'a, T: 'a> StyleStructRef<'a, T> @@ -2067,21 +2083,45 @@ impl<'a, T: 'a> StyleStructRef<'a, T> /// borrowed value, or returning the owned one. pub fn mutate(&mut self) -> &mut T { if let StyleStructRef::Borrowed(v) = *self { - *self = StyleStructRef::Owned(Arc::new((**v).clone())); + *self = StyleStructRef::Owned(UniqueArc::new((**v).clone())); } match *self { - StyleStructRef::Owned(ref mut v) => Arc::get_mut(v).unwrap(), + StyleStructRef::Owned(ref mut v) => v, StyleStructRef::Borrowed(..) => unreachable!(), + StyleStructRef::Vacated => panic!("Accessed vacated style struct") } } + /// Extract a unique Arc from this struct, vacating it. + /// + /// The vacated state is a transient one, please put the Arc back + /// when done via `put()`. This function is to be used to separate + /// the struct being mutated from the computed context + pub fn take(&mut self) -> UniqueArc { + use std::mem::replace; + let inner = replace(self, StyleStructRef::Vacated); + + match inner { + StyleStructRef::Owned(arc) => arc, + StyleStructRef::Borrowed(arc) => UniqueArc::new((**arc).clone()), + StyleStructRef::Vacated => panic!("Accessed vacated style struct"), + } + } + + /// Replace vacated ref with an arc + pub fn put(&mut self, arc: UniqueArc) { + debug_assert!(matches!(*self, StyleStructRef::Vacated)); + *self = StyleStructRef::Owned(arc); + } + /// Get a mutable reference to the owned struct, or `None` if the struct /// hasn't been mutated. pub fn get_if_mutated(&mut self) -> Option<<&mut T> { match *self { - StyleStructRef::Owned(ref mut v) => Some(Arc::get_mut(v).unwrap()), + StyleStructRef::Owned(ref mut v) => Some(v), StyleStructRef::Borrowed(..) => None, + StyleStructRef::Vacated => panic!("Accessed vacated style struct") } } @@ -2089,8 +2129,9 @@ impl<'a, T: 'a> StyleStructRef<'a, T> /// appropriate. pub fn build(self) -> Arc { match self { - StyleStructRef::Owned(v) => v, + StyleStructRef::Owned(v) => v.shareable(), StyleStructRef::Borrowed(v) => v.clone(), + StyleStructRef::Vacated => panic!("Accessed vacated style struct") } } } @@ -2102,6 +2143,7 @@ impl<'a, T: 'a> Deref for StyleStructRef<'a, T> { match *self { StyleStructRef::Owned(ref v) => &**v, StyleStructRef::Borrowed(v) => &**v, + StyleStructRef::Vacated => panic!("Accessed vacated style struct") } } } @@ -2183,6 +2225,16 @@ impl<'a> StyleBuilder<'a> { self.${style_struct.ident}.mutate() } + /// Gets a mutable view of the current `${style_struct.name}` style. + pub fn take_${style_struct.name_lower}(&mut self) -> UniqueArc { + self.${style_struct.ident}.take() + } + + /// Gets a mutable view of the current `${style_struct.name}` style. + pub fn put_${style_struct.name_lower}(&mut self, s: UniqueArc) { + self.${style_struct.ident}.put(s) + } + /// Gets a mutable view of the current `${style_struct.name}` style, /// only if it's been mutated before. pub fn get_${style_struct.name_lower}_if_mutated(&mut self) diff --git a/servo/components/style/stylearc.rs b/servo/components/style/stylearc.rs index 01885dc481bb..9b355e7d211e 100644 --- a/servo/components/style/stylearc.rs +++ b/servo/components/style/stylearc.rs @@ -31,7 +31,7 @@ use std::convert::From; use std::fmt; use std::hash::{Hash, Hasher}; use std::mem; -use std::ops::Deref; +use std::ops::{Deref, DerefMut}; use std::sync::atomic; use std::sync::atomic::Ordering::{Acquire, Relaxed, Release}; @@ -71,6 +71,40 @@ pub struct Arc { ptr: *mut ArcInner, } +/// An Arc that is known to be uniquely owned +/// +/// This lets us build arcs that we can mutate before +/// freezing, without needing to change the allocation +pub struct UniqueArc(Arc); + +impl UniqueArc { + #[inline] + /// Construct a new UniqueArc + pub fn new(data: T) -> Self { + UniqueArc(Arc::new(data)) + } + + #[inline] + /// Convert to a shareable Arc once we're done using it + pub fn shareable(self) -> Arc { + self.0 + } +} + +impl Deref for UniqueArc { + type Target = T; + fn deref(&self) -> &T { + &*self.0 + } +} + +impl DerefMut for UniqueArc { + fn deref_mut(&mut self) -> &mut T { + // We know this to be uniquely owned + unsafe { &mut (*self.0.ptr).data } + } +} + unsafe impl Send for Arc {} unsafe impl Sync for Arc {} diff --git a/servo/components/style/values/computed/mod.rs b/servo/components/style/values/computed/mod.rs index 19cc22edf270..f1721e552cdc 100644 --- a/servo/components/style/values/computed/mod.rs +++ b/servo/components/style/values/computed/mod.rs @@ -100,6 +100,42 @@ impl<'a> Context<'a> { pub fn mutate_style(&mut self) -> &mut StyleBuilder<'a> { &mut self.style } } +/// An iterator over a slice of computed values +#[derive(Clone)] +pub struct ComputedVecIter<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> { + cx: &'cx Context<'cx_a>, + values: &'a [S], +} + +impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ComputedVecIter<'a, 'cx, 'cx_a, S> { + /// Construct an iterator from a slice of specified values and a context + pub fn new(cx: &'cx Context<'cx_a>, values: &'a [S]) -> Self { + ComputedVecIter { + cx: cx, + values: values, + } + } +} + +impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ExactSizeIterator for ComputedVecIter<'a, 'cx, 'cx_a, S> { + fn len(&self) -> usize { + self.values.len() + } +} + +impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> Iterator for ComputedVecIter<'a, 'cx, 'cx_a, S> { + type Item = S::ComputedValue; + fn next(&mut self) -> Option { + if let Some((next, rest)) = self.values.split_first() { + let ret = next.to_computed_value(self.cx); + self.values = rest; + Some(ret) + } else { + None + } + } +} + /// A trait to represent the conversion between computed and specified values. pub trait ToComputedValue { /// The computed value type we're going to be converted to. diff --git a/servo/components/style_traits/Cargo.toml b/servo/components/style_traits/Cargo.toml index 3acba6598204..f95e5f00e806 100644 --- a/servo/components/style_traits/Cargo.toml +++ b/servo/components/style_traits/Cargo.toml @@ -12,6 +12,7 @@ path = "lib.rs" [features] servo = ["heapsize", "heapsize_derive", "serde", "serde_derive", "cssparser/heapsize", "cssparser/serde"] +gecko = [] [dependencies] app_units = "0.4" diff --git a/servo/components/style_traits/cursor.rs b/servo/components/style_traits/cursor.rs index 447dfe0966e6..cd48571d06d5 100644 --- a/servo/components/style_traits/cursor.rs +++ b/servo/components/style_traits/cursor.rs @@ -7,21 +7,30 @@ use super::ToCss; macro_rules! define_cursor { - ($( $css: expr => $variant: ident = $value: expr, )+) => { + ( + common properties = [ + $( $c_css: expr => $c_variant: ident = $c_value: expr, )+ + ] + gecko properties = [ + $( $g_css: expr => $g_variant: ident = $g_value: expr, )+ + ] + ) => { /// https://drafts.csswg.org/css-ui/#cursor #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize, HeapSizeOf))] #[repr(u8)] #[allow(missing_docs)] pub enum Cursor { - $( $variant = $value ),+ + $( $c_variant = $c_value, )+ + $( #[cfg(feature = "gecko")] $g_variant = $g_value, )+ } impl Cursor { /// Given a CSS keyword, get the corresponding cursor enum. pub fn from_css_keyword(keyword: &str) -> Result { match_ignore_ascii_case! { &keyword, - $( $css => Ok(Cursor::$variant), )+ + $( $c_css => Ok(Cursor::$c_variant), )+ + $( #[cfg(feature = "gecko")] $g_css => Ok(Cursor::$g_variant), )+ _ => Err(()) } } @@ -30,7 +39,8 @@ macro_rules! define_cursor { impl ToCss for Cursor { fn to_css(&self, dest: &mut W) -> ::std::fmt::Result where W: ::std::fmt::Write { match *self { - $( Cursor::$variant => dest.write_str($css) ),+ + $( Cursor::$c_variant => dest.write_str($c_css), )+ + $( #[cfg(feature = "gecko")] Cursor::$g_variant => dest.write_str($g_css), )+ } } } @@ -39,39 +49,48 @@ macro_rules! define_cursor { define_cursor! { - "none" => None = 0, - "default" => Default = 1, - "pointer" => Pointer = 2, - "context-menu" => ContextMenu = 3, - "help" => Help = 4, - "progress" => Progress = 5, - "wait" => Wait = 6, - "cell" => Cell = 7, - "crosshair" => Crosshair = 8, - "text" => Text = 9, - "vertical-text" => VerticalText = 10, - "alias" => Alias = 11, - "copy" => Copy = 12, - "move" => Move = 13, - "no-drop" => NoDrop = 14, - "not-allowed" => NotAllowed = 15, - "grab" => Grab = 16, - "grabbing" => Grabbing = 17, - "e-resize" => EResize = 18, - "n-resize" => NResize = 19, - "ne-resize" => NeResize = 20, - "nw-resize" => NwResize = 21, - "s-resize" => SResize = 22, - "se-resize" => SeResize = 23, - "sw-resize" => SwResize = 24, - "w-resize" => WResize = 25, - "ew-resize" => EwResize = 26, - "ns-resize" => NsResize = 27, - "nesw-resize" => NeswResize = 28, - "nwse-resize" => NwseResize = 29, - "col-resize" => ColResize = 30, - "row-resize" => RowResize = 31, - "all-scroll" => AllScroll = 32, - "zoom-in" => ZoomIn = 33, - "zoom-out" => ZoomOut = 34, + common properties = [ + "none" => None = 0, + "default" => Default = 1, + "pointer" => Pointer = 2, + "context-menu" => ContextMenu = 3, + "help" => Help = 4, + "progress" => Progress = 5, + "wait" => Wait = 6, + "cell" => Cell = 7, + "crosshair" => Crosshair = 8, + "text" => Text = 9, + "vertical-text" => VerticalText = 10, + "alias" => Alias = 11, + "copy" => Copy = 12, + "move" => Move = 13, + "no-drop" => NoDrop = 14, + "not-allowed" => NotAllowed = 15, + "grab" => Grab = 16, + "grabbing" => Grabbing = 17, + "e-resize" => EResize = 18, + "n-resize" => NResize = 19, + "ne-resize" => NeResize = 20, + "nw-resize" => NwResize = 21, + "s-resize" => SResize = 22, + "se-resize" => SeResize = 23, + "sw-resize" => SwResize = 24, + "w-resize" => WResize = 25, + "ew-resize" => EwResize = 26, + "ns-resize" => NsResize = 27, + "nesw-resize" => NeswResize = 28, + "nwse-resize" => NwseResize = 29, + "col-resize" => ColResize = 30, + "row-resize" => RowResize = 31, + "all-scroll" => AllScroll = 32, + "zoom-in" => ZoomIn = 33, + "zoom-out" => ZoomOut = 34, + ] + // gecko only properties + gecko properties = [ + "-moz-grab" => MozGrab = 35, + "-moz-grabbing" => MozGrabbing = 36, + "-moz-zoom-in" => MozZoomIn = 37, + "-moz-zoom-out" => MozZoomOut = 38, + ] } diff --git a/servo/components/webdriver_server/Cargo.toml b/servo/components/webdriver_server/Cargo.toml index 13647ef703d8..43204dbd0314 100644 --- a/servo/components/webdriver_server/Cargo.toml +++ b/servo/components/webdriver_server/Cargo.toml @@ -10,7 +10,7 @@ name = "webdriver_server" path = "lib.rs" [dependencies] -base64 = "0.4.1" +base64 = "0.4.2" cookie = "0.6" euclid = "0.11" hyper = "0.10" diff --git a/servo/servo-tidy.toml b/servo/servo-tidy.toml index ee41d4761519..6bc386c85f0b 100644 --- a/servo/servo-tidy.toml +++ b/servo/servo-tidy.toml @@ -31,7 +31,7 @@ num = [] [ignore] # Ignored packages with duplicated versions -packages = [] +packages = ["bitflags"] # Files that are ignored for all tidy and lint checks. files = [ # Helper macro where actually a pseudo-element per line makes sense. diff --git a/taskcluster/ci/build-signing/kind.yml b/taskcluster/ci/build-signing/kind.yml index 6ebd4f4f027a..5f5f22e6ced9 100644 --- a/taskcluster/ci/build-signing/kind.yml +++ b/taskcluster/ci/build-signing/kind.yml @@ -14,3 +14,6 @@ kind-dependencies: only-for-attributes: - nightly + +not-for-build-platforms: + - win64-nightly/opt diff --git a/taskcluster/ci/build/windows.yml b/taskcluster/ci/build/windows.yml index 8b1082a9353b..1854db30a185 100644 --- a/taskcluster/ci/build/windows.yml +++ b/taskcluster/ci/build/windows.yml @@ -94,6 +94,30 @@ win64/opt: config: - builds/taskcluster_firefox_windows_64_opt.py +win64-nightly/opt: + description: "Win64 Nightly" + index: + product: firefox + job-name: win64-opt + type: nightly + attributes: + nightly: true + treeherder: + platform: windows2012-64/opt + symbol: tc(N) + tier: 2 + worker-type: aws-provisioner-v1/gecko-{level}-b-win2012 + worker: + implementation: generic-worker + max-run-time: 7200 + run: + using: mozharness + script: mozharness/scripts/fx_desktop_build.py + config: + - builds/taskcluster_firefox_windows_64_opt.py + - disable_signing.py + - taskcluster_nightly.py + win64/pgo: description: "Win64 Opt PGO" index: diff --git a/taskcluster/ci/hazard/kind.yml b/taskcluster/ci/hazard/kind.yml index 318781254e6b..293cb9bb2390 100644 --- a/taskcluster/ci/hazard/kind.yml +++ b/taskcluster/ci/hazard/kind.yml @@ -18,8 +18,6 @@ job-defaults: implementation: docker-worker max-run-time: 36000 docker-image: {in-tree: desktop-build} - env: - MOZ_AUTOMATION: "1" jobs: linux64-shell-haz/debug: diff --git a/taskcluster/ci/upload-symbols/kind.yml b/taskcluster/ci/upload-symbols/kind.yml index b27ae8322c4c..1489424e2e70 100644 --- a/taskcluster/ci/upload-symbols/kind.yml +++ b/taskcluster/ci/upload-symbols/kind.yml @@ -20,6 +20,7 @@ only-for-build-platforms: - android-api-15-nightly/opt - android-x86-nightly/opt - macosx64-nightly/opt + - win64-nightly/opt job-template: label: # see transforms diff --git a/taskcluster/scripts/builder/build-l10n.sh b/taskcluster/scripts/builder/build-l10n.sh index 77d97d0e5ff9..be16955a5445 100755 --- a/taskcluster/scripts/builder/build-l10n.sh +++ b/taskcluster/scripts/builder/build-l10n.sh @@ -35,7 +35,6 @@ fail() { export MOZ_CRASHREPORTER_NO_REPORT=1 export MOZ_OBJDIR=obj-firefox export TINDERBOX_OUTPUT=1 -export MOZ_AUTOMATION=1 # Ensure that in tree libraries can be found export LIBRARY_PATH=$LIBRARY_PATH:$WORKSPACE/src/obj-firefox:$WORKSPACE/src/gcc/lib64 diff --git a/taskcluster/taskgraph/target_tasks.py b/taskcluster/taskgraph/target_tasks.py index 954c67a7d768..2eef9622a865 100644 --- a/taskcluster/taskgraph/target_tasks.py +++ b/taskcluster/taskgraph/target_tasks.py @@ -151,8 +151,8 @@ def target_tasks_cedar(full_task_graph, parameters): if platform not in ['linux64']: return False if task.attributes.get('unittest_suite'): - if not (task.attributes['unittest_suite'].startswith('mochitest') - or 'xpcshell' in task.attributes['unittest_suite']): + if not (task.attributes['unittest_suite'].startswith('mochitest') or + 'xpcshell' in task.attributes['unittest_suite']): return False return True return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)] @@ -318,3 +318,18 @@ def target_tasks_nightly_macosx(full_task_graph, parameters): if platform in ('macosx64-nightly', ): return task.attributes.get('nightly', False) return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)] + + +# nightly_win64 should be refactored to be nightly_all once +# https://bugzilla.mozilla.org/show_bug.cgi?id=1267425 dependent bugs are +# implemented +@_target_task('nightly_win64') +def target_tasks_nightly_win64(full_task_graph, parameters): + """Select the set of tasks required for a nightly build of win64. The + nightly build process involves a pipeline of builds, signing, + and, eventually, uploading the tasks to balrog.""" + def filter(task): + platform = task.attributes.get('build_platform') + if platform in ('win64-nightly', ): + return task.attributes.get('nightly', False) + return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)] diff --git a/taskcluster/taskgraph/transforms/task.py b/taskcluster/taskgraph/transforms/task.py index 5172f33c8cbc..e2366f54a447 100644 --- a/taskcluster/taskgraph/transforms/task.py +++ b/taskcluster/taskgraph/transforms/task.py @@ -958,6 +958,18 @@ def build_task(config, tasks): attributes = task.get('attributes', {}) attributes['run_on_projects'] = task.get('run-on-projects', ['all']) + # Set MOZ_AUTOMATION on all jobs. + if task['worker']['implementation'] in ( + 'generic-worker', + 'docker-engine', + 'native-engine', + 'docker-worker', + ): + payload = task_def.get('payload') + if payload: + env = payload.setdefault('env', {}) + env['MOZ_AUTOMATION'] = '1' + yield { 'label': task['label'], 'task': task_def, diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/software_update.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/software_update.py index 7721b04a690f..4756dbdd1fa4 100644 --- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/software_update.py +++ b/testing/marionette/puppeteer/firefox/firefox_puppeteer/api/software_update.py @@ -360,14 +360,13 @@ class SoftwareUpdate(BaseLib): :param update_url: URL to the update snippet """ + import urllib2 try: - import urllib2 response = urllib2.urlopen(update_url) return response.read() - except Exception: + except urllib2.URLError: exc, val, tb = sys.exc_info() - - raise exc, "Failed to retrieve update snippet: {}".format(val.reason), tb + raise Exception, "Failed to retrieve update snippet: {}".format(val), tb def get_formatted_update_url(self, force=False): """Retrieve the formatted AUS update URL the update snippet is retrieved from. diff --git a/testing/mozharness/configs/builds/releng_base_android_64_builds.py b/testing/mozharness/configs/builds/releng_base_android_64_builds.py index 126cddbaa26e..cd7672931395 100644 --- a/testing/mozharness/configs/builds/releng_base_android_64_builds.py +++ b/testing/mozharness/configs/builds/releng_base_android_64_builds.py @@ -72,7 +72,6 @@ config = { 'use_package_as_marfile': True, 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', diff --git a/testing/mozharness/configs/builds/releng_base_linux_32_builds.py b/testing/mozharness/configs/builds/releng_base_linux_32_builds.py index ce84dc6e97f6..c54c6ce17079 100644 --- a/testing/mozharness/configs/builds/releng_base_linux_32_builds.py +++ b/testing/mozharness/configs/builds/releng_base_linux_32_builds.py @@ -78,7 +78,6 @@ config = { 'publish_nightly_en_US_routes': True, 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', diff --git a/testing/mozharness/configs/builds/releng_base_linux_64_builds.py b/testing/mozharness/configs/builds/releng_base_linux_64_builds.py index a04fd4d61243..faa8c515f27e 100644 --- a/testing/mozharness/configs/builds/releng_base_linux_64_builds.py +++ b/testing/mozharness/configs/builds/releng_base_linux_64_builds.py @@ -77,7 +77,6 @@ config = { 'publish_nightly_en_US_routes': True, 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', diff --git a/testing/mozharness/configs/builds/releng_base_mac_64_builds.py b/testing/mozharness/configs/builds/releng_base_mac_64_builds.py index 6a49f1671457..305e98f9b78f 100644 --- a/testing/mozharness/configs/builds/releng_base_mac_64_builds.py +++ b/testing/mozharness/configs/builds/releng_base_mac_64_builds.py @@ -44,7 +44,6 @@ config = { 'publish_nightly_en_US_routes': True, 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', 'CHOWN_ROOT': '~/bin/chown_root', diff --git a/testing/mozharness/configs/builds/releng_base_mac_64_cross_builds.py b/testing/mozharness/configs/builds/releng_base_mac_64_cross_builds.py index 2f912d4861f7..2adf4646eb07 100644 --- a/testing/mozharness/configs/builds/releng_base_mac_64_cross_builds.py +++ b/testing/mozharness/configs/builds/releng_base_mac_64_cross_builds.py @@ -49,7 +49,6 @@ config = { 'stage_platform': 'macosx64', 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', 'TINDERBOX_OUTPUT': '1', diff --git a/testing/mozharness/configs/builds/releng_base_windows_32_builds.py b/testing/mozharness/configs/builds/releng_base_windows_32_builds.py index 84d366ad6062..ab56666f6a81 100644 --- a/testing/mozharness/configs/builds/releng_base_windows_32_builds.py +++ b/testing/mozharness/configs/builds/releng_base_windows_32_builds.py @@ -57,7 +57,6 @@ config = { 'publish_nightly_en_US_routes': True, 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'BINSCOPE': 'C:/Program Files (x86)/Microsoft/SDL BinScope/BinScope.exe', 'HG_SHARE_BASE_DIR': 'C:/builds/hg-shared', 'MOZ_CRASHREPORTER_NO_REPORT': '1', diff --git a/testing/mozharness/configs/builds/releng_base_windows_64_builds.py b/testing/mozharness/configs/builds/releng_base_windows_64_builds.py index b37d978bdb0b..47d0fc1d4de9 100644 --- a/testing/mozharness/configs/builds/releng_base_windows_64_builds.py +++ b/testing/mozharness/configs/builds/releng_base_windows_64_builds.py @@ -56,7 +56,6 @@ config = { 'stage_platform': 'win64', 'publish_nightly_en_US_routes': True, 'env': { - 'MOZ_AUTOMATION': '1', 'HG_SHARE_BASE_DIR': 'C:/builds/hg-shared', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/32_artifact.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/32_artifact.py index daa428f59bdf..79dec2830094 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/32_artifact.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/32_artifact.py @@ -45,7 +45,6 @@ config = { 'publish_nightly_en_US_routes': False, 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/32_debug.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/32_debug.py index c5685f3737b1..ff4c581bb510 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/32_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/32_debug.py @@ -22,7 +22,6 @@ config = { #### 32 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': MOZ_OBJDIR, diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/32_debug_artifact.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/32_debug_artifact.py index b55210b70374..0fc83c342fd2 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/32_debug_artifact.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/32_debug_artifact.py @@ -49,7 +49,6 @@ config = { 'publish_nightly_en_US_routes': False, 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': MOZ_OBJDIR, diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/32_qr_debug.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/32_qr_debug.py index 8defab032df0..515d11478441 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/32_qr_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/32_qr_debug.py @@ -22,7 +22,6 @@ config = { #### 32 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': MOZ_OBJDIR, diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_add-on-devel.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_add-on-devel.py index eaf34fbf9b9a..7f6ab4732003 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_add-on-devel.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_add-on-devel.py @@ -22,7 +22,6 @@ config = { #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', 'TINDERBOX_OUTPUT': '1', diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_artifact.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_artifact.py index 518855a57196..d3adfdf1f117 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_artifact.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_artifact.py @@ -47,7 +47,6 @@ config = { 'publish_nightly_en_US_routes': False, 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan.py index 1a455aaf8ebb..0269d1101361 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan.py @@ -26,7 +26,6 @@ asan.manifest", #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan_and_debug.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan_and_debug.py index f5bab47c02f3..c8a69ca41304 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan_and_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan_and_debug.py @@ -27,7 +27,6 @@ asan.manifest", #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan_tc.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan_tc.py index 1a455aaf8ebb..0269d1101361 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan_tc.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan_tc.py @@ -26,7 +26,6 @@ asan.manifest", #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan_tc_and_debug.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan_tc_and_debug.py index f5bab47c02f3..c8a69ca41304 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan_tc_and_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_asan_tc_and_debug.py @@ -27,7 +27,6 @@ asan.manifest", #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_code_coverage.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_code_coverage.py index 1f8a518a4189..a03840bc2b99 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_code_coverage.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_code_coverage.py @@ -23,7 +23,6 @@ config = { #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_debug.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_debug.py index dd51f2955d51..da3bc74eead6 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_debug.py @@ -22,7 +22,6 @@ config = { #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': MOZ_OBJDIR, diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_debug_artifact.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_debug_artifact.py index 28ff8feb58c8..fbbf37ad8e94 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_debug_artifact.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_debug_artifact.py @@ -43,7 +43,6 @@ config = { 'publish_nightly_en_US_routes': False, 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': MOZ_OBJDIR, diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_qr_debug.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_qr_debug.py index 520ac3ae09af..3739c5c9ad05 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_qr_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_qr_debug.py @@ -22,7 +22,6 @@ config = { #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': MOZ_OBJDIR, diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stat_and_debug.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stat_and_debug.py index 8b3f5484b1cd..119810398422 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stat_and_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stat_and_debug.py @@ -37,7 +37,6 @@ config = { 'publish_nightly_en_US_routes': False, 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stat_and_opt.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stat_and_opt.py index bec30a9d88d5..becd57750b3f 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stat_and_opt.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stat_and_opt.py @@ -37,7 +37,6 @@ config = { 'publish_nightly_en_US_routes': False, 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stylo.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stylo.py index 5127565bfb8b..1a0340c9a30b 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stylo.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stylo.py @@ -21,7 +21,6 @@ config = { #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': MOZ_OBJDIR, diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stylo_debug.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stylo_debug.py index 04efa070e580..7e864f87eee2 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stylo_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stylo_debug.py @@ -21,7 +21,6 @@ config = { 'enable_talos_sendchange': False, 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': MOZ_OBJDIR, diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_valgrind.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_valgrind.py index c7a2fba5638d..b4e02c50e9a3 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_valgrind.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_valgrind.py @@ -28,7 +28,6 @@ releng.manifest", #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'DISPLAY': ':2', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', diff --git a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_add-on-devel.py b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_add-on-devel.py index 9b6a3e251375..c92ed68bffe9 100644 --- a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_add-on-devel.py +++ b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_add-on-devel.py @@ -23,7 +23,6 @@ config = { #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', 'TINDERBOX_OUTPUT': '1', diff --git a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_artifact.py b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_artifact.py index b591cadb4391..1f094748c5b7 100644 --- a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_artifact.py +++ b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_artifact.py @@ -42,7 +42,6 @@ config = { 'publish_nightly_en_US_routes': False, 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', 'CHOWN_ROOT': '~/bin/chown_root', diff --git a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_debug.py b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_debug.py index 6f6940c85401..d343c33eb489 100644 --- a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_debug.py @@ -21,7 +21,6 @@ config = { #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', 'TINDERBOX_OUTPUT': '1', diff --git a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_debug_st_an.py b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_debug_st_an.py index 4edacff909d0..4a27d2fd83b2 100644 --- a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_debug_st_an.py +++ b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_debug_st_an.py @@ -17,7 +17,6 @@ config = { #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', 'TINDERBOX_OUTPUT': '1', diff --git a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_opt_st_an.py b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_opt_st_an.py index f29800f14f73..e69d75771f94 100644 --- a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_opt_st_an.py +++ b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_opt_st_an.py @@ -17,7 +17,6 @@ config = { #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', 'TINDERBOX_OUTPUT': '1', diff --git a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_qr_debug.py b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_qr_debug.py index 43d106d35a71..790a26530f96 100644 --- a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_qr_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_cross_qr_debug.py @@ -21,7 +21,6 @@ config = { #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', 'TINDERBOX_OUTPUT': '1', diff --git a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_debug.py b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_debug.py index b584adfe7b10..a72806d480bb 100644 --- a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_debug.py @@ -23,7 +23,6 @@ config = { #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': 'obj-firefox', 'TINDERBOX_OUTPUT': '1', diff --git a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_debug_artifact.py b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_debug_artifact.py index 0a57f81ce213..ae01b1575c0c 100644 --- a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_debug_artifact.py +++ b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_debug_artifact.py @@ -43,7 +43,6 @@ config = { 'publish_nightly_en_US_routes': False, 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': MOZ_OBJDIR, 'TINDERBOX_OUTPUT': '1', diff --git a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_stat_and_debug.py b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_stat_and_debug.py index c27a98bc3f32..88ee2cc56916 100644 --- a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_stat_and_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_stat_and_debug.py @@ -28,7 +28,6 @@ clang.manifest", #### 64 bit build specific ##### 'env': { 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'HG_SHARE_BASE_DIR': '/builds/hg-shared', 'MOZ_OBJDIR': MOZ_OBJDIR, 'TINDERBOX_OUTPUT': '1', diff --git a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_add-on-devel.py b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_add-on-devel.py index 69658ea9a421..efc3c230e6e4 100644 --- a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_add-on-devel.py +++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_add-on-devel.py @@ -21,7 +21,6 @@ config = { 'BINSCOPE': 'C:/Program Files (x86)/Microsoft/SDL BinScope/BinScope.exe', 'HG_SHARE_BASE_DIR': 'C:/builds/hg-shared', 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PATH': 'C:/mozilla-build/nsis-3.01;C:/mozilla-build/python27;' diff --git a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_debug.py b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_debug.py index 70e90194ef01..3ab58e2c87af 100644 --- a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_debug.py @@ -23,7 +23,6 @@ config = { 'BINSCOPE': 'C:/Program Files (x86)/Microsoft/SDL BinScope/BinScope.exe', 'HG_SHARE_BASE_DIR': 'C:/builds/hg-shared', 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PATH': 'C:/mozilla-build/nsis-3.01;C:/mozilla-build/python27;' diff --git a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_stat_and_debug.py b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_stat_and_debug.py index e364e339fc4f..95ecb97e3714 100644 --- a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_stat_and_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_stat_and_debug.py @@ -27,7 +27,6 @@ clang.manifest", 'BINSCOPE': 'C:/Program Files (x86)/Microsoft/SDL BinScope/BinScope.exe', 'HG_SHARE_BASE_DIR': 'C:/builds/hg-shared', 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PATH': 'C:/mozilla-build/nsis-3.01;C:/mozilla-build/python27;' diff --git a/testing/mozharness/configs/builds/releng_sub_windows_configs/64_add-on-devel.py b/testing/mozharness/configs/builds/releng_sub_windows_configs/64_add-on-devel.py index ce5d6f6279cc..4caf0dfad4c1 100644 --- a/testing/mozharness/configs/builds/releng_sub_windows_configs/64_add-on-devel.py +++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/64_add-on-devel.py @@ -20,7 +20,6 @@ config = { 'env': { 'BINSCOPE': 'C:/Program Files (x86)/Microsoft/SDL BinScope/BinScope.exe', 'HG_SHARE_BASE_DIR': 'C:/builds/hg-shared', - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PATH': 'C:/mozilla-build/nsis-3.01;C:/mozilla-build/python27;' diff --git a/testing/mozharness/configs/builds/releng_sub_windows_configs/64_debug.py b/testing/mozharness/configs/builds/releng_sub_windows_configs/64_debug.py index 37306dafa1ae..57f0dd32c64c 100644 --- a/testing/mozharness/configs/builds/releng_sub_windows_configs/64_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/64_debug.py @@ -22,7 +22,6 @@ config = { 'env': { 'BINSCOPE': 'C:/Program Files (x86)/Microsoft/SDL BinScope/BinScope.exe', 'HG_SHARE_BASE_DIR': 'C:/builds/hg-shared', - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PATH': 'C:/mozilla-build/nsis-3.01;C:/mozilla-build/python27;' diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_win32_clang.py b/testing/mozharness/configs/builds/taskcluster_firefox_win32_clang.py index b0b43a68d185..04c90cb8d9ff 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_win32_clang.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_win32_clang.py @@ -63,7 +63,6 @@ config = { ), 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x86/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_win32_clang_debug.py b/testing/mozharness/configs/builds/taskcluster_firefox_win32_clang_debug.py index 021d2919f737..f27686b6f489 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_win32_clang_debug.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_win32_clang_debug.py @@ -64,7 +64,6 @@ config = { ), 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x86/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_win32_qr_debug.py b/testing/mozharness/configs/builds/taskcluster_firefox_win32_qr_debug.py index e73a3246e46e..7ece4511f847 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_win32_qr_debug.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_win32_qr_debug.py @@ -65,7 +65,6 @@ config = { ), 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x86/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_win32_qr_opt.py b/testing/mozharness/configs/builds/taskcluster_firefox_win32_qr_opt.py index 6ec595b9f369..124c6eb7bf27 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_win32_qr_opt.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_win32_qr_opt.py @@ -64,7 +64,6 @@ config = { ), 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x86/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_win64_asan_debug.py b/testing/mozharness/configs/builds/taskcluster_firefox_win64_asan_debug.py index aa3527bd10b1..37f04162fe78 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_win64_asan_debug.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_win64_asan_debug.py @@ -60,7 +60,6 @@ config = { 'publish_nightly_en_US_routes': True, 'env': { 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': '/c/Program Files (x86)/Windows Kits/10/Debuggers/x64/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_win64_asan_opt.py b/testing/mozharness/configs/builds/taskcluster_firefox_win64_asan_opt.py index 1409ce732169..46a96d05c84c 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_win64_asan_opt.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_win64_asan_opt.py @@ -59,7 +59,6 @@ config = { 'publish_nightly_en_US_routes': True, 'env': { 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': '/c/Program Files (x86)/Windows Kits/10/Debuggers/x64/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_win64_clang.py b/testing/mozharness/configs/builds/taskcluster_firefox_win64_clang.py index 8b9ffdbe2bcd..d81862e61ee9 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_win64_clang.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_win64_clang.py @@ -59,7 +59,6 @@ config = { 'publish_nightly_en_US_routes': True, 'env': { 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x64/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_win64_clang_debug.py b/testing/mozharness/configs/builds/taskcluster_firefox_win64_clang_debug.py index 75165b8a95fc..da2346629b4d 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_win64_clang_debug.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_win64_clang_debug.py @@ -60,7 +60,6 @@ config = { 'publish_nightly_en_US_routes': True, 'env': { 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x64/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_win64_qr_debug.py b/testing/mozharness/configs/builds/taskcluster_firefox_win64_qr_debug.py index 423b547fa765..c07caa80c6d2 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_win64_qr_debug.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_win64_qr_debug.py @@ -56,7 +56,6 @@ config = { 'publish_nightly_en_US_routes': True, 'env': { 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x64/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_win64_qr_opt.py b/testing/mozharness/configs/builds/taskcluster_firefox_win64_qr_opt.py index 3c8ff03baa67..f5405720a9d6 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_win64_qr_opt.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_win64_qr_opt.py @@ -55,7 +55,6 @@ config = { 'publish_nightly_en_US_routes': True, 'env': { 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x64/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_addondevel.py b/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_addondevel.py index 32f4f5258cb1..f2202233f919 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_addondevel.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_addondevel.py @@ -64,7 +64,6 @@ config = { ), 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x86/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_debug.py b/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_debug.py index 7c05722ff7e2..e7174a0729e1 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_debug.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_debug.py @@ -65,7 +65,6 @@ config = { ), 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x86/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_opt.py b/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_opt.py index d99785876d7b..1d33aa220061 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_opt.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_opt.py @@ -64,7 +64,6 @@ config = { ), 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), 'MOZBUILD_STATE_PATH': os.path.join(os.getcwd(), '.mozbuild'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x86/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_addondevel.py b/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_addondevel.py index 74c273126cb8..b90a8d4484b2 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_addondevel.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_addondevel.py @@ -61,7 +61,6 @@ config = { 'publish_nightly_en_US_routes': False, 'env': { 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x64/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_debug.py b/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_debug.py index d87ce623242a..1c3dbcf20ed2 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_debug.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_debug.py @@ -61,7 +61,6 @@ config = { 'publish_nightly_en_US_routes': True, 'env': { 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x64/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_opt.py b/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_opt.py index 63549031f014..e2341e5c3596 100644 --- a/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_opt.py +++ b/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_opt.py @@ -60,7 +60,6 @@ config = { 'publish_nightly_en_US_routes': True, 'env': { 'HG_SHARE_BASE_DIR': os.path.join('y:', os.sep, 'hg-shared'), - 'MOZ_AUTOMATION': '1', 'MOZ_CRASHREPORTER_NO_REPORT': '1', 'MOZ_OBJDIR': 'obj-firefox', 'PDBSTR_PATH': 'C:/Program Files (x86)/Windows Kits/10/Debuggers/x64/srcsrv/pdbstr.exe', diff --git a/testing/mozharness/configs/merge_day/central_to_aurora.py b/testing/mozharness/configs/merge_day/central_to_aurora.py deleted file mode 100644 index 0a0df5f965e4..000000000000 --- a/testing/mozharness/configs/merge_day/central_to_aurora.py +++ /dev/null @@ -1,96 +0,0 @@ -import os - -ABS_WORK_DIR = os.path.join(os.getcwd(), "build") -config = { - "log_name": "central_to_aurora", - "version_files": [ - {"file": "browser/config/version.txt", "suffix": ""}, - {"file": "browser/config/version_display.txt", "suffix": ""}, - {"file": "config/milestone.txt", "suffix": ""}, - ], - "replacements": [ - # File, from, to - ("{}/{}".format(d, f), - "ac_add_options --with-branding=mobile/android/branding/nightly", - "ac_add_options --with-branding=mobile/android/branding/aurora") - for d in ["mobile/android/config/mozconfigs/android-api-15/", - "mobile/android/config/mozconfigs/android-x86/"] - for f in ["debug", "nightly", "l10n-nightly"] - ] + [ - # File, from, to - ("{}/{}".format(d, f), - "ac_add_options --with-branding=browser/branding/nightly", - "ac_add_options --with-branding=browser/branding/aurora") - for d in ["browser/config/mozconfigs/linux32", - "browser/config/mozconfigs/linux64", - "browser/config/mozconfigs/win32", - "browser/config/mozconfigs/win64", - "browser/config/mozconfigs/macosx64"] - for f in ["debug", "nightly", "l10n-mozconfig"] - ] + [ - # File, from, to - ("{}/{}".format(d, f), - "ac_add_options --with-l10n-base=../../l10n-central", - "ac_add_options --with-l10n-base=../../mozilla-aurora") - for d in ["mobile/android/config/mozconfigs/android-api-15/", - "mobile/android/config/mozconfigs/android-x86/"] - for f in ["l10n-nightly", "l10n-release"] - ] + [ - # File, from, to - (f, "ac_add_options --enable-profiling", "") for f in - ["mobile/android/config/mozconfigs/android-api-15/nightly", - "mobile/android/config/mozconfigs/android-x86/nightly", - "browser/config/mozconfigs/linux32/nightly", - "browser/config/mozconfigs/linux64/nightly", - "browser/config/mozconfigs/macosx64/nightly", - "browser/config/mozconfigs/win32/nightly", - "browser/config/mozconfigs/win64/nightly"] - ] + [ - # File, from, to - ("browser/confvars.sh", - "ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-central", - "ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-aurora"), - ("browser/confvars.sh", - "MAR_CHANNEL_ID=firefox-mozilla-central", - "MAR_CHANNEL_ID=firefox-mozilla-aurora"), - ("browser/config/mozconfigs/whitelist", - "ac_add_options --with-branding=browser/branding/nightly", - "ac_add_options --with-branding=browser/branding/aurora"), - ], - "locale_files": [ - "browser/locales/shipped-locales", - "browser/locales/all-locales", - "mobile/android/locales/maemo-locales", - "mobile/android/locales/all-locales", - "mobile/locales/l10n-changesets.json", - ], - - "vcs_share_base": os.path.join(ABS_WORK_DIR, 'hg-shared'), - # "hg_share_base": None, - "tools_repo_url": "https://hg.mozilla.org/build/tools", - "tools_repo_branch": "default", - "from_repo_url": "ssh://hg.mozilla.org/mozilla-central", - "to_repo_url": "ssh://hg.mozilla.org/releases/mozilla-aurora", - - "base_tag": "FIREFOX_AURORA_%(major_version)s_BASE", - "end_tag": "FIREFOX_AURORA_%(major_version)s_END", - - "migration_behavior": "central_to_aurora", - - "balrog_rules_to_lock": [ - 8, # Fennec aurora channel - 10, # Firefox aurora channel - 18, # MetroFirefox aurora channel - ], - "balrog_credentials_file": "oauth.txt", - - "virtualenv_modules": [ - "requests==2.8.1", - ], - - "post_merge_builders": [], - "post_merge_nightly_branches": [ - "mozilla-central", - "mozilla-aurora", - ], -} diff --git a/testing/mozharness/configs/merge_day/aurora_to_beta.py b/testing/mozharness/configs/merge_day/central_to_beta.py similarity index 69% rename from testing/mozharness/configs/merge_day/aurora_to_beta.py rename to testing/mozharness/configs/merge_day/central_to_beta.py index 77b1e494640b..a189fec3d58f 100644 --- a/testing/mozharness/configs/merge_day/aurora_to_beta.py +++ b/testing/mozharness/configs/merge_day/central_to_beta.py @@ -3,7 +3,7 @@ import os ABS_WORK_DIR = os.path.join(os.getcwd(), "build") config = { - "log_name": "aurora_to_beta", + "log_name": "central_to_beta", "version_files": [ {"file": "browser/config/version.txt", "suffix": ""}, {"file": "browser/config/version_display.txt", "suffix": "b1"}, @@ -12,50 +12,48 @@ config = { "replacements": [ # File, from, to ("{}/{}".format(d, f), - "ac_add_options --with-branding=mobile/android/branding/aurora", + "ac_add_options --with-branding=mobile/android/branding/nightly", "ac_add_options --with-branding=mobile/android/branding/beta") for d in ["mobile/android/config/mozconfigs/android-api-15/", "mobile/android/config/mozconfigs/android-x86/"] for f in ["debug", "nightly", "l10n-nightly"] ] + [ # File, from, to - ("{}/{}".format(d, f), - "ac_add_options --with-l10n-base=../../mozilla-aurora", - "ac_add_options --with-l10n-base=../../mozilla-beta") - for d in ["mobile/android/config/mozconfigs/android-api-15/", - "mobile/android/config/mozconfigs/android-x86/"] - for f in ["l10n-nightly", "l10n-release"] - ] + [ - # File, from, to - ("{}/{}".format(d, f), - "ac_add_options --with-branding=browser/branding/aurora", - "ac_add_options --with-branding=browser/branding/nightly") - for d in ["browser/config/mozconfigs/linux32", - "browser/config/mozconfigs/linux64", - "browser/config/mozconfigs/win32", - "browser/config/mozconfigs/win64", - "browser/config/mozconfigs/macosx64"] - for f in ["debug", "nightly"] - ] + [ - # File, from, to - (f, "ac_add_options --with-branding=browser/branding/aurora", - "ac_add_options --enable-official-branding") + (f, "ac_add_options --with-branding=browser/branding/nightly", + "ac_add_options --enable-official-branding") for f in ["browser/config/mozconfigs/linux32/l10n-mozconfig", "browser/config/mozconfigs/linux64/l10n-mozconfig", "browser/config/mozconfigs/win32/l10n-mozconfig", "browser/config/mozconfigs/win64/l10n-mozconfig", "browser/config/mozconfigs/macosx64/l10n-mozconfig"] ] + [ + # File, from, to + ("{}/{}".format(d, f), + "ac_add_options --with-l10n-base=../../l10n-central", + "ac_add_options --with-l10n-base=../../mozilla-beta") + for d in ["mobile/android/config/mozconfigs/android-api-15/", + "mobile/android/config/mozconfigs/android-x86/"] + for f in ["l10n-nightly", "l10n-release"] + ] + [ + # File, from, to + (f, "ac_add_options --enable-profiling", "") for f in + ["mobile/android/config/mozconfigs/android-api-15/nightly", + "mobile/android/config/mozconfigs/android-x86/nightly", + "browser/config/mozconfigs/linux32/nightly", + "browser/config/mozconfigs/linux64/nightly", + "browser/config/mozconfigs/macosx64/nightly", + "browser/config/mozconfigs/win32/nightly", + "browser/config/mozconfigs/win64/nightly"] + ] + [ + # File, from, to ("browser/confvars.sh", - "ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-aurora", + "ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-central", "ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-beta,firefox-mozilla-release"), ("browser/confvars.sh", - "MAR_CHANNEL_ID=firefox-mozilla-aurora", + "MAR_CHANNEL_ID=firefox-mozilla-central", "MAR_CHANNEL_ID=firefox-mozilla-beta"), - ("browser/config/mozconfigs/whitelist", - "ac_add_options --with-branding=browser/branding/aurora", - "ac_add_options --with-branding=browser/branding/nightly"), ] + [ + # File, from, to ("build/mozconfig.common", "MOZ_REQUIRE_SIGNING=${MOZ_REQUIRE_SIGNING-0}", "MOZ_REQUIRE_SIGNING=${MOZ_REQUIRE_SIGNING-1}"), @@ -68,13 +66,13 @@ config = { # "hg_share_base": None, "tools_repo_url": "https://hg.mozilla.org/build/tools", "tools_repo_branch": "default", - "from_repo_url": "ssh://hg.mozilla.org/releases/mozilla-aurora", + "from_repo_url": "ssh://hg.mozilla.org/mozilla-central", "to_repo_url": "ssh://hg.mozilla.org/releases/mozilla-beta", "base_tag": "FIREFOX_BETA_%(major_version)s_BASE", "end_tag": "FIREFOX_BETA_%(major_version)s_END", - "migration_behavior": "aurora_to_beta", + "migration_behavior": "central_to_beta", "virtualenv_modules": [ "requests==2.8.1", diff --git a/testing/mozharness/mozharness/mozilla/firefox/__init__.py b/testing/mozharness/mozharness/mozilla/firefox/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/testing/mozharness/mozharness/mozilla/firefox/autoconfig.py b/testing/mozharness/mozharness/mozilla/firefox/autoconfig.py new file mode 100644 index 000000000000..ba6bd5a60b9b --- /dev/null +++ b/testing/mozharness/mozharness/mozilla/firefox/autoconfig.py @@ -0,0 +1,64 @@ +''' This module helps modifying Firefox with autoconfig files.''' +# 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 mozharness.base.script import platform_name + +AUTOCONFIG_TEXT = '''// Any comment. You must start the file with a comment! +// This entry tells the browser to load a mozilla.cfg +pref("general.config.filename", "mozilla.cfg"); +pref("general.config.obscure_value", 0); +''' + + +def write_autoconfig_files(fx_install_dir, + cfg_contents, + autoconfig_contents=AUTOCONFIG_TEXT): + ''' Generate autoconfig files to modify Firefox's set up + + Read documentation in here: + https://developer.mozilla.org/en-US/Firefox/Enterprise_deployment#Configuration + + fx_install_dir - path to Firefox installation + cfg_contents - .cfg file containing JavaScript changes for Firefox + autoconfig_contents - autoconfig.js content to refer to .cfg gile + ''' + with open(_cfg_file_path(fx_install_dir), 'w') as fd: + fd.write(cfg_contents) + with open(_autoconfig_path(fx_install_dir), 'w') as fd: + fd.write(autoconfig_contents) + + +def _autoconfig_path(fx_install_dir): + platform = platform_name() + if platform in ('win32', 'win64'): + return os.path.join(fx_install_dir, + 'defaults', 'pref', 'autoconfig.js') + elif platform in ('linux', 'linux64'): + return os.path.join(fx_install_dir, + 'defaults/pref/autoconfig.js') + elif platform in ('macosx'): + return os.path.join(fx_install_dir, + 'Contents/Resources/defaults/pref/autoconfig.js') + else: + raise Exception('Invalid platform.') + + +def _cfg_file_path(fx_install_dir): + ''' + Windows: defaults\pref + Mac: Firefox.app/Contents/Resources/defaults/pref + Linux: defaults/pref + ''' + platform = platform_name() + if platform in ('win32', 'win64'): + return os.path.join(fx_install_dir, 'mozilla.cfg') + elif platform in ('linux', 'linux64'): + return os.path.join(fx_install_dir, 'mozilla.cfg') + elif platform in ('macosx'): + return os.path.join(fx_install_dir, + 'Contents/Resources/mozilla.cfg') + else: + raise Exception('Invalid platform.') diff --git a/testing/mozharness/mozharness/mozilla/mitmproxy.py b/testing/mozharness/mozharness/mozilla/mitmproxy.py new file mode 100644 index 000000000000..5309a4e1b524 --- /dev/null +++ b/testing/mozharness/mozharness/mozilla/mitmproxy.py @@ -0,0 +1,47 @@ +'''This helps loading mitmproxy's cert and change proxy settings for Firefox.''' +# 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 mozharness.mozilla.firefox.autoconfig import write_autoconfig_files + +DEFAULT_CERT_PATH = os.path.join(os.getenv('HOME'), + '.mitmproxy', 'mitmproxy-ca-cert.cer') +MITMPROXY_SETTINGS = '''// Start with a comment +// Load up mitmproxy cert +var Cc = Components.classes; +var Ci = Components.interfaces; +var certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB); +var certdb2 = certdb; + +try { +certdb2 = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB2); +} catch (e) {} + +cert = "%(cert)s"; +certdb2.addCertFromBase64(cert, "C,C,C", ""); + +// Use mitmdump as the proxy +// Manual proxy configuration +pref("network.proxy.type", 1); +pref("network.proxy.http", "127.0.0.1"); +pref("network.proxy.http_port", 8080); +pref("network.proxy.ssl", "127.0.0.1"); +pref("network.proxy.ssl_port", 8080); +''' + + +def configure_mitmproxy(fx_install_dir, certificate_path=DEFAULT_CERT_PATH): + certificate = _read_certificate(certificate_path) + write_autoconfig_files(fx_install_dir=fx_install_dir, + cfg_contents=MITMPROXY_SETTINGS % { + 'cert': certificate}) + + +def _read_certificate(certificate_path): + ''' Return the certificate's hash from the certificate file.''' + # NOTE: mitmproxy's certificates do not exist until one of its binaries + # has been executed once on the host + with open(certificate_path, 'r') as fd: + contents = fd.read() + return ''.join(contents.splitlines()[1:-1]) diff --git a/testing/mozharness/scripts/merge_day/gecko_migration.py b/testing/mozharness/scripts/merge_day/gecko_migration.py index 0e9f0979d85e..c9353704e0aa 100755 --- a/testing/mozharness/scripts/merge_day/gecko_migration.py +++ b/testing/mozharness/scripts/merge_day/gecko_migration.py @@ -7,8 +7,8 @@ # ***** END LICENSE BLOCK ***** """ gecko_migration.py -Merge day script for gecko (mozilla-central -> mozilla-aurora, -mozilla-aurora -> mozilla-beta, mozilla-beta -> mozilla-release). +Merge day script for gecko (mozilla-central -> mozilla-beta, +mozilla-beta -> mozilla-release). Ported largely from http://hg.mozilla.org/build/tools/file/084bc4e2fc76/release/beta2release.py @@ -33,8 +33,7 @@ from mozharness.mozilla.buildbot import BuildbotMixin from mozharness.mozilla.repo_manipulation import MercurialRepoManipulationMixin VALID_MIGRATION_BEHAVIORS = ( - "beta_to_release", "aurora_to_beta", "central_to_aurora", "release_to_esr", - "bump_second_digit", + "beta_to_release", "central_to_beta", "release_to_esr", "bump_second_digit", ) @@ -170,7 +169,7 @@ class GeckoMigration(MercurialScript, BalrogMixin, VirtualenvMixin, def query_commit_dirs(self): dirs = self.query_abs_dirs() commit_dirs = [dirs['abs_to_dir']] - if self.config['migration_behavior'] == 'central_to_aurora': + if self.config['migration_behavior'] == 'central_to_beta': commit_dirs.append(dirs['abs_from_dir']) return commit_dirs @@ -288,8 +287,8 @@ class GeckoMigration(MercurialScript, BalrogMixin, VirtualenvMixin, self.write_to_file(clobber_file, new_contents) def bump_version(self, cwd, curr_version, next_version, curr_suffix, - next_suffix, bump_major=False): - """ Bump versions (m-c, m-a, m-b). + next_suffix, bump_major=False, use_config_suffix=False): + """ Bump versions (m-c, m-b). At some point we may want to unhardcode these filenames into config """ @@ -297,7 +296,10 @@ class GeckoMigration(MercurialScript, BalrogMixin, VirtualenvMixin, next_weave_version = str(int(curr_weave_version) + 1) for f in self.config["version_files"]: from_ = "%s.0%s" % (curr_version, curr_suffix) - to = "%s.0%s%s" % (next_version, next_suffix, f["suffix"]) + if use_config_suffix: + to = "%s.0%s%s" % (next_version, next_suffix, f["suffix"]) + else: + to = "%s.0%s" % (next_version, next_suffix) self.replace(os.path.join(cwd, f["file"]), from_, to) # only applicable for m-c @@ -314,8 +316,8 @@ class GeckoMigration(MercurialScript, BalrogMixin, VirtualenvMixin, ) # Branch-specific workflow helper methods {{{1 - def central_to_aurora(self, end_tag): - """ mozilla-central -> mozilla-aurora behavior. + def central_to_beta(self, end_tag): + """ mozilla-central -> mozilla-beta behavior. We could have all of these individually toggled by flags, but by separating into workflow methods we can be more precise about @@ -323,48 +325,21 @@ class GeckoMigration(MercurialScript, BalrogMixin, VirtualenvMixin, staging beta user repo migrations. """ dirs = self.query_abs_dirs() - self.info("Reverting locales") - hg = self.query_exe("hg", return_type="list") - for f in self.config["locale_files"]: - self.run_command( - hg + ["revert", "-r", end_tag, f], - cwd=dirs['abs_to_dir'], - error_list=HgErrorList, - halt_on_failure=True, - ) - next_ma_version = self.get_version(dirs['abs_to_dir'])[0] - self.bump_version(dirs['abs_to_dir'], next_ma_version, next_ma_version, "a1", "a2") + next_mb_version = self.get_version(dirs['abs_to_dir'])[0] + self.bump_version(dirs['abs_to_dir'], next_mb_version, next_mb_version, "a1", "", use_config_suffix=True) self.apply_replacements() # bump m-c version curr_mc_version = self.get_version(dirs['abs_from_dir'])[0] next_mc_version = str(int(curr_mc_version) + 1) self.bump_version( dirs['abs_from_dir'], curr_mc_version, next_mc_version, "a1", "a1", - bump_major=True + bump_major=True, + use_config_suffix=False ) # touch clobber files self.touch_clobber_file(dirs['abs_from_dir']) self.touch_clobber_file(dirs['abs_to_dir']) - def aurora_to_beta(self, *args, **kwargs): - """ mozilla-aurora -> mozilla-beta behavior. - - We could have all of these individually toggled by flags, but - by separating into workflow methods we can be more precise about - what happens in each workflow, while allowing for things like - staging beta user repo migrations. - """ - dirs = self.query_abs_dirs() - mb_version = self.get_version(dirs['abs_to_dir'])[0] - self.bump_version(dirs['abs_to_dir'], mb_version, mb_version, "a2", "") - self.apply_replacements() - self.touch_clobber_file(dirs['abs_to_dir']) - # TODO mozconfig diffing - # The build/tools version only checks the mozconfigs from hgweb, so - # can't help pre-push. The in-tree mozconfig diffing requires a mach - # virtualenv to be installed. If we want this sooner we can put this - # in the push action; otherwise we may just wait until we have in-tree - # mozconfig checking. def beta_to_release(self, *args, **kwargs): """ mozilla-beta -> mozilla-release behavior. diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 8346eac77a3a..d15626d6f53e 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -211714,11 +211714,11 @@ "testharness" ], "web-animations/animation-model/animation-types/property-list.js": [ - "2843e53e0bf500d529062dce14889693fdf9f58a", + "7845e786fa31d2a707a018ca99e3f3bb53fb3083", "support" ], "web-animations/animation-model/animation-types/property-types.js": [ - "b42366e9ef71bc6671543a05a85a5b932b2e2e03", + "634bf959bd37624d1846a4b87595eee8b90f9146", "support" ], "web-animations/animation-model/animation-types/spacing-keyframes-filters.html": [ diff --git a/testing/web-platform/meta/web-animations/animation-model/animation-types/addition-per-property.html.ini b/testing/web-platform/meta/web-animations/animation-model/animation-types/addition-per-property.html.ini index 2ee458e8b2d6..96a6536e7174 100644 --- a/testing/web-platform/meta/web-animations/animation-model/animation-types/addition-per-property.html.ini +++ b/testing/web-platform/meta/web-animations/animation-model/animation-types/addition-per-property.html.ini @@ -4,3 +4,7 @@ prefs: [layout.css.contain.enabled:true, layout.css.initial-letter.enabled:true, [column-gap: "normal" onto "200px"] expected: FAIL bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1356241 + + [stroke-dasharray: dasharray] + expected: FAIL + bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1361738 diff --git a/testing/web-platform/tests/web-animations/animation-model/animation-types/property-list.js b/testing/web-platform/tests/web-animations/animation-model/animation-types/property-list.js index 41513df28a9b..ea5cec70caa3 100644 --- a/testing/web-platform/tests/web-animations/animation-model/animation-types/property-list.js +++ b/testing/web-platform/tests/web-animations/animation-model/animation-types/property-list.js @@ -1235,8 +1235,7 @@ var gCSSProperties = { }, 'stroke-dasharray': { // https://svgwg.org/svg2-draft/painting.html#StrokeDasharrayProperty - types: [ - ] + types: [ 'dasharray' ] }, 'stroke-dashoffset': { // https://svgwg.org/svg2-draft/painting.html#StrokeDashoffsetProperty @@ -1260,13 +1259,11 @@ var gCSSProperties = { }, 'stroke-miterlimit': { // https://svgwg.org/svg2-draft/painting.html#StrokeMiterlimitProperty - types: [ - ] + types: [ 'positiveNumber' ] }, 'stroke-opacity': { // https://svgwg.org/svg2-draft/painting.html#StrokeOpacityProperty - types: [ - ] + types: [ 'opacity' ] }, 'stroke-width': { // https://svgwg.org/svg2-draft/painting.html#StrokeWidthProperty diff --git a/testing/web-platform/tests/web-animations/animation-model/animation-types/property-types.js b/testing/web-platform/tests/web-animations/animation-model/animation-types/property-types.js index 27537ee22607..55737defabbf 100644 --- a/testing/web-platform/tests/web-animations/animation-model/animation-types/property-types.js +++ b/testing/web-platform/tests/web-animations/animation-model/animation-types/property-types.js @@ -405,6 +405,41 @@ const positiveNumberType = { }; +// Test using float values in the range [0, 1] +const opacityType = { + testInterpolation: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: [0.3, 0.8] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples(animation, idlName, + [{ time: 500, expected: '0.55' }]); + }, property + ' supports animating as a [0, 1] number'); + }, + + testAddition: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 0.3; + var animation = target.animate({ [idlName]: [0.3, 0.8] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '0.6' }]); + }, property + ': [0, 1] number'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = 0.8; + var animation = target.animate({ [idlName]: [0.3, 0.8] }, + { duration: 1000, composite: 'add' }); + testAnimationSamples(animation, idlName, [{ time: 0, expected: '1' }]); + }, property + ': [0, 1] number (clamped)'); + }, + +}; + const visibilityType = { testInterpolation: function(property, setup) { test(function(t) { @@ -1218,6 +1253,57 @@ const rectType = { }, } +// stroke-dasharray: none | [ | | ]* +const dasharrayType = { + testInterpolation: function(property, setup) { + percentageType.testInterpolation(property, setup); + positiveNumberType.testInterpolation(property, setup); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: + ['8, 16, 4', + '4, 8, 12, 16'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples( + animation, idlName, + [{ time: 500, expected: '6, 12, 8, 12, 10, 6, 10, 16, 4, 8, 14, 10' }]); + }, property + ' supports animating as a dasharray (mismatched length)'); + + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + var animation = target.animate({ [idlName]: + ['2, 50%, 6, 10', + '6, 30%, 2, 2'] }, + { duration: 1000, fill: 'both' }); + testAnimationSamples( + animation, idlName, + [{ time: 500, expected: '4, 40%, 4, 6' }]); + }, property + ' supports animating as a dasharray (mixed number and percentage)'); + + }, + + // Note that stroke-dasharray is non-additive property, so we should write this + // additive test case that animating value replaces underlying values. + // See https://www.w3.org/TR/SVG2/painting.html#StrokeDashing. + testAddition: function(property, setup) { + test(function(t) { + var idlName = propertyToIDL(property); + var target = createTestElement(t, setup); + target.style[idlName] = '6, 30%, 2px'; + var animation = target.animate({ [idlName]: + ['1, 2, 3, 4, 5', + '6, 7, 8, 9, 10'] }, + { duration: 1000, fill: 'add' }); + testAnimationSamples( + animation, idlName, + [{ time: 0, expected: '1, 2, 3, 4, 5' }]); + }, property + ': dasharray'); + }, +} + const types = { color: colorType, discrete: discreteType, @@ -1229,11 +1315,13 @@ const types = { lengthPercentageOrCalc: lengthPercentageOrCalcType, lengthPair: lengthPairType, positiveNumber: positiveNumberType, + opacity: opacityType, transformList: transformListType, visibility: visibilityType, boxShadowList: boxShadowListType, textShadowList: textShadowListType, rect: rectType, position: positionType, + dasharray: dasharrayType, }; diff --git a/toolkit/components/extensions/ext-management.js b/toolkit/components/extensions/ext-management.js index f1e1f3a1f482..f661cc3f1002 100644 --- a/toolkit/components/extensions/ext-management.js +++ b/toolkit/components/extensions/ext-management.js @@ -11,6 +11,17 @@ XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", XPCOMUtils.defineLazyServiceGetter(this, "promptService", "@mozilla.org/embedcomp/prompt-service;1", "nsIPromptService"); +XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter", + "resource://devtools/shared/event-emitter.js"); + +XPCOMUtils.defineLazyGetter(this, "GlobalManager", () => { + const {GlobalManager} = Cu.import("resource://gre/modules/Extension.jsm", {}); + return GlobalManager; +}); + +var { + ExtensionError, +} = ExtensionUtils; function _(key, ...args) { if (args.length) { @@ -30,79 +41,212 @@ function installType(addon) { return "normal"; } +function getExtensionInfoForAddon(extension, addon) { + let extInfo = { + id: addon.id, + name: addon.name, + description: addon.description || "", + version: addon.version, + mayDisable: !!(addon.permissions & AddonManager.PERM_CAN_DISABLE), + enabled: addon.isActive, + optionsUrl: addon.optionsURL || "", + installType: installType(addon), + type: addon.type, + }; + + if (extension) { + let m = extension.manifest; + extInfo.permissions = Array.from(extension.permissions).filter(perm => { + return !extension.whiteListedHosts.pat.includes(perm); + }); + extInfo.hostPermissions = extension.whiteListedHosts.pat; + extInfo.shortName = m.short_name || ""; + if (m.icons) { + extInfo.icons = Object.keys(m.icons).map(key => { + return {size: Number(key), url: m.icons[key]}; + }); + } + } + + if (!addon.isActive) { + extInfo.disabledReason = "unknown"; + } + if (addon.homepageURL) { + extInfo.homepageUrl = addon.homepageURL; + } + if (addon.updateURL) { + extInfo.updateUrl = addon.updateURL; + } + return extInfo; +} + +const listenerMap = new WeakMap(); +// Some management APIs are intentionally limited. +const allowedTypes = ["theme"]; + +class AddonListener { + constructor() { + AddonManager.addAddonListener(this); + EventEmitter.decorate(this); + } + + release() { + AddonManager.removeAddonListener(this); + } + + getExtensionInfo(addon) { + let ext = addon.isWebExtension && GlobalManager.extensionMap.get(addon.id); + return getExtensionInfoForAddon(ext, addon); + } + + onEnabled(addon) { + if (!allowedTypes.includes(addon.type)) { + return; + } + this.emit("onEnabled", this.getExtensionInfo(addon)); + } + + onDisabled(addon) { + if (!allowedTypes.includes(addon.type)) { + return; + } + this.emit("onDisabled", this.getExtensionInfo(addon)); + } + + onInstalled(addon) { + if (!allowedTypes.includes(addon.type)) { + return; + } + this.emit("onInstalled", this.getExtensionInfo(addon)); + } + + onUninstalled(addon) { + if (!allowedTypes.includes(addon.type)) { + return; + } + this.emit("onUninstalled", this.getExtensionInfo(addon)); + } +} + +let addonListener; + +function getListener(extension, context) { + if (!listenerMap.has(extension)) { + if (!addonListener) { + addonListener = new AddonListener(); + } + listenerMap.set(extension, {}); + context.callOnClose({ + close: () => { + listenerMap.delete(extension); + if (listenerMap.length === 0) { + addonListener.release(); + addonListener = null; + } + }, + }); + } + return addonListener; +} + this.management = class extends ExtensionAPI { getAPI(context) { let {extension} = context; return { management: { - getSelf: function() { - return new Promise((resolve, reject) => AddonManager.getAddonByID(extension.id, addon => { - try { - let m = extension.manifest; - let extInfo = { - id: extension.id, - name: addon.name, - shortName: m.short_name || "", - description: addon.description || "", - version: addon.version, - mayDisable: !!(addon.permissions & AddonManager.PERM_CAN_DISABLE), - enabled: addon.isActive, - optionsUrl: addon.optionsURL || "", - permissions: Array.from(extension.permissions).filter(perm => { - return !extension.whiteListedHosts.pat.includes(perm); - }), - hostPermissions: extension.whiteListedHosts.pat, - installType: installType(addon), - }; - if (addon.homepageURL) { - extInfo.homepageUrl = addon.homepageURL; - } - if (addon.updateURL) { - extInfo.updateUrl = addon.updateURL; - } - if (m.icons) { - extInfo.icons = Object.keys(m.icons).map(key => { - return {size: Number(key), url: m.icons[key]}; - }); - } - - resolve(extInfo); - } catch (err) { - reject(err); - } - })); - }, - - uninstallSelf: function(options) { - return new Promise((resolve, reject) => { - if (options && options.showConfirmDialog) { - let message = _("uninstall.confirmation.message", extension.name); - if (options.dialogMessage) { - message = `${options.dialogMessage}\n${message}`; - } - let title = _("uninstall.confirmation.title", extension.name); - let buttonFlags = promptService.BUTTON_POS_0 * promptService.BUTTON_TITLE_IS_STRING + - promptService.BUTTON_POS_1 * promptService.BUTTON_TITLE_IS_STRING; - let button0Title = _("uninstall.confirmation.button-0.label"); - let button1Title = _("uninstall.confirmation.button-1.label"); - let response = promptService.confirmEx(null, title, message, buttonFlags, button0Title, button1Title, null, null, {value: 0}); - if (response == 1) { - return reject({message: "User cancelled uninstall of extension"}); - } - } - AddonManager.getAddonByID(extension.id, addon => { - let canUninstall = Boolean(addon.permissions & AddonManager.PERM_CAN_UNINSTALL); - if (!canUninstall) { - return reject({message: "The add-on cannot be uninstalled"}); - } - try { - addon.uninstall(); - } catch (err) { - return reject(err); - } - }); + async getAll() { + let addons = await AddonManager.getAddonsByTypes(allowedTypes); + return addons.map(addon => { + // If the extension is enabled get it and use it for more data. + let ext = addon.isWebExtension && GlobalManager.extensionMap.get(addon.id); + return getExtensionInfoForAddon(ext, addon); }); }, + + async getSelf() { + let addon = await AddonManager.getAddonByID(extension.id); + return getExtensionInfoForAddon(extension, addon); + }, + + async uninstallSelf(options) { + if (options && options.showConfirmDialog) { + let message = _("uninstall.confirmation.message", extension.name); + if (options.dialogMessage) { + message = `${options.dialogMessage}\n${message}`; + } + let title = _("uninstall.confirmation.title", extension.name); + let buttonFlags = promptService.BUTTON_POS_0 * promptService.BUTTON_TITLE_IS_STRING + + promptService.BUTTON_POS_1 * promptService.BUTTON_TITLE_IS_STRING; + let button0Title = _("uninstall.confirmation.button-0.label"); + let button1Title = _("uninstall.confirmation.button-1.label"); + let response = promptService.confirmEx(null, title, message, buttonFlags, button0Title, button1Title, null, null, {value: 0}); + if (response == 1) { + throw new ExtensionError("User cancelled uninstall of extension"); + } + } + let addon = await AddonManager.getAddonByID(extension.id); + let canUninstall = Boolean(addon.permissions & AddonManager.PERM_CAN_UNINSTALL); + if (!canUninstall) { + throw new ExtensionError("The add-on cannot be uninstalled"); + } + addon.uninstall(); + }, + + async setEnabled(id, enabled) { + let addon = await AddonManager.getAddonByID(id); + if (!addon) { + throw new ExtensionError(`No such addon ${id}`); + } + if (!allowedTypes.includes(addon.type)) { + throw new ExtensionError("setEnabled applies only to theme addons"); + } + addon.userDisabled = !enabled; + }, + + onDisabled: new SingletonEventManager(context, "management.onDisabled", fire => { + let listener = (event, data) => { + fire.async(data); + }; + + getListener(extension, context).on("onDisabled", listener); + return () => { + getListener(extension, context).off("onDisabled", listener); + }; + }).api(), + + onEnabled: new SingletonEventManager(context, "management.onEnabled", fire => { + let listener = (event, data) => { + fire.async(data); + }; + + getListener(extension, context).on("onEnabled", listener); + return () => { + getListener(extension, context).off("onEnabled", listener); + }; + }).api(), + + onInstalled: new SingletonEventManager(context, "management.onInstalled", fire => { + let listener = (event, data) => { + fire.async(data); + }; + + getListener(extension, context).on("onInstalled", listener); + return () => { + getListener(extension, context).off("onInstalled", listener); + }; + }).api(), + + onUninstalled: new SingletonEventManager(context, "management.onUninstalled", fire => { + let listener = (event, data) => { + fire.async(data); + }; + + getListener(extension, context).on("onUninstalled", listener); + return () => { + getListener(extension, context).off("onUninstalled", listener); + }; + }).api(), + }, }; } diff --git a/toolkit/components/extensions/schemas/management.json b/toolkit/components/extensions/schemas/management.json index 413ff1d0d9f2..b4339e3bc1b3 100644 --- a/toolkit/components/extensions/schemas/management.json +++ b/toolkit/components/extensions/schemas/management.json @@ -69,7 +69,8 @@ }, "shortName": { "description": "A short version of the name of this extension.", - "type": "string" + "type": "string", + "optional": true }, "description": { "description": "The description of this extension.", @@ -126,6 +127,7 @@ "permissions": { "description": "Returns a list of API based permissions.", "type": "array", + "optional": true, "items" : { "type": "string" } @@ -133,6 +135,7 @@ "hostPermissions": { "description": "Returns a list of host based permissions.", "type": "array", + "optional": true, "items" : { "type": "string" } @@ -149,7 +152,6 @@ "name": "getAll", "type": "function", "permissions": ["management"], - "unsupported": true, "description": "Returns a list of information about installed extensions.", "async": "callback", "parameters": [ @@ -244,6 +246,81 @@ "parameters": [] } ] + }, + { + "name": "setEnabled", + "type": "function", + "permissions": ["management"], + "description": "Enables or disables the given add-on.", + "async": "callback", + "parameters": [ + { + "name": "id", + "type": "string", + "description": "ID of the add-on to enable/disable." + }, + { + "name": "enabled", + "type": "boolean", + "description": "Whether to enable or disable the add-on." + }, + { + "name": "callback", + "type": "function", + "optional": true, + "parameters": [] + } + ] + } + ], + "events": [ + { + "name": "onDisabled", + "type": "function", + "permissions": ["management"], + "description": "Fired when an addon has been disabled.", + "parameters": [ + { + "name": "info", + "$ref": "ExtensionInfo" + } + ] + }, + { + "name": "onEnabled", + "type": "function", + "permissions": ["management"], + "description": "Fired when an addon has been enabled.", + "parameters": [ + { + "name": "info", + "$ref": "ExtensionInfo" + } + ] + }, + { + "name": "onInstalled", + "type": "function", + "permissions": ["management"], + "description": "Fired when an addon has been installed.", + "parameters": [ + { + "name": "info", + "$ref": "ExtensionInfo" + } + ] + }, + { + "name": "onUninstalled", + "type": "function", + "permissions": ["management"], + "description": "Fired when an addon has been uninstalled.", + "parameters": [ + { + "name": "info", + "$ref": "ExtensionInfo" + } + ] } ] } diff --git a/toolkit/components/extensions/test/browser/browser.ini b/toolkit/components/extensions/test/browser/browser.ini index 38bdfa91836a..c07a78991195 100644 --- a/toolkit/components/extensions/test/browser/browser.ini +++ b/toolkit/components/extensions/test/browser/browser.ini @@ -7,3 +7,4 @@ support-files = [browser_ext_themes_lwtsupport.js] [browser_ext_themes_multiple_backgrounds.js] [browser_ext_themes_persistence.js] +[browser_ext_management_themes.js] diff --git a/toolkit/components/extensions/test/browser/browser_ext_management_themes.js b/toolkit/components/extensions/test/browser/browser_ext_management_themes.js new file mode 100644 index 000000000000..13727ece8024 --- /dev/null +++ b/toolkit/components/extensions/test/browser/browser_ext_management_themes.js @@ -0,0 +1,133 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +const {LightweightThemeManager} = Cu.import("resource://gre/modules/LightweightThemeManager.jsm", {}); + +add_task(async function setup() { + await SpecialPowers.pushPrefEnv({ + set: [["extensions.webextensions.themes.enabled", true]], + }); +}); + +add_task(async function test_management_themes() { + let theme = ExtensionTestUtils.loadExtension({ + manifest: { + "name": "Simple theme test", + "version": "1.0", + "description": "test theme", + "theme": { + "images": { + "headerURL": "image1.png", + }, + }, + }, + files: { + "image1.png": BACKGROUND, + }, + useAddonManager: "temporary", + }); + + async function background() { + browser.management.onInstalled.addListener(info => { + browser.test.log(`${info.name} was installed`); + browser.test.assertEq(info.type, "theme", "addon is theme"); + browser.test.sendMessage("onInstalled", info.name); + }); + browser.management.onDisabled.addListener(info => { + browser.test.log(`${info.name} was disabled`); + browser.test.assertEq(info.type, "theme", "addon is theme"); + browser.test.sendMessage("onDisabled", info.name); + }); + browser.management.onEnabled.addListener(info => { + browser.test.log(`${info.name} was enabled`); + browser.test.assertEq(info.type, "theme", "addon is theme"); + browser.test.sendMessage("onEnabled", info.name); + }); + browser.management.onUninstalled.addListener(info => { + browser.test.log(`${info.name} was uninstalled`); + browser.test.assertEq(info.type, "theme", "addon is theme"); + browser.test.sendMessage("onUninstalled", info.name); + }); + + async function getAddon(type) { + let addons = await browser.management.getAll(); + // We get the 3 built-in themes plus the lwt and our addon. + browser.test.assertEq(5, addons.length, "got expected addons"); + let found; + for (let addon of addons) { + browser.test.assertEq(addon.type, "theme", "addon is theme"); + if (type == "theme" && addon.id.includes("temporary-addon")) { + found = addon; + } else if (type == "enabled" && addon.enabled) { + found = addon; + } + } + return found; + } + + browser.test.onMessage.addListener(async (msg) => { + let theme = await getAddon("theme"); + browser.test.assertEq(theme.description, "test theme", "description is correct"); + browser.test.assertTrue(theme.enabled, "theme is enabled"); + await browser.management.setEnabled(theme.id, false); + + theme = await getAddon("theme"); + + browser.test.assertTrue(!theme.enabled, "theme is disabled"); + let addon = getAddon("enabled"); + browser.test.assertTrue(addon, "another theme was enabled"); + + await browser.management.setEnabled(theme.id, true); + theme = await getAddon("theme"); + addon = await getAddon("enabled"); + browser.test.assertEq(theme.id, addon.id, "theme is enabled"); + + browser.test.sendMessage("done"); + }); + } + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions: ["management"], + }, + background, + }); + await extension.startup(); + + // Test LWT + LightweightThemeManager.currentTheme = { + id: "lwt@personas.mozilla.org", + version: "1", + name: "Bling", + description: "SO MUCH BLING!", + author: "Pixel Pusher", + homepageURL: "http://mochi.test:8888/data/index.html", + headerURL: "http://mochi.test:8888/data/header.png", + previewURL: "http://mochi.test:8888/data/preview.png", + iconURL: "http://mochi.test:8888/data/icon.png", + textcolor: Math.random().toString(), + accentcolor: Math.random().toString(), + }; + is(await extension.awaitMessage("onInstalled"), "Bling", "LWT installed"); + is(await extension.awaitMessage("onDisabled"), "Default", "default disabled"); + is(await extension.awaitMessage("onEnabled"), "Bling", "LWT enabled"); + + await theme.startup(); + is(await extension.awaitMessage("onInstalled"), "Simple theme test", "webextension theme installed"); + is(await extension.awaitMessage("onDisabled"), "Bling", "LWT disabled"); + // no enabled event when installed. + + extension.sendMessage("test"); + is(await extension.awaitMessage("onEnabled"), "Default", "default enabled"); + is(await extension.awaitMessage("onDisabled"), "Simple theme test", "addon disabled"); + is(await extension.awaitMessage("onEnabled"), "Simple theme test", "addon enabled"); + is(await extension.awaitMessage("onDisabled"), "Default", "default disabled"); + await extension.awaitMessage("done"); + + await Promise.all([ + theme.unload(), + extension.awaitMessage("onUninstalled"), + ]); + await extension.unload(); +}); diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_management.js b/toolkit/components/extensions/test/xpcshell/test_ext_management.js index b19554a57ed6..c10c2fe15a23 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_management.js +++ b/toolkit/components/extensions/test/xpcshell/test_ext_management.js @@ -2,9 +2,18 @@ /* vim: set sts=2 sw=2 et tw=80: */ "use strict"; +XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", + "resource://gre/modules/AddonManager.jsm"); + +add_task(function* setup() { + yield ExtensionTestUtils.startAddonManager(); +}); + add_task(function* test_management_schema() { - function background() { + async function background() { browser.test.assertTrue(browser.management, "browser.management API exists"); + let self = await browser.management.getSelf(); + browser.test.assertEq(browser.runtime.id, self.id, "got self"); browser.test.notifyPass("management-schema"); } @@ -13,6 +22,7 @@ add_task(function* test_management_schema() { permissions: ["management"], }, background: `(${background})()`, + useAddonManager: "temporary", }); yield extension.startup(); yield extension.awaitFinish("management-schema"); diff --git a/toolkit/components/places/nsPlacesTriggers.h b/toolkit/components/places/nsPlacesTriggers.h index d64ffa098625..caef8b9c0427 100644 --- a/toolkit/components/places/nsPlacesTriggers.h +++ b/toolkit/components/places/nsPlacesTriggers.h @@ -63,28 +63,30 @@ * have higher priority, and more generically "www." prefixed hosts come before * unprefixed ones. * Given a host, examine associated pages and: - * - if all of the typed pages start with https://www. return https://www. - * - if all of the typed pages start with https:// return https:// + * - if at least half the typed pages start with https://www. return https://www. + * - if at least half the typed pages start with https:// return https:// * - if all of the typed pages start with ftp: return ftp:// - * - if all of the typed pages start with www. return www. + * - This is because mostly people will want to visit the http version + * of the site. + * - if at least half the typed pages start with www. return www. * - otherwise don't use any prefix */ #define HOSTS_PREFIX_PRIORITY_FRAGMENT \ "SELECT CASE " \ - "WHEN 1 = ( " \ - "SELECT min(substr(url,1,12) = 'https://www.') FROM moz_places h " \ + "WHEN ( " \ + "SELECT round(avg(substr(url,1,12) = 'https://www.')) FROM moz_places h " \ "WHERE (" HOST_TO_REVHOST_PREDICATE ") AND +h.typed = 1 " \ ") THEN 'https://www.' " \ - "WHEN 1 = ( " \ - "SELECT min(substr(url,1,8) = 'https://') FROM moz_places h " \ + "WHEN ( " \ + "SELECT round(avg(substr(url,1,8) = 'https://')) FROM moz_places h " \ "WHERE (" HOST_TO_REVHOST_PREDICATE ") AND +h.typed = 1 " \ ") THEN 'https://' " \ "WHEN 1 = ( " \ "SELECT min(substr(url,1,4) = 'ftp:') FROM moz_places h " \ "WHERE (" HOST_TO_REVHOST_PREDICATE ") AND +h.typed = 1 " \ ") THEN 'ftp://' " \ - "WHEN 1 = ( " \ - "SELECT min(substr(url,1,11) = 'http://www.') FROM moz_places h " \ + "WHEN ( " \ + "SELECT round(avg(substr(url,1,11) = 'http://www.')) FROM moz_places h " \ "WHERE (" HOST_TO_REVHOST_PREDICATE ") AND +h.typed = 1 " \ ") THEN 'www.' " \ "END " diff --git a/toolkit/components/places/tests/unifiedcomplete/test_trimming.js b/toolkit/components/places/tests/unifiedcomplete/test_trimming.js index e55b009ff964..34ff20ee854b 100644 --- a/toolkit/components/places/tests/unifiedcomplete/test_trimming.js +++ b/toolkit/components/places/tests/unifiedcomplete/test_trimming.js @@ -131,7 +131,7 @@ add_task(function* test_priority_1() { yield cleanup(); }); -add_task(function* test_periority_2() { +add_task(function* test_priority_2() { do_print( "Ensuring correct priority 2"); yield PlacesTestUtils.addVisits([ { uri: NetUtil.newURI("https://mozilla.org/test/"), transition: TRANSITION_TYPED }, @@ -147,7 +147,7 @@ add_task(function* test_periority_2() { yield cleanup(); }); -add_task(function* test_periority_3() { +add_task(function* test_priority_3() { do_print("Ensuring correct priority 3"); yield PlacesTestUtils.addVisits([ { uri: NetUtil.newURI("ftp://mozilla.org/test/"), transition: TRANSITION_TYPED }, @@ -162,7 +162,7 @@ add_task(function* test_periority_3() { yield cleanup(); }); -add_task(function* test_periority_4() { +add_task(function* test_priority_4() { do_print("Ensuring correct priority 4"); yield PlacesTestUtils.addVisits([ { uri: NetUtil.newURI("http://www.mozilla.org/test/"), transition: TRANSITION_TYPED }, @@ -171,7 +171,7 @@ add_task(function* test_periority_4() { yield check_autocomplete({ search: "mo", autofilled: "mozilla.org/", - completed: "mozilla.org/" + completed: "www.mozilla.org/" }); yield cleanup(); }); diff --git a/toolkit/components/places/tests/unit/test_hosts_triggers.js b/toolkit/components/places/tests/unit/test_hosts_triggers.js index c9285eddc2d7..35b723e650f5 100644 --- a/toolkit/components/places/tests/unit/test_hosts_triggers.js +++ b/toolkit/components/places/tests/unit/test_hosts_triggers.js @@ -31,20 +31,34 @@ function isHostInMozPlaces(aURI) { return result; } -function isHostInMozHosts(aURI, aTyped, aPrefix) { +function checkHostInMozHosts(aURI, aTyped, aPrefix, aShouldBePresent = true) { + if (typeof aURI == "string") { + aURI = new URL(aURI); + } let stmt = DBConn().createStatement( `SELECT host, typed, prefix FROM moz_hosts WHERE host = fixup_url(:host) AND frecency NOTNULL` ); - let result = false; + let result; stmt.params.host = aURI.host; if (stmt.executeStep()) { - result = aTyped == stmt.row.typed && aPrefix == stmt.row.prefix; + result = {typed: stmt.row.typed, prefix: stmt.row.prefix}; } stmt.finalize(); - return result; + + if (aShouldBePresent) { + Assert.ok(result, "Result should be defined."); + Assert.equal(result.typed, aTyped, "The typed field should match."); + Assert.equal(result.prefix, aPrefix, "The prefix field should match."); + } else { + Assert.strictEqual(result, undefined); + } +} + +function checkHostNotInMozHosts(aURI, aTyped, aPrefix) { + checkHostInMozHosts(aURI, aTyped, aPrefix, false); } var urls = [{uri: NetUtil.newURI("http://visit1.mozilla.org"), @@ -77,16 +91,16 @@ add_task(function* test_moz_hosts_update() { yield PlacesTestUtils.addVisits(places); - do_check_true(isHostInMozHosts(urls[0].uri, urls[0].typed, urls[0].prefix)); - do_check_true(isHostInMozHosts(urls[1].uri, urls[1].typed, urls[1].prefix)); - do_check_true(isHostInMozHosts(urls[2].uri, urls[2].typed, urls[2].prefix)); + checkHostInMozHosts(urls[0].uri, urls[0].typed, urls[0].prefix); + checkHostInMozHosts(urls[1].uri, urls[1].typed, urls[1].prefix); + checkHostInMozHosts(urls[2].uri, urls[2].typed, urls[2].prefix); }); add_task(function* test_remove_places() { yield PlacesUtils.history.remove(urls.map(x => x.uri)); for (let idx in urls) { - do_check_false(isHostInMozHosts(urls[idx].uri, urls[idx].typed, urls[idx].prefix)); + checkHostNotInMozHosts(urls[idx].uri, urls[idx].typed, urls[idx].prefix); } }); @@ -107,8 +121,8 @@ add_task(function* test_bookmark_changes() { let newUri = NetUtil.newURI(NEW_URL); do_check_true(isHostInMozPlaces(newUri)); - do_check_true(isHostInMozHosts(newUri, false, null)); - do_check_false(isHostInMozHosts(NetUtil.newURI("http://test.mozilla.org"), false, null)); + checkHostInMozHosts(newUri, false, null); + checkHostNotInMozHosts(NetUtil.newURI("http://test.mozilla.org"), false, null); }); add_task(function* test_bookmark_removal() { @@ -118,7 +132,7 @@ add_task(function* test_bookmark_removal() { PlacesUtils.bookmarks.removeItem(itemId); yield PlacesTestUtils.clearHistory(); - do_check_false(isHostInMozHosts(newUri, false, null)); + checkHostNotInMozHosts(newUri, false, null); }); add_task(function* test_moz_hosts_typed_update() { @@ -133,7 +147,7 @@ add_task(function* test_moz_hosts_typed_update() { yield PlacesTestUtils.addVisits(places); - do_check_true(isHostInMozHosts(TEST_URI, true, null)); + checkHostInMozHosts(TEST_URI, true, null); yield PlacesTestUtils.clearHistory(); }); @@ -156,7 +170,7 @@ add_task(function* test_moz_hosts_www_remove() { let prefix = /www/.test(aURIToKeep.spec) ? "www." : null; dump_table("moz_hosts"); dump_table("moz_places"); - do_check_true(isHostInMozHosts(aURIToKeep, true, prefix)); + checkHostInMozHosts(aURIToKeep, true, prefix); } const TEST_URI = NetUtil.newURI("http://rem.mozilla.com"); @@ -175,7 +189,7 @@ add_task(function* test_moz_hosts_ftp_matchall() { { uri: TEST_URI_2, transition: TRANSITION_TYPED } ]); - do_check_true(isHostInMozHosts(TEST_URI_1, true, "ftp://")); + checkHostInMozHosts(TEST_URI_1, true, "ftp://"); }); add_task(function* test_moz_hosts_ftp_not_matchall() { @@ -187,7 +201,7 @@ add_task(function* test_moz_hosts_ftp_not_matchall() { { uri: TEST_URI_2, transition: TRANSITION_TYPED } ]); - do_check_true(isHostInMozHosts(TEST_URI_1, true, null)); + checkHostInMozHosts(TEST_URI_1, true, null); }); add_task(function* test_moz_hosts_update_2() { @@ -202,9 +216,155 @@ add_task(function* test_moz_hosts_update_2() { }]; yield PlacesTestUtils.addVisits(places); - do_check_true(isHostInMozHosts(TEST_URI_1, true, "https://www.")); + checkHostInMozHosts(TEST_URI_1, true, "https://www."); }); -function run_test() { - run_next_test(); +function getTestSection(baseURL1, baseURL2, baseURL2Prefix, extra) { + let extraStr = ""; + let expectedSimplePrefix = null; + let expectedUpgradePrefix = baseURL2Prefix; + if (extra) { + extraStr = ` (${extra})`; + expectedSimplePrefix = `${extra}.`; + expectedUpgradePrefix = `${baseURL2Prefix}${extra}.`; + } + return [{ + title: `Test simple url${extraStr}`, + visits: [{ uri: baseURL1, transition: TRANSITION_TYPED }], + expect: [baseURL1, true, expectedSimplePrefix] + }, { + title: `Test upgrade url${extraStr}`, + visits: [{ uri: baseURL2, transition: TRANSITION_TYPED }], + expect: [baseURL2, true, expectedUpgradePrefix] + }, { + title: `Test remove simple completely${extraStr}`, + remove: baseURL1, + expect: [baseURL2, true, expectedUpgradePrefix] + }, { + title: `Test add more visits${extraStr}`, + visits: [ + { uri: baseURL2, transition: TRANSITION_TYPED }, + { uri: baseURL1, transition: TRANSITION_TYPED }, + ], + expect: [baseURL2, true, expectedUpgradePrefix] + }, { + title: `Test remove upgrade url${extraStr}`, + remove: baseURL2, + expect: [baseURL2, true, expectedSimplePrefix] + }]; } + +const hostsUpdateTests = [{ + title: "Upgrade Secure/Downgrade Insecure", + tests: getTestSection("http://example.com", "https://example.com", "https://") +}, { + title: "Upgrade Secure/Downgrade Insecure (www)", + tests: getTestSection("http://www.example1.com", "https://www.example1.com", "https://", "www") +}, { + title: "Upgrade Secure/Downgrade non-www to www", + tests: getTestSection("http://example3.com", "http://www.example3.com", "www.") +}, { + title: "Switch to/from ftp", + tests: [{ + title: `Test normal url`, + visits: [{ uri: "http://example4.com", transition: TRANSITION_TYPED }], + expect: ["http://example4.com", true, null] + }, { + title: `Test switch to ftp`, + visits: [{ uri: "ftp://example4.com", transition: TRANSITION_TYPED }], + // ftp is only switched to if all pages are ftp:// + remove: ["http://example4.com"], + expect: ["ftp://example4.com", true, "ftp://"] + }, { + title: `Test visit http`, + visits: [{ uri: "http://example4.com", transition: TRANSITION_TYPED }], + expect: ["ftp://example4.com", true, null] + }] +}, { + title: "Multiple URLs for source", + tests: [{ + title: `Test simple insecure`, + visits: [{ uri: "http://example2.com", transition: TRANSITION_TYPED }], + expect: ["http://example2.com", true, null] + }, { + title: `Test upgrade secure`, + visits: [{ uri: "https://example2.com", transition: TRANSITION_TYPED }], + expect: ["https://example2.com", true, "https://"] + }, { + title: `Test extra insecure visit`, + visits: [{ uri: "http://example2.com/fake", transition: TRANSITION_TYPED }], + expect: ["https://example2.com", true, null] + }, { + title: `Test extra secure visits`, + visits: [ + { uri: "https://example2.com/foo", transition: TRANSITION_TYPED }, + { uri: "https://example2.com/bar", transition: TRANSITION_TYPED }, + ], + expect: ["https://example2.com", true, "https://"] + }, { + title: `Test remove secure`, + remove: ["https://example2.com", "https://example2.com/foo", "https://example2.com/bar"], + expect: ["https://example2.com", true, null] + }] +}, { + title: "Test upgrade tree", + tests: [{ + title: `Add ftp`, + visits: [{ uri: "ftp://example5.com", transition: TRANSITION_TYPED }], + expect: ["http://example5.com", true, "ftp://"] + }, { + title: `Add basic http`, + visits: [{ uri: "http://example5.com", transition: TRANSITION_TYPED }], + expect: ["http://example5.com", true, null] + }, { + title: `Add basic www`, + visits: [ + // Add multiples to exceed the average. + { uri: "http://www.example5.com", transition: TRANSITION_TYPED }, + { uri: "http://www.example5.com/past", transition: TRANSITION_TYPED } + ], + expect: ["http://example5.com", true, "www."] + }, { + title: `Add https`, + visits: [ + // Add multiples to exceed the average. + { uri: "https://example5.com", transition: TRANSITION_TYPED }, + { uri: "https://example5.com/past", transition: TRANSITION_TYPED }, + { uri: "https://example5.com/mak", transition: TRANSITION_TYPED }, + { uri: "https://example5.com/standard8", transition: TRANSITION_TYPED } + ], + expect: ["https://example5.com", true, "https://"] + }, { + title: `Add https www`, + visits: [ + // Add multiples to exceed the average. + { uri: "https://www.example5.com", transition: TRANSITION_TYPED }, + { uri: "https://www.example5.com/quantum", transition: TRANSITION_TYPED }, + { uri: "https://www.example5.com/photon", transition: TRANSITION_TYPED }, + { uri: "https://www.example5.com/dash", transition: TRANSITION_TYPED }, + { uri: "https://www.example5.com/flow", transition: TRANSITION_TYPED }, + { uri: "https://www.example5.com/persona", transition: TRANSITION_TYPED }, + { uri: "https://www.example5.com/ff_fx", transition: TRANSITION_TYPED }, + { uri: "https://www.example5.com/search", transition: TRANSITION_TYPED } + ], + expect: ["https://example5.com", true, "https://www."] + }] +}]; + +add_task(function* test_moz_hosts_update() { + for (const section of hostsUpdateTests) { + do_print(section.title); + + for (const test of section.tests) { + do_print(test.title); + + if ("visits" in test) { + yield PlacesTestUtils.addVisits(test.visits); + } + if ("remove" in test) { + yield PlacesUtils.history.remove(test.remove); + } + checkHostInMozHosts(test.expect[0], test.expect[1], test.expect[2]); + } + } +}); diff --git a/toolkit/components/reader/.eslintrc.js b/toolkit/components/reader/.eslintrc.js index e9cb53b780e1..a76f51c4be90 100644 --- a/toolkit/components/reader/.eslintrc.js +++ b/toolkit/components/reader/.eslintrc.js @@ -2,192 +2,11 @@ module.exports = { "rules": { - // Braces only needed for multi-line arrow function blocks - // "arrow-body-style": ["error", "as-needed"], - - // Require spacing around => - // "arrow-spacing": "error", - - // Always require spacing around a single line block - // "block-spacing": "warn", - - // No newline before open brace for a block - "brace-style": "error", - - // No space before always a space after a comma - "comma-spacing": ["error", {"before": false, "after": true}], - - // Commas at the end of the line not the start - // "comma-style": "error", - - // Don't require spaces around computed properties - // "computed-property-spacing": ["error", "never"], - - // Functions must always return something or nothing - "consistent-return": "error", - - // Require braces around blocks that start a new line - // Note that this rule is likely to be overridden on a per-directory basis - // very frequently. - // "curly": ["error", "multi-line"], - - // Always require a trailing EOL - "eol-last": "error", - - // Require function* name() - // "generator-star-spacing": ["error", {"before": false, "after": true}], - - // Two space indent "indent": ["error", 2, { "SwitchCase": 1 }], - - // Space after colon not before in property declarations - "key-spacing": ["error", { "beforeColon": false, "afterColon": true, "mode": "minimum" }], - - // Unix linebreaks - "linebreak-style": ["error", "unix"], - - // Always require parenthesis for new calls "new-parens": "error", - - // Use [] instead of Array() - // "no-array-constructor": "error", - - // No duplicate arguments in function declarations - "no-dupe-args": "error", - - // No duplicate keys in object declarations - "no-dupe-keys": "error", - - // No duplicate cases in switch statements - "no-duplicate-case": "error", - - // No labels - "no-labels": "error", - - // If an if block ends with a return no need for an else block - "no-else-return": "error", - - // No empty statements - "no-empty": "error", - - // No empty character classes in regex - "no-empty-character-class": "error", - - // Disallow empty destructuring - "no-empty-pattern": "error", - - // No assiging to exception variable - // "no-ex-assign": "error", - - // No using !! where casting to boolean is already happening - // "no-extra-boolean-cast": "error", - - // No double semicolon - "no-extra-semi": "error", - - // No overwriting defined functions - "no-func-assign": "error", - - // Declarations in Program or Function Body "no-inner-declarations": "error", - - // No invalid regular expresions - "no-invalid-regexp": "error", - - // No odd whitespace characters - "no-irregular-whitespace": "error", - - // No single if block inside an else block - "no-lonely-if": "error", - - // No mixing spaces and tabs in indent - "no-mixed-spaces-and-tabs": ["error", "smart-tabs"], - - // No unnecessary spacing - "no-multi-spaces": ["error", { exceptions: { "AssignmentExpression": true, "VariableDeclarator": true, "ArrayExpression": true, "ObjectExpression": true } }], - - // No reassigning native JS objects - "no-native-reassign": "error", - - // Nested ternary statements are confusing - "no-nested-ternary": "error", - - // Use {} instead of new Object() - // "no-new-object": "error", - - // No Math() or JSON() - "no-obj-calls": "error", - - // No octal literals - "no-octal": "error", - - // No redeclaring variables - "no-redeclare": "error", - - // No unnecessary comparisons - "no-self-compare": "error", - - // No declaring variables from an outer scope "no-shadow": "error", - - // No declaring variables that hide things like arguments - "no-shadow-restricted-names": "error", - - // No trailing whitespace - "no-trailing-spaces": "error", - - // No using undeclared variables - // "no-undef": "error", - - // Error on newline where a semicolon is needed - "no-unexpected-multiline": "error", - - // No unreachable statements - "no-unreachable": "error", - - // No expressions where a statement is expected - // "no-unused-expressions": "error", - - // No declaring variables that are never used "no-unused-vars": ["error", {"vars": "all", "args": "none"}], - - // No using variables before defined - // "no-use-before-define": ["error", "nofunc"], - - // No using with - "no-with": "error", - - // Always require semicolon at end of statement "semi": ["error", "always"], - - // Require space after keywords - "keyword-spacing": "error", - - // Require space before blocks - "space-before-blocks": "error", - - // Never use spaces before function parentheses - // "space-before-function-paren": ["error", { "anonymous": "always", "named": "never" }], - - // Require spaces before finally, catch, etc. - // "space-before-keywords": ["error", "always"], - - // No space padding in parentheses - // "space-in-parens": ["error", "never"], - - // Require spaces around operators - // "space-infix-ops": "error", - - // Require spaces after return, throw and case - // "space-return-throw-case": "error", - - // ++ and -- should not need spacing - // "space-unary-ops": ["error", { "words": true, "nonwords": false }], - - // No comparisons to NaN - "use-isnan": "error", - - // Only check typeof against valid results - "valid-typeof": "error", }, } diff --git a/toolkit/components/telemetry/pingsender/pingsender_win.cpp b/toolkit/components/telemetry/pingsender/pingsender_win.cpp index 62dbb747e50d..698153ec92f0 100644 --- a/toolkit/components/telemetry/pingsender/pingsender_win.cpp +++ b/toolkit/components/telemetry/pingsender/pingsender_win.cpp @@ -8,6 +8,8 @@ #include #include +#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup") + namespace PingSender { using std::string; diff --git a/toolkit/content/widgets/remote-browser.xml b/toolkit/content/widgets/remote-browser.xml index d40fb8ef26e1..dc53c41526c1 100644 --- a/toolkit/content/widgets/remote-browser.xml +++ b/toolkit/content/widgets/remote-browser.xml @@ -291,7 +291,7 @@ return { permitUnload: true, timedOut: false }; } - const kTimeout = 5000; + const kTimeout = 1000; let finished = false; let responded = false; diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp index 021d7e726465..ce7fb248b930 100644 --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -3618,7 +3618,7 @@ OOPDeinit() delete pidToMinidump; pidToMinidump = nullptr; -#if defined(XP_WIN) +#if defined(XP_WIN) || defined(XP_MACOSX) mozilla::SmprintfFree(childCrashNotifyPipe); childCrashNotifyPipe = nullptr; #endif diff --git a/toolkit/modules/NewTabUtils.jsm b/toolkit/modules/NewTabUtils.jsm index 98173a0f8042..427b73771e9e 100644 --- a/toolkit/modules/NewTabUtils.jsm +++ b/toolkit/modules/NewTabUtils.jsm @@ -927,82 +927,6 @@ var ActivityStreamProvider = { }); }, - /* - * Initializes Activity Stream provider - adds a history observer and a - * bookmarks observer. - */ - init() { - PlacesUtils.history.addObserver(this.historyObserver, true); - PlacesUtils.bookmarks.addObserver(this.bookmarksObsever, true); - }, - - /** - * A set of functions called by @mozilla.org/browser/nav-historyservice - * All history events are emitted from this object. - */ - historyObserver: { - onDeleteURI(uri) { - Services.obs.notifyObservers(null, "newtab-deleteURI", {url: uri.spec}); - }, - - onClearHistory() { - Services.obs.notifyObservers(null, "newtab-clearHistory"); - }, - - onFrecencyChanged(uri, newFrecency, guid, hidden, lastVisitDate) { - if (!hidden && lastVisitDate) { - Services.obs.notifyObservers(null, "newtab-linkChanged", { - url: uri.spec, - frecency: newFrecency, - lastVisitDate, - type: "history" - }); - } - }, - - onManyFrecenciesChanged() { - Services.obs.notifyObservers(null, "newtab-manyLinksChanged"); - }, - - onTitleChanged(uri, newTitle) { - Services.obs.notifyObservers(null, "newtab-linkChanged", {url: uri.spec, title: newTitle}); - }, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver, - Ci.nsISupportsWeakReference]) - }, - - /** - * A set of functions called by @mozilla.org/browser/nav-bookmarks-service - * All bookmark events are emitted from this object. - */ - bookmarksObsever: { - onItemAdded(id, folderId, index, type, uri, title, dateAdded, guid) { - if (type === PlacesUtils.bookmarks.TYPE_BOOKMARK) { - ActivityStreamProvider.getBookmark(guid).then(bookmark => { - Services.obs.notifyObservers(null, "newtab-bookmarkAdded", bookmark); - }).catch(Cu.reportError); - } - }, - - onItemRemoved(id, folderId, index, type, uri) { - if (type === PlacesUtils.bookmarks.TYPE_BOOKMARK) { - Services.obs.notifyObservers(null, "newtab-bookmarkRemoved", {bookmarkId: id, url: uri.spec}); - } - }, - - onItemChanged(id, property, isAnnotation, value, lastModified, type, parent, guid) { - if (type === PlacesUtils.bookmarks.TYPE_BOOKMARK) { - ActivityStreamProvider.getBookmark(guid).then(bookmark => { - Services.obs.notifyObservers(null, "newtab-bookmarkChanged", bookmark); - }).catch(Cu.reportError); - } - }, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver, - Ci.nsISupportsWeakReference]) - }, - /* * Gets the top frecent sites for Activity Stream. * @@ -1172,7 +1096,7 @@ var ActivityStreamLinks = { }, onLinkBlocked(aLink) { - Services.obs.notifyObservers(null, "newtab-linkChanged", {url: aLink.url, blocked: true}) + Services.obs.notifyObservers(null, "newtab-linkBlocked", aLink.url); }, /** @@ -1843,7 +1767,6 @@ this.NewTabUtils = { init: function NewTabUtils_init() { if (this.initWithoutProviders()) { PlacesProvider.init(); - ActivityStreamProvider.init(); Links.addProvider(PlacesProvider); BlockedLinks.addObserver(Links); BlockedLinks.addObserver(ActivityStreamLinks); diff --git a/toolkit/modules/SelectContentHelper.jsm b/toolkit/modules/SelectContentHelper.jsm index ca9a4687a27c..f8221fdd875b 100644 --- a/toolkit/modules/SelectContentHelper.jsm +++ b/toolkit/modules/SelectContentHelper.jsm @@ -42,6 +42,7 @@ this.SelectContentHelper = function(aElement, aOptions, aGlobal) { this._uaColor = null; this._uaSelectBackgroundColor = null; this._uaSelectColor = null; + this._closeAfterBlur = true; this.init(); this.showDropDown(); this._updateTimer = new DeferredTask(this._update.bind(this), 0); @@ -60,6 +61,8 @@ this.SelectContentHelper.prototype = { this.global.addMessageListener("Forms:MouseOver", this); this.global.addMessageListener("Forms:MouseOut", this); this.global.addMessageListener("Forms:MouseUp", this); + this.global.addMessageListener("Forms:SearchFocused", this); + this.global.addMessageListener("Forms:BlurDropDown-Pong", this); this.global.addEventListener("pagehide", this, { mozSystemGroup: true }); this.global.addEventListener("mozhidedropdown", this, { mozSystemGroup: true }); this.element.addEventListener("blur", this, { mozSystemGroup: true }); @@ -81,6 +84,8 @@ this.SelectContentHelper.prototype = { this.global.removeMessageListener("Forms:MouseOver", this); this.global.removeMessageListener("Forms:MouseOut", this); this.global.removeMessageListener("Forms:MouseUp", this); + this.global.removeMessageListener("Forms:SearchFocused", this); + this.global.removeMessageListener("Forms:BlurDropDown-Pong", this); this.global.removeEventListener("pagehide", this, { mozSystemGroup: true }); this.global.removeEventListener("mozhidedropdown", this, { mozSystemGroup: true }); this.element.removeEventListener("blur", this, { mozSystemGroup: true }); @@ -269,6 +274,18 @@ this.SelectContentHelper.prototype = { this.dispatchMouseEvent(win, this.element, "click"); } break; + + case "Forms:SearchFocused": + this._closeAfterBlur = false; + break; + + case "Forms:BlurDropDown-Pong": + if (!this._closeAfterBlur || !gOpen) { + return; + } + this.global.sendAsyncMessage("Forms:HideDropDown", {}); + this.uninit(); + break; } }, @@ -280,7 +297,17 @@ this.SelectContentHelper.prototype = { this.uninit(); } break; - case "blur": + case "blur": { + if (this.element !== event.target) { + break; + } + this._closeAfterBlur = true; + // Send a ping-pong message to make sure that we wait for + // enough cycles to pass from the potential focusing of the + // search box to disable closing-after-blur. + this.global.sendAsyncMessage("Forms:BlurDropDown-Ping", {}); + break; + } case "mozhidedropdown": if (this.element === event.target) { this.global.sendAsyncMessage("Forms:HideDropDown", {}); diff --git a/toolkit/modules/SelectParentHelper.jsm b/toolkit/modules/SelectParentHelper.jsm index efab1ed8d0b1..cf8ba8d86782 100644 --- a/toolkit/modules/SelectParentHelper.jsm +++ b/toolkit/modules/SelectParentHelper.jsm @@ -186,10 +186,14 @@ this.SelectParentHelper = { }, receiveMessage(msg) { + if (!currentBrowser) { + return; + } + if (msg.name == "Forms:UpdateDropDown") { // Sanity check - we'd better know what the currently // opened menulist is, and what browser it belongs to... - if (!currentMenulist || !currentBrowser) { + if (!currentMenulist) { return; } @@ -212,6 +216,8 @@ this.SelectParentHelper = { // Restore scroll position to what it was prior to the update. scrollBox.scrollTop = scrollTop; + } else if (msg.name == "Forms:BlurDropDown-Ping") { + currentBrowser.messageManager.sendAsyncMessage("Forms:BlurDropDown-Pong", {}); } }, @@ -224,6 +230,7 @@ this.SelectParentHelper = { browser.ownerGlobal.addEventListener("keydown", this, true); browser.ownerGlobal.addEventListener("fullscreen", this, true); browser.messageManager.addMessageListener("Forms:UpdateDropDown", this); + browser.messageManager.addMessageListener("Forms:BlurDropDown-Ping", this); }, _unregisterListeners(browser, popup) { @@ -235,6 +242,7 @@ this.SelectParentHelper = { browser.ownerGlobal.removeEventListener("keydown", this, true); browser.ownerGlobal.removeEventListener("fullscreen", this, true); browser.messageManager.removeMessageListener("Forms:UpdateDropDown", this); + browser.messageManager.removeMessageListener("Forms:BlurDropDown-Ping", this); }, }; @@ -461,6 +469,7 @@ function onSearchFocus() { let menupopup = searchObj.parentElement; menupopup.parentElement.menuBoxObject.activeChild = null; menupopup.setAttribute("ignorekeys", "true"); + currentBrowser.messageManager.sendAsyncMessage("Forms:SearchFocused", {}); } function onSearchBlur() { diff --git a/toolkit/mozapps/extensions/test/browser/browser-common.ini b/toolkit/mozapps/extensions/test/browser/browser-common.ini index 8233416a6ba1..9356b00ed51a 100644 --- a/toolkit/mozapps/extensions/test/browser/browser-common.ini +++ b/toolkit/mozapps/extensions/test/browser/browser-common.ini @@ -53,7 +53,6 @@ skip-if = os == 'win' # Disabled on Windows due to intermittent failures (bug 11 [browser_types.js] [browser_inlinesettings.js] [browser_inlinesettings_browser.js] -skip-if = os == 'win' # Disabled on Windows due to highly frequent intermittent failures (bug 1355998) [browser_inlinesettings_custom.js] [browser_inlinesettings_info.js] [browser_tabsettings.js] diff --git a/toolkit/themes/shared/in-content/info-pages.inc.css b/toolkit/themes/shared/in-content/info-pages.inc.css index 865fdb2a8130..b51a9887d1e5 100644 --- a/toolkit/themes/shared/in-content/info-pages.inc.css +++ b/toolkit/themes/shared/in-content/info-pages.inc.css @@ -9,10 +9,7 @@ body { flex-direction: column; box-sizing: border-box; min-height: 100vh; - padding-top: 0; - padding-bottom: 0; - padding-inline-start: calc(48px + 4.6em); - padding-inline-end: 48px; + padding: 0 48px; align-items: center; justify-content: center; } @@ -37,7 +34,7 @@ body { background-size: 1.6em; margin-inline-start: -2.3em; padding-inline-start: 2.3em; - font-size: 2.5em; + font-size: 2.2em; } .title:-moz-locale-dir(rtl), @@ -51,11 +48,7 @@ body { padding-bottom: 0.4em; } -@media (max-width: 675px) { - body { - padding: 0 48px; - } - +@media (max-width: 970px) { .title { background-image: none !important; padding-inline-start: 0; diff --git a/tools/profiler/gecko/Profiler.jsm b/tools/profiler/gecko/Profiler.jsm deleted file mode 100644 index c61218875bd0..000000000000 --- a/tools/profiler/gecko/Profiler.jsm +++ /dev/null @@ -1,16 +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/. */ - -"use strict"; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cr = Components.results; - -this.EXPORTED_SYMBOLS = ["Profiler"]; - -this.Profiler = { - -}; - diff --git a/tools/profiler/moz.build b/tools/profiler/moz.build index d2064a607d1e..8a4af33e3c67 100644 --- a/tools/profiler/moz.build +++ b/tools/profiler/moz.build @@ -16,9 +16,6 @@ if CONFIG['MOZ_GECKO_PROFILER']: 'public/shared-libraries.h', 'public/StoreSequencer.h', ] - EXTRA_JS_MODULES += [ - 'gecko/Profiler.jsm', - ] UNIFIED_SOURCES += [ 'core/platform.cpp', 'core/ProfileBuffer.cpp', diff --git a/widget/windows/PDFViaEMFPrintHelper.cpp b/widget/windows/PDFViaEMFPrintHelper.cpp new file mode 100644 index 000000000000..b0a66d326edf --- /dev/null +++ b/widget/windows/PDFViaEMFPrintHelper.cpp @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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/. */ + +#include "PDFViaEMFPrintHelper.h" +#include "nsIFileStreams.h" +#include "WindowsEMF.h" +#include "nsFileStreams.h" +#include "mozilla/UniquePtrExtensions.h" +#include "mozilla/dom/File.h" +#include "mozilla/Unused.h" + +static +float ComputeScaleFactor(int aDCWidth, int aDCHeight, + int aPageWidth, int aPageHeight) +{ + MOZ_ASSERT(aPageWidth !=0 && aPageWidth != 0); + + float scaleFactor = 1.0; + // If page fits DC - no scaling needed. + if (aDCWidth < aPageWidth || aDCHeight < aPageHeight) { + float xFactor = + static_cast(aDCWidth) / static_cast (aPageWidth); + float yFactor = + static_cast(aDCHeight) / static_cast (aPageHeight); + scaleFactor = std::min(xFactor, yFactor); + } + return scaleFactor; +} + +PDFViaEMFPrintHelper::PDFViaEMFPrintHelper(PRLibrary* aPDFiumLibrary) + : mPDFiumLibrary(aPDFiumLibrary) + , mPDFDoc(nullptr) +{ + MOZ_ASSERT(mPDFiumLibrary); +} + +PDFViaEMFPrintHelper::~PDFViaEMFPrintHelper() +{ + CloseDocument(); +} + +bool +PDFViaEMFPrintHelper::LoadPDFDataToBuffer(nsIFile *aFile) +{ + RefPtr inputStream = new nsFileInputStream(); + if (NS_FAILED(inputStream->Init(aFile, -1, -1, 0))) { + return false; + } + + int64_t size = 0; + inputStream->GetSize(&size); + NS_ENSURE_TRUE(size > 0, false); + + if (!mPDFFileContents.resize(size)) { + return false; + } + + uint32_t bytesRead = 0; + inputStream->Read(mPDFFileContents.begin(), size, &bytesRead); + MOZ_ASSERT(bytesRead == size); + return true; +} + +nsresult +PDFViaEMFPrintHelper::OpenDocument(nsIFile *aFile) +{ + MOZ_ASSERT(aFile); + if (mPDFDoc) { + MOZ_ASSERT_UNREACHABLE("We can only open one PDF at a time"); + return NS_ERROR_FAILURE; + } + + if (!mPDFiumEngine) { + mPDFiumEngine = MakeUnique(mPDFiumLibrary); + } + + if (!LoadPDFDataToBuffer(aFile)) { + return NS_ERROR_FAILURE; + } + // Create Bug 1359713 to implement loading document by path in + // PDFiumEngineShim. + mPDFDoc = mPDFiumEngine->LoadMemDocument(mPDFFileContents.begin(), + mPDFFileContents.length(), + nullptr); + if (!mPDFDoc) { + mPDFFileContents.clear(); + return NS_ERROR_FAILURE; + } + + if (mPDFiumEngine->GetPageCount(mPDFDoc) < 1) { + CloseDocument(); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +bool +PDFViaEMFPrintHelper::RenderPageToDC(HDC aDC, unsigned int aPageIndex, + int aPageWidth, int aPageHeight) +{ + MOZ_ASSERT(aDC && mPDFDoc); + MOZ_ASSERT(static_cast(aPageIndex) < + mPDFiumEngine->GetPageCount(mPDFDoc)); + + if (aPageWidth <= 0 || aPageHeight <= 0) { + return false; + } + + FPDF_PAGE pdfPage = mPDFiumEngine->LoadPage(mPDFDoc, aPageIndex); + NS_ENSURE_TRUE(pdfPage, false); + + int dcWidth = ::GetDeviceCaps(aDC, HORZRES); + int dcHeight = ::GetDeviceCaps(aDC, VERTRES); + float scaleFactor = ComputeScaleFactor(dcWidth,dcHeight, + aPageWidth, aPageHeight); + int savedState = ::SaveDC(aDC); + ::SetGraphicsMode(aDC, GM_ADVANCED); + XFORM xform = { 0 }; + xform.eM11 = xform.eM22 = scaleFactor; + ::ModifyWorldTransform(aDC, &xform, MWT_LEFTMULTIPLY); + + // The caller wanted all drawing to happen within the bounds specified. + // Based on scale calculations, our destination rect might be larger + // than the bounds. Set the clip rect to the bounds. + ::IntersectClipRect(aDC, 0, 0, aPageWidth, aPageHeight); + + mPDFiumEngine->RenderPage(aDC, pdfPage, + 0, 0, aPageWidth, aPageHeight, + 0, FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH); + mPDFiumEngine->ClosePage(pdfPage); + ::RestoreDC(aDC, savedState); + + return true; +} + +bool +PDFViaEMFPrintHelper::DrawPage(HDC aPrinterDC, unsigned int aPageIndex, + int aPageWidth, int aPageHeight) +{ + // There is a comment in Chromium. + // https://cs.chromium.org/chromium/src/pdf/pdfium/pdfium_engine.cc?rcl=9ad9f6860b4d6a4ec7f7f975b2c99672e02d5d49&l=4008 + // Some PDFs seems to render very slowly if RenderPageToDC is directly used + // on a printer DC. + // The way Chromium works around the issue at the code linked above is to + // print to a bitmap and send that to a printer. Instead of doing that we + // render to an EMF file and replay that on the printer DC. It is unclear + // whether our approach will avoid the performance issues though. Bug + // 1359298 covers investigating that. + + MOZ_ASSERT(aPrinterDC); + WindowsEMF emf; + bool result = emf.InitForDrawing(); + NS_ENSURE_TRUE(result, false); + + result = RenderPageToDC(emf.GetDC(), aPageIndex, aPageWidth, aPageHeight); + NS_ENSURE_TRUE(result, false); + + RECT printRect = {0, 0, aPageWidth, aPageHeight}; + result = emf.Playback(aPrinterDC, &printRect); + return result; +} + +bool +PDFViaEMFPrintHelper::DrawPageToFile(const wchar_t* aFilePath, + unsigned int aPageIndex, + int aPageWidth, int aPageHeight) +{ + WindowsEMF emf; + bool result = emf.InitForDrawing(aFilePath); + NS_ENSURE_TRUE(result, false); + + result = RenderPageToDC(emf.GetDC(), aPageIndex, aPageWidth, aPageHeight); + NS_ENSURE_TRUE(result, false); + return emf.SaveToFile(); +} + +void +PDFViaEMFPrintHelper::CloseDocument() +{ + if (mPDFDoc) { + mPDFiumEngine->CloseDocument(mPDFDoc); + mPDFDoc = nullptr; + mPDFFileContents.clear(); + } +} \ No newline at end of file diff --git a/widget/windows/PDFViaEMFPrintHelper.h b/widget/windows/PDFViaEMFPrintHelper.h new file mode 100644 index 000000000000..01b58b015de9 --- /dev/null +++ b/widget/windows/PDFViaEMFPrintHelper.h @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */ + +#ifndef PDFVIAEMFPRINTHELPER_H_ +#define PDFVIAEMFPRINTHELPER_H_ + +#include "nsCOMPtr.h" +#include "PDFiumEngineShim.h" +#include "mozilla/Vector.h" + +/* include windows.h for the HDC definitions that we need. */ +#include + +class nsIFile; +class nsFileInputStream; + +namespace mozilla { +namespace widget { + +/** + * This class helps draw a PDF file to a given Windows DC. + * To do that it first converts the PDF file to EMF. + * Windows EMF: + * https://msdn.microsoft.com/en-us/windows/hardware/drivers/print/emf-data-type + */ +class PDFViaEMFPrintHelper +{ +public: + explicit PDFViaEMFPrintHelper(PRLibrary* aPDFiumLibrary); + ~PDFViaEMFPrintHelper(); + + /** Loads the specified PDF file. */ + NS_IMETHOD OpenDocument(nsIFile *aFile); + + /** Releases document buffer. */ + void CloseDocument(); + + int GetPageCount() { return mPDFiumEngine->GetPageCount(mPDFDoc); } + + /** Convert specified PDF page to EMF and draw the EMF onto the given DC. */ + bool DrawPage(HDC aPrinterDC, unsigned int aPageIndex, + int aPageWidth, int aPageHeight); + + /** Convert specified PDF page to EMF and save it to file. */ + bool DrawPageToFile(const wchar_t* aFilePath, unsigned int aPageIndex, + int aPageWidth, int aPageHeight); + +private: + + bool LoadPDFDataToBuffer(nsIFile *aFile); + + bool RenderPageToDC(HDC aDC, unsigned int aPageIndex, + int aPageWidth, int aPageHeight); + + UniquePtr mPDFiumEngine; + FPDF_DOCUMENT mPDFDoc; + Vector mPDFFileContents; + PRLibrary* mPDFiumLibrary; +}; + +} // namespace widget +} // namespace mozilla + +#endif /* PDFVIAEMFPRINTHELPER_H_ */ \ No newline at end of file diff --git a/widget/windows/PDFiumEngineShim.cpp b/widget/windows/PDFiumEngineShim.cpp new file mode 100644 index 000000000000..4bd89b720d40 --- /dev/null +++ b/widget/windows/PDFiumEngineShim.cpp @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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/. */ + +#include "PDFiumEngineShim.h" + + +namespace mozilla { +namespace widget { + +PDFiumEngineShim::PDFiumEngineShim(PRLibrary* aLibrary) + : mPRLibrary(aLibrary) + , mFPDF_InitLibrary(nullptr) + , mFPDF_DestroyLibrary(nullptr) + , mFPDF_LoadMemDocument(nullptr) + , mFPDF_CloseDocument(nullptr) + , mFPDF_GetPageCount(nullptr) + , mFPDF_GetPageSizeByIndex(nullptr) + , mFPDF_LoadPage(nullptr) + , mFPDF_ClosePage(nullptr) + , mFPDF_RenderPage(nullptr) + , mFPDF_RenderPage_Close(nullptr) + , mInitialized(false) +{ + MOZ_ASSERT(mPRLibrary); +} + +PDFiumEngineShim::~PDFiumEngineShim() +{ +} + +bool +PDFiumEngineShim::InitSymbolsAndLibrary() +{ + if (mInitialized) { + return true; + } + + mFPDF_InitLibrary = (FPDF_InitLibrary_Pfn)PR_FindFunctionSymbol( + mPRLibrary, "FPDF_InitLibrary"); + if (!mFPDF_InitLibrary) { + return false; + } + mFPDF_DestroyLibrary = (FPDF_DestroyLibrary_Pfn)PR_FindFunctionSymbol( + mPRLibrary, "FPDF_DestroyLibrary"); + if (!mFPDF_DestroyLibrary) { + return false; + } + mFPDF_LoadMemDocument = (FPDF_LoadMemDocument_Pfn)PR_FindFunctionSymbol( + mPRLibrary, "FPDF_LoadMemDocument"); + if (!mFPDF_LoadMemDocument) { + return false; + } + mFPDF_CloseDocument = (FPDF_CloseDocument_Pfn)PR_FindFunctionSymbol( + mPRLibrary, "FPDF_CloseDocument"); + if (!mFPDF_CloseDocument) { + return false; + } + mFPDF_GetPageCount = (FPDF_GetPageCount_Pfn)PR_FindFunctionSymbol( + mPRLibrary, "FPDF_GetPageCount"); + if (!mFPDF_GetPageCount) { + return false; + } + mFPDF_GetPageSizeByIndex = (FPDF_GetPageSizeByIndex_Pfn)PR_FindFunctionSymbol( + mPRLibrary, "FPDF_GetPageSizeByIndex"); + if (!mFPDF_GetPageSizeByIndex) { + return false; + } + mFPDF_LoadPage = (FPDF_LoadPage_Pfn)PR_FindFunctionSymbol( + mPRLibrary, "FPDF_LoadPage"); + if (!mFPDF_LoadPage) { + return false; + } + mFPDF_ClosePage = (FPDF_ClosePage_Pfn)PR_FindFunctionSymbol( + mPRLibrary, "FPDF_ClosePage"); + if (!mFPDF_ClosePage) { + return false; + } + mFPDF_RenderPage = (FPDF_RenderPage_Pfn)PR_FindFunctionSymbol( + mPRLibrary, "FPDF_RenderPage"); + if (!mFPDF_RenderPage) { + return false; + } + mFPDF_RenderPage_Close = (FPDF_RenderPage_Close_Pfn)PR_FindFunctionSymbol( + mPRLibrary, "FPDF_RenderPage_Close"); + if (!mFPDF_RenderPage_Close) { + return false; + } + + InitLibrary(); + mInitialized = true; + return true; +} + +void +PDFiumEngineShim::InitLibrary() +{ + mFPDF_InitLibrary(); +} + +void +PDFiumEngineShim::DestroyLibrary() +{ + mFPDF_DestroyLibrary(); +} + +FPDF_DOCUMENT +PDFiumEngineShim::LoadMemDocument(const void* aDataBuf, + int aSize, + FPDF_BYTESTRING aPassword) +{ + if (!mInitialized) { + if (!InitSymbolsAndLibrary()) { + return nullptr; + } + } + + return mFPDF_LoadMemDocument(aDataBuf, aSize, aPassword); +} + +void +PDFiumEngineShim::CloseDocument(FPDF_DOCUMENT aDocument) +{ + MOZ_ASSERT(mInitialized); + mFPDF_CloseDocument(aDocument); + DestroyLibrary(); + mInitialized = false; +} + +int +PDFiumEngineShim::GetPageCount(FPDF_DOCUMENT aDocument) +{ + MOZ_ASSERT(mInitialized); + return mFPDF_GetPageCount(aDocument); +} + +int +PDFiumEngineShim::GetPageSizeByIndex(FPDF_DOCUMENT aDocument, + int aPageIndex, + double* aWidth, + double* aHeight) +{ + MOZ_ASSERT(mInitialized); + return mFPDF_GetPageSizeByIndex(aDocument, aPageIndex, aWidth, aHeight); +} + +FPDF_PAGE +PDFiumEngineShim::LoadPage(FPDF_DOCUMENT aDocument, int aPageIndex) +{ + MOZ_ASSERT(mInitialized); + return mFPDF_LoadPage(aDocument, aPageIndex); +} + +void +PDFiumEngineShim::ClosePage(FPDF_PAGE aPage) +{ + MOZ_ASSERT(mInitialized); + mFPDF_ClosePage(aPage); +} + +void +PDFiumEngineShim::RenderPage(HDC aDC, FPDF_PAGE aPage, + int aStartX, int aStartY, + int aSizeX, int aSizeY, + int aRotate, int aFlags) +{ + MOZ_ASSERT(mInitialized); + mFPDF_RenderPage(aDC, aPage, aStartX, aStartY, + aSizeX, aSizeY, aRotate, aFlags); +} + +void +PDFiumEngineShim::RenderPage_Close(FPDF_PAGE aPage) +{ + MOZ_ASSERT(mInitialized); + mFPDF_RenderPage_Close(aPage); +} + +} // namespace widget +} // namespace mozilla \ No newline at end of file diff --git a/widget/windows/PDFiumEngineShim.h b/widget/windows/PDFiumEngineShim.h new file mode 100644 index 000000000000..1f44a38e49fc --- /dev/null +++ b/widget/windows/PDFiumEngineShim.h @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */ + +#ifndef PDFIUMENGINESHIM_H +#define PDFIUMENGINESHIM_H + +#include "prlink.h" + +/* include windows.h for the HDC definitions that we need. */ +#include + +namespace mozilla { +namespace widget { +/** + * Create Bug 1349139 to replace following defines with an appropriate include file. + */ +// Page rendering flags. They can be combined with bit-wise OR. +// +// Set if annotations are to be rendered. +#define FPDF_ANNOT 0x01 +// Set if using text rendering optimized for LCD display. +#define FPDF_LCD_TEXT 0x02 +// Don't use the native text output available on some platforms +#define FPDF_NO_NATIVETEXT 0x04 +// Grayscale output. +#define FPDF_GRAYSCALE 0x08 +// Set if you want to get some debug info. +#define FPDF_DEBUG_INFO 0x80 +// Set if you don't want to catch exceptions. +#define FPDF_NO_CATCH 0x100 +// Limit image cache size. +#define FPDF_RENDER_LIMITEDIMAGECACHE 0x200 +// Always use halftone for image stretching. +#define FPDF_RENDER_FORCEHALFTONE 0x400 +// Render for printing. +#define FPDF_PRINTING 0x800 +// Set to disable anti-aliasing on text. +#define FPDF_RENDER_NO_SMOOTHTEXT 0x1000 +// Set to disable anti-aliasing on images. +#define FPDF_RENDER_NO_SMOOTHIMAGE 0x2000 +// Set to disable anti-aliasing on paths. +#define FPDF_RENDER_NO_SMOOTHPATH 0x4000 +// Set whether to render in a reverse Byte order, this flag is only used when +// rendering to a bitmap. +#define FPDF_REVERSE_BYTE_ORDER 0x10 + +// PDF types +typedef void* FPDF_ACTION; +typedef void* FPDF_BITMAP; +typedef void* FPDF_BOOKMARK; +typedef void* FPDF_CLIPPATH; +typedef void* FPDF_DEST; +typedef void* FPDF_DOCSCHHANDLE; +typedef void* FPDF_DOCUMENT; +typedef void* FPDF_FONT; +typedef void* FPDF_HMODULE; +typedef void* FPDF_LINK; +typedef void* FPDF_MODULEMGR; +typedef void* FPDF_PAGE; +typedef void* FPDF_PAGELINK; +typedef void* FPDF_PAGEOBJECT; // Page object(text, path, etc) +typedef void* FPDF_PAGERANGE; +typedef void* FPDF_PATH; +typedef void* FPDF_RECORDER; +typedef void* FPDF_SCHHANDLE; +typedef void* FPDF_STRUCTELEMENT; +typedef void* FPDF_STRUCTTREE; +typedef void* FPDF_TEXTPAGE; + +// Basic data types +typedef int FPDF_BOOL; +typedef int FPDF_ERROR; +typedef unsigned long FPDF_DWORD; +typedef float FS_FLOAT; + +typedef const char* FPDF_BYTESTRING; + +typedef void (*FPDF_InitLibrary_Pfn)(); +typedef void (*FPDF_DestroyLibrary_Pfn)(); +typedef FPDF_DOCUMENT (*FPDF_LoadMemDocument_Pfn)(const void* aDataBuf, + int aSize, + FPDF_BYTESTRING aPassword); +typedef void(*FPDF_CloseDocument_Pfn)(FPDF_DOCUMENT aDocument); + +typedef int (*FPDF_GetPageCount_Pfn)(FPDF_DOCUMENT aDocument); +typedef int (*FPDF_GetPageSizeByIndex_Pfn)(FPDF_DOCUMENT aDocument, + int aPageIndex, + double* aWidth, + double* aWeight); + +typedef FPDF_PAGE (*FPDF_LoadPage_Pfn)(FPDF_DOCUMENT aDocument, int aPageIndex); +typedef void (*FPDF_ClosePage_Pfn)(FPDF_PAGE aPage); +typedef void (*FPDF_RenderPage_Pfn)(HDC aDC, + FPDF_PAGE aPage, + int aStartX, + int aStartY, + int aSizeX, + int aSizeY, + int aRotate, + int aFlags); +typedef void (*FPDF_RenderPage_Close_Pfn) (FPDF_PAGE aPage); + + +/** + * This class exposes an interface to the PDFium library and + * takes care of loading and linking to the appropriate PDFium symbols. + */ +class PDFiumEngineShim +{ +public: + + explicit PDFiumEngineShim(PRLibrary* aLibrary); + ~PDFiumEngineShim(); + + FPDF_DOCUMENT LoadMemDocument(const void* aDataBuf, + int aSize, + FPDF_BYTESTRING aPassword); + void CloseDocument(FPDF_DOCUMENT aDocument); + int GetPageCount(FPDF_DOCUMENT aDocument); + int GetPageSizeByIndex(FPDF_DOCUMENT aDocument, int aPageIndex, + double* aWidth, double* aHeight); + + FPDF_PAGE LoadPage(FPDF_DOCUMENT aDocument, int aPageIndex); + void ClosePage(FPDF_PAGE aPage); + void RenderPage(HDC aDC, FPDF_PAGE aPage, + int aStartX, int aStartY, + int aSizeX, int aSizeY, + int aRotate, int aFlags); + + void RenderPage_Close(FPDF_PAGE aPage); + +private: + + bool InitSymbolsAndLibrary(); + void InitLibrary(); + void DestroyLibrary(); + + PRLibrary* mPRLibrary; + bool mInitialized ; + + FPDF_InitLibrary_Pfn mFPDF_InitLibrary; + FPDF_DestroyLibrary_Pfn mFPDF_DestroyLibrary; + FPDF_LoadMemDocument_Pfn mFPDF_LoadMemDocument; + FPDF_CloseDocument_Pfn mFPDF_CloseDocument; + FPDF_GetPageCount_Pfn mFPDF_GetPageCount; + FPDF_GetPageSizeByIndex_Pfn mFPDF_GetPageSizeByIndex; + FPDF_LoadPage_Pfn mFPDF_LoadPage; + FPDF_ClosePage_Pfn mFPDF_ClosePage; + FPDF_RenderPage_Pfn mFPDF_RenderPage; + FPDF_RenderPage_Close_Pfn mFPDF_RenderPage_Close; + +}; + +} // namespace widget +} // namespace mozilla + +#endif /* PDFIUMENGINESHIM_H */ \ No newline at end of file diff --git a/widget/windows/WindowsEMF.cpp b/widget/windows/WindowsEMF.cpp new file mode 100644 index 000000000000..d59a6977bcb7 --- /dev/null +++ b/widget/windows/WindowsEMF.cpp @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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/. */ + +#include "WindowsEMF.h" + + +namespace mozilla { +namespace widget { + +WindowsEMF::WindowsEMF() + : mDC(nullptr) + , mEmf(nullptr) +{ +} + +WindowsEMF::~WindowsEMF() +{ + FinishDocument(); + ReleaseEMFHandle(); +} + +bool +WindowsEMF::InitForDrawing(const wchar_t* aMetafilePath /* = nullptr */) +{ + MOZ_ASSERT(!mDC && !mEmf, "InitForDrawing and InitFromFileContents is" + " designed to be used either one at once."); + + mDC = ::CreateEnhMetaFile(nullptr, aMetafilePath, nullptr, nullptr); + return !!mDC; +} + +bool +WindowsEMF::InitFromFileContents(const wchar_t* aMetafilePath) +{ + MOZ_ASSERT(aMetafilePath); + MOZ_ASSERT(!mDC && !mEmf, "InitForDrawing and InitFromFileContents is" + " designed to be used either one at once."); + + mEmf = ::GetEnhMetaFileW(aMetafilePath); + return !!mEmf; +} + +bool +WindowsEMF::FinishDocument() +{ + if (mDC) { + mEmf = ::CloseEnhMetaFile(mDC); + mDC = nullptr; + } + return !!mEmf; +} + +void +WindowsEMF::ReleaseEMFHandle() +{ + if (mEmf) { + ::DeleteEnhMetaFile(mEmf); + mEmf = nullptr; + } +} + +bool +WindowsEMF::Playback(HDC aDeviceContext, const RECT* aRect) +{ + MOZ_ASSERT(aRect); + if (!FinishDocument()) { + return false; + } + + return ::PlayEnhMetaFile(aDeviceContext, mEmf, aRect) != 0; +} + +bool +WindowsEMF::SaveToFile() +{ + if (!FinishDocument()) { + return false; + } + ReleaseEMFHandle(); + return true; +} + +} // namespace widget +} // namespace mozilla \ No newline at end of file diff --git a/widget/windows/WindowsEMF.h b/widget/windows/WindowsEMF.h new file mode 100644 index 000000000000..1ea0513a6fb6 --- /dev/null +++ b/widget/windows/WindowsEMF.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */ + +#ifndef MOZILLA_WIDGET_WINDOWSEMF_H +#define MOZILLA_WIDGET_WINDOWSEMF_H + +/* include windows.h for the HDC definitions that we need. */ +#include + +namespace mozilla { +namespace widget { + +/** + * Windows Enhance Metafile: https://en.wikipedia.org/wiki/Windows_Metafile + * A metafile, also called a vector image, is an image that is stored as a + * sequence of drawing commands and settings. The commands and settings + * recorded in a Metafile object can be stored in memory or saved to a file. + * + * The metafile device context is used for all drawing operations required to + * create the picture. When the system processes a GDI function associated with + * a metafile DC, it converts the function into the appropriate data and stores + * this data in a record appended to the metafile. + */ +class WindowsEMF +{ +public: + WindowsEMF(); + ~WindowsEMF(); + + /** + * Initializes the object with the path of a file where the EMF data stream + * should be stored. Callers are then expected to call GetDC() to draw output + * before going on to call Playback() or SaveToFile() to generate the EMF + * output. + */ + bool InitForDrawing(const wchar_t* aMetafilePath = nullptr); + + /** + * Initializes the object with an existing EMF file. Consumers cannot use + * GetDC() to obtain an HDC to modify the file. They can only use Playback(). + */ + bool InitFromFileContents(const wchar_t* aMetafilePath); + + /** + * If this object was initiaziled using InitForDrawing() then this function + * returns an HDC that can be drawn to generate the EMF output. Otherwise it + * returns null. After finishing with the HDC, consumers could call Playback() + * to draw EMF onto the given DC or call SaveToFile() to finish writing the + * EMF file. + */ + HDC GetDC() { return mDC; } + + /** + * Play the EMF's drawing commands onto the given DC. + */ + bool Playback(HDC aDeviceContext, const RECT* aRect); + + /** + * Called to generate the EMF file once a consumer has finished drawing to + * the HDC returned by GetDC(), if initializes the object with the path of a + * file. + */ + bool SaveToFile(); + +private: + + WindowsEMF(const WindowsEMF& aEMF) = delete; + bool FinishDocument(); + void ReleaseEMFHandle(); + + /* Compiled EMF data handle. */ + HENHMETAFILE mEmf; + HDC mDC; +}; + +} // namespace widget +} // namespace mozilla + +#endif /* MOZILLA_WIDGET_WINDOWSEMF_H */ \ No newline at end of file diff --git a/widget/windows/moz.build b/widget/windows/moz.build index 3c74cc1ac507..a97190d94958 100644 --- a/widget/windows/moz.build +++ b/widget/windows/moz.build @@ -20,6 +20,8 @@ EXPORTS.mozilla.widget += [ 'CompositorWidgetChild.h', 'CompositorWidgetParent.h', 'InProcessWinCompositorWidget.h', + 'PDFiumEngineShim.h', + 'PDFViaEMFPrintHelper.h', 'WinCompositorWidget.h', 'WinMessages.h', 'WinModifierKeyState.h', @@ -92,6 +94,9 @@ if CONFIG['NS_PRINTING']: 'nsDeviceContextSpecWin.cpp', 'nsPrintOptionsWin.cpp', 'nsPrintSettingsWin.cpp', + 'PDFiumEngineShim.cpp', + 'PDFViaEMFPrintHelper.cpp', + 'WindowsEMF.cpp', ] if CONFIG['NS_ENABLE_TSF']: diff --git a/widget/windows/nsDragService.cpp b/widget/windows/nsDragService.cpp index ce366da5a61a..af04ffbfae36 100644 --- a/widget/windows/nsDragService.cpp +++ b/widget/windows/nsDragService.cpp @@ -45,6 +45,7 @@ using namespace mozilla; using namespace mozilla::gfx; +using namespace mozilla::widget; //------------------------------------------------------------------------- // diff --git a/xpcom/threads/MozPromise.h b/xpcom/threads/MozPromise.h index 97f0ea21f0d1..3f95004a5699 100644 --- a/xpcom/threads/MozPromise.h +++ b/xpcom/threads/MozPromise.h @@ -1328,11 +1328,11 @@ InvokeAsync(AbstractThread* aTarget, ThisType* aThisVal, const char* aCallerName RefPtr(ThisType::*aMethod)(ArgTypes...), ActualArgTypes&&... aArgs) { - static_assert(!detail::Any(IsPointer::value...), + static_assert(!detail::Any(IsPointer::Type>::value...), "Cannot pass pointer types through InvokeAsync, Storages must be provided"); static_assert(sizeof...(ArgTypes) == sizeof...(ActualArgTypes), "Method's ArgTypes and ActualArgTypes should have equal sizes"); - return detail::InvokeAsyncImpl::Type>...>( + return detail::InvokeAsyncImpl::Type>...>( aTarget, aThisVal, aCallerName, aMethod, Forward(aArgs)...); }