Merge mozilla-central to inbound. a=merge CLOSED TREE
authorGurzau Raul <rgurzau@mozilla.com>
Fri, 31 Aug 2018 07:08:44 +0300
changeset 482504 19f0b4b0fada080b2f2cbdc6a554aba739b7739a
parent 482476 930e12a89a4371a2b62c9fef59d6be4eed21914e (current diff)
parent 482503 02f33375bc170cc26faeb9284f11d74f653565ea (diff)
child 482505 e9d7d713913290df6f3e1c4a23677b5a96194e81
push id232
push userfmarier@mozilla.com
push dateWed, 05 Sep 2018 20:45:54 +0000
reviewersmerge
milestone63.0a1
Merge mozilla-central to inbound. a=merge CLOSED TREE
other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.h
other-licenses/7zstub/src/CPP/7zip/Bundles/SFXSetup/resource.rc
other-licenses/7zstub/src/CPP/7zip/UI/FileManager/ProgressDialog.cpp
--- a/accessible/tests/browser/events/browser_test_textcaret.js
+++ b/accessible/tests/browser/events/browser_test_textcaret.js
@@ -9,38 +9,37 @@
 function caretMoveChecker(target, caretOffset) {
   return function(event) {
     let cmEvent = event.QueryInterface(nsIAccessibleCaretMoveEvent);
     return cmEvent.accessible == getAccessible(target) && cmEvent.caretOffset == caretOffset;
   };
 }
 
 async function checkURLBarCaretEvents() {
-  let url = "about:mozilla";
+  const kURL = "about:mozilla";
+  let newWin = await BrowserTestUtils.openNewBrowserWindow();
+  newWin.gBrowser.selectedBrowser.loadURI(kURL);
 
-  let onDocLoad = waitForEvent(
+  await waitForEvent(
     EVENT_DOCUMENT_LOAD_COMPLETE,
     event => {
       try {
-        return event.accessible.QueryInterface(nsIAccessibleDocument).URL == url;
+        return event.accessible.QueryInterface(nsIAccessibleDocument).URL == kURL;
       } catch (e) {
         return false;
       }
     }
   );
-  let [ newWin ] = await Promise.all([
-    BrowserTestUtils.openNewBrowserWindow({ url }),
-    onDocLoad
-  ]);
+  info("Loaded " + kURL);
 
   let urlbarInputEl = newWin.document.getElementById("urlbar").inputField;
   let urlbarInput = getAccessible(urlbarInputEl, [ nsIAccessibleText ]);
 
   let onCaretMove = waitForEvents([
-    [ EVENT_TEXT_CARET_MOVED, caretMoveChecker(urlbarInput, url.length) ],
+    [ EVENT_TEXT_CARET_MOVED, caretMoveChecker(urlbarInput, kURL.length) ],
     [ EVENT_FOCUS, urlbarInput ]
   ]);
 
   urlbarInput.caretOffset = -1;
   await onCaretMove;
   ok(true, "Caret move in URL bar #1");
 
   onCaretMove = waitForEvent(
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1257,21 +1257,17 @@ pref("full-screen-api.enabled", true);
 // Startup Crash Tracking
 // number of startup crashes that can occur before starting into safe mode automatically
 // (this pref has no effect if more than 6 hours have passed since the last crash)
 pref("toolkit.startup.max_resumed_crashes", 3);
 
 // Whether to use RegisterApplicationRestart to restart the browser and resume
 // the session on next Windows startup
 #if defined(XP_WIN)
-#if defined(NIGHTLY_BUILD)
 pref("toolkit.winRegisterApplicationRestart", true);
-#else
-pref("toolkit.winRegisterApplicationRestart", false);
-#endif
 #endif
 
 // Whether we use pdfium to view content with the pdf mime type.
 // Note: if the pref is set to false while Firefox is open, it won't
 // take effect until there are no open pdfium tabs.
 pref("pdfium.enabled", false);
 
 // Completely disable pdf.js as an option to preview pdfs within firefox.
--- a/browser/app/winlauncher/LauncherProcessWin.cpp
+++ b/browser/app/winlauncher/LauncherProcessWin.cpp
@@ -35,17 +35,17 @@
 static bool
 PostCreationSetup(HANDLE aChildProcess, HANDLE aChildMainThread,
                   const bool aIsSafeMode)
 {
   return mozilla::InitializeDllBlocklistOOP(aChildProcess);
 }
 
 #if !defined(PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON)
-# define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON (0x00000001ui64 << 60)
+# define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON (0x00000001ULL << 60)
 #endif // !defined(PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON)
 
 #if (_WIN32_WINNT < 0x0602)
 BOOL WINAPI
 SetProcessMitigationPolicy(PROCESS_MITIGATION_POLICY aMitigationPolicy,
                            PVOID aBuffer, SIZE_T aBufferLen);
 #endif // (_WIN32_WINNT >= 0x0602)
 
--- a/browser/base/content/browser-captivePortal.js
+++ b/browser/base/content/browser-captivePortal.js
@@ -108,16 +108,22 @@ var CaptivePortalWatcher = {
   },
 
   _captivePortalDetected() {
     if (this._delayedCaptivePortalDetectedInProgress) {
       return;
     }
 
     let win = BrowserWindowTracker.getTopWindow();
+    // Used by tests: ignore the main test window in order to enable testing of
+    // the case where we have no open windows.
+    if (win && win.document.documentElement.getAttribute("ignorecaptiveportal")) {
+      win = null;
+    }
+
     // If no browser window has focus, open and show the tab when we regain focus.
     // This is so that if a different application was focused, when the user
     // (re-)focuses a browser window, we open the tab immediately in that window
     // so they can log in before continuing to browse.
     if (win != Services.ww.activeWindow) {
       this._delayedCaptivePortalDetectedInProgress = true;
       Services.obs.addObserver(this, "xul-window-visible");
     }
@@ -131,16 +137,22 @@ var CaptivePortalWatcher = {
    * the tab if needed after a short delay to allow the recheck to complete.
    */
   _delayedCaptivePortalDetected() {
     if (!this._delayedCaptivePortalDetectedInProgress) {
       return;
     }
 
     let win = BrowserWindowTracker.getTopWindow();
+    // Used by tests: ignore the main test window in order to enable testing of
+    // the case where we have no open windows.
+    if (win && win.document.documentElement.getAttribute("ignorecaptiveportal")) {
+      win = null;
+    }
+
     if (win != Services.ww.activeWindow) {
       // The window that got focused was not a browser window.
       return;
     }
     Services.obs.removeObserver(this, "xul-window-visible");
     this._delayedCaptivePortalDetectedInProgress = false;
 
     if (win != window) {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4287,16 +4287,29 @@ function toOpenWindowByType(inType, uri,
   if (topWindow)
     topWindow.focus();
   else if (features)
     window.open(uri, "_blank", features);
   else
     window.open(uri, "_blank", "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar");
 }
 
+/**
+ * Open a new browser window.
+ *
+ * @param {Object} options
+ *        {
+ *          private: A boolean indicating if the window should be
+ *                   private
+ *          remote:  A boolean indicating if the window should run
+ *                   remote browser tabs or not. If omitted, the window
+ *                   will choose the profile default state.
+ *        }
+ * @return a reference to the new window.
+ */
 function OpenBrowserWindow(options) {
   var telemetryObj = {};
   TelemetryStopwatch.start("FX_NEW_WINDOW_MS", telemetryObj);
 
   var handler = Cc["@mozilla.org/browser/clh;1"]
                   .getService(Ci.nsIBrowserHandler);
   var defaultArgs = handler.defaultArgs;
   var wintype = document.documentElement.getAttribute("windowtype");
--- a/browser/base/content/popup-notifications.inc
+++ b/browser/base/content/popup-notifications.inc
@@ -80,8 +80,32 @@
       </popupnotificationcontent>
     </popupnotification>
 
     <popupnotification id="addon-installed-notification" hidden="true">
       <popupnotificationcontent class="addon-installed-notification-content" orient="vertical">
         <description>&addonPostInstallMessage.label;</description>
       </popupnotificationcontent>
     </popupnotification>
+
+    <popupnotification id="contextual-feature-recommendation-notification" hidden="true">
+      <popupnotificationheader id="cfr-notification-header">
+        <stack id="cfr-notification-header-stack">
+          <description id="cfr-notification-header-label"></description>
+          <label id="cfr-notification-header-link" class="text-link">
+            <xul:image id="cfr-notification-header-image"/>
+          </label>
+        </stack>
+      </popupnotificationheader>
+      <popupnotificationcontent>
+        <description id="cfr-notification-author"></description>
+      </popupnotificationcontent>
+      <popupnotificationfooter id="cfr-notification-footer" orient="vertical">
+        <description id="cfr-notification-footer-text"/>
+        <hbox id="cfr-notification-footer-addon-info">
+          <hbox id="cfr-notification-footer-filled-stars"/>
+          <hbox id="cfr-notification-footer-empty-stars"/>
+          <label id="cfr-notification-footer-users"/>
+          <spacer id="cfr-notification-footer-spacer" hidden="true"/>
+          <label id="cfr-notification-footer-learn-more-link" class="text-link"/>
+        </hbox>
+      </popupnotificationfooter>
+    </popupnotification>
--- a/browser/base/content/test/captivePortal/head.js
+++ b/browser/base/content/test/captivePortal/head.js
@@ -15,32 +15,23 @@ const PORTAL_NOTIFICATION_VALUE = "capti
 async function setupPrefsAndRecentWindowBehavior() {
   await SpecialPowers.pushPrefEnv({
     set: [["captivedetect.canonicalURL", CANONICAL_URL],
           ["captivedetect.canonicalContent", CANONICAL_CONTENT]],
   });
   // We need to test behavior when a portal is detected when there is no browser
   // window, but we can't close the default window opened by the test harness.
   // Instead, we deactivate CaptivePortalWatcher in the default window and
-  // exclude it from BrowserWindowTracker.getTopWindow in an attempt to
-  // mask its presence.
+  // exclude it using an attribute to mask its presence.
   window.CaptivePortalWatcher.uninit();
-  let getTopWindowCopy = BrowserWindowTracker.getTopWindow;
-  let defaultWindow = window;
-  BrowserWindowTracker.getTopWindow = () => {
-    let win = getTopWindowCopy();
-    if (win == defaultWindow) {
-      return null;
-    }
-    return win;
-  };
+  window.document.documentElement.setAttribute("ignorecaptiveportal", "true");
 
   registerCleanupFunction(function cleanUp() {
-    BrowserWindowTracker.getTopWindow = getTopWindowCopy;
     window.CaptivePortalWatcher.init();
+    window.document.documentElement.removeAttribute("ignorecaptiveportal");
   });
 }
 
 async function portalDetected() {
   Services.obs.notifyObservers(null, "captive-portal-login");
   await BrowserTestUtils.waitForCondition(() => {
     return cps.state == cps.LOCKED_PORTAL;
   }, "Waiting for Captive Portal Service to update state after portal detected.");
--- a/browser/base/content/test/forms/browser_selectpopup.js
+++ b/browser/base/content/test/forms/browser_selectpopup.js
@@ -585,28 +585,34 @@ add_task(async function test_large_popup
 
   await performLargePopupTests(window);
 
   BrowserTestUtils.removeTab(tab);
 });
 
 // This test checks the same as the previous test but in a new smaller window.
 add_task(async function test_large_popup_in_small_window() {
-  let newwin = await BrowserTestUtils.openNewBrowserWindow({ width: 400, height: 400 });
+  let newWin = await BrowserTestUtils.openNewBrowserWindow();
+
+  let resizePromise = BrowserTestUtils.waitForEvent(newWin, "resize", false, e => {
+    return newWin.innerHeight <= 400 && newWin.innerWidth <= 400;
+  });
+  newWin.resizeTo(400, 400);
+  await resizePromise;
 
   const pageUrl = "data:text/html," + escape(PAGECONTENT_SMALL);
-  let browserLoadedPromise = BrowserTestUtils.browserLoaded(newwin.gBrowser.selectedBrowser);
-  await BrowserTestUtils.loadURI(newwin.gBrowser.selectedBrowser, pageUrl);
+  let browserLoadedPromise = BrowserTestUtils.browserLoaded(newWin.gBrowser.selectedBrowser);
+  await BrowserTestUtils.loadURI(newWin.gBrowser.selectedBrowser, pageUrl);
   await browserLoadedPromise;
 
-  newwin.gBrowser.selectedBrowser.focus();
+  newWin.gBrowser.selectedBrowser.focus();
 
-  await performLargePopupTests(newwin);
+  await performLargePopupTests(newWin);
 
-  await BrowserTestUtils.closeWindow(newwin);
+  await BrowserTestUtils.closeWindow(newWin);
 });
 
 async function performSelectSearchTests(win) {
   let browser = win.gBrowser.selectedBrowser;
   await ContentTask.spawn(browser, null, async function() {
     let doc = content.document;
     let select = doc.getElementById("one");
 
--- a/browser/base/content/test/plugins/browser_private_clicktoplay.js
+++ b/browser/base/content/test/plugins/browser_private_clicktoplay.js
@@ -21,17 +21,18 @@ function finishTest() {
 }
 
 let createPrivateWindow = async function createPrivateWindow(url) {
   gPrivateWindow = await BrowserTestUtils.openNewBrowserWindow({private: true});
   ok(!!gPrivateWindow, "should have created a private window.");
   gPrivateBrowser = gPrivateWindow.getBrowser().selectedBrowser;
 
   BrowserTestUtils.loadURI(gPrivateBrowser, url);
-  await BrowserTestUtils.browserLoaded(gPrivateBrowser);
+  await BrowserTestUtils.browserLoaded(gPrivateBrowser, false, url);
+  info("loaded " + url);
 };
 
 add_task(async function test() {
   registerCleanupFunction(function() {
     clearAllPluginPermissions();
     getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_ENABLED;
     getTestPlugin("Second Test Plug-in").enabledState = Ci.nsIPluginTag.STATE_ENABLED;
   });
--- a/browser/base/content/test/sidebar/browser_sidebar_adopt.js
+++ b/browser/base/content/test/sidebar/browser_sidebar_adopt.js
@@ -14,21 +14,21 @@ function failIfSidebarFocusedFires() {
 }
 
 add_task(async function testAdoptedTwoWindows() {
   // First open a new window, show the sidebar in that window, and close it.
   // Then, open another new window and confirm that the sidebar is closed since it is
   // being adopted from the main window which doesn't have a shown sidebar. See Bug 1407737.
   info("Ensure that sidebar state is adopted only from the opener");
 
-  let win1 = await BrowserTestUtils.openNewBrowserWindow({opener: window});
+  let win1 = await BrowserTestUtils.openNewBrowserWindow();
   await win1.SidebarUI.show("viewBookmarksSidebar");
   await BrowserTestUtils.closeWindow(win1);
 
-  let win2 = await BrowserTestUtils.openNewBrowserWindow({opener: window});
+  let win2 = await BrowserTestUtils.openNewBrowserWindow();
   ok(!win2.document.getElementById("sidebar-button").hasAttribute("checked"), "Sidebar button isn't checked");
   ok(!win2.SidebarUI.isOpen, "Sidebar is closed");
   await BrowserTestUtils.closeWindow(win2);
 });
 
 add_task(async function testEventsReceivedInMainWindow() {
   info("Opening the sidebar and expecting both SidebarShown and SidebarFocused events");
 
@@ -41,17 +41,17 @@ add_task(async function testEventsReceiv
 
   ok(true, "SidebarShown and SidebarFocused events fired on a new window");
 });
 
 add_task(async function testEventReceivedInNewWindow() {
   info("Opening a new window and expecting the SidebarFocused event to not fire");
 
   let promiseNewWindow = BrowserTestUtils.waitForNewWindow();
-  BrowserTestUtils.openNewBrowserWindow({opener: window});
+  BrowserTestUtils.openNewBrowserWindow();
   let win = await promiseNewWindow;
 
   let adoptedShown = BrowserTestUtils.waitForEvent(win, "SidebarShown");
   win.addEventListener("SidebarFocused", failIfSidebarFocusedFires);
 
   registerCleanupFunction(async function() {
     win.removeEventListener("SidebarFocused", failIfSidebarFocusedFires);
     await BrowserTestUtils.closeWindow(win);
--- a/browser/components/customizableui/test/browser_editcontrols_update.js
+++ b/browser/components/customizableui/test/browser_editcontrols_update.js
@@ -197,16 +197,21 @@ add_task(async function finish() {
 
 // Test updating in the initial state when the edit-controls are on the panel but
 // have not yet been created. This needs to be done in a new window to ensure that
 // other tests haven't opened the panel.
 add_task(async function test_initial_state() {
   let testWindow = await BrowserTestUtils.openNewBrowserWindow();
   await SimpleTest.promiseFocus(testWindow);
 
+  // For focusing the URL bar to have an effect, we need to ensure the URL bar isn't
+  // initially focused:
+  testWindow.gBrowser.selectedTab.focus();
+  await TestUtils.waitForCondition(() => !testWindow.gURLBar.focused);
+
   let overridePromise = expectCommandUpdate(isMac, testWindow);
 
   testWindow.gURLBar.focus();
   testWindow.gURLBar.value = "test";
 
   await overridePromise;
 
   // Commands won't update when no edit UI is present. They default to being
--- a/browser/components/customizableui/test/browser_sidebar_toggle.js
+++ b/browser/components/customizableui/test/browser_sidebar_toggle.js
@@ -37,15 +37,15 @@ add_task(async function() {
   is(SidebarUI.currentID, "viewBookmarksSidebar", "Default sidebar selected");
   await SidebarUI.show("viewHistorySidebar");
 
   await hideSidebar();
   await showSidebar();
   is(SidebarUI.currentID, "viewHistorySidebar", "Selected sidebar remembered");
 
   await hideSidebar();
-  let otherWin = await BrowserTestUtils.openNewBrowserWindow({opener: window});
+  let otherWin = await BrowserTestUtils.openNewBrowserWindow();
   await showSidebar(otherWin);
   is(otherWin.SidebarUI.currentID, "viewHistorySidebar", "Selected sidebar remembered across windows");
   await hideSidebar(otherWin);
 
   await BrowserTestUtils.closeWindow(otherWin);
 });
--- a/browser/components/extensions/test/browser/browser_ext_omnibox.js
+++ b/browser/components/extensions/test/browser/browser_ext_omnibox.js
@@ -113,17 +113,23 @@ add_task(async function() {
     // waitForAutocompleteResultAt can distinguish different cases.
     let char = ((inputSessionSerial++) % 10).toString();
     EventUtils.sendString(char);
 
     await expectEvent("on-input-changed-fired", {text: char});
     // Wait for the autocomplete search. Note that we cannot wait for the search
     // to be complete, since the add-on doesn't communicate when it's done, so
     // just check matches count.
-    await waitForAutocompleteResultAt(indexToWaitFor);
+    try {
+      await waitForAutocompleteResultAt(indexToWaitFor);
+    } catch (e) {
+      // Print message for debugging. Discard data:-URIs.
+      info(gURLBar.popup.richlistbox.outerHTML.replace(/data:image[^"\s]+/g, "data:image..."));
+      throw e;
+    }
 
     return char;
   }
 
   async function testInputEvents() {
     gURLBar.focus();
 
     // Start an input session by typing in <keyword><space>.
--- a/browser/components/extensions/test/browser/browser_ext_sidebarAction_windows.js
+++ b/browser/components/extensions/test/browser/browser_ext_sidebarAction_windows.js
@@ -43,17 +43,17 @@ add_task(async function sidebar_windows(
   ok(elements.length > 0, "have a menuitem");
   let style = elements[0].getAttribute("style");
   ok(style.includes("webextension-menuitem-image"), "this menu has style");
 
   let secondSidebar = extension.awaitMessage("sidebar");
 
   // SidebarUI relies on window.opener being set, which is normal behavior when
   // using menu or key commands to open a new browser window.
-  let win = await BrowserTestUtils.openNewBrowserWindow({opener: window});
+  let win = await BrowserTestUtils.openNewBrowserWindow();
 
   await secondSidebar;
   ok(!win.document.getElementById("sidebar-box").hidden, "sidebar box is visible in second window");
   // Check that the menuitem has our image styling.
   elements = win.document.getElementsByClassName("webextension-menuitem");
   ok(elements.length > 0, "have a menuitem");
   style = elements[0].getAttribute("style");
   ok(style.includes("webextension-menuitem-image"), "this menu has style");
--- a/browser/components/newtab/lib/CFRPageActions.jsm
+++ b/browser/components/newtab/lib/CFRPageActions.jsm
@@ -1,13 +1,15 @@
 /* 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 { Localization } = ChromeUtils.import("resource://gre/modules/Localization.jsm", {});
+
 const POPUP_NOTIFICATION_ID = "contextual-feature-recommendation";
 
 const DELAY_BEFORE_EXPAND_MS = 1000;
 const DURATION_OF_EXPAND_MS = 5000;
 
 /**
  * A WeakMap from browsers to {host, recommendation} pairs. Recommendations are
  * defined in the ExtensionDoorhanger.schema.json.
@@ -38,26 +40,30 @@ class PageAction {
     // Please use dispatchUserAction instead.
     this._dispatchToASRouter = dispatchToASRouter;
 
     this._popupStateChange = this._popupStateChange.bind(this);
     this._collapse = this._collapse.bind(this);
     this._handleClick = this._handleClick.bind(this);
     this.dispatchUserAction = this.dispatchUserAction.bind(this);
 
+    this._l10n = new Localization([
+      "browser/newtab/asrouter.ftl"
+    ]);
+
     // Saved timeout IDs for scheduled state changes, so they can be cancelled
     this.stateTransitionTimeoutIDs = [];
 
     this.container.onclick = this._handleClick;
   }
 
-  async show(notificationText, shouldExpand = false) {
+  async show(notification_text, shouldExpand = false) {
     this.container.hidden = false;
 
-    this.label.value = notificationText;
+    this.label.value = await this.getStrings({string: notification_text});
 
     // Wait for layout to flush to avoid a synchronous reflow then calculate the
     // label width. We can safely get the width even though the recommendation is
     // collapsed; the label itself remains full width (with its overflow hidden)
     await this.window.promiseDocumentFlushed;
     const [{width}] = this.label.getClientRects();
     this.urlbar.style.setProperty("--cfr-label-width", `${width}px`);
 
@@ -124,20 +130,48 @@ class PageAction {
   // the popup, e.g. by hitting <esc>
   _popupStateChange(state) {
     if (["dismissed", "removed"].includes(state)) {
       this._collapse();
     }
   }
 
   /**
+   * getStrings - Handles getting the localized strings vs message overrides.
+   *              If string_id is not defined it assumes you passed in an override
+   *              message and it just returns it.
+   *              If hasAttributes is true it will try to fetch and reduce them
+   *              into an object with key and value.
+   */
+  async getStrings({string, hasAttributes}) {
+    if (!string.string_id) {
+      return string;
+    }
+
+    const [localeStrings] = await this._l10n.formatMessages([{id: string.string_id}]);
+
+    if (hasAttributes && localeStrings.attributes) {
+      const attributes = localeStrings.attributes.reduce((acc, attribute) => {
+        acc[attribute.name] = attribute.value;
+        return acc;
+      }, {});
+      return {
+        value: localeStrings.value,
+        attributes
+      };
+    } else {
+      return localeStrings.value;
+    }
+  }
+
+  /**
    * Respond to a user click on the recommendation by showing a doorhanger/
    * popup notification
    */
-  _handleClick(event) {
+  async _handleClick(event) {
     const browser = this.window.gBrowser.selectedBrowser;
     if (!RecommendationMap.has(browser)) {
       // There's no recommendation for this browser, so the user shouldn't have
       // been able to click
       this.hide();
       return;
     }
     const {content} = RecommendationMap.get(browser);
@@ -146,39 +180,41 @@ class PageAction {
     // doorhanger is showing
     this._clearScheduledStateChanges();
 
     // A hacky way of setting the popup anchor outside the usual url bar icon box
     // See https://searchfox.org/mozilla-central/rev/847b64cc28b74b44c379f9bff4f415b97da1c6d7/toolkit/modules/PopupNotifications.jsm#42
     browser.cfrpopupnotificationanchor = this.container;
 
     const {primary, secondary} = content.buttons;
+    const primaryBtnStrings = await this.getStrings({string: primary.label, hasAttributes: true});
+    const secondaryBtnStrings = await this.getStrings({string: secondary.label, hasAttributes: true});
 
     const mainAction = {
-      label: primary.label,
-      accessKey: primary.accessKey,
+      label: primaryBtnStrings.value,
+      accessKey: primaryBtnStrings.attributes.accesskey,
       callback: () => this.dispatchUserAction(primary.action)
     };
 
     const secondaryActions = [{
-      label: secondary.label,
-      accessKey: secondary.accessKey,
+      label: secondaryBtnStrings.value,
+      accessKey: secondaryBtnStrings.attributes.accesskey,
       callback: this._collapse
     }];
 
     const options = {
       popupIconURL: content.addon.icon,
       hideClose: true,
       eventCallback: this._popupStateChange
     };
 
     this.window.PopupNotifications.show(
       browser,
       POPUP_NOTIFICATION_ID,
-      content.text,
+      await this.getStrings({string: content.text}),
       "cfr",
       mainAction,
       secondaryActions,
       options
     );
   }
 }
 
@@ -202,17 +238,17 @@ const CFRPageActions = {
     if (!pageAction || browser !== win.gBrowser.selectedBrowser) {
       return;
     }
     if (RecommendationMap.has(browser)) {
       const {host, content} = RecommendationMap.get(browser);
       if (isHostMatch(browser, host)) {
         // The browser has a recommendation specified with this host, so show
         // the page action
-        pageAction.show(content.notification_text);
+        pageAction.show(this.getStrings({string: content.notification_text}));
       } else {
         // The user has navigated away from the specified host in the given
         // browser, so the recommendation is no longer valid and should be removed
         RecommendationMap.delete(browser);
         pageAction.hide();
       }
     } else {
       // There's no recommendation specified for this browser, so hide the page action
@@ -230,17 +266,17 @@ const CFRPageActions = {
   async forceRecommendation(browser, recommendation, dispatchToASRouter) {
     // If we are forcing via the Admin page, the browser comes in a different format
     const win = browser.browser.ownerGlobal;
     const {id, content} = recommendation;
     RecommendationMap.set(browser.browser, {id, content});
     if (!PageActionMap.has(win)) {
       PageActionMap.set(win, new PageAction(win, dispatchToASRouter));
     }
-    await PageActionMap.get(win).show(recommendation.content.notification_text, true);
+    await PageActionMap.get(win).show(this.getStrings({string: recommendation.content.notification_text}), true);
     return true;
   },
 
   /**
    * Add a recommendation specific to the given browser and host.
    * @param browser             The browser for the recommendation
    * @param host                The host for the recommendation
    * @param recommendation      The recommendation to show
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about.js
@@ -8,17 +8,17 @@ const CB_UI_ENABLED_PREF = "browser.cont
 
 /**
  * Opens a new private window and loads "about:privatebrowsing" there.
  */
 async function openAboutPrivateBrowsing() {
   let win = await BrowserTestUtils.openNewBrowserWindow({ private: true });
   let tab = win.gBrowser.selectedBrowser;
   tab.loadURI("about:privatebrowsing");
-  await BrowserTestUtils.browserLoaded(tab);
+  await BrowserTestUtils.browserLoaded(tab, false, "about:privatebrowsing");
   return { win, tab };
 }
 
 /**
  * Clicks the given link and checks this opens a new tab with the given URI.
  */
 async function testLinkOpensTab({ win, tab, elementId, expectedUrl }) {
   let newTabPromise = BrowserTestUtils.waitForNewTab(win.gBrowser, expectedUrl);
--- a/browser/components/sessionstore/test/browser_394759_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_394759_perwindowpb.js
@@ -12,18 +12,17 @@ const TESTS = [
     key: "bug 394759 PB",
     value: "uniq" + r() },
 ];
 
 function promiseTestOpenCloseWindow(aIsPrivate, aTest) {
   return (async function() {
     let win = await BrowserTestUtils.openNewBrowserWindow({ "private": aIsPrivate });
     win.gBrowser.selectedBrowser.loadURI(aTest.url);
-    await promiseBrowserLoaded(win.gBrowser.selectedBrowser);
-    await Promise.resolve();
+    await promiseBrowserLoaded(win.gBrowser.selectedBrowser, true, aTest.url);
     // Mark the window with some unique data to be restored later on.
     ss.setWindowValue(win, aTest.key, aTest.value);
     await TabStateFlusher.flushWindow(win);
     // Close.
     await BrowserTestUtils.closeWindow(win);
   })();
 }
 
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/browser/newtab/asrouter.ftl
@@ -0,0 +1,45 @@
+# 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/.
+
+cfr-doorhanger-extension-heading = Recommended Extension
+
+cfr-doorhanger-extension-sumo-link =
+  .tooltiptext = Why am I seeing this
+
+cfr-doorhanger-extension-cancel-button = Not Now
+  .accesskey = N
+
+cfr-doorhanger-extension-ok-button = Add Now
+  .accesskey = A
+
+cfr-doorhanger-extension-learn-more-link = Learn more
+
+# This string is used on a new line below the add-on name
+# Variables:
+#   $name (String) - Add-on author name
+cfr-doorhanger-extension-author = by { $name }
+
+# This is a notification displayed in the address bar.
+# When clicked it opens a panel with a message for the user.
+cfr-doorhanger-extension-notification = Recommendation
+
+## Add-on statistics
+## These strings are used to display the total number of
+## users and rating for an add-on. They are shown next to each other.
+
+# Variables:
+#   $total (Number) - The rating of the add-on from 1 to 5
+cfr-doorhanger-extension-rating =
+  .tooltiptext =
+    { $total ->
+        [one] { $total } star
+       *[other] { $total } stars
+    }
+# Variables:
+#   $total (Number) - The total number of users using the add-on
+cfr-doorhanger-extension-total-users =
+  { $total ->
+      [one] { $total } user
+     *[other] { $total } users
+  }
--- a/browser/themes/shared/browser.inc.css
+++ b/browser/themes/shared/browser.inc.css
@@ -160,8 +160,118 @@
   --arrowpanel-background: var(--default-arrowpanel-background);
   --arrowpanel-color: var(--default-arrowpanel-color);
   --arrowpanel-border-color: var(--default-arrowpanel-border-color);
 }
 
 #widget-overflow .webextension-popup-browser {
   background: #fff;
 }
+
+/* Contextual Feature Recommendation popup-notification */
+
+:root {
+  --cfr-notification-header-image: url(resource://activity-stream/data/content/assets/glyph-help-24.svg);
+  --cfr-notification-footer-star: url(resource://activity-stream/data/content/assets/glyph-star-17.svg);
+}
+
+#cfr-notification-header {
+  width: 100%;
+  text-align: center;
+  box-shadow: 0px 1px 0px rgba(0, 0, 0, 0.2);
+}
+
+#cfr-notification-header-stack {
+  width: 100%;
+}
+
+#cfr-notification-header-label {
+  margin: 9px;
+  font-size: 12px;
+  font-weight: 600;
+}
+
+#cfr-notification-header-link {
+  margin: 7px;
+  color: var(--lwt-text-color);
+  cursor: default;
+}
+
+#cfr-notification-header-image {
+  width: 19px;
+  height: 19px;
+  padding: 2px;
+  -moz-context-properties: fill, fill-opacity;
+  fill: currentColor;
+  fill-opacity: 0.6;
+  list-style-image: var(--cfr-notification-header-image);
+}
+
+#cfr-notification-header-image:hover {
+  background-color: hsla(0,0%,70%,.2);
+  border-radius: 2px;
+}
+
+#contextual-feature-recommendation-notification .popup-notification-icon {
+  margin-inline-end: 4px;
+}
+
+#contextual-feature-recommendation-notification .popup-notification-body-container {
+  padding-bottom: 0;
+}
+
+#contextual-feature-recommendation-notification popupnotificationcontent {
+  margin-top: 0;
+}
+
+#contextual-feature-recommendation-notification description {
+  margin-bottom: 0;
+}
+
+#cfr-notification-footer {
+  padding: 10px var(--arrowpanel-padding);
+}
+
+#cfr-notification-footer-text,
+#cfr-notification-footer-users,
+#cfr-notification-footer-learn-more-link {
+  margin: 0;
+}
+
+#cfr-notification-footer-addon-info {
+  align-items: center;
+  display: flex;
+  margin-top: 10px;
+  margin-bottom: 6px;
+}
+
+#cfr-notification-footer-filled-stars,
+#cfr-notification-footer-empty-stars {
+  -moz-context-properties: fill, fill-opacity;
+  background-image: var(--cfr-notification-footer-star);
+  background-size: 17px;
+  fill: var(--lwt-text-color);
+  fill-opacity: 0.7;
+  height: 16px;
+}
+
+#cfr-notification-footer-filled-stars:-moz-locale-dir(rtl),
+#cfr-notification-footer-empty-stars {
+  background-position-x: right;
+}
+
+#cfr-notification-footer-filled-stars,
+#cfr-notification-footer-empty-stars:-moz-locale-dir(rtl) {
+  background-position-x: left;
+}
+
+#cfr-notification-footer-empty-stars[tooltiptext] {
+  margin-inline-end: 6px;
+  opacity: 0.3;
+}
+
+#cfr-notification-footer-users {
+  opacity: 0.7;
+}
+
+#cfr-notification-footer-spacer {
+  flex-grow: 1;
+}
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1511,17 +1511,18 @@ nsIDocument::nsIDocument()
     mFlashClassification(FlashClassification::Unclassified),
     mBoxObjectTable(nullptr),
     mCurrentOrientationAngle(0),
     mCurrentOrientationType(OrientationType::Portrait_primary),
     mServoRestyleRootDirtyBits(0),
     mThrowOnDynamicMarkupInsertionCounter(0),
     mIgnoreOpensDuringUnloadCounter(0),
     mNumTrackersFound(0),
-    mNumTrackersBlocked(0)
+    mNumTrackersBlocked(0),
+    mDocLWTheme(Doc_Theme_Uninitialized)
 {
   SetIsInDocument();
   SetIsConnected(true);
 
   if (StaticPrefs::layout_css_use_counters_enabled()) {
     mStyleUseCounters.reset(Servo_UseCounters_Create());
   }
 }
@@ -12406,16 +12407,53 @@ nsIDocument::GetDocShell() const
 
 void
 nsIDocument::SetStateObject(nsIStructuredCloneContainer *scContainer)
 {
   mStateObjectContainer = scContainer;
   mStateObjectCached = nullptr;
 }
 
+nsIDocument::DocumentTheme
+nsIDocument::GetDocumentLWTheme()
+{
+  if (mDocLWTheme == Doc_Theme_Uninitialized) {
+    mDocLWTheme = ThreadSafeGetDocumentLWTheme();
+  }
+  return mDocLWTheme;
+}
+
+nsIDocument::DocumentTheme
+nsIDocument::ThreadSafeGetDocumentLWTheme() const
+{
+  if (!nsContentUtils::IsSystemPrincipal(NodePrincipal())) {
+    return Doc_Theme_None;
+  }
+
+  if (mDocLWTheme != Doc_Theme_Uninitialized) {
+    return mDocLWTheme;
+  }
+
+  DocumentTheme theme = Doc_Theme_None; // No lightweight theme by default
+  Element* element = GetRootElement();
+  if (element && element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::lwtheme,
+                                      nsGkAtoms::_true, eCaseMatters)) {
+    theme = Doc_Theme_Neutral;
+    nsAutoString lwTheme;
+    element->GetAttr(kNameSpaceID_None, nsGkAtoms::lwthemetextcolor, lwTheme);
+    if (lwTheme.EqualsLiteral("dark")) {
+      theme = Doc_Theme_Dark;
+    } else if (lwTheme.EqualsLiteral("bright")) {
+      theme = Doc_Theme_Bright;
+    }
+  }
+
+  return theme;
+}
+
 already_AddRefed<Element>
 nsIDocument::CreateHTMLElement(nsAtom* aTag)
 {
   RefPtr<mozilla::dom::NodeInfo> nodeInfo;
   nodeInfo = mNodeInfoManager->GetNodeInfo(aTag, nullptr, kNameSpaceID_XHTML,
                                            ELEMENT_NODE);
   MOZ_ASSERT(nodeInfo, "GetNodeInfo should never fail");
 
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2795,18 +2795,19 @@ public:
   void SetStateObject(nsIStructuredCloneContainer *scContainer);
 
   /**
    * Returns Doc_Theme_None if there is no lightweight theme specified,
    * Doc_Theme_Dark for a dark theme, Doc_Theme_Bright for a light theme, and
    * Doc_Theme_Neutral for any other theme. This is used to determine the state
    * of the pseudoclasses :-moz-lwtheme and :-moz-lwtheme-text.
    */
-  virtual DocumentTheme GetDocumentLWTheme() { return Doc_Theme_None; }
-  virtual DocumentTheme ThreadSafeGetDocumentLWTheme() const { return Doc_Theme_None; }
+  DocumentTheme GetDocumentLWTheme();
+  DocumentTheme ThreadSafeGetDocumentLWTheme() const;
+  void ResetDocumentLWTheme() { mDocLWTheme = Doc_Theme_Uninitialized; }
 
   // Whether we're a media document or not.
   enum class MediaDocumentKind
   {
     NotMedia,
     Video,
     Image,
     Plugin,
@@ -4534,16 +4535,20 @@ protected:
 
   nsCOMPtr<nsIDOMXULCommandDispatcher> mCommandDispatcher; // [OWNER] of the focus tracker
 
   // At the moment, trackers might be blocked by Tracking Protection or FastBlock.
   // In order to know the numbers of trackers detected and blocked, we add
   // these two values here and those are shared by TP and FB.
   uint32_t mNumTrackersFound;
   uint32_t mNumTrackersBlocked;
+
+  // document lightweight theme for use with :-moz-lwtheme, :-moz-lwtheme-brighttext
+  // and :-moz-lwtheme-darktext
+  DocumentTheme                         mDocLWTheme;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
 
 /**
  * mozAutoSubtreeModified batches DOM mutations so that a DOMSubtreeModified
  * event is dispatched, if necessary, when the outermost mozAutoSubtreeModified
  * object is deleted.
--- a/dom/tests/browser/browser_bug1236512.js
+++ b/dom/tests/browser/browser_bug1236512.js
@@ -38,22 +38,26 @@ async function waitContentVisibilityChan
 /**
  * This test is to test the visibility state will change to "hidden" when browser
  * window is fully covered by another non-translucent application. Note that we
  * only support this on Mac for now, other platforms don't support reporting
  * occlusion state.
  */
 add_task(async function() {
   info("creating test window");
+  let winTest = await BrowserTestUtils.openNewBrowserWindow();
   // Specify the width, height, left and top, so that the new window can be
   // fully covered by "window".
-  let winTest = await BrowserTestUtils.openNewBrowserWindow({ width: 500,
-                                                              height: 500,
-                                                              left: 200,
-                                                              top: 200 });
+  let resizePromise = BrowserTestUtils.waitForEvent(winTest, "resize", false, e => {
+    return winTest.innerHeight <= 500 && winTest.innerWidth <= 500;
+  });
+  winTest.moveTo(200, 200);
+  winTest.resizeTo(500, 500);
+  await resizePromise;
+
   let browserTest = winTest.gBrowser;
 
   info(`loading test page: ${testPageURL}`);
   browserTest.selectedBrowser.loadURI(testPageURL);
   await BrowserTestUtils.browserLoaded(browserTest.selectedBrowser);
 
   info("test init visibility state");
   await testContentVisibilityState(false /* isHidden */, browserTest);
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -264,17 +264,17 @@ partial interface Element {
   [Throws, Func="nsDocument::IsUnprefixedFullscreenEnabled", NeedsCallerType]
   void requestFullscreen();
   [Throws, BinaryName="requestFullscreen", NeedsCallerType]
   void mozRequestFullScreen();
 };
 
 // https://w3c.github.io/pointerlock/#extensions-to-the-element-interface
 partial interface Element {
-  [NeedsCallerType]
+  [NeedsCallerType, Pref="dom.pointer-lock.enabled"]
   void requestPointerLock();
 };
 
 // Mozilla-specific additions to support devtools
 partial interface Element {
   // Support reporting of Flexbox properties
   /**
    * If this element has a display:flex or display:inline-flex style,
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -150,17 +150,16 @@ namespace dom {
 XULDocument::XULDocument(void)
     : XMLDocument("application/vnd.mozilla.xul+xml"),
       mNextSrcLoadWaiter(nullptr),
       mApplyingPersistedAttrs(false),
       mIsWritingFastLoad(false),
       mDocumentLoaded(false),
       mStillWalking(false),
       mPendingSheets(0),
-      mDocLWTheme(Doc_Theme_Uninitialized),
       mCurrentScriptProto(nullptr),
       mOffThreadCompiling(false),
       mOffThreadCompileStringBuf(nullptr),
       mOffThreadCompileStringLength(0),
       mResolutionPhase(nsForwardReference::eStart),
       mBroadcasterMap(nullptr),
       mInitialLayoutComplete(false),
       mHandlingDelayedAttrChange(false),
@@ -2650,52 +2649,16 @@ void
 XULDocument::DirectionChanged(const char* aPrefName, XULDocument* aDoc)
 {
   // Reset the direction and restyle the document if necessary.
   if (aDoc) {
       aDoc->ResetDocumentDirection();
   }
 }
 
-nsIDocument::DocumentTheme
-XULDocument::GetDocumentLWTheme()
-{
-    if (mDocLWTheme == Doc_Theme_Uninitialized) {
-        mDocLWTheme = ThreadSafeGetDocumentLWTheme();
-    }
-    return mDocLWTheme;
-}
-
-nsIDocument::DocumentTheme
-XULDocument::ThreadSafeGetDocumentLWTheme() const
-{
-    if (mDocLWTheme != Doc_Theme_Uninitialized) {
-        return mDocLWTheme;
-    }
-
-    DocumentTheme theme = Doc_Theme_None; // No lightweight theme by default
-    Element* element = GetRootElement();
-    nsAutoString hasLWTheme;
-    if (element &&
-        element->GetAttr(kNameSpaceID_None, nsGkAtoms::lwtheme, hasLWTheme) &&
-        !(hasLWTheme.IsEmpty()) &&
-        hasLWTheme.EqualsLiteral("true")) {
-        theme = Doc_Theme_Neutral;
-        nsAutoString lwTheme;
-        element->GetAttr(kNameSpaceID_None, nsGkAtoms::lwthemetextcolor, lwTheme);
-        if (!(lwTheme.IsEmpty())) {
-            if (lwTheme.EqualsLiteral("dark"))
-                theme = Doc_Theme_Dark;
-            else if (lwTheme.EqualsLiteral("bright"))
-                theme = Doc_Theme_Bright;
-        }
-    }
-    return theme;
-}
-
 JSObject*
 XULDocument::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return XULDocument_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/xul/XULDocument.h
+++ b/dom/xul/XULDocument.h
@@ -118,21 +118,16 @@ public:
 
     virtual bool IsDocumentRightToLeft() override;
 
     /**
      * Reset the document direction so that it is recomputed.
      */
     void ResetDocumentDirection();
 
-    virtual nsIDocument::DocumentTheme GetDocumentLWTheme() override;
-    virtual nsIDocument::DocumentTheme ThreadSafeGetDocumentLWTheme() const override;
-
-    void ResetDocumentLWTheme() { mDocLWTheme = Doc_Theme_Uninitialized; }
-
     NS_IMETHOD OnScriptCompileComplete(JSScript* aScript, nsresult aStatus) override;
 
     NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(XULDocument, XMLDocument)
 
     void TraceProtos(JSTracer* aTrc);
 
     void RemoveBroadcastListenerFor(Element& aBroadcaster, Element& aListener,
                                     const nsAString& aAttr);
@@ -213,22 +208,16 @@ protected:
      * mStillWalking prevents DoneLoading (and StartLayout) from being
      * called in this situation.
      */
     bool                       mStillWalking;
 
     uint32_t mPendingSheets;
 
     /**
-     * document lightweight theme for use with :-moz-lwtheme, :-moz-lwtheme-brighttext
-     * and :-moz-lwtheme-darktext
-     */
-    DocumentTheme                         mDocLWTheme;
-
-    /**
      * Context stack, which maintains the state of the Builder and allows
      * it to be interrupted.
      */
     class ContextStack {
     protected:
         struct Entry {
             nsXULPrototypeElement* mPrototype;
             nsIContent*            mElement;
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -863,20 +863,18 @@ nsXULElement::AfterSetAttr(int32_t aName
                 } else if (aName == nsGkAtoms::localedir) {
                     // if the localedir changed on the root element, reset the document direction
                     if (document->IsXULDocument()) {
                         document->AsXULDocument()->ResetDocumentDirection();
                     }
                 } else if (aName == nsGkAtoms::lwtheme ||
                          aName == nsGkAtoms::lwthemetextcolor) {
                     // if the lwtheme changed, make sure to reset the document lwtheme cache
-                    if (document->IsXULDocument()) {
-                        document->AsXULDocument()->ResetDocumentLWTheme();
-                        UpdateBrightTitlebarForeground(document);
-                    }
+                    document->ResetDocumentLWTheme();
+                    UpdateBrightTitlebarForeground(document);
                 } else if (aName == nsGkAtoms::brighttitlebarforeground) {
                     UpdateBrightTitlebarForeground(document);
                 }
             }
         } else {
             if (mNodeInfo->Equals(nsGkAtoms::window)) {
                 if (aName == nsGkAtoms::hidechrome) {
                     HideWindowChrome(false);
@@ -890,20 +888,18 @@ nsXULElement::AfterSetAttr(int32_t aName
                 if (aName == nsGkAtoms::localedir) {
                     // if the localedir changed on the root element, reset the document direction
                     if (doc->IsXULDocument()) {
                         doc->AsXULDocument()->ResetDocumentDirection();
                     }
                 } else if ((aName == nsGkAtoms::lwtheme ||
                             aName == nsGkAtoms::lwthemetextcolor)) {
                     // if the lwtheme changed, make sure to restyle appropriately
-                    if (doc->IsXULDocument()) {
-                        doc->AsXULDocument()->ResetDocumentLWTheme();
-                        UpdateBrightTitlebarForeground(doc);
-                    }
+                    doc->ResetDocumentLWTheme();
+                    UpdateBrightTitlebarForeground(doc);
                 } else if (aName == nsGkAtoms::brighttitlebarforeground) {
                     UpdateBrightTitlebarForeground(doc);
                 } else if (aName == nsGkAtoms::drawintitlebar) {
                     SetDrawsInTitlebar(false);
                 } else if (aName == nsGkAtoms::drawtitle) {
                     SetDrawsTitle(false);
                 }
             }
--- a/extensions/cookie/test/unit/test_domain_eviction.js
+++ b/extensions/cookie/test/unit/test_domain_eviction.js
@@ -14,16 +14,19 @@ function run_test()
 
 function continue_test()
 {
   do_run_generator(test_generator);
 }
 
 function* do_run_test()
 {
+  // Set quotaPerHost to maxPerHost - 1, so there is only one cookie
+  // will be evicted everytime.
+  Services.prefs.setIntPref("network.cookie.quotaPerHost", 49);
   // Set the base domain limit to 50 so we have a known value.
   Services.prefs.setIntPref("network.cookie.maxPerHost", 50);
 
   let futureExpiry = Math.floor(Date.now() / 1000 + 1000);
 
   // test eviction under the 50 cookies per base domain limit. this means
   // that cookies for foo.com and bar.foo.com should count toward this limit,
   // while cookies for baz.com should not. there are several tests we perform
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -302,17 +302,17 @@ GDIFontEntry::TestCharacterMap(uint32_t 
 
         // previous code was using the group style
         gfxFontStyle fakeStyle;
         if (!IsUpright()) {
             fakeStyle.style = FontSlantStyle::Italic();
         }
         fakeStyle.weight = Weight().Min();
 
-        RefPtr<gfxFont> tempFont = FindOrMakeFont(&fakeStyle, false);
+        RefPtr<gfxFont> tempFont = FindOrMakeFont(&fakeStyle, nullptr);
         if (!tempFont || !tempFont->Valid())
             return false;
         gfxGDIFont *font = static_cast<gfxGDIFont*>(tempFont.get());
 
         HDC dc = GetDC((HWND)nullptr);
         SetGraphicsMode(dc, GM_ADVANCED);
         HFONT hfont = font->GetHFONT();
         HFONT oldFont = (HFONT)SelectObject(dc, hfont);
--- a/memory/replace/logalloc/replay/Replay.cpp
+++ b/memory/replace/logalloc/replay/Replay.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #define MOZ_MEMORY_IMPL
 #include "mozmemory_wrap.h"
 
 #ifdef _WIN32
 #include <windows.h>
 #include <io.h>
-typedef int ssize_t;
+typedef intptr_t ssize_t;
 #else
 #include <sys/mman.h>
 #include <unistd.h>
 #endif
 #include <algorithm>
 #include <cstdio>
 #include <cstring>
 
--- a/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationHelper.java
+++ b/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationHelper.java
@@ -96,32 +96,41 @@ public final class NotificationHelper im
         /**
          * Mozilla Location Services notification channel.
          */
         DOWNLOAD,
         /**
          *  Media notification channel
          */
         MEDIA,
+        /**
+         * Built-in updater - use only when <code>AppConstants.MOZ_UPDATER</code> is true.
+         */
+        UPDATER,
     }
 
     // Holds the mapping between the Channel enum used by the rest of our codebase and the
     // channel ID used for communication with the system NotificationManager.
-    private final Map<Channel, String> mDefinedNotificationChannels = new HashMap<Channel, String>(4) {{
+    private final Map<Channel, String> mDefinedNotificationChannels = new HashMap<Channel, String>(5) {{
         final String DEFAULT_CHANNEL_TAG = "default-notification-channel";
         put(Channel.DEFAULT, DEFAULT_CHANNEL_TAG);
 
         final String MLS_CHANNEL_TAG = "mls-notification-channel";
         put(Channel.MLS, MLS_CHANNEL_TAG);
 
         final String DOWNLOAD_NOTIFICATION_TAG = "download-notification-channel";
         put(Channel.DOWNLOAD, DOWNLOAD_NOTIFICATION_TAG);
 
         final String MEDIA_CHANNEL_TAG = "media-notification-channel";
         put(Channel.MEDIA, MEDIA_CHANNEL_TAG);
+
+        if (AppConstants.MOZ_UPDATER) {
+            final String UPDATER_CHANNEL_TAG = "updater-notification-channel";
+            put(Channel.UPDATER, UPDATER_CHANNEL_TAG);
+        }
     }};
 
     // Holds a list of notifications that should be cleared if the Fennec Activity is shut down.
     // Will not include ongoing or persistent notifications that are tied to Gecko's lifecycle.
     private SimpleArrayMap<String, GeckoBundle> mClearableNotifications;
 
     private boolean mInitialized;
     private static NotificationHelper sInstance;
@@ -188,16 +197,23 @@ public final class NotificationHelper im
 
                 case MEDIA: {
                     channel = new NotificationChannel(mDefinedNotificationChannels.get(definedChannel),
                             mContext.getString(R.string.media_notification_channel),
                             NotificationManager.IMPORTANCE_LOW);
                 }
                 break;
 
+                case UPDATER: {
+                    channel = new NotificationChannel(mDefinedNotificationChannels.get(definedChannel),
+                            mContext.getString(R.string.updater_notification_channel),
+                            NotificationManager.IMPORTANCE_LOW);
+                }
+                break;
+
                 case DEFAULT:
                 default: {
                     channel = new NotificationChannel(mDefinedNotificationChannels.get(definedChannel),
                             mContext.getString(R.string.default_notification_channel),
                             NotificationManager.IMPORTANCE_HIGH);
                 }
                 break;
             }
--- a/mobile/android/base/java/org/mozilla/gecko/updater/Updater.java
+++ b/mobile/android/base/java/org/mozilla/gecko/updater/Updater.java
@@ -230,17 +230,17 @@ public class Updater {
                 .setStyle(bigTextStyle)
                 .setAutoCancel(true)
                 .setSmallIcon(R.drawable.ic_status_logo)
                 .setColor(ContextCompat.getColor(context, R.color.rejection_red))
                 .setContentIntent(pendingIntent);
 
         if (!AppConstants.Versions.preO) {
             builder.setChannelId(NotificationHelper.getInstance(context)
-                    .getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
+                    .getNotificationChannel(NotificationHelper.Channel.UPDATER).getId());
         }
 
         NotificationManagerCompat.from(context)
                 .notify(R.id.updateServicePermissionNotification, builder.build());
     }
 
     @SuppressLint("NewApi")
     private void startDownload(UpdateInfo info, int flags) {
@@ -273,17 +273,17 @@ public class Updater {
             builder.setWhen(System.currentTimeMillis());
             builder.setAutoCancel(true);
             builder.setContentTitle(getString(R.string.updater_start_title));
             builder.setContentText(getString(R.string.updater_start_select));
             builder.setContentIntent(contentIntent);
 
             if (!AppConstants.Versions.preO) {
                 builder.setChannelId(NotificationHelper.getInstance(context)
-                        .getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
+                        .getNotificationChannel(NotificationHelper.Channel.UPDATER).getId());
             }
 
             notificationManager.notify(notificationId, builder.build());
 
             return;
         }
 
         File pkg = downloadUpdatePackage(info, hasFlag(flags, FLAG_OVERWRITE_EXISTING));
@@ -315,17 +315,17 @@ public class Updater {
             builder.setWhen(System.currentTimeMillis());
             builder.setAutoCancel(true);
             builder.setContentTitle(getString(R.string.updater_apply_title));
             builder.setContentText(getString(R.string.updater_apply_select));
             builder.setContentIntent(contentIntent);
 
             if (!AppConstants.Versions.preO) {
                 builder.setChannelId(NotificationHelper.getInstance(context)
-                        .getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
+                        .getNotificationChannel(NotificationHelper.Channel.UPDATER).getId());
             }
 
             notificationManager.notify(notificationId, builder.build());
         }
     }
 
     private File downloadUpdatePackage(UpdateInfo info, boolean overwriteExisting) {
         URL url = null;
@@ -466,21 +466,22 @@ public class Updater {
         PendingIntent contentIntent = PendingIntent.getBroadcast(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
         PendingIntent deleteIntent = PendingIntent.getBroadcast(context, 0, cancelIntent, PendingIntent.FLAG_CANCEL_CURRENT);
 
         notifBuilder = new NotificationCompat.Builder(context);
         notifBuilder.setContentTitle(getString(R.string.updater_downloading_title))
                 .setContentText(shouldApplyImmediately ? "" : getString(R.string.updater_downloading_select))
                 .setSmallIcon(android.R.drawable.stat_sys_download)
                 .setContentIntent(contentIntent)
-                .setDeleteIntent(deleteIntent);
+                .setDeleteIntent(deleteIntent)
+                .setOnlyAlertOnce(true);
 
         if (!AppConstants.Versions.preO) {
             notifBuilder.setChannelId(NotificationHelper.getInstance(context)
-                    .getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
+                    .getNotificationChannel(NotificationHelper.Channel.UPDATER).getId());
         }
 
         notifBuilder.setProgress(100, 0, true);
         notificationManager.notify(notificationId, notifBuilder.build());
     }
 
     @SuppressLint("NewApi")
     private void showDownloadFailure() {
@@ -493,17 +494,17 @@ public class Updater {
         builder.setSmallIcon(R.drawable.ic_status_logo);
         builder.setWhen(System.currentTimeMillis());
         builder.setContentTitle(getString(R.string.updater_downloading_title_failed));
         builder.setContentText(getString(R.string.updater_downloading_retry));
         builder.setContentIntent(contentIntent);
 
         if (!AppConstants.Versions.preO) {
             builder.setChannelId(NotificationHelper.getInstance(context)
-                    .getNotificationChannel(NotificationHelper.Channel.DEFAULT).getId());
+                    .getNotificationChannel(NotificationHelper.Channel.UPDATER).getId());
         }
 
         notificationManager.notify(notificationId, builder.build());
     }
 
     private void applyUpdate(File updateFile) {
         shouldApplyImmediately = false;
 
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -894,8 +894,9 @@ Picture-in-picture mini window -->
 <!ENTITY pip_pause_button_title "Pause">
 <!ENTITY pip_pause_button_description "Pause playing">
 
 <!-- Notification channels names -->
 <!ENTITY default_notification_channel "&brandShortName;">
 <!ENTITY mls_notification_channel "&vendorShortName; Location Service">
 <!ENTITY download_notification_channel "Downloads">
 <!ENTITY media_notification_channel "Media playback">
+<!ENTITY updater_notification_channel "App updates">
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -647,9 +647,10 @@
   <string name="pip_play_button_description">&pip_play_button_description;</string>
   <string name="pip_pause_button_title">&pip_pause_button_title;</string>
   <string name="pip_pause_button_description">&pip_pause_button_description;</string>
 
   <string name="default_notification_channel">&default_notification_channel;</string>
   <string name="mls_notification_channel">&mls_notification_channel;</string>
   <string name="media_notification_channel">&media_notification_channel;</string>
   <string name="download_notification_channel">&download_notification_channel;</string>
+  <string name="updater_notification_channel">&updater_notification_channel;</string>
 </resources>
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -190,16 +190,22 @@ pref("dom.performance.time_to_non_blank_
 pref("dom.performance.time_to_dom_content_flushed.enabled", false);
 
 // Enable Performance Observer API
 pref("dom.enable_performance_observer", true);
 
 // Enable requestIdleCallback API
 pref("dom.requestIdleCallback.enabled", true);
 
+// Enable Pointer Lock API
+// This is added for accessibility purpose. When user has no way to exit
+// pointer lock (e.g. no keyboard available), they can use this pref to
+// disable the Pointer Lock API altogether.
+pref("dom.pointer-lock.enabled", true);
+
 // Whether the Gamepad API is enabled
 pref("dom.gamepad.enabled", true);
 pref("dom.gamepad.test.enabled", false);
 #ifdef RELEASE_OR_BETA
 pref("dom.gamepad.non_standard_events.enabled", false);
 #else
 pref("dom.gamepad.non_standard_events.enabled", true);
 #endif
--- a/mozglue/misc/interceptor/TargetFunction.h
+++ b/mozglue/misc/interceptor/TargetFunction.h
@@ -803,30 +803,30 @@ public:
 
     return std::move(result);
   }
 
 private:
   template <typename T>
   struct ChasePointerHelper
   {
-    template <typename MMPolicy>
-    static T Result(const MMPolicy&, T aValue)
+    template <typename MMPolicy_>
+    static T Result(const MMPolicy_&, T aValue)
     {
       return aValue;
     }
   };
 
   template <typename T>
   struct ChasePointerHelper<T*>
   {
-    template <typename MMPolicy>
-    static auto Result(const MMPolicy& aPolicy, T* aValue)
+    template <typename MMPolicy_>
+    static auto Result(const MMPolicy_& aPolicy, T* aValue)
     {
-      ReadOnlyTargetFunction<MMPolicy> ptr(aPolicy, aValue);
+      ReadOnlyTargetFunction<MMPolicy_> ptr(aPolicy, aValue);
       return ptr.template ChasePointer<T>();
     }
   };
 
 public:
   // Keep chasing pointers until T is not a pointer type anymore
   template <typename T>
   auto ChasePointer()
--- a/mozglue/tests/interceptor/moz.build
+++ b/mozglue/tests/interceptor/moz.build
@@ -11,16 +11,16 @@ GeckoCppUnitTests(
     ],
     linkage=None
 )
 
 OS_LIBS += [
     'ole32',
 ]
 
-if CONFIG['OS_TARGET'] == 'WINNT' and CONFIG['CC_TYPE'] == 'gcc':
+if CONFIG['OS_TARGET'] == 'WINNT' and CONFIG['CC_TYPE'] in ('gcc', 'clang'):
     # This allows us to use wmain as the entry point on mingw
     LDFLAGS += [
         '-municode',
     ]
 
 if CONFIG['CC_TYPE'] == 'clang-cl':
     AllowCompilerWarnings()  # workaround for bug 1090497
--- a/netwerk/test/TestCookie.cpp
+++ b/netwerk/test/TestCookie.cpp
@@ -25,16 +25,17 @@
 
 using mozilla::Unused;
 
 static NS_DEFINE_CID(kCookieServiceCID, NS_COOKIESERVICE_CID);
 static NS_DEFINE_CID(kPrefServiceCID,   NS_PREFSERVICE_CID);
 
 // various pref strings
 static const char kCookiesPermissions[] = "network.cookie.cookieBehavior";
+static const char kPrefCookieQuotaPerHost[] = "network.cookie.quotaPerHost";
 static const char kCookiesMaxPerHost[] = "network.cookie.maxPerHost";
 static const char kCookieLeaveSecurityAlone[] = "network.cookie.leave-secure-alone";
 
 #define OFFSET_ONE_WEEK int64_t(604800) * PR_USEC_PER_SEC
 #define OFFSET_ONE_DAY int64_t(86400) * PR_USEC_PER_SEC
 
 //Set server time or expiry time
 void
@@ -174,16 +175,19 @@ CheckResult(const char *aLhs, uint32_t a
 void
 InitPrefs(nsIPrefBranch *aPrefBranch)
 {
     // init some relevant prefs, so the tests don't go awry.
     // we use the most restrictive set of prefs we can;
     // however, we don't test third party blocking here.
     aPrefBranch->SetIntPref(kCookiesPermissions, 0); // accept all
     aPrefBranch->SetBoolPref(kCookieLeaveSecurityAlone, true);
+    // Set quotaPerHost to maxPerHost - 1, so there is only one cookie
+    // will be evicted everytime.
+    aPrefBranch->SetIntPref(kPrefCookieQuotaPerHost, 49);
     // Set the base domain limit to 50 so we have a known value.
     aPrefBranch->SetIntPref(kCookiesMaxPerHost, 50);
 }
 
 
 TEST(TestCookie,TestCookieMain)
 {
     nsresult rv0;
--- a/security/certverifier/ExtendedValidation.cpp
+++ b/security/certverifier/ExtendedValidation.cpp
@@ -160,54 +160,16 @@ static const struct EVInfo kEVInfos[] = 
     { 0x62, 0xDD, 0x0B, 0xE9, 0xB9, 0xF5, 0x0A, 0x16, 0x3E, 0xA0, 0xF8,
       0xE7, 0x5C, 0x05, 0x3B, 0x1E, 0xCA, 0x57, 0xEA, 0x55, 0xC8, 0x68,
       0x8F, 0x64, 0x7C, 0x68, 0x81, 0xF2, 0xC8, 0x35, 0x7B, 0x95 },
     "MEUxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMT"
     "FlN3aXNzU2lnbiBHb2xkIENBIC0gRzI=",
     "ALtAHEP1Xk+w",
   },
   {
-    // CN=VeriSign Class 3 Public Primary Certification Authority - G5,OU="(c) 2006 VeriSign, Inc. - For authorized use only",OU=VeriSign Trust Network,O="VeriSign, Inc.",C=US
-    "2.16.840.1.113733.1.7.23.6",
-    "VeriSign EV OID",
-    { 0x9A, 0xCF, 0xAB, 0x7E, 0x43, 0xC8, 0xD8, 0x80, 0xD0, 0x6B, 0x26,
-      0x2A, 0x94, 0xDE, 0xEE, 0xE4, 0xB4, 0x65, 0x99, 0x89, 0xC3, 0xD0,
-      0xCA, 0xF1, 0x9B, 0xAF, 0x64, 0x05, 0xE4, 0x1A, 0xB7, 0xDF },
-    "MIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV"
-    "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA2IFZl"
-    "cmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMT"
-    "PFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB"
-    "dXRob3JpdHkgLSBHNQ==",
-    "GNrRniZ96LtKIVjNzGs7Sg==",
-  },
-  {
-    // CN=GeoTrust Primary Certification Authority,O=GeoTrust Inc.,C=US
-    "1.3.6.1.4.1.14370.1.6",
-    "GeoTrust EV OID",
-    { 0x37, 0xD5, 0x10, 0x06, 0xC5, 0x12, 0xEA, 0xAB, 0x62, 0x64, 0x21,
-      0xF1, 0xEC, 0x8C, 0x92, 0x01, 0x3F, 0xC5, 0xF8, 0x2A, 0xE9, 0x8E,
-      0xE5, 0x33, 0xEB, 0x46, 0x19, 0xB8, 0xDE, 0xB4, 0xD0, 0x6C },
-    "MFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQD"
-    "EyhHZW9UcnVzdCBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5",
-    "GKy1av1pthU6Y2yv2vrEoQ==",
-  },
-  {
-    // CN=thawte Primary Root CA,OU="(c) 2006 thawte, Inc. - For authorized use only",OU=Certification Services Division,O="thawte, Inc.",C=US
-    "2.16.840.1.113733.1.7.48.1",
-    "Thawte EV OID",
-    { 0x8D, 0x72, 0x2F, 0x81, 0xA9, 0xC1, 0x13, 0xC0, 0x79, 0x1D, 0xF1,
-      0x36, 0xA2, 0x96, 0x6D, 0xB2, 0x6C, 0x95, 0x0A, 0x97, 0x1D, 0xB4,
-      0x6B, 0x41, 0x99, 0xF4, 0xEA, 0x54, 0xB7, 0x8B, 0xFB, 0x9F },
-    "MIGpMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3RlLCBJbmMuMSgwJgYDVQQL"
-    "Ex9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYDVQQLEy8oYykg"
-    "MjAwNiB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0G"
-    "A1UEAxMWdGhhd3RlIFByaW1hcnkgUm9vdCBDQQ==",
-    "NE7VVyDV7exJ9C/ON9srbQ==",
-  },
-  {
     // CN=XRamp Global Certification Authority,O=XRamp Security Services Inc,OU=www.xrampsecurity.com,C=US
     "2.16.840.1.114404.1.1.2.4.1",
     "Trustwave EV OID",
     { 0xCE, 0xCD, 0xDC, 0x90, 0x50, 0x99, 0xD8, 0xDA, 0xDF, 0xC5, 0xB1,
       0xD2, 0x09, 0xB7, 0x37, 0xCB, 0xE2, 0xC1, 0x8C, 0xFB, 0x2C, 0x10,
       0xC0, 0xFF, 0x0B, 0xCF, 0x0D, 0x32, 0x86, 0xFC, 0x1A, 0xA2 },
     "MIGCMQswCQYDVQQGEwJVUzEeMBwGA1UECxMVd3d3LnhyYW1wc2VjdXJpdHkuY29t"
     "MSQwIgYDVQQKExtYUmFtcCBTZWN1cml0eSBTZXJ2aWNlcyBJbmMxLTArBgNVBAMT"
@@ -560,55 +522,16 @@ static const struct EVInfo kEVInfos[] = 
     { 0xEE, 0xC5, 0x49, 0x6B, 0x98, 0x8C, 0xE9, 0x86, 0x25, 0xB9, 0x34,
       0x09, 0x2E, 0xEC, 0x29, 0x08, 0xBE, 0xD0, 0xB0, 0xF3, 0x16, 0xC2,
       0xD4, 0x73, 0x0C, 0x84, 0xEA, 0xF1, 0xF3, 0xD3, 0x48, 0x81 },
     "MFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMM"
     "IUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOQ==",
     "CYP0",
   },
   {
-    // CN=VeriSign Universal Root Certification Authority,OU="(c) 2008 VeriSign, Inc. - For authorized use only",OU=VeriSign Trust Network,O="VeriSign, Inc.",C=US
-    "2.16.840.1.113733.1.7.23.6",
-    "VeriSign EV OID",
-    { 0x23, 0x99, 0x56, 0x11, 0x27, 0xA5, 0x71, 0x25, 0xDE, 0x8C, 0xEF,
-      0xEA, 0x61, 0x0D, 0xDF, 0x2F, 0xA0, 0x78, 0xB5, 0xC8, 0x06, 0x7F,
-      0x4E, 0x82, 0x82, 0x90, 0xBF, 0xB8, 0x60, 0xE8, 0x4B, 0x3C },
-    "MIG9MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV"
-    "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZl"
-    "cmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMT"
-    "L1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5",
-    "QBrEZCGzEyEDDrvkEhrFHQ==",
-  },
-  {
-    // CN=GeoTrust Primary Certification Authority - G3,OU=(c) 2008 GeoTrust Inc. - For authorized use only,O=GeoTrust Inc.,C=US
-    "1.3.6.1.4.1.14370.1.6",
-    "GeoTrust EV OID",
-    { 0xB4, 0x78, 0xB8, 0x12, 0x25, 0x0D, 0xF8, 0x78, 0x63, 0x5C, 0x2A,
-      0xA7, 0xEC, 0x7D, 0x15, 0x5E, 0xAA, 0x62, 0x5E, 0xE8, 0x29, 0x16,
-      0xE2, 0xCD, 0x29, 0x43, 0x61, 0x88, 0x6C, 0xD1, 0xFB, 0xD4 },
-    "MIGYMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjE5MDcGA1UE"
-    "CxMwKGMpIDIwMDggR2VvVHJ1c3QgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBv"
-    "bmx5MTYwNAYDVQQDEy1HZW9UcnVzdCBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0"
-    "aG9yaXR5IC0gRzM=",
-    "FaxulBmyeUtB9iepwxgPHw==",
-  },
-  {
-    // CN=thawte Primary Root CA - G3,OU="(c) 2008 thawte, Inc. - For authorized use only",OU=Certification Services Division,O="thawte, Inc.",C=US
-    "2.16.840.1.113733.1.7.48.1",
-    "Thawte EV OID",
-    { 0x4B, 0x03, 0xF4, 0x58, 0x07, 0xAD, 0x70, 0xF2, 0x1B, 0xFC, 0x2C,
-      0xAE, 0x71, 0xC9, 0xFD, 0xE4, 0x60, 0x4C, 0x06, 0x4C, 0xF5, 0xFF,
-      0xB6, 0x86, 0xBA, 0xE5, 0xDB, 0xAA, 0xD7, 0xFD, 0xD3, 0x4C },
-    "MIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3RlLCBJbmMuMSgwJgYDVQQL"
-    "Ex9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYDVQQLEy8oYykg"
-    "MjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG"
-    "A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz",
-    "YAGXt0an6rS0mtZLL/eQ+w==",
-  },
-  {
     // CN = Autoridad de Certificacion Firmaprofesional CIF A62634068, C = ES
     "1.3.6.1.4.1.13177.10.1.3.10",
     "Firmaprofesional EV OID",
     { 0x04, 0x04, 0x80, 0x28, 0xBF, 0x1F, 0x28, 0x64, 0xD4, 0x8F, 0x9A,
       0xD4, 0xD8, 0x32, 0x94, 0x36, 0x6A, 0x82, 0x88, 0x56, 0x55, 0x3F,
       0x3B, 0x14, 0x30, 0x3F, 0x90, 0x14, 0x7F, 0x5D, 0x40, 0xEF },
     "MFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNh"
     "Y2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjg=",
@@ -850,30 +773,16 @@ static const struct EVInfo kEVInfos[] = 
       0xCD, 0x98, 0xB6, 0x21, 0x49, 0xE5, 0x49, 0x4A, 0x67, 0xF5, 0x84,
       0x5E, 0x7B, 0xD1, 0xED, 0x01, 0x9F, 0x27, 0xB8, 0x6B, 0xD6 },
     "MG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNU"
     "RSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds"
     "b2JhbCBSb290IEdCIENB",
     "drEgUnTwhYdGs/gjGvbCwA==",
   },
   {
-    // CN=VeriSign Class 3 Public Primary Certification Authority - G4,OU="(c) 2007 VeriSign, Inc. - For authorized use only",OU=VeriSign Trust Network,O="VeriSign, Inc.",C=US
-    "2.16.840.1.113733.1.7.23.6",
-    "VeriSign EV OID",
-    { 0x69, 0xDD, 0xD7, 0xEA, 0x90, 0xBB, 0x57, 0xC9, 0x3E, 0x13, 0x5D,
-      0xC8, 0x5E, 0xA6, 0xFC, 0xD5, 0x48, 0x0B, 0x60, 0x32, 0x39, 0xBD,
-      0xC4, 0x54, 0xFC, 0x75, 0x8B, 0x2A, 0x26, 0xCF, 0x7F, 0x79 },
-    "MIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV"
-    "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA3IFZl"
-    "cmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMT"
-    "PFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB"
-    "dXRob3JpdHkgLSBHNA==",
-    "L4D+I4wOIg9IZxIokYessw==",
-  },
-  {
     // CN=Amazon Root CA 1,O=Amazon,C=US
     "2.23.140.1.1",
     "CA/Browser Forum EV OID",
     { 0x8E, 0xCD, 0xE6, 0x88, 0x4F, 0x3D, 0x87, 0xB1, 0x12, 0x5B, 0xA3,
       0x1A, 0xC3, 0xFC, 0xB1, 0x3D, 0x70, 0x16, 0xDE, 0x7F, 0x57, 0xCC,
       0x90, 0x4F, 0xE1, 0xCB, 0x97, 0xC6, 0xAE, 0x98, 0x19, 0x6E },
     "MDkxCzAJBgNVBAYTAlVTMQ8wDQYDVQQKEwZBbWF6b24xGTAXBgNVBAMTEEFtYXpv"
     "biBSb290IENBIDE=",
--- a/security/manager/ssl/nsNSSComponent.h
+++ b/security/manager/ssl/nsNSSComponent.h
@@ -58,20 +58,16 @@ public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSINSSCOMPONENT
   NS_DECL_NSIOBSERVER
 
   nsresult Init();
 
   static nsresult GetNewPrompter(nsIPrompt** result);
 
-  // The following two methods are thread-safe.
-  static bool AreAnyWeakCiphersEnabled();
-  static void UseWeakCiphersOnSocket(PRFileDesc* fd);
-
   static void FillTLSVersionRange(SSLVersionRange& rangeOut,
                                   uint32_t minFromPrefs,
                                   uint32_t maxFromPrefs,
                                   SSLVersionRange defaults);
 
 protected:
   virtual ~nsNSSComponent();
 
--- a/security/manager/ssl/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/nsNSSIOLayer.cpp
@@ -2572,23 +2572,16 @@ nsSSLIOLayerSetOptions(PRFileDesc* fd, b
       }
     }
     // tell NSS the max enabled version to make anti-downgrade effective
     if (SECSuccess != SSL_SetDowngradeCheckVersion(fd, maxEnabledVersion)) {
       return NS_ERROR_FAILURE;
     }
   }
 
-  if (range.max > SSL_LIBRARY_VERSION_TLS_1_2) {
-    SSL_CipherPrefSet(fd, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, false);
-    SSL_CipherPrefSet(fd, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, false);
-    SSL_CipherPrefSet(fd, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, false);
-    SSL_CipherPrefSet(fd, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, false);
-  }
-
   // Include a modest set of named groups.
   // Please change getKeaGroupName in nsNSSCallbacks.cpp when changing the list
   // here.
   const SSLNamedGroup namedGroups[] = {
     ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
     ssl_grp_ec_secp521r1, ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072
   };
   if (SECSuccess != SSL_NamedGroupConfig(fd, namedGroups,
--- a/taskcluster/scripts/misc/build-clang-7-pre-mingw.sh
+++ b/taskcluster/scripts/misc/build-clang-7-pre-mingw.sh
@@ -10,17 +10,17 @@ UPLOAD_DIR=$HOME/artifacts
 TOOLCHAIN_DIR=$WORKSPACE/moz-toolchain
 INSTALL_DIR=$TOOLCHAIN_DIR/build/stage3/clang
 CROSS_PREFIX_DIR=$INSTALL_DIR/x86_64-w64-mingw32
 SRC_DIR=$TOOLCHAIN_DIR/src
 
 CLANG_VERSION=7.0.0
 make_flags="-j$(nproc)"
 
-mingw_version=30af18252d4e965e98612e215b8cf6b7ae42c01a
+mingw_version=5b72d83ec57e2aba171e9fe78a48104c5037f20d
 libunwind_version=86ab23972978242b6f9e27cebc239f3e8428b1af
 
 binutils_version=2.27
 binutils_ext=bz2
 binutils_sha=369737ce51587f92466041a97ab7d2358c6d9e1b6490b3940eb09fb0a9a6ac88
 
 # This is default value of _WIN32_WINNT. Gecko configure script explicitly sets this,
 # so this is not used to build Gecko itself. We default to 0x600, which is Windows Vista.
--- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
+++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
@@ -20,16 +20,19 @@ var EXPORTED_SYMBOLS = [
 ];
 
 ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://testing-common/TestUtils.jsm");
 ChromeUtils.import("resource://testing-common/ContentTask.jsm");
 
+ChromeUtils.defineModuleGetter(this, "BrowserWindowTracker",
+  "resource:///modules/BrowserWindowTracker.jsm");
+
 Services
   .mm
   .loadFrameScript(
     "chrome://mochikit/content/tests/BrowserTestUtils/content-utils.js", true);
 
 ChromeUtils.defineModuleGetter(this, "E10SUtils",
   "resource://gre/modules/E10SUtils.jsm");
 
@@ -696,71 +699,29 @@ var BrowserTestUtils = {
           resolve(subject.QueryInterface(Ci.nsIDOMWindow));
         }
       }
       Services.ww.registerNotification(observer);
     });
   },
 
   /**
-   * @param {Object} options
-   *        {
-   *          private: A boolean indicating if the window should be
-   *                   private
-   *          remote:  A boolean indicating if the window should run
-   *                   remote browser tabs or not. If omitted, the window
-   *                   will choose the profile default state.
-   *          width: Desired width of window
-   *          height: Desired height of window
-   *        }
+   * Open a new browser window from an existing one.
+   * This relies on OpenBrowserWindow in browser.js, and waits for the window
+   * to be completely loaded before resolving.
+   *
    * @return {Promise}
    *         Resolves with the new window once it is loaded.
    */
   async openNewBrowserWindow(options = {}) {
-    let argString = Cc["@mozilla.org/supports-string;1"].
-                    createInstance(Ci.nsISupportsString);
-    argString.data = "";
-    let features = "chrome,dialog=no,all";
-    let opener = null;
-
-    if (options.opener) {
-      opener = options.opener;
-    }
-
-    if (options.private) {
-      features += ",private";
-    }
-
-    if (options.width) {
-      features += ",width=" + options.width;
-    }
-    if (options.height) {
-      features += ",height=" + options.height;
+    let currentWin = BrowserWindowTracker.getTopWindow({private: false});
+    if (!currentWin) {
+      throw new Error("Can't open a new browser window from this helper if no non-private window is open.");
     }
-
-    if (options.left) {
-      features += ",left=" + options.left;
-    }
-
-    if (options.top) {
-      features += ",top=" + options.top;
-    }
-
-    if (options.hasOwnProperty("remote")) {
-      let remoteState = options.remote ? "remote" : "non-remote";
-      features += `,${remoteState}`;
-    }
-
-    if (options.url) {
-      argString.data = options.url;
-    }
-
-    let win = Services.ww.openWindow(
-      opener, AppConstants.BROWSER_CHROME_URL, "_blank",
-      features, argString);
+    let win = currentWin.OpenBrowserWindow(options);
 
     // Wait for browser-delayed-startup-finished notification, it indicates
     // that the window has loaded completely and is ready to be used for
     // testing.
     let startupPromise =
       TestUtils.topicObserved("browser-delayed-startup-finished",
                               subject => subject == win).then(() => win);
 
--- a/toolkit/components/extensions/parent/ext-proxy.js
+++ b/toolkit/components/extensions/parent/ext-proxy.js
@@ -223,16 +223,21 @@ this.proxy = class extends ExtensionAPI 
 
               if (!Services.policies.isAllowed("changeProxySettings")) {
                 throw new ExtensionError(
                   "Proxy settings are being managed by the Policies manager.");
               }
 
               let value = details.value;
 
+              // proxyType is optional and it should default to "system" when missing.
+              if (value.proxyType == null) {
+                value.proxyType = "system";
+              }
+
               if (!PROXY_TYPES_MAP.has(value.proxyType)) {
                 throw new ExtensionError(
                   `${value.proxyType} is not a valid value for proxyType.`);
               }
 
               if (value.httpProxyAll) {
                 // Match what about:preferences does with proxy settings
                 // since the proxy service does not check the value
--- a/toolkit/components/extensions/test/mochitest/test_ext_cookies_permissions_bad.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_cookies_permissions_bad.html
@@ -12,18 +12,23 @@
 <body>
 
 <script type="text/javascript">
 "use strict";
 
 add_task(async function init() {
   // We need to trigger a cookie eviction in order to test our batch delete
   // observer.
+
+  // Set quotaPerHost to maxPerHost - 1, so there is only one cookie
+  // will be evicted everytime.
+  SpecialPowers.setIntPref("network.cookie.quotaPerHost", 2);
   SpecialPowers.setIntPref("network.cookie.maxPerHost", 3);
   SimpleTest.registerCleanupFunction(() => {
+    SpecialPowers.clearUserPref("network.cookie.quotaPerHost");
     SpecialPowers.clearUserPref("network.cookie.maxPerHost");
   });
 });
 
 add_task(async function test_bad_cookie_permissions() {
   info("Test non-matching, non-secure domain with non-secure cookie");
   await testCookies({
     permissions: ["http://example.com/", "cookies"],
--- a/toolkit/components/extensions/test/mochitest/test_ext_cookies_permissions_good.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_cookies_permissions_good.html
@@ -12,18 +12,23 @@
 <body>
 
 <script type="text/javascript">
 "use strict";
 
 add_task(async function init() {
   // We need to trigger a cookie eviction in order to test our batch delete
   // observer.
+
+  // Set quotaPerHost to maxPerHost - 1, so there is only one cookie
+  // will be evicted everytime.
+  SpecialPowers.setIntPref("network.cookie.quotaPerHost", 2);
   SpecialPowers.setIntPref("network.cookie.maxPerHost", 3);
   SimpleTest.registerCleanupFunction(() => {
+    SpecialPowers.clearUserPref("network.cookie.quotaPerHost");
     SpecialPowers.clearUserPref("network.cookie.maxPerHost");
   });
 });
 
 add_task(async function test_good_cookie_permissions() {
   info("Test matching, non-secure domain with non-secure cookie");
   await testCookies({
     permissions: ["http://example.com/", "cookies"],
--- a/toolkit/components/extensions/test/xpcshell/test_ext_proxy_config.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_proxy_config.js
@@ -100,16 +100,19 @@ add_task(async function test_browser_set
       httpProxyAll: false,
       socksVersion: 5,
       passthrough: "localhost, 127.0.0.1",
       http: "",
       ftp: "",
       ssl: "",
       socks: "",
     };
+
+    expectedConfig.proxyType = expectedConfig.proxyType || "system";
+
     return testSetting(
       config, expectedPrefs, Object.assign(proxyConfig, expectedConfig)
     );
   }
 
   await testProxy(
     {proxyType: "none"},
     {"network.proxy.type": proxySvc.PROXYCONFIG_DIRECT},
@@ -136,16 +139,29 @@ add_task(async function test_browser_set
     },
     {
       "network.proxy.type": proxySvc.PROXYCONFIG_SYSTEM,
       "signon.autologin.proxy": false,
       "network.proxy.socks_remote_dns": false,
     },
   );
 
+  // Verify that proxyType is optional and it defaults to "system".
+  await testProxy(
+    {
+      autoLogin: false,
+      proxyDNS: false,
+    },
+    {
+      "network.proxy.type": proxySvc.PROXYCONFIG_SYSTEM,
+      "signon.autologin.proxy": false,
+      "network.proxy.socks_remote_dns": false,
+    },
+  );
+
   await testProxy(
     {
       proxyType: "autoConfig",
       autoConfigUrl: "http://mozilla.org",
     },
     {
       "network.proxy.type": proxySvc.PROXYCONFIG_PAC,
       "network.proxy.autoconfig_url": "http://mozilla.org",
--- a/toolkit/content/widgets/notification.xml
+++ b/toolkit/content/widgets/notification.xml
@@ -483,16 +483,19 @@
           ]]>
         </body>
       </method>
     </implementation>
   </binding>
 
   <binding id="popup-notification">
     <content orient="vertical">
+      <xul:hbox class="popup-notification-header-container">
+        <children includes="popupnotificationheader"/>
+      </xul:hbox>
       <xul:hbox align="start" class="popup-notification-body-container">
         <xul:image class="popup-notification-icon"
                    xbl:inherits="popupid,src=icon,class=iconclass"/>
         <xul:vbox flex="1" pack="start"
                   class="popup-notification-body" xbl:inherits="popupid">
           <xul:hbox align="start">
             <xul:vbox flex="1">
               <xul:label class="popup-notification-origin header"
@@ -513,16 +516,19 @@
           <children includes="popupnotificationcontent"/>
           <xul:label class="text-link popup-notification-learnmore-link"
                      xbl:inherits="onclick=learnmoreclick,href=learnmoreurl">&learnMore;</xul:label>
           <xul:checkbox anonid="checkbox"
                         xbl:inherits="hidden=checkboxhidden,checked=checkboxchecked,label=checkboxlabel,oncommand=checkboxcommand" />
           <xul:description class="popup-notification-warning" xbl:inherits="hidden=warninghidden,xbl:text=warninglabel"/>
         </xul:vbox>
       </xul:hbox>
+      <xul:hbox class="popup-notification-footer-container">
+        <children includes="popupnotificationfooter"/>
+      </xul:hbox>
       <xul:hbox class="popup-notification-button-container">
         <children includes="button"/>
         <xul:button anonid="secondarybutton"
                     class="popup-notification-button"
                     xbl:inherits="oncommand=secondarybuttoncommand,label=secondarybuttonlabel,accesskey=secondarybuttonaccesskey,hidden=secondarybuttonhidden"/>
         <xul:toolbarseparator xbl:inherits="hidden=dropmarkerhidden"/>
         <xul:button anonid="menubutton"
                     type="menu"
--- a/toolkit/library/moz.build
+++ b/toolkit/library/moz.build
@@ -307,16 +307,17 @@ if CONFIG['OS_ARCH'] == 'WINNT':
         'portabledeviceguids',
         'wininet',
         'wbemuuid',
         'wintrust',
         'wtsapi32',
         'locationapi',
         'sapi',
         'dxguid',
+        'dhcpcsvc',
     ]
     if CONFIG['ACCESSIBILITY']:
         OS_LIBS += [
             'oleacc',
         ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     OS_LIBS += [
--- a/toolkit/themes/shared/popupnotification.inc.css
+++ b/toolkit/themes/shared/popupnotification.inc.css
@@ -1,12 +1,18 @@
 /* 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/. */
 
+.popup-notification-header-container,
+.popup-notification-footer-container {
+  display: flex;
+  max-width: calc(2 * var(--arrowpanel-padding) + 32px + 4px + 25em);
+}
+
 .popup-notification-body-container {
   padding: var(--arrowpanel-padding);
 }
 
 .popup-notification-icon {
   width: 32px;
   height: 32px;
   margin-inline-end: var(--arrowpanel-padding);