Merge mozilla-central to inbound. a=merge CLOSED TREE
authorGurzau Raul <rgurzau@mozilla.com>
Fri, 01 Mar 2019 09:28:28 +0200
changeset 519795 53c9ecc53bbfb67ba5d90271398bf54cb80a5f25
parent 519794 3ea769ff9a9a04270cd445f6acd4ea0714650eb1 (current diff)
parent 519712 9d39099e5fc5768e979dda950af84df76ba4734d (diff)
child 519796 e097bf9457c31adfe082dd38397f0794a674a746
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to inbound. a=merge CLOSED TREE
browser/base/content/test/trackingUI/browser_trackingUI_cryptominers.js
browser/base/content/test/trackingUI/browser_trackingUI_fingerprinters.js
caps/nsJSPrincipals.cpp
docshell/base/BrowsingContext.cpp
dom/canvas/OffscreenCanvas.cpp
dom/html/HTMLMediaElement.cpp
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
dom/ipc/MemoryReportRequest.cpp
dom/media/ipc/RDDChild.cpp
dom/media/ipc/RDDParent.cpp
dom/serviceworkers/ServiceWorkerRegistrar.cpp
gfx/gl/GLContext.cpp
gfx/gl/SkiaGLGlue.cpp
gfx/gl/SkiaGLGlue.h
gfx/ipc/GPUChild.cpp
gfx/ipc/GPUParent.cpp
gfx/layers/client/CanvasClient.cpp
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxWindowsPlatform.cpp
gfx/webrender_bindings/RenderCompositorEGL.cpp
js/src/shell/js.cpp
mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoVRManager.java
netwerk/ipc/SocketProcessChild.cpp
netwerk/ipc/SocketProcessParent.cpp
netwerk/url-classifier/UrlClassifierCommon.cpp
netwerk/url-classifier/UrlClassifierCommon.h
netwerk/url-classifier/UrlClassifierFeatureBase.cpp
netwerk/url-classifier/UrlClassifierFeatureBase.h
netwerk/url-classifier/UrlClassifierFeatureCryptomining.cpp
netwerk/url-classifier/UrlClassifierFeatureFingerprinting.cpp
netwerk/url-classifier/UrlClassifierFeatureTrackingAnnotation.cpp
netwerk/url-classifier/UrlClassifierFeatureTrackingProtection.cpp
security/sandbox/linux/glue/SandboxPrefBridge.cpp
toolkit/components/antitracking/test/browser/3rdParty.html
toolkit/components/antitracking/test/browser/browser.ini
toolkit/components/antitracking/test/browser/browser_blockingCookies.js
toolkit/components/antitracking/test/browser/browser_blockingDOMCache.js
toolkit/components/antitracking/test/browser/browser_blockingIndexedDb.js
toolkit/components/antitracking/test/browser/browser_blockingIndexedDbInWorkers.js
toolkit/components/antitracking/test/browser/browser_blockingLocalStorage.js
toolkit/components/antitracking/test/browser/browser_blockingMessaging.js
toolkit/components/antitracking/test/browser/browser_blockingServiceWorkers.js
toolkit/components/antitracking/test/browser/browser_blockingSessionStorage.js
toolkit/components/antitracking/test/browser/browser_blockingSharedWorkers.js
toolkit/components/antitracking/test/browser/browser_partitionedLocalStorage.js
toolkit/components/antitracking/test/browser/browser_storageAccessRemovalNavigateSubframe.js
toolkit/components/antitracking/test/browser/head.js
toolkit/components/antitracking/test/browser/storageAccessAPIHelpers.js
toolkit/components/url-classifier/tests/browser/classifierTester.js
xpcom/base/CycleCollectedJSRuntime.cpp
xpcom/base/nsMemoryReporterManager.cpp
--- a/browser/base/content/aboutRestartRequired.xhtml
+++ b/browser/base/content/aboutRestartRequired.xhtml
@@ -21,17 +21,17 @@
     <!-- PAGE CONTAINER (for styling purposes only) -->
     <div id="errorPageContainer">
       <div id="text-container">
         <div id="title">
           <h1 id="title-text" data-l10n-id="restart-required-header"></h1>
         </div>
         <div id="errorLongContent">
           <div id="errorLongDesc">
-            <p data-l10n-id="restart-required-intro"></p>
+            <p data-l10n-id="restart-required-intro-brand"></p>
             <p data-l10n-id="restart-required-description"></p>
           </div>
         </div>
       </div>
       <!-- Restart Button -->
       <div id="restartButtonContainer" class="button-container">
         <button id="restart" data-l10n-id="restart-button-label" class="primary" autocomplete="off"
                 onclick="AboutRestartRequired.restart();"></button>
--- a/browser/base/content/browser-captivePortal.js
+++ b/browser/base/content/browser-captivePortal.js
@@ -256,17 +256,17 @@ var CaptivePortalWatcher = {
           userContextId: gBrowser.contentPrincipal.userContextId,
         }),
       });
       this._captivePortalTab = Cu.getWeakReference(tab);
     }
 
     gBrowser.selectedTab = tab;
 
-    let canonicalURI = makeURI(this.canonicalURL);
+    let canonicalURI = Services.io.newURI(this.canonicalURL);
 
     // When we are no longer captive, close the tab if it's at the canonical URL.
     let tabCloser = () => {
       Services.obs.removeObserver(tabCloser, "captive-portal-login-abort");
       Services.obs.removeObserver(tabCloser, "captive-portal-login-success");
       if (!tab || tab.closing || !tab.parentNode || !tab.linkedBrowser ||
           !tab.linkedBrowser.currentURI.equalsExceptRef(canonicalURI)) {
         return;
--- a/browser/base/content/newInstallPage.js
+++ b/browser/base/content/newInstallPage.js
@@ -39,31 +39,30 @@ async function requestFlowMetrics() {
   throw new Error(`Failed to retrieve metrics: ${response.status}`);
 }
 
 async function submitForm(event) {
   // We never want to submit the form.
   event.preventDefault();
 
   let input = document.getElementById("sync-input");
-  input.disabled = true;
-  document.getElementById("sync-button").disabled = true;
 
   let { flowId, flowBeginTime } = await metrics;
 
   let requestURL = new URL(await endpoint);
   appendParams(requestURL, {
     "action": "email",
     "utm_campaign": CAMPAIGN,
     "email": input.value,
     "flow_id": flowId,
     "flow_begin_time": flowBeginTime,
   });
 
   window.open(requestURL, "_blank", "noopener");
+  document.getElementById("sync").hidden = true;
 }
 
 const endpoint = RPMGetFxAccountsEndpoint(ENTRYPOINT);
 
 // This must come before the CSP is set or it will be blocked.
 const metrics = requestFlowMetrics();
 
 document.addEventListener("DOMContentLoaded", () => {
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -2424,17 +2424,18 @@
           let updatePositionalAttr = gBrowser.selectedTab == this;
 
           gBrowser.clearMultiSelectedTabs(updatePositionalAttr);
         }
 
         if (event.originalTarget.classList.contains("tab-icon-sound") ||
             (event.originalTarget.classList.contains("tab-icon-overlay") &&
              (event.originalTarget.hasAttribute("soundplaying") ||
-              event.originalTarget.hasAttribute("muted")))) {
+              event.originalTarget.hasAttribute("muted") ||
+              event.originalTarget.hasAttribute("activemedia-blocked")))) {
           if (this.multiselected) {
             gBrowser.toggleMuteAudioOnMultiSelectedTabs(this);
           } else {
             this.toggleMuteAudio();
           }
           return;
         }
 
--- a/browser/base/content/test/general/browser_findbarClose.js
+++ b/browser/base/content/test/general/browser_findbarClose.js
@@ -22,15 +22,14 @@ add_task(async function findbar_test() {
     let awaitLoad = ContentTaskUtils.waitForEvent(iframe, "load", false);
     iframe.src = "https://example.org/";
     await awaitLoad;
   });
 
   ok(!gFindBar.hidden, "the Find bar isn't hidden after the location of a " +
      "subdocument changes");
 
-  let findBarClosePromise = promiseWaitForEvent(gBrowser, "findbarclose");
+  let findBarClosePromise = BrowserTestUtils.waitForEvent(gBrowser, "findbarclose");
   gFindBar.close();
   await findBarClosePromise;
 
   gBrowser.removeTab(newTab);
 });
-
--- a/browser/base/content/test/performance/browser.ini
+++ b/browser/base/content/test/performance/browser.ini
@@ -3,16 +3,17 @@
 # do almost nothing unless browser.startup.record is true.
 # gfx.canvas.willReadFrequently.enable is just an optimization, but needs to be
 # set during early startup to have an impact as a canvas will be used by
 # startupRecorder.js
 prefs =
   # Skip migration work in BG__migrateUI for browser_startup.js since it isn't
   # representative of common startup.
   browser.migration.version=9999999
+  browser.urlbar.quantumbar=true
   browser.startup.record=true
   gfx.canvas.willReadFrequently.enable=true
   # The form autofill framescript is only used in certain locales if this
   # pref is set to 'detect', which is the default value on non-Nightly.
   extensions.formautofill.available='on'
 support-files =
   head.js
 [browser_appmenu.js]
--- a/browser/base/content/test/performance/browser_urlbar_keyed_search.js
+++ b/browser/base/content/test/performance/browser_urlbar_keyed_search.js
@@ -1,199 +1,53 @@
 "use strict";
 
-// There are a _lot_ of reflows in this test, and processing them takes
-// time. On slower builds, we need to boost our allowed test time.
-requestLongerTimeout(5);
+// This tests searching in the urlbar (a.k.a. the quantumbar).
 
 /**
  * WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
  * is a whitelist that should slowly go away as we improve the performance of
  * the front-end. Instead of adding more reflows to the whitelist, you should
  * be modifying your code to avoid the reflow.
  *
  * See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
  * for tips on how to do that.
  */
 
-/* These reflows happen only the first time the awesomebar panel opens. */
-const EXPECTED_REFLOWS_FIRST_OPEN = [];
-if (AppConstants.platform != "macosx" &&
-    (AppConstants.DEBUG ||
-     AppConstants.platform == "win")) {
-  EXPECTED_REFLOWS_FIRST_OPEN.push({
+/* These reflows happen only the first time the panel opens. */
+const EXPECTED_REFLOWS_FIRST_OPEN = [
+  // This is the this.panel.openPopup() call in UrlbarView._openPanel.  See bug
+  // 1359989, which was filed against the legacy awesomebar but applies here too
+  // because it seems to be caused by platform code.
+  {
+    stack: [
+      "_openPanel@resource:///modules/UrlbarView.jsm",
+      "onQueryResults@resource:///modules/UrlbarView.jsm",
+      "_notify@resource:///modules/UrlbarController.jsm",
+      "receiveResults@resource:///modules/UrlbarController.jsm",
+      "notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
+      "add@resource:///modules/UrlbarProvidersManager.jsm",
+      "onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
+    ],
+  },
+  {
     stack: [
       "__rebuild@chrome://browser/content/search/search-one-offs.js",
       /* This is limited to a one-line stack, because the next item is an async
          function and as such not supported on all trees, according to bug 1501761.
-      "async*set popup@chrome://browser/content/search/search-one-offs.js",
-      "_syncOneOffSearchesEnabled@chrome://browser/content/urlbarBindings.xml",
-      "toggleOneOffSearches@chrome://browser/content/urlbarBindings.xml",
-      "_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
-      "@chrome://browser/content/urlbarBindings.xml",
-      "_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
-      "openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
-      "openPopup@chrome://global/content/bindings/autocomplete.xml",
-      "set_popupOpen@chrome://global/content/bindings/autocomplete.xml",*/
+      "async*_rebuild@chrome://browser/content/search/search-one-offs.js",
+      "async*_on_popupshowing@chrome://browser/content/search/search-one-offs.js",
+      "handleEvent@chrome://browser/content/search/search-one-offs.js",
+      "_openPanel@resource:///modules/UrlbarView.jsm",
+      "onQueryResults@resource:///modules/UrlbarView.jsm",
+      "_notify@resource:///modules/UrlbarController.jsm",
+      "receiveResults@resource:///modules/UrlbarController.jsm",
+      "notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
+      "add@resource:///modules/UrlbarProvidersManager.jsm",
+      "onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
+      */
     ],
-  });
-}
-EXPECTED_REFLOWS_FIRST_OPEN.push(
-  {
-    stack: [
-      "_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "handleOverUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "_reuseAcItem@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
-      "_invalidate@chrome://global/content/bindings/autocomplete.xml",
-      "invalidate@chrome://global/content/bindings/autocomplete.xml",
-    ],
-    maxCount: 60, // This number should only ever go down - never up.
-  },
-
-  {
-    stack: [
-      "_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "handleOverUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
-      "openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
-      "openPopup@chrome://global/content/bindings/autocomplete.xml",
-      "set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
-    ],
-    maxCount: 6, // This number should only ever go down - never up.
   },
-
-  // Bug 1359989
-  {
-    stack: [
-      "_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
-      "openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
-      "openPopup@chrome://global/content/bindings/autocomplete.xml",
-      "set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
-    ],
-  }
-);
-
-// These extra reflows happen on beta/release as one of the default bookmarks in
-// bookmarks.html.in has a long URL.
-if (AppConstants.RELEASE_OR_BETA) {
-  EXPECTED_REFLOWS_FIRST_OPEN.push({
-    stack: [
-      "_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "_onUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "MozAutocompleteRichlistitem/<@chrome://global/content/elements/autocomplete-richlistitem.js",
-    ],
-    maxCount: 6,
-  },
-  {
-    stack: [
-      "_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "_onOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "MozAutocompleteRichlistitem/<@chrome://global/content/elements/autocomplete-richlistitem.js",
-    ],
-    maxCount: 6,
-  },
-  {
-    stack: [
-      "_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "_adjustAcItem@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
-      "_invalidate@chrome://global/content/bindings/autocomplete.xml",
-      "invalidate@chrome://global/content/bindings/autocomplete.xml",
-    ],
-    maxCount: 12,
-  });
-}
+];
 
-/**
- * Returns a Promise that resolves once the AwesomeBar popup for a particular
- * window has appeared after having done a search for its input text.
- *
- * @param win (browser window)
- *        The window to do the search in.
- * @returns Promise
- */
-async function promiseSearchComplete(win) {
-  let URLBar = win.gURLBar;
-  if (URLBar.popup.state != "open") {
-    await BrowserTestUtils.waitForEvent(URLBar.popup, "popupshown");
-  }
-  await BrowserTestUtils.waitForCondition(() => {
-    return URLBar.controller.searchStatus >=
-      Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH;
-  });
-
-  // There are several setTimeout(fn, 0); calls inside autocomplete.xml
-  // that we need to wait for. Since those have higher priority than
-  // idle callbacks, we can be sure they will have run once this
-  // idle callback is called. The timeout seems to be required in
-  // automation - presumably because the machines can be pretty busy
-  // especially if it's GC'ing from previous tests.
-  await new Promise(resolve => win.requestIdleCallback(resolve, { timeout: 1000 }));
-}
-
-add_task(async function setup() {
-  await addDummyHistoryEntries();
+add_task(async function quantumbar() {
+  await runUrlbarTest(false, true, EXPECTED_REFLOWS_FIRST_OPEN);
 });
-
-/**
- * This test ensures that there are no unexpected uninterruptible reflows when
- * typing into the URL bar with the default values in Places.
- */
-add_task(async function() {
-  let win = await prepareSettledWindow();
-
-  let URLBar = win.gURLBar;
-  let popup = URLBar.popup;
-
-  URLBar.focus();
-  URLBar.value = "";
-
-  let dropmarkerRect = document.getAnonymousElementByAttribute(gURLBar,
-    "anonid", "historydropmarker").getBoundingClientRect();
-  let textBoxRect = document.getAnonymousElementByAttribute(gURLBar,
-    "anonid", "moz-input-box").getBoundingClientRect();
-
-  await withPerfObserver(async function() {
-    let oldInvalidate = popup.invalidate.bind(popup);
-    let oldResultsAdded = popup.onResultsAdded.bind(popup);
-
-    // We need to invalidate the frame tree outside of the normal
-    // mechanism since invalidations and result additions to the
-    // URL bar occur without firing JS events (which is how we
-    // normally know to dirty the frame tree).
-    popup.invalidate = (reason) => {
-      dirtyFrame(win);
-      oldInvalidate(reason);
-    };
-
-    popup.onResultsAdded = () => {
-      dirtyFrame(win);
-      oldResultsAdded();
-    };
-
-    // Only keying in 6 characters because the number of reflows triggered
-    // is so high that we risk timing out the test if we key in any more.
-    const SEARCH_TERM = "ows-10";
-    for (let i = 0; i < SEARCH_TERM.length; ++i) {
-      let char = SEARCH_TERM[i];
-      EventUtils.synthesizeKey(char, {}, win);
-      await promiseSearchComplete(win);
-    }
-
-    let hiddenPromise = BrowserTestUtils.waitForEvent(URLBar.popup, "popuphidden");
-    EventUtils.synthesizeKey("VK_ESCAPE", {}, win);
-    await hiddenPromise;
-  }, {expectedReflows: EXPECTED_REFLOWS_FIRST_OPEN,
-      frames: {filter: rects => rects.filter(r => !(
-        // We put text into the urlbar so expect its textbox to change.
-        (r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
-         r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom) ||
-        // The dropmarker is replaced with the go arrow during the test.
-        // dropmarkerRect.left isn't always an integer, hence the - 1 and + 1
-        (r.x1 >= dropmarkerRect.left - 1 && r.x2 <= dropmarkerRect.right + 1 &&
-         r.y1 >= dropmarkerRect.top && r.y2 <= dropmarkerRect.bottom)
-        // XXX For some reason the awesomebar panel isn't in our screenshots,
-        // but that's where we actually expect many changes.
-      ))}}, win);
-
-  await BrowserTestUtils.closeWindow(win);
-});
copy from browser/base/content/test/performance/browser_urlbar_keyed_search.js
copy to browser/base/content/test/performance/browser_urlbar_keyed_search_legacy.js
--- a/browser/base/content/test/performance/browser_urlbar_keyed_search.js
+++ b/browser/base/content/test/performance/browser_urlbar_keyed_search_legacy.js
@@ -1,10 +1,13 @@
 "use strict";
 
+// This tests searching in the legacy urlbar implementation (a.k.a. the
+// awesomebar).
+
 // There are a _lot_ of reflows in this test, and processing them takes
 // time. On slower builds, we need to boost our allowed test time.
 requestLongerTimeout(5);
 
 /**
  * WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
  * is a whitelist that should slowly go away as we improve the performance of
  * the front-end. Instead of adding more reflows to the whitelist, you should
@@ -98,102 +101,11 @@ if (AppConstants.RELEASE_OR_BETA) {
       "_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
       "_invalidate@chrome://global/content/bindings/autocomplete.xml",
       "invalidate@chrome://global/content/bindings/autocomplete.xml",
     ],
     maxCount: 12,
   });
 }
 
-/**
- * Returns a Promise that resolves once the AwesomeBar popup for a particular
- * window has appeared after having done a search for its input text.
- *
- * @param win (browser window)
- *        The window to do the search in.
- * @returns Promise
- */
-async function promiseSearchComplete(win) {
-  let URLBar = win.gURLBar;
-  if (URLBar.popup.state != "open") {
-    await BrowserTestUtils.waitForEvent(URLBar.popup, "popupshown");
-  }
-  await BrowserTestUtils.waitForCondition(() => {
-    return URLBar.controller.searchStatus >=
-      Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH;
-  });
-
-  // There are several setTimeout(fn, 0); calls inside autocomplete.xml
-  // that we need to wait for. Since those have higher priority than
-  // idle callbacks, we can be sure they will have run once this
-  // idle callback is called. The timeout seems to be required in
-  // automation - presumably because the machines can be pretty busy
-  // especially if it's GC'ing from previous tests.
-  await new Promise(resolve => win.requestIdleCallback(resolve, { timeout: 1000 }));
-}
-
-add_task(async function setup() {
-  await addDummyHistoryEntries();
+add_task(async function awesomebar() {
+  await runUrlbarTest(true, true, EXPECTED_REFLOWS_FIRST_OPEN);
 });
-
-/**
- * This test ensures that there are no unexpected uninterruptible reflows when
- * typing into the URL bar with the default values in Places.
- */
-add_task(async function() {
-  let win = await prepareSettledWindow();
-
-  let URLBar = win.gURLBar;
-  let popup = URLBar.popup;
-
-  URLBar.focus();
-  URLBar.value = "";
-
-  let dropmarkerRect = document.getAnonymousElementByAttribute(gURLBar,
-    "anonid", "historydropmarker").getBoundingClientRect();
-  let textBoxRect = document.getAnonymousElementByAttribute(gURLBar,
-    "anonid", "moz-input-box").getBoundingClientRect();
-
-  await withPerfObserver(async function() {
-    let oldInvalidate = popup.invalidate.bind(popup);
-    let oldResultsAdded = popup.onResultsAdded.bind(popup);
-
-    // We need to invalidate the frame tree outside of the normal
-    // mechanism since invalidations and result additions to the
-    // URL bar occur without firing JS events (which is how we
-    // normally know to dirty the frame tree).
-    popup.invalidate = (reason) => {
-      dirtyFrame(win);
-      oldInvalidate(reason);
-    };
-
-    popup.onResultsAdded = () => {
-      dirtyFrame(win);
-      oldResultsAdded();
-    };
-
-    // Only keying in 6 characters because the number of reflows triggered
-    // is so high that we risk timing out the test if we key in any more.
-    const SEARCH_TERM = "ows-10";
-    for (let i = 0; i < SEARCH_TERM.length; ++i) {
-      let char = SEARCH_TERM[i];
-      EventUtils.synthesizeKey(char, {}, win);
-      await promiseSearchComplete(win);
-    }
-
-    let hiddenPromise = BrowserTestUtils.waitForEvent(URLBar.popup, "popuphidden");
-    EventUtils.synthesizeKey("VK_ESCAPE", {}, win);
-    await hiddenPromise;
-  }, {expectedReflows: EXPECTED_REFLOWS_FIRST_OPEN,
-      frames: {filter: rects => rects.filter(r => !(
-        // We put text into the urlbar so expect its textbox to change.
-        (r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
-         r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom) ||
-        // The dropmarker is replaced with the go arrow during the test.
-        // dropmarkerRect.left isn't always an integer, hence the - 1 and + 1
-        (r.x1 >= dropmarkerRect.left - 1 && r.x2 <= dropmarkerRect.right + 1 &&
-         r.y1 >= dropmarkerRect.top && r.y2 <= dropmarkerRect.bottom)
-        // XXX For some reason the awesomebar panel isn't in our screenshots,
-        // but that's where we actually expect many changes.
-      ))}}, win);
-
-  await BrowserTestUtils.closeWindow(win);
-});
--- a/browser/base/content/test/performance/browser_urlbar_search.js
+++ b/browser/base/content/test/performance/browser_urlbar_search.js
@@ -1,198 +1,69 @@
 "use strict";
 
-// There are a _lot_ of reflows in this test, and processing them takes
-// time. On slower builds, we need to boost our allowed test time.
-requestLongerTimeout(5);
+// This tests searching in the urlbar (a.k.a. the quantumbar).
 
 /**
  * WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
  * is a whitelist that should slowly go away as we improve the performance of
  * the front-end. Instead of adding more reflows to the whitelist, you should
  * be modifying your code to avoid the reflow.
  *
  * See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
  * for tips on how to do that.
  */
 
-/* These reflows happen only the first time the awesomebar panel opens. */
-const EXPECTED_REFLOWS_FIRST_OPEN = [];
-if (AppConstants.platform != "macosx" &&
-    (AppConstants.DEBUG ||
-     AppConstants.platform == "linux" ||
-     AppConstants.isPlatformAndVersionAtLeast("win", "10"))) {
-  EXPECTED_REFLOWS_FIRST_OPEN.push({
+/* These reflows happen only the first time the panel opens. */
+const EXPECTED_REFLOWS_FIRST_OPEN = [
+  {
+    stack: [
+      "_openPanel@resource:///modules/UrlbarView.jsm",
+      "onQueryResults@resource:///modules/UrlbarView.jsm",
+      "_notify@resource:///modules/UrlbarController.jsm",
+      "receiveResults@resource:///modules/UrlbarController.jsm",
+      "notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
+      "add@resource:///modules/UrlbarProvidersManager.jsm",
+      "onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
+    ],
+  },
+  {
     stack: [
       "__rebuild@chrome://browser/content/search/search-one-offs.js",
       /* This is limited to a one-line stack, because the next item is an async
          function and as such not supported on all trees, according to bug 1501761.
-      "async*set popup@chrome://browser/content/search/search-one-offs.js",
-      "_syncOneOffSearchesEnabled@chrome://browser/content/urlbarBindings.xml",
-      "toggleOneOffSearches@chrome://browser/content/urlbarBindings.xml",
-      "_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
-      "@chrome://browser/content/urlbarBindings.xml",
-      "_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
-      "openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
-      "openPopup@chrome://global/content/bindings/autocomplete.xml",
-      "set_popupOpen@chrome://global/content/bindings/autocomplete.xml",*/
-    ],
-  });
-}
-EXPECTED_REFLOWS_FIRST_OPEN.push(
-  {
-    stack: [
-      "_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "handleOverUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "_reuseAcItem@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
-      "_invalidate@chrome://global/content/bindings/autocomplete.xml",
-      "invalidate@chrome://global/content/bindings/autocomplete.xml",
-    ],
-    maxCount: 36, // This number should only ever go down - never up.
-  },
-
-  {
-    stack: [
-      "_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "handleOverUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
-      "openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
-      "openPopup@chrome://global/content/bindings/autocomplete.xml",
-      "set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
-    ],
-    maxCount: 6, // This number should only ever go down - never up.
-  },
-
-  // Bug 1359989
-  {
-    stack: [
-      "_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
-      "openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
-      "openPopup@chrome://global/content/bindings/autocomplete.xml",
-      "set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
-    ],
-  }
-);
-
-/* These reflows happen everytime the awesomebar panel opens. */
-const EXPECTED_REFLOWS_SECOND_OPEN = [
-  {
-    stack: [
-      "_handleOverflow@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "handleOverUnderflow@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "_reuseAcItem@chrome://global/content/elements/autocomplete-richlistitem.js",
-      "_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
-      "_invalidate@chrome://global/content/bindings/autocomplete.xml",
-      "invalidate@chrome://global/content/bindings/autocomplete.xml",
-    ],
-    maxCount: 24, // This number should only ever go down - never up.
-  },
-
-  // Bug 1359989
-  {
-    stack: [
-      "_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
-      "openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
-      "openPopup@chrome://global/content/bindings/autocomplete.xml",
-      "set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
+      "async*_rebuild@chrome://browser/content/search/search-one-offs.js",
+      "async*_on_popupshowing@chrome://browser/content/search/search-one-offs.js",
+      "handleEvent@chrome://browser/content/search/search-one-offs.js",
+      "_openPanel@resource:///modules/UrlbarView.jsm",
+      "onQueryResults@resource:///modules/UrlbarView.jsm",
+      "_notify@resource:///modules/UrlbarController.jsm",
+      "receiveResults@resource:///modules/UrlbarController.jsm",
+      "notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
+      "add@resource:///modules/UrlbarProvidersManager.jsm",
+      "onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
+      */
     ],
   },
 ];
 
-const SEARCH_TERM = "urlbar-reflows-" + Date.now();
-
-add_task(async function setup() {
-  await addDummyHistoryEntries(SEARCH_TERM);
-});
-
-/**
- * This test ensures that there are no unexpected
- * uninterruptible reflows when typing into the URL bar
- * with the default values in Places.
- */
-add_task(async function() {
-  let win = await prepareSettledWindow();
-
-  let URLBar = win.gURLBar;
-  let popup = URLBar.popup;
-
-  URLBar.focus();
-  URLBar.value = SEARCH_TERM;
-  let testFn = async function() {
-    let oldInvalidate = popup.invalidate.bind(popup);
-    let oldResultsAdded = popup.onResultsAdded.bind(popup);
-    let oldSetTimeout = win.setTimeout;
-
-    // We need to invalidate the frame tree outside of the normal
-    // mechanism since invalidations and result additions to the
-    // URL bar occur without firing JS events (which is how we
-    // normally know to dirty the frame tree).
-    popup.invalidate = (reason) => {
-      dirtyFrame(win);
-      oldInvalidate(reason);
-    };
-
-    popup.onResultsAdded = () => {
-      dirtyFrame(win);
-      oldResultsAdded();
-    };
-
-    win.setTimeout = (fn, ms) => {
-      return oldSetTimeout(() => {
-        dirtyFrame(win);
-        fn();
-      }, ms);
-    };
+/* These reflows happen every time the panel opens. */
+const EXPECTED_REFLOWS_SECOND_OPEN = [
+  // This is the this.panel.openPopup() call in UrlbarView._openPanel.  See bug
+  // 1359989, which was filed against the legacy awesomebar but applies here too
+  // because it seems to be caused by platform code.
+  {
+    stack: [
+      "_openPanel@resource:///modules/UrlbarView.jsm",
+      "onQueryResults@resource:///modules/UrlbarView.jsm",
+      "_notify@resource:///modules/UrlbarController.jsm",
+      "receiveResults@resource:///modules/UrlbarController.jsm",
+      "notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
+      "add@resource:///modules/UrlbarProvidersManager.jsm",
+      "onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
+    ],
+  },
+];
 
-    URLBar.controller.startSearch(URLBar.value);
-    await BrowserTestUtils.waitForEvent(URLBar.popup, "popupshown");
-    await BrowserTestUtils.waitForCondition(() => {
-      return URLBar.controller.searchStatus >=
-        Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH;
-    });
-    let matchCount = URLBar.popup.matchCount;
-    await BrowserTestUtils.waitForCondition(() => {
-      return URLBar.popup.richlistbox.children.length == matchCount;
-    });
-
-    URLBar.controller.stopSearch();
-    // There are several setTimeout(fn, 0); calls inside autocomplete.xml
-    // that we need to wait for. Since those have higher priority than
-    // idle callbacks, we can be sure they will have run once this
-    // idle callback is called. The timeout seems to be required in
-    // automation - presumably because the machines can be pretty busy
-    // especially if it's GC'ing from previous tests.
-    await new Promise(resolve => win.requestIdleCallback(resolve, { timeout: 1000 }));
-
-    let hiddenPromise = BrowserTestUtils.waitForEvent(URLBar.popup, "popuphidden");
-    EventUtils.synthesizeKey("VK_ESCAPE", {}, win);
-    await hiddenPromise;
-  };
-
-  let dropmarkerRect = document.getAnonymousElementByAttribute(gURLBar,
-    "anonid", "historydropmarker").getBoundingClientRect();
-  let textBoxRect = document.getAnonymousElementByAttribute(gURLBar,
-    "anonid", "moz-input-box").getBoundingClientRect();
-  let expectedRects = {
-    filter: rects => rects.filter(r => !(
-      // We put text into the urlbar so expect its textbox to change.
-      (r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
-       r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom) ||
-      // The dropmarker is displayed as active during some of the test.
-      // dropmarkerRect.left isn't always an integer, hence the - 1 and + 1
-      (r.x1 >= dropmarkerRect.left - 1 && r.x2 <= dropmarkerRect.right + 1 &&
-       r.y1 >= dropmarkerRect.top && r.y2 <= dropmarkerRect.bottom)
-      // XXX For some reason the awesomebar panel isn't in our screenshots,
-      // but that's where we actually expect many changes.
-    )),
-  };
-
-  info("First opening");
-  await withPerfObserver(testFn, {expectedReflows: EXPECTED_REFLOWS_FIRST_OPEN,
-                                  frames: expectedRects}, win);
-
-  info("Second opening");
-  await withPerfObserver(testFn, {expectedReflows: EXPECTED_REFLOWS_SECOND_OPEN,
-                                  frames: expectedRects}, win);
-
-  await BrowserTestUtils.closeWindow(win);
+add_task(async function quantumbar() {
+  await runUrlbarTest(false, false, EXPECTED_REFLOWS_FIRST_OPEN,
+                      EXPECTED_REFLOWS_SECOND_OPEN);
 });
copy from browser/base/content/test/performance/browser_urlbar_search.js
copy to browser/base/content/test/performance/browser_urlbar_search_legacy.js
--- a/browser/base/content/test/performance/browser_urlbar_search.js
+++ b/browser/base/content/test/performance/browser_urlbar_search_legacy.js
@@ -1,10 +1,13 @@
 "use strict";
 
+// This tests searching in the legacy urlbar implementation (a.k.a. the
+// awesomebar).
+
 // There are a _lot_ of reflows in this test, and processing them takes
 // time. On slower builds, we need to boost our allowed test time.
 requestLongerTimeout(5);
 
 /**
  * WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
  * is a whitelist that should slowly go away as we improve the performance of
  * the front-end. Instead of adding more reflows to the whitelist, you should
@@ -93,106 +96,12 @@ const EXPECTED_REFLOWS_SECOND_OPEN = [
       "_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
       "openPopup@chrome://global/content/bindings/autocomplete.xml",
       "set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
     ],
   },
 ];
 
-const SEARCH_TERM = "urlbar-reflows-" + Date.now();
-
-add_task(async function setup() {
-  await addDummyHistoryEntries(SEARCH_TERM);
+add_task(async function awesomebar() {
+  await runUrlbarTest(true, false, EXPECTED_REFLOWS_FIRST_OPEN,
+                      EXPECTED_REFLOWS_SECOND_OPEN);
 });
-
-/**
- * This test ensures that there are no unexpected
- * uninterruptible reflows when typing into the URL bar
- * with the default values in Places.
- */
-add_task(async function() {
-  let win = await prepareSettledWindow();
-
-  let URLBar = win.gURLBar;
-  let popup = URLBar.popup;
-
-  URLBar.focus();
-  URLBar.value = SEARCH_TERM;
-  let testFn = async function() {
-    let oldInvalidate = popup.invalidate.bind(popup);
-    let oldResultsAdded = popup.onResultsAdded.bind(popup);
-    let oldSetTimeout = win.setTimeout;
-
-    // We need to invalidate the frame tree outside of the normal
-    // mechanism since invalidations and result additions to the
-    // URL bar occur without firing JS events (which is how we
-    // normally know to dirty the frame tree).
-    popup.invalidate = (reason) => {
-      dirtyFrame(win);
-      oldInvalidate(reason);
-    };
-
-    popup.onResultsAdded = () => {
-      dirtyFrame(win);
-      oldResultsAdded();
-    };
-
-    win.setTimeout = (fn, ms) => {
-      return oldSetTimeout(() => {
-        dirtyFrame(win);
-        fn();
-      }, ms);
-    };
-
-    URLBar.controller.startSearch(URLBar.value);
-    await BrowserTestUtils.waitForEvent(URLBar.popup, "popupshown");
-    await BrowserTestUtils.waitForCondition(() => {
-      return URLBar.controller.searchStatus >=
-        Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH;
-    });
-    let matchCount = URLBar.popup.matchCount;
-    await BrowserTestUtils.waitForCondition(() => {
-      return URLBar.popup.richlistbox.children.length == matchCount;
-    });
-
-    URLBar.controller.stopSearch();
-    // There are several setTimeout(fn, 0); calls inside autocomplete.xml
-    // that we need to wait for. Since those have higher priority than
-    // idle callbacks, we can be sure they will have run once this
-    // idle callback is called. The timeout seems to be required in
-    // automation - presumably because the machines can be pretty busy
-    // especially if it's GC'ing from previous tests.
-    await new Promise(resolve => win.requestIdleCallback(resolve, { timeout: 1000 }));
-
-    let hiddenPromise = BrowserTestUtils.waitForEvent(URLBar.popup, "popuphidden");
-    EventUtils.synthesizeKey("VK_ESCAPE", {}, win);
-    await hiddenPromise;
-  };
-
-  let dropmarkerRect = document.getAnonymousElementByAttribute(gURLBar,
-    "anonid", "historydropmarker").getBoundingClientRect();
-  let textBoxRect = document.getAnonymousElementByAttribute(gURLBar,
-    "anonid", "moz-input-box").getBoundingClientRect();
-  let expectedRects = {
-    filter: rects => rects.filter(r => !(
-      // We put text into the urlbar so expect its textbox to change.
-      (r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
-       r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom) ||
-      // The dropmarker is displayed as active during some of the test.
-      // dropmarkerRect.left isn't always an integer, hence the - 1 and + 1
-      (r.x1 >= dropmarkerRect.left - 1 && r.x2 <= dropmarkerRect.right + 1 &&
-       r.y1 >= dropmarkerRect.top && r.y2 <= dropmarkerRect.bottom)
-      // XXX For some reason the awesomebar panel isn't in our screenshots,
-      // but that's where we actually expect many changes.
-    )),
-  };
-
-  info("First opening");
-  await withPerfObserver(testFn, {expectedReflows: EXPECTED_REFLOWS_FIRST_OPEN,
-                                  frames: expectedRects}, win);
-
-  info("Second opening");
-  await withPerfObserver(testFn, {expectedReflows: EXPECTED_REFLOWS_SECOND_OPEN,
-                                  frames: expectedRects}, win);
-
-  await BrowserTestUtils.closeWindow(win);
-});
--- a/browser/base/content/test/performance/head.js
+++ b/browser/base/content/test/performance/head.js
@@ -1,15 +1,15 @@
 "use strict";
 
-ChromeUtils.defineModuleGetter(this, "PlacesUtils",
-  "resource://gre/modules/PlacesUtils.jsm");
-ChromeUtils.defineModuleGetter(this, "PlacesTestUtils",
-  "resource://testing-common/PlacesTestUtils.jsm");
-
+XPCOMUtils.defineLazyModuleGetters(this, {
+  PlacesTestUtils: "resource://testing-common/PlacesTestUtils.jsm",
+  PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
+  UrlbarTestUtils: "resource://testing-common/UrlbarTestUtils.jsm",
+});
 
 /**
  * This function can be called if the test needs to trigger frame dirtying
  * outside of the normal mechanism.
  *
  * @param win (dom window)
  *        The window in which the frame tree needs to be marked as dirty.
  */
@@ -634,8 +634,126 @@ async function withPerfObserver(testFn, 
   await promiseTestDone;
 
   let reflows = await promiseReflows;
   reportUnexpectedReflows(reflows, exceptions.expectedReflows);
 
   let frames = await promiseFrames;
   reportUnexpectedFlicker(frames, exceptions.frames);
 }
+
+/**
+ * This test ensures that there are no unexpected
+ * uninterruptible reflows when typing into the URL bar
+ * with the default values in Places.
+ *
+ * @param {bool} useAwesomebar
+ *        Pass true if the legacy awesomebar is enabled.  Pass false if the
+ *        quantumbar is enabled.
+ * @param {bool} keyed
+ *        Pass true to synthesize typing the search string one key at a time.
+ * @param {array} expectedReflowsFirstOpen
+ *        The array of expected reflow stacks when the panel is first opened.
+ * @param {array} [expectedReflowsSecondOpen]
+ *        The array of expected reflow stacks when the panel is subsequently
+ *        opened, if you're testing opening the panel twice.
+ */
+async function runUrlbarTest(useAwesomebar,
+                             keyed,
+                             expectedReflowsFirstOpen,
+                             expectedReflowsSecondOpen = null) {
+  const SEARCH_TERM = keyed ? "" : "urlbar-reflows-" + Date.now();
+  await addDummyHistoryEntries(SEARCH_TERM);
+
+  let win = await prepareSettledWindow();
+
+  let URLBar = win.gURLBar;
+
+  URLBar.focus();
+  URLBar.value = SEARCH_TERM;
+  let testFn = async function() {
+    if (useAwesomebar) {
+      let popup = URLBar.popup;
+      let oldInvalidate = popup.invalidate.bind(popup);
+      let oldResultsAdded = popup.onResultsAdded.bind(popup);
+      let oldSetTimeout = win.setTimeout;
+
+      // We need to invalidate the frame tree outside of the normal
+      // mechanism since invalidations and result additions to the
+      // URL bar occur without firing JS events (which is how we
+      // normally know to dirty the frame tree).
+      popup.invalidate = (reason) => {
+        dirtyFrame(win);
+        oldInvalidate(reason);
+      };
+
+      popup.onResultsAdded = () => {
+        dirtyFrame(win);
+        oldResultsAdded();
+      };
+
+      win.setTimeout = (fn, ms) => {
+        return oldSetTimeout(() => {
+          dirtyFrame(win);
+          fn();
+        }, ms);
+      };
+    }
+
+    let waitExtra = async () => {
+      // There are several setTimeout(fn, 0); calls inside autocomplete.xml
+      // that we need to wait for. Since those have higher priority than
+      // idle callbacks, we can be sure they will have run once this
+      // idle callback is called. The timeout seems to be required in
+      // automation - presumably because the machines can be pretty busy
+      // especially if it's GC'ing from previous tests.
+      await new Promise(resolve => win.requestIdleCallback(resolve, { timeout: 1000 }));
+    };
+
+    if (keyed) {
+      // Only keying in 6 characters because the number of reflows triggered
+      // is so high that we risk timing out the test if we key in any more.
+      let searchTerm = "ows-10";
+      for (let i = 0; i < searchTerm.length; ++i) {
+        let char = searchTerm[i];
+        EventUtils.synthesizeKey(char, {}, win);
+        await UrlbarTestUtils.promiseSearchComplete(win);
+        await waitExtra();
+      }
+    } else {
+      await UrlbarTestUtils.promiseAutocompleteResultPopup(win, URLBar.value,
+                                                           SimpleTest.waitForFocus);
+      await waitExtra();
+    }
+
+    await UrlbarTestUtils.promisePopupClose(win);
+  };
+
+  let dropmarkerRect = win.document.getAnonymousElementByAttribute(URLBar.textbox,
+    "anonid", "historydropmarker").getBoundingClientRect();
+  let textBoxRect = win.document.getAnonymousElementByAttribute(URLBar.textbox,
+    "anonid", "moz-input-box").getBoundingClientRect();
+  let expectedRects = {
+    filter: rects => rects.filter(r => !(
+      // We put text into the urlbar so expect its textbox to change.
+      (r.x1 >= textBoxRect.left && r.x2 <= textBoxRect.right &&
+       r.y1 >= textBoxRect.top && r.y2 <= textBoxRect.bottom) ||
+      // The dropmarker is displayed as active during some of the test.
+      // dropmarkerRect.left isn't always an integer, hence the - 1 and + 1
+      (r.x1 >= dropmarkerRect.left - 1 && r.x2 <= dropmarkerRect.right + 1 &&
+       r.y1 >= dropmarkerRect.top && r.y2 <= dropmarkerRect.bottom)
+      // XXX For some reason the awesomebar panel isn't in our screenshots,
+      // but that's where we actually expect many changes.
+    )),
+  };
+
+  info(`First opening, useAwesomebar=${useAwesomebar}`);
+  await withPerfObserver(testFn, {expectedReflows: expectedReflowsFirstOpen,
+                                  frames: expectedRects}, win);
+
+  if (expectedReflowsSecondOpen) {
+    info(`Second opening, useAwesomebar=${useAwesomebar}`);
+    await withPerfObserver(testFn, {expectedReflows: expectedReflowsSecondOpen,
+                                    frames: expectedRects}, win);
+  }
+
+  await BrowserTestUtils.closeWindow(win);
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/performance/legacyurlbar/browser.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+prefs =
+  browser.urlbar.quantumbar=false
+
+[../browser_urlbar_keyed_search_legacy.js]
+skip-if = (os == 'linux') || (os == 'win' && debug) || (os == 'win' && bits == 32) # Disabled on Linux and Windows debug due to perma failures. Bug 1392320. Disabled on Win32 because of intermittent OOM failures (bug 1448241).
+[../browser_urlbar_search_legacy.js]
+skip-if = (debug || ccov) && (os == 'linux' || os == 'win') || (os == 'win' && bits == 32) # Disabled on Linux and Windows debug and ccov due to intermittent timeouts. Bug 1414126, bug 1426611. Disabled on Win32 because of intermittent OOM failures (bug 1448241)
--- a/browser/base/content/test/permissions/browser_autoplay_blocked.js
+++ b/browser/base/content/test/permissions/browser_autoplay_blocked.js
@@ -1,14 +1,17 @@
 /*
  * Test that a blocked request to autoplay media is shown to the user
  */
 
 const AUTOPLAY_PAGE  = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com") + "browser_autoplay_blocked.html";
 
+const AUTOPLAY_PREF = "media.autoplay.default";
+const AUTOPLAY_PERM = "autoplay-media";
+
 function openIdentityPopup() {
   let promise = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
   gIdentityHandler._identityBox.click();
   return promise;
 }
 
 function closeIdentityPopup() {
   let promise = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popuphidden");
@@ -16,45 +19,61 @@ function closeIdentityPopup() {
   return promise;
 }
 
 function autoplayBlockedIcon() {
   return document.querySelector("#blocked-permissions-container " +
                                 ".blocked-permission-icon.autoplay-media-icon");
 }
 
+function sleep(ms) {
+  /* eslint-disable mozilla/no-arbitrary-setTimeout */
+  return new Promise(resolve => setTimeout(resolve, ms));
+}
+
+async function blockedIconShown(browser) {
+  // May need to wait for `GloballyAutoplayBlocked` event before showing icon.
+  if (BrowserTestUtils.is_hidden(autoplayBlockedIcon())) {
+    await BrowserTestUtils.waitForEvent(browser, "GloballyAutoplayBlocked");
+  }
+  ok(!BrowserTestUtils.is_hidden(autoplayBlockedIcon()), "Blocked icon is shown");
+}
+
+add_task(async function setup() {
+  registerCleanupFunction(() => {
+    Services.perms.removeAll();
+    Services.prefs.clearUserPref(AUTOPLAY_PREF);
+  });
+});
+
 add_task(async function testMainViewVisible() {
-  Services.prefs.setIntPref("media.autoplay.default", Ci.nsIAutoplay.ALLOWED);
+  Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.ALLOWED);
 
   await BrowserTestUtils.withNewTab(AUTOPLAY_PAGE, async function() {
     let permissionsList = document.getElementById("identity-popup-permission-list");
     let emptyLabel = permissionsList.nextElementSibling.nextElementSibling;
 
     ok(BrowserTestUtils.is_hidden(autoplayBlockedIcon()), "Blocked icon not shown");
 
     await openIdentityPopup();
     ok(!BrowserTestUtils.is_hidden(emptyLabel), "List of permissions is empty");
     await closeIdentityPopup();
   });
 
-  Services.prefs.setIntPref("media.autoplay.default", Ci.nsIAutoplay.BLOCKED);
+  Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.BLOCKED);
 
   await BrowserTestUtils.withNewTab(AUTOPLAY_PAGE, async function(browser) {
     let permissionsList = document.getElementById("identity-popup-permission-list");
     let emptyLabel = permissionsList.nextElementSibling.nextElementSibling;
 
-    if (BrowserTestUtils.is_hidden(autoplayBlockedIcon())) {
-      // The block icon would be showed after tab receives `GloballyAutoplayBlocked` event.
-      await BrowserTestUtils.waitForEvent(browser, "GloballyAutoplayBlocked");
-    }
-    ok(!BrowserTestUtils.is_hidden(autoplayBlockedIcon()), "Blocked icon is shown");
+    await blockedIconShown(browser);
 
     await openIdentityPopup();
     ok(BrowserTestUtils.is_hidden(emptyLabel), "List of permissions is not empty");
-    let labelText = SitePermissions.getPermissionLabel("autoplay-media");
+    let labelText = SitePermissions.getPermissionLabel(AUTOPLAY_PERM);
     let labels = permissionsList.querySelectorAll(".identity-popup-permission-label");
     is(labels.length, 1, "One permission visible in main view");
     is(labels[0].textContent, labelText, "Correct value");
 
     let menulist = document.getElementById("identity-popup-popup-menulist");
     Assert.equal(menulist.label, "Block");
 
     await EventUtils.synthesizeMouseAtCenter(menulist, { type: "mousedown" });
@@ -65,15 +84,67 @@ add_task(async function testMainViewVisi
     let menuitem = menulist.getElementsByTagName("menuitem")[0];
     Assert.equal(menuitem.getAttribute("label"), "Allow");
 
     menuitem.click();
     menulist.menupopup.hidePopup();
     await closeIdentityPopup();
 
     let uri = Services.io.newURI(AUTOPLAY_PAGE);
-    let state = SitePermissions.get(uri, "autoplay-media").state;
+    let state = SitePermissions.get(uri, AUTOPLAY_PERM).state;
     Assert.equal(state, SitePermissions.ALLOW);
   });
 
   Services.perms.removeAll();
-  Services.prefs.clearUserPref("media.autoplay.default");
 });
+
+add_task(async function testGloballyBlockedOnNewWindow() {
+  Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.BLOCKED);
+
+  let uri = Services.io.newURI(AUTOPLAY_PAGE);
+
+  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, uri.spec);
+  await blockedIconShown(tab.linkedBrowser);
+
+  Assert.deepEqual(SitePermissions.get(uri, AUTOPLAY_PERM, tab.linkedBrowser), {
+    state: SitePermissions.BLOCK,
+    scope: SitePermissions.SCOPE_PERSISTENT,
+  });
+
+  let promiseWin = BrowserTestUtils.waitForNewWindow();
+  gBrowser.replaceTabWithWindow(tab);
+  let win = await promiseWin;
+  tab = win.gBrowser.selectedTab;
+
+  Assert.deepEqual(SitePermissions.get(uri, AUTOPLAY_PERM, tab.linkedBrowser), {
+    state: SitePermissions.BLOCK,
+    scope: SitePermissions.SCOPE_PERSISTENT,
+  });
+
+  SitePermissions.remove(uri, AUTOPLAY_PERM, tab.linkedBrowser);
+  await BrowserTestUtils.closeWindow(win);
+});
+
+add_task(async function testBFCache() {
+  Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.BLOCKED);
+
+  await BrowserTestUtils.withNewTab("about:home", async function(browser) {
+    await BrowserTestUtils.loadURI(browser, AUTOPLAY_PAGE);
+    await blockedIconShown(browser);
+    Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.ALLOWED);
+
+    gBrowser.goBack();
+    await TestUtils.waitForCondition(() => {
+      return BrowserTestUtils.is_hidden(autoplayBlockedIcon());
+    });
+
+    gBrowser.goForward();
+
+    // Sleep here to prevent false positives, the icon gets shown with an
+    // async `GloballyAutoplayBlocked` event. The sleep gives it a little
+    // time for it to show otherwise there is a chance it passes before it
+    // would have shown.
+    await sleep(100);
+    ok(BrowserTestUtils.is_hidden(autoplayBlockedIcon()), "Blocked icon is hidden");
+  });
+
+  Services.perms.removeAll();
+});
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -3,22 +3,21 @@
  * 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/. */
 
 // Services = object with smart getters for common XPCOM services
 var {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 var {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
-ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
-                               "resource://gre/modules/PrivateBrowsingUtils.jsm");
-
 XPCOMUtils.defineLazyModuleGetters(this, {
   BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
   ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm",
+  ExtensionSettingsStore: "resource://gre/modules/ExtensionSettingsStore.jsm",
+  PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
   ShellService: "resource:///modules/ShellService.jsm",
 });
 
 XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
                                    "@mozilla.org/browser/aboutnewtab-service;1",
                                    "nsIAboutNewTabService");
 
 Object.defineProperty(this, "BROWSER_NEW_TAB_URL", {
@@ -26,19 +25,20 @@ Object.defineProperty(this, "BROWSER_NEW
   get() {
     if (PrivateBrowsingUtils.isWindowPrivate(window)) {
       if (!PrivateBrowsingUtils.permanentPrivateBrowsing &&
           !aboutNewTabService.overridden) {
         return "about:privatebrowsing";
       }
       // If the extension does not have private browsing permission,
       // use about:privatebrowsing.
-      if (aboutNewTabService.newTabURL.startsWith("moz-extension")) {
-        let url = new URL(aboutNewTabService.newTabURL);
-        if (!WebExtensionPolicy.getByHostname(url.hostname).privateBrowsingAllowed) {
+      let extensionInfo = ExtensionSettingsStore.getSetting("url_overrides", "newTabURL");
+      if (extensionInfo) {
+        let policy = WebExtensionPolicy.getByID(extensionInfo.id);
+        if (!policy || !policy.privateBrowsingAllowed) {
           return "about:privatebrowsing";
         }
       }
     }
     return aboutNewTabService.newTabURL;
   },
 });
 
--- a/browser/base/moz.build
+++ b/browser/base/moz.build
@@ -31,16 +31,17 @@ BROWSER_CHROME_MANIFESTS += [
     'content/test/general/browser.ini',
     'content/test/historySwipeAnimation/browser.ini',
     'content/test/keyboard/browser.ini',
     'content/test/metaTags/browser.ini',
     'content/test/pageActions/browser.ini',
     'content/test/pageinfo/browser.ini',
     'content/test/performance/browser.ini',
     'content/test/performance/hidpi/browser.ini',
+    'content/test/performance/legacyurlbar/browser.ini',
     'content/test/performance/lowdpi/browser.ini',
     'content/test/permissions/browser.ini',
     'content/test/plugins/browser.ini',
     'content/test/popupNotifications/browser.ini',
     'content/test/popups/browser.ini',
     'content/test/referrer/browser.ini',
     'content/test/sanitize/browser.ini',
     'content/test/sidebar/browser.ini',
--- a/browser/components/BrowserContentHandler.jsm
+++ b/browser/components/BrowserContentHandler.jsm
@@ -204,17 +204,17 @@ function getPostUpdateOverridePage(defau
  */
 function openBrowserWindow(cmdLine, triggeringPrincipal, urlOrUrlList, postData = null,
                            forcePrivate = false) {
   let chromeURL = AppConstants.BROWSER_CHROME_URL;
 
   let args;
   if (!urlOrUrlList) {
     // Just pass in the defaultArgs directly. We'll use system principal on the other end.
-    args = [gBrowserContentHandler.getDefaultArgs(forcePrivate)];
+    args = [gBrowserContentHandler.defaultArgs];
   } else {
     let pService = Cc["@mozilla.org/toolkit/profile-service;1"].
                   getService(Ci.nsIToolkitProfileService);
     if (cmdLine && cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH &&
         pService.createdAlternateProfile) {
       let url = getNewInstallPage();
       if (Array.isArray(urlOrUrlList)) {
         urlOrUrlList.unshift(url);
@@ -515,17 +515,17 @@ nsBrowserContentHandler.prototype = {
     info += "  --window-size width[,height] Width and optionally height of screenshot.\n";
     info += "  --search <term>    Search <term> with your default search engine.\n";
     info += "  --setDefaultBrowser Set this app as the default browser.\n";
     return info;
   },
 
   /* nsIBrowserHandler */
 
-  getDefaultArgs(forcePrivate = false) {
+  get defaultArgs() {
     var prefb = Services.prefs;
 
     if (!gFirstWindow) {
       gFirstWindow = true;
       if (PrivateBrowsingUtils.isInTemporaryAutoStartMode) {
         return "about:privatebrowsing";
       }
     }
@@ -600,17 +600,17 @@ nsBrowserContentHandler.prototype = {
         overridePage = additionalPage;
       }
     }
 
     var startPage = "";
     try {
       var choice = prefb.getIntPref("browser.startup.page");
       if (choice == 1 || choice == 3)
-        startPage = forcePrivate ? HomePage.getPrivate() : HomePage.get();
+        startPage = HomePage.get();
     } catch (e) {
       Cu.reportError(e);
     }
 
     if (startPage == "about:blank")
       startPage = "";
 
     let skipStartPage = ((override == OVERRIDE_NEW_PROFILE) || (override == OVERRIDE_ALTERNATE_PROFILE)) &&
@@ -618,20 +618,16 @@ nsBrowserContentHandler.prototype = {
     // Only show the startPage if we're not restoring an update session and are
     // not set to skip the start page on this profile
     if (overridePage && startPage && !willRestoreSession && !skipStartPage)
       return overridePage + "|" + startPage;
 
     return overridePage || startPage || "about:blank";
   },
 
-  get defaultArgs() {
-    return this.getDefaultArgs(PrivateBrowsingUtils.permanentPrivateBrowsing);
-  },
-
   mFeatures: null,
 
   getFeatures: function bch_features(cmdLine) {
     if (this.mFeatures === null) {
       this.mFeatures = "";
 
       if (cmdLine) {
         try {
--- a/browser/components/customizableui/test/browser_909779_overflow_toolbars_new_window.js
+++ b/browser/components/customizableui/test/browser_909779_overflow_toolbars_new_window.js
@@ -6,26 +6,26 @@
 
 // Resize to a small window, open a new window, check that new window handles overflow properly
 add_task(async function() {
   let originalWindowWidth = window.outerWidth;
   let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
   ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
   let oldChildCount = CustomizableUI.getCustomizationTarget(navbar).childElementCount;
   window.resizeTo(kForceOverflowWidthPx, window.outerHeight);
-  await waitForCondition(() => navbar.hasAttribute("overflowing"));
+  await TestUtils.waitForCondition(() => navbar.hasAttribute("overflowing"));
   ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
 
   ok(CustomizableUI.getCustomizationTarget(navbar).childElementCount < oldChildCount, "Should have fewer children.");
   let newWindow = await openAndLoadWindow();
   let otherNavBar = newWindow.document.getElementById(CustomizableUI.AREA_NAVBAR);
-  await waitForCondition(() => otherNavBar.hasAttribute("overflowing"));
+  await TestUtils.waitForCondition(() => otherNavBar.hasAttribute("overflowing"));
   ok(otherNavBar.hasAttribute("overflowing"), "Other window should have an overflowing toolbar.");
   await promiseWindowClosed(newWindow);
 
   window.resizeTo(originalWindowWidth, window.outerHeight);
-  await waitForCondition(() => !navbar.hasAttribute("overflowing"));
+  await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing"));
   ok(!navbar.hasAttribute("overflowing"), "Should no longer have an overflowing toolbar.");
 });
 
 add_task(async function asyncCleanup() {
   await resetCustomization();
 });
--- a/browser/components/extensions/parent/ext-windows.js
+++ b/browser/components/extensions/parent/ext-windows.js
@@ -186,23 +186,18 @@ this.windows = class extends ExtensionAP
               for (let url of createData.url) {
                 array.appendElement(mkstr(url));
               }
               args.appendElement(array);
             } else {
               args.appendElement(mkstr(createData.url));
             }
           } else {
-            let url;
-            if (createData.incognito) {
-              url = PrivateBrowsingUtils.permanentPrivateBrowsing ?
-                HomePage.getPrivate().split("|", 1)[0] : "about:privatebrowsing";
-            } else {
-              url = HomePage.get().split("|", 1)[0];
-            }
+            let url = createData.incognito && !PrivateBrowsingUtils.permanentPrivateBrowsing ?
+              "about:privatebrowsing" : HomePage.get().split("|", 1)[0];
             args.appendElement(mkstr(url));
 
             if (url.startsWith("about:") &&
                 !context.checkLoadURL(url, {dontReportErrors: true})) {
               // The extension principal cannot directly load about:-URLs,
               // except for about:blank. So use the system principal instead.
               principal = Services.scriptSecurityManager.getSystemPrincipal();
             }
--- a/browser/components/extensions/test/browser/browser_ext_chrome_settings_overrides_home.js
+++ b/browser/components/extensions/test/browser/browser_ext_chrome_settings_overrides_home.js
@@ -466,52 +466,16 @@ add_task(async function test_overriding_
   await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
 
   is(win.gURLBar.value, "", "home page not used in private window");
 
   await extension.unload();
   await BrowserTestUtils.closeWindow(win);
 });
 
-add_task(async function test_overriding_home_page_incognito_not_allowed_bypass() {
-  await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
-
-  let extension = ExtensionTestUtils.loadExtension({
-    manifest: {
-      name: "extension",
-    },
-    background() {
-      browser.test.sendMessage("url", browser.runtime.getURL("home.html"));
-    },
-    files: {"home.html": "<h1>1</h1>"},
-    useAddonManager: "temporary",
-  });
-
-  await extension.startup();
-  let url = await extension.awaitMessage("url");
-
-  // Verify manually setting the pref to the extension page does not work.
-  let changed = promisePrefChangeObserved(HOMEPAGE_URL_PREF);
-  Services.prefs.setStringPref(HOMEPAGE_URL_PREF, url);
-  await changed;
-  let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
-  let win = OpenBrowserWindow({private: true});
-  await windowOpenedPromise;
-  win.BrowserHome();
-  await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
-
-  is(win.gURLBar.value, "", "home page not used in private window");
-  changed = promisePrefChangeObserved(HOMEPAGE_URL_PREF);
-  Services.prefs.clearUserPref(HOMEPAGE_URL_PREF);
-  await changed;
-
-  await extension.unload();
-  await BrowserTestUtils.closeWindow(win);
-});
-
 add_task(async function test_overriding_home_page_incognito_spanning() {
   await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
 
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       chrome_settings_overrides: {"homepage": "home.html"},
       name: "private extension",
       applications: {
@@ -541,8 +505,35 @@ add_task(async function test_overriding_
 
   let popupHidden = promisePopupHidden(panel);
   panel.hidePopup();
   await popupHidden;
 
   await extension.unload();
   await BrowserTestUtils.closeWindow(win);
 });
+
+add_task(async function test_overriding_home_page_incognito_external() {
+  await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      chrome_settings_overrides: {"homepage": "https://example.com/home.html"},
+      name: "extension",
+    },
+    useAddonManager: "temporary",
+  });
+
+  await extension.startup();
+
+  // Verify a private window does not open the extension page.
+  let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
+  let win = OpenBrowserWindow({private: true});
+  await windowOpenedPromise;
+  win.BrowserHome();
+  await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
+
+  is(win.gURLBar.value, "", "home page not used in private window");
+  is(gBrowser.selectedBrowser.currentURI.spec, "about:home", "home page not used in private window");
+
+  await extension.unload();
+  await BrowserTestUtils.closeWindow(win);
+});
--- a/browser/components/extensions/test/browser/browser_ext_url_overrides_newtab.js
+++ b/browser/components/extensions/test/browser/browser_ext_url_overrides_newtab.js
@@ -599,68 +599,16 @@ add_task(async function test_overriding_
   is(win.gURLBar.value, "", "directly set newtab not used in private window");
 
   aboutNewTabService.newTabURL = origUrl;
 
   await extension.unload();
   await BrowserTestUtils.closeWindow(win);
 });
 
-add_task(async function test_overriding_newtab_incognito_not_allowed_bypass() {
-  await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
-
-  let extension = ExtensionTestUtils.loadExtension({
-    manifest: {
-      name: "extension",
-      applications: {
-        gecko: {id: "@not-allowed-newtab"},
-      },
-    },
-    background() {
-      browser.test.sendMessage("url", browser.runtime.getURL("newtab.html"));
-    },
-    files: {
-      "newtab.html": `
-        <!DOCTYPE html>
-        <head>
-          <meta charset="utf-8"/></head>
-        <html>
-          <body>
-          </body>
-        </html>
-      `,
-    },
-    useAddonManager: "permanent",
-  });
-
-  await extension.startup();
-  let url = await extension.awaitMessage("url");
-
-  // Verify setting the pref directly doesn't bypass permissions.
-  let origUrl = aboutNewTabService.newTabURL;
-  aboutNewTabService.newTabURL = url;
-
-  // Verify a private window does not open the extension page.  We would
-  // get an extra notification that we don't listen for if it gets loaded.
-  let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
-  let win = OpenBrowserWindow({private: true});
-  await windowOpenedPromise;
-
-  let newTabOpened = waitForNewTab();
-  win.BrowserOpenTab();
-  await newTabOpened;
-
-  is(win.gURLBar.value, "", "directly set newtab not used in private window");
-
-  aboutNewTabService.newTabURL = origUrl;
-
-  await extension.unload();
-  await BrowserTestUtils.closeWindow(win);
-});
-
 add_task(async function test_overriding_newtab_incognito_spanning() {
   await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
 
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       chrome_url_overrides: {"newtab": "newtab.html"},
       name: "extension",
       applications: {
--- a/browser/locales/en-US/browser/aboutRestartRequired.ftl
+++ b/browser/locales/en-US/browser/aboutRestartRequired.ftl
@@ -1,11 +1,11 @@
 # 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/.
 
 restart-required-title = Restart Required
 restart-required-header = Sorry. We just need to do one small thing to keep going.
-restart-required-intro = We have just installed an update in the background. Click Restart { -brand-short-name } to finish
+restart-required-intro-brand = { -brand-short-name } has just been updated in the background. Click Restart { -brand-short-name } to finish
     applying it.
 restart-required-description = We will restore all your pages, windows and tabs afterwards, so you can be on your way quickly.
 
 restart-button-label = Restart { -brand-short-name }
--- a/browser/modules/HomePage.jsm
+++ b/browser/modules/HomePage.jsm
@@ -7,16 +7,18 @@
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["HomePage"];
 
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
                                "resource://gre/modules/PrivateBrowsingUtils.jsm");
+ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore",
+                               "resource://gre/modules/ExtensionSettingsStore.jsm");
 
 const kPrefName = "browser.startup.homepage";
 
 function getHomepagePref(useDefault) {
   let homePage;
   let prefs = Services.prefs;
   if (useDefault) {
     prefs = prefs.getDefaultBranch(null);
@@ -43,43 +45,34 @@ function getHomepagePref(useDefault) {
 
   return homePage;
 }
 
 let HomePage = {
   get(aWindow) {
     if (PrivateBrowsingUtils.permanentPrivateBrowsing ||
         (aWindow && PrivateBrowsingUtils.isWindowPrivate(aWindow))) {
-      return this.getPrivate();
+      // If an extension controls the setting and does not have private
+      // browsing permission, use the default setting.
+      let extensionInfo = ExtensionSettingsStore.getSetting("prefs", "homepage_override");
+      if (extensionInfo) {
+        let policy = WebExtensionPolicy.getByID(extensionInfo.id);
+        if (!policy || !policy.privateBrowsingAllowed) {
+          return this.getDefault();
+        }
+      }
     }
+
     return getHomepagePref();
   },
 
   getDefault() {
     return getHomepagePref(true);
   },
 
-  getPrivate() {
-    let homePages = getHomepagePref();
-    if (!homePages.includes("moz-extension")) {
-      return homePages;
-    }
-    // Verify private access and build a new list.
-    let privateHomePages = homePages.split("|").filter(page => {
-      let url = new URL(page);
-      if (url.protocol !== "moz-extension:") {
-        return true;
-      }
-      let policy = WebExtensionPolicy.getByHostname(url.hostname);
-      return policy && policy.privateBrowsingAllowed;
-    });
-    // Extensions may not be ready on startup, fallback to defaults.
-    return privateHomePages.join("|") || this.getDefault();
-  },
-
   get overridden() {
     return Services.prefs.prefHasUserValue(kPrefName);
   },
 
   set(value) {
     Services.prefs.setStringPref(kPrefName, value);
   },
 
--- a/browser/modules/SitePermissions.jsm
+++ b/browser/modules/SitePermissions.jsm
@@ -152,27 +152,29 @@ const GloballyBlockedPermissions = {
 
     // Listen to any top level navigations, once we see one clear the flag
     // and remove the listener.
     browser.addProgressListener({
       QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
                                               Ci.nsISupportsWeakReference]),
       onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
         if (aWebProgress.isTopLevel) {
-          GloballyBlockedPermissions.remove(browser, id);
+          GloballyBlockedPermissions.remove(browser, id, prePath);
           browser.removeProgressListener(this);
         }
       },
     });
   },
 
   // Removes a permission with the specified id for the specified browser.
-  remove(browser, id) {
+  remove(browser, id, prePath = null) {
     let entry = this._stateByBrowser.get(browser);
-    let prePath = browser.currentURI.prePath;
+    if (!prePath) {
+      prePath = browser.currentURI.prePath;
+    }
     if (entry && entry[prePath]) {
       delete entry[prePath][id];
     }
   },
 
   // Gets all permissions for the specified browser.
   // Note that only permissions that apply to the current URI
   // of the passed browser element will be returned.
@@ -187,16 +189,25 @@ const GloballyBlockedPermissions = {
           id,
           state: SitePermissions.BLOCK,
           scope: SitePermissions.SCOPE_GLOBAL,
         });
       }
     }
     return permissions;
   },
+
+  // Copies the globally blocked permission state of one browser
+  // into a new entry for the other browser.
+  copy(browser, newBrowser) {
+    let entry = this._stateByBrowser.get(browser);
+    if (entry) {
+      this._stateByBrowser.set(newBrowser, entry);
+    }
+  },
 };
 
 /**
  * A module to manage permanent and temporary permissions
  * by URI and browser.
  *
  * Some methods have the side effect of dispatching a "PermissionStateChange"
  * event on changes to temporary permissions, as mentioned in the respective docs.
@@ -589,16 +600,17 @@ var SitePermissions = {
    *
    * @param {Browser} browser
    *        The browser object to copy from.
    * @param {Browser} newBrowser
    *        The browser object to copy to.
    */
   copyTemporaryPermissions(browser, newBrowser) {
     TemporaryPermissions.copy(browser, newBrowser);
+    GloballyBlockedPermissions.copy(browser, newBrowser);
   },
 
   /**
    * Returns the localized label for the permission with the given ID, to be
    * used in a UI for managing permissions.
    *
    * @param {string} permissionID
    *        The permission to get the label for.
--- a/browser/modules/test/browser/browser_UsageTelemetry_content.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_content.js
@@ -79,21 +79,19 @@ add_task(async function test_context_men
   TelemetryTestUtils.assertKeyedScalar(scalars, SCALAR_CONTEXT_MENU, "search", 1);
   Assert.equal(Object.keys(scalars[SCALAR_CONTEXT_MENU]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.contextmenu", 1);
 
   // Also check events.
-  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
-  TelemetryTestUtils.assertEvents(events, [
-    ["navigation", "search", "contextmenu", null, {engine: "other-MozSearch"}],
-  ]);
+  TelemetryTestUtils.assertEvents(
+    [{object: "contextmenu", value: null, extra: {engine: "other-MozSearch"}}],
+    {category: "navigation", method: "search"});
 
   contextMenu.hidePopup();
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
   BrowserTestUtils.removeTab(tab);
 });
 
 add_task(async function test_about_newtab() {
   // Let's reset the counts.
@@ -117,16 +115,14 @@ add_task(async function test_about_newta
   TelemetryTestUtils.assertKeyedScalar(scalars, SCALAR_ABOUT_NEWTAB, "search_enter", 1);
   Assert.equal(Object.keys(scalars[SCALAR_ABOUT_NEWTAB]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.newtab", 1);
 
   // Also check events.
-  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
-  TelemetryTestUtils.assertEvents(events, [
-    ["navigation", "search", "about_newtab", "enter", {engine: "other-MozSearch"}],
-  ]);
+  TelemetryTestUtils.assertEvents(
+    [{object: "about_newtab", value: "enter", extra: {engine: "other-MozSearch"}}],
+    {category: "navigation", method: "search"});
 
   BrowserTestUtils.removeTab(tab);
 });
--- a/browser/modules/test/browser/browser_UsageTelemetry_content_aboutHome.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_content_aboutHome.js
@@ -73,16 +73,14 @@ add_task(async function test_abouthome_a
   TelemetryTestUtils.assertKeyedScalar(scalars, SCALAR_ABOUT_HOME, "search_enter", 1);
   Assert.equal(Object.keys(scalars[SCALAR_ABOUT_HOME]).length, 1,
     "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.abouthome", 1);
 
   // Also check events.
-  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
-  TelemetryTestUtils.assertEvents(events, [
-    ["navigation", "search", "about_home", "enter", {engine: "other-MozSearch"}],
-  ]);
+  TelemetryTestUtils.assertEvents(
+    [{object: "about_home", value: "enter", extra: {engine: "other-MozSearch"}}],
+    {category: "navigation", method: "search"});
 
   BrowserTestUtils.removeTab(tab);
 });
--- a/browser/modules/test/browser/browser_UsageTelemetry_searchbar.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_searchbar.js
@@ -115,21 +115,19 @@ add_task(async function test_plainQuery(
   TelemetryTestUtils.assertKeyedScalar(scalars, SCALAR_SEARCHBAR, "search_enter", 1);
   Assert.equal(Object.keys(scalars[SCALAR_SEARCHBAR]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.searchbar", 1);
 
   // Also check events.
-  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
-  TelemetryTestUtils.assertEvents(events, [
-    ["navigation", "search", "searchbar", "enter", {engine: "other-MozSearch"}],
-  ]);
+  TelemetryTestUtils.assertEvents(
+    [{object: "searchbar", value: "enter", extra: {engine: "other-MozSearch"}}],
+    {category: "navigation", method: "search"});
 
   // Check the histograms as well.
   let resultMethods = resultMethodHist.snapshot();
   checkHistogramResults(resultMethods,
     URLBAR_SELECTED_RESULT_METHODS.enter,
     "FX_SEARCHBAR_SELECTED_RESULT_METHOD");
 
   BrowserTestUtils.removeTab(tab);
@@ -162,21 +160,19 @@ add_task(async function test_oneOff_ente
   TelemetryTestUtils.assertKeyedScalar(scalars, SCALAR_SEARCHBAR, "search_oneoff", 1);
   Assert.equal(Object.keys(scalars[SCALAR_SEARCHBAR]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch2.searchbar", 1);
 
   // Also check events.
-  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
-  TelemetryTestUtils.assertEvents(events, [
-    ["navigation", "search", "searchbar", "oneoff", {engine: "other-MozSearch2"}],
-  ]);
+  TelemetryTestUtils.assertEvents(
+    [{object: "searchbar", value: "oneoff", extra: {engine: "other-MozSearch2"}}],
+    {category: "navigation", method: "search"});
 
   // Check the histograms as well.
   let resultMethods = resultMethodHist.snapshot();
   checkHistogramResults(resultMethods,
     URLBAR_SELECTED_RESULT_METHODS.enter,
     "FX_SEARCHBAR_SELECTED_RESULT_METHOD");
 
   BrowserTestUtils.removeTab(tab);
@@ -278,21 +274,19 @@ add_task(async function test_suggestion_
   Assert.equal(Object.keys(scalars[SCALAR_SEARCHBAR]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   let searchEngineId = "other-" + suggestionEngine.name;
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, searchEngineId + ".searchbar", 1);
 
   // Also check events.
-  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
-  TelemetryTestUtils.assertEvents(events, [
-    ["navigation", "search", "searchbar", "suggestion", {engine: searchEngineId}],
-  ]);
+  TelemetryTestUtils.assertEvents(
+    [{object: "searchbar", value: "suggestion", extra: {engine: searchEngineId}}],
+    {category: "navigation", method: "search"});
 
   // Check the histograms as well.
   let resultMethods = resultMethodHist.snapshot();
   checkHistogramResults(resultMethods,
     URLBAR_SELECTED_RESULT_METHODS.click,
     "FX_SEARCHBAR_SELECTED_RESULT_METHOD");
 
   await Services.search.setDefault(previousEngine);
--- a/browser/modules/test/browser/browser_UsageTelemetry_urlbar.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_urlbar.js
@@ -149,19 +149,19 @@ add_task(async function test_simpleQuery
   Assert.equal(Object.keys(scalars[SCALAR_URLBAR]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.urlbar", 1);
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.alias", undefined);
 
   // Also check events.
-  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
-  TelemetryTestUtils.assertEvents(events, [["navigation", "search", "urlbar", "enter", {engine: "other-MozSearch"}]]);
+  TelemetryTestUtils.assertEvents(
+    [["navigation", "search", "urlbar", "enter", {engine: "other-MozSearch"}]],
+    {category: "navigation", method: "search"});
 
   // Check the histograms as well.
   TelemetryTestUtils.assertHistogram(resultIndexHist, 0, 1);
 
   TelemetryTestUtils.assertHistogram(resultTypeHist,
     URLBAR_SELECTED_RESULT_TYPES.searchengine, 1);
 
   TelemetryTestUtils.assertKeyedHistogramValue(resultIndexByTypeHist,
@@ -197,19 +197,19 @@ add_task(async function test_searchAlias
   Assert.equal(Object.keys(scalars[SCALAR_URLBAR]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.urlbar", 1);
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.alias", undefined);
 
   // Also check events.
-  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
-  TelemetryTestUtils.assertEvents(events, [["navigation", "search", "urlbar", "alias", {engine: "other-MozSearch"}]]);
+  TelemetryTestUtils.assertEvents(
+    [["navigation", "search", "urlbar", "alias", {engine: "other-MozSearch"}]],
+    {category: "navigation", method: "search"});
 
   // Check the histograms as well.
   TelemetryTestUtils.assertHistogram(resultIndexHist, 0, 1);
 
   TelemetryTestUtils.assertHistogram(resultTypeHist,
     URLBAR_SELECTED_RESULT_TYPES.searchengine, 1);
 
   TelemetryTestUtils.assertKeyedHistogramValue(resultIndexByTypeHist,
@@ -276,19 +276,19 @@ add_task(async function test_oneOff_ente
   Assert.equal(Object.keys(scalars[SCALAR_URLBAR]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.urlbar", 1);
   TelemetryTestUtils.assertKeyedHistogramSum(search_hist, "other-MozSearch.alias", undefined);
 
   // Also check events.
-  let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
-  TelemetryTestUtils.assertEvents(events, [["navigation", "search", "urlbar", "oneoff", {engine: "other-MozSearch"}]]);
+  TelemetryTestUtils.assertEvents(
+    [["navigation", "search", "urlbar", "oneoff", {engine: "other-MozSearch"}]],
+    {category: "navigation", method: "search"});
 
   // Check the histograms as well.
   TelemetryTestUtils.assertHistogram(resultIndexHist, 0, 1);
 
   TelemetryTestUtils.assertHistogram(resultTypeHist,
     URLBAR_SELECTED_RESULT_TYPES.searchengine, 1);
 
   TelemetryTestUtils.assertKeyedHistogramValue(resultIndexByTypeHist,
@@ -377,19 +377,19 @@ add_task(async function test_suggestion_
     Assert.equal(Object.keys(scalars[SCALAR_URLBAR]).length, 1,
                 "This search must only increment one entry in the scalar.");
 
     // Make sure SEARCH_COUNTS contains identical values.
     let searchEngineId = "other-" + engine.name;
     TelemetryTestUtils.assertKeyedHistogramSum(search_hist, searchEngineId + ".urlbar", 1);
 
     // Also check events.
-    let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-    events = (events.parent || []).filter(e => e[1] == "navigation" && e[2] == "search");
-    TelemetryTestUtils.assertEvents(events, [["navigation", "search", "urlbar", "suggestion", {engine: searchEngineId}]]);
+    TelemetryTestUtils.assertEvents(
+      [["navigation", "search", "urlbar", "suggestion", {engine: searchEngineId}]],
+      {category: "navigation", method: "search"});
 
     // Check the histograms as well.
     TelemetryTestUtils.assertHistogram(resultIndexHist, 3, 1);
 
     TelemetryTestUtils.assertHistogram(resultTypeHist,
       URLBAR_SELECTED_RESULT_TYPES.searchsuggestion, 1);
 
     TelemetryTestUtils.assertKeyedHistogramValue(resultIndexByTypeHist,
--- a/caps/nsJSPrincipals.cpp
+++ b/caps/nsJSPrincipals.cpp
@@ -242,18 +242,19 @@ static bool ReadPrincipalInfo(JSStructur
 #ifdef FUZZING
     if (originNoSuffix.IsEmpty()) {
       return false;
     }
 #endif
 
     MOZ_DIAGNOSTIC_ASSERT(!originNoSuffix.IsEmpty());
 
-    aInfo =
-        ContentPrincipalInfo(attrs, originNoSuffix, spec, std::move(policies));
+    // XXX: Do we care about mDomain for structured clone?
+    aInfo = ContentPrincipalInfo(attrs, originNoSuffix, spec, Nothing(),
+                                 std::move(policies));
   } else {
 #ifdef FUZZING
     return false;
 #else
     MOZ_CRASH("unexpected principal structured clone tag");
 #endif
   }
 
--- a/devtools/client/framework/test/browser_toolbox_telemetry_close.js
+++ b/devtools/client/framework/test/browser_toolbox_telemetry_close.js
@@ -1,50 +1,47 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const { Toolbox } = require("devtools/client/framework/toolbox");
+const { TelemetryTestUtils } = ChromeUtils.import("resource://testing-common/TelemetryTestUtils.jsm");
 
 const URL = "data:text/html;charset=utf8,browser_toolbox_telemetry_close.js";
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
 const { RIGHT, BOTTOM } = Toolbox.HostType;
 const DATA = [
   {
-    timestamp: null,
     category: "devtools.main",
     method: "close",
     object: "tools",
     value: null,
     extra: {
       host: "right",
-      width: "1440",
+      width: w => w > 0,
     },
   },
   {
-    timestamp: null,
     category: "devtools.main",
     method: "close",
     object: "tools",
     value: null,
     extra: {
       host: "bottom",
-      width: "1440",
+      width: w => w > 0,
     },
   },
 ];
 
 add_task(async function() {
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
-  ok(!snapshot.parent, "No events have been logged for the main process");
+  TelemetryTestUtils.assertNumberOfEvents(0);
 
   await openAndCloseToolbox("webconsole", RIGHT);
   await openAndCloseToolbox("webconsole", BOTTOM);
 
   checkResults();
 });
 
 async function openAndCloseToolbox(toolId, host) {
@@ -52,30 +49,10 @@ async function openAndCloseToolbox(toolI
   const target = await TargetFactory.forTab(tab);
   const toolbox = await gDevTools.showToolbox(target, toolId);
 
   await toolbox.switchHost(host);
   await toolbox.destroy();
 }
 
 function checkResults() {
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
-  const events = snapshot.parent.filter(event => event[1] === "devtools.main" &&
-                                                 event[2] === "close" &&
-                                                 event[3] === "tools" &&
-                                                 event[4] === null
-  );
-
-  for (const i in DATA) {
-    const [ timestamp, category, method, object, value, extra ] = events[i];
-    const expected = DATA[i];
-
-    // ignore timestamp
-    ok(timestamp > 0, "timestamp is greater than 0");
-    is(category, expected.category, "category is correct");
-    is(method, expected.method, "method is correct");
-    is(object, expected.object, "object is correct");
-    is(value, expected.value, "value is correct");
-
-    is(extra.host, expected.extra.host, "host is correct");
-    ok(extra.width > 0, "width is greater than 0");
-  }
+  TelemetryTestUtils.assertEvents(DATA, {category: "devtools.main", method: "close", object: "tools"});
 }
--- a/devtools/client/inspector/boxmodel/test/browser_boxmodel_jump-to-rule-on-hover.js
+++ b/devtools/client/inspector/boxmodel/test/browser_boxmodel_jump-to-rule-on-hover.js
@@ -11,16 +11,17 @@ const TEST_URI =
   `<style>
     #box {
       margin: 5px;
     }
   </style>
   <div id="box"></div>`;
 
 add_task(async function() {
+  await pushPref("devtools.layout.boxmodel.highlightProperty", true);
   await addTab("data:text/html," + encodeURIComponent(TEST_URI));
   const { inspector, boxmodel } = await openLayoutView();
   await selectNode("#box", inspector);
 
   info("Test that hovering over margin-top value highlights the property in rules view.");
   const ruleView = await inspector.getPanel("ruleview").view;
   const el = boxmodel.document.querySelector(".boxmodel-margin.boxmodel-top > span");
 
--- a/devtools/client/inspector/boxmodel/test/browser_boxmodel_show-tooltip-for-unassociated-rule.js
+++ b/devtools/client/inspector/boxmodel/test/browser_boxmodel_show-tooltip-for-unassociated-rule.js
@@ -11,16 +11,17 @@ const L10N = new LocalizationHelper("dev
 
 const TEST_URI =
   `<style>
     #box {}
   </style>
   <div id="box"></div>`;
 
 add_task(async function() {
+  await pushPref("devtools.layout.boxmodel.highlightProperty", true);
   await addTab("data:text/html," + encodeURIComponent(TEST_URI));
   const { inspector, boxmodel } = await openLayoutView();
   const { rulePreviewTooltip } = boxmodel;
   await selectNode("#box", inspector);
 
   info("Test that hovering over margin-top shows tooltip showing 'No associated rule'.");
   const el = boxmodel.document.querySelector(".boxmodel-margin.boxmodel-top > span");
 
--- a/devtools/client/inspector/changes/ChangesContextMenu.js
+++ b/devtools/client/inspector/changes/ChangesContextMenu.js
@@ -23,16 +23,17 @@ class ChangesContextMenu {
     this.inspector = this.view.inspector;
     // Document object to which the Changes panel belongs to.
     this.document = this.view.document;
     // DOM element container for the Changes panel content.
     this.panel = this.document.getElementById("sidebar-panel-changes");
     // Window object to which the Changes panel belongs to.
     this.window = this.document.defaultView;
 
+    this._onCopyDeclaration = this.view.copyDeclaration.bind(this.view);
     this._onCopyRule = this.view.copyRule.bind(this.view);
     this._onCopySelection = this.view.copySelection.bind(this.view);
     this._onSelectAll = this._onSelectAll.bind(this);
   }
 
   show(event) {
     this._openMenu({
       target: event.target,
@@ -50,26 +51,34 @@ class ChangesContextMenu {
     const menuitemCopy = new MenuItem({
       label: getStr("changes.contextmenu.copy"),
       accesskey: getStr("changes.contextmenu.copy.accessKey"),
       click: this._onCopySelection,
       disabled: !this._hasTextSelected(),
     });
     menu.append(menuitemCopy);
 
+    const declEl = target.closest(".changes__declaration");
     const ruleEl = target.closest("[data-rule-id]");
     const ruleId = ruleEl ? ruleEl.dataset.ruleId : null;
 
-    if (ruleId) {
+    if (ruleId || declEl) {
       // Copy Rule option
       menu.append(new MenuItem({
         label: getStr("changes.contextmenu.copyRule"),
         click: () => this._onCopyRule(ruleId),
       }));
 
+      // Copy Declaration option. Visible only if there is a declaration element target.
+      menu.append(new MenuItem({
+        label: getStr("changes.contextmenu.copyDeclaration"),
+        click: () => this._onCopyDeclaration(declEl),
+        visible: !!declEl,
+      }));
+
       menu.append(new MenuItem({
         type: "separator",
       }));
     }
 
     // Select All option
     const menuitemSelectAll = new MenuItem({
       label: getStr("changes.contextmenu.selectAll"),
--- a/devtools/client/inspector/changes/ChangesView.js
+++ b/devtools/client/inspector/changes/ChangesView.js
@@ -142,16 +142,32 @@ class ChangesView {
       filter.sourceIds = [sourceId];
     }
 
     const text = getChangesStylesheet(state, filter);
     clipboardHelper.copyString(text);
   }
 
   /**
+   * Handler for the "Copy Declaration" option from the context menu.
+   * Builds a CSS declaration string with the property name and value, and copies it
+   * to the clipboard. The declaration is commented out if it is marked as removed.
+   *
+   * @param {DOMElement} element
+   *        Host element of a CSS declaration rendered the Changes panel.
+   */
+  copyDeclaration(element) {
+    const name = element.querySelector(".changes__declaration-name").textContent;
+    const value = element.querySelector(".changes__declaration-value").textContent;
+    const isRemoved = element.classList.contains("diff-remove");
+    const text = isRemoved ? `/* ${name}: ${value}; */` : `${name}: ${value};`;
+    clipboardHelper.copyString(text);
+  }
+
+  /**
    * Handler for the "Copy Rule" option from the context menu.
    * Gets the full content of the target CSS rule (including any changes applied)
    * and copies it to the clipboard.
    *
    * @param {String} ruleId
    *        Rule id of the target CSS rule.
    */
   async copyRule(ruleId) {
--- a/devtools/client/inspector/changes/components/CSSDeclaration.js
+++ b/devtools/client/inspector/changes/components/CSSDeclaration.js
@@ -23,19 +23,19 @@ class CSSDeclaration extends PureCompone
       className: "",
       marker: null,
     };
   }
 
   render() {
     const { className, marker, property, value } = this.props;
 
-    return dom.div({ className: `declaration ${className}` },
+    return dom.div({ className: `changes__declaration ${className}` },
       marker,
-      dom.span({ className: "declaration-name theme-fg-color3"}, property),
+      dom.span({ className: "changes__declaration-name theme-fg-color3"}, property),
       ": ",
-      dom.span({ className: "declaration-value theme-fg-color1"}, value),
+      dom.span({ className: "changes__declaration-value theme-fg-color1"}, value),
       ";"
     );
   }
 }
 
 module.exports = CSSDeclaration;
--- a/devtools/client/inspector/changes/test/head.js
+++ b/devtools/client/inspector/changes/test/head.js
@@ -39,26 +39,26 @@ registerCleanupFunction(() => {
  *         If omitted, all declarations will be returned.
  * @param  {DOMNode} containerNode
  *         Optional element to restrict results to declaration DOM elements which are
  *         descendants of this container node.
  *         If omitted, all declarations will be returned
  * @return {Array}
  */
 function getDeclarations(panelDoc, selector = "", containerNode = null) {
-  const els = panelDoc.querySelectorAll(`#sidebar-panel-changes .declaration${selector}`);
+  const els = panelDoc.querySelectorAll(`.changes__declaration${selector}`);
 
   return [...els]
     .filter(el => {
       return containerNode ? containerNode.contains(el) : true;
     })
     .map(el => {
       return {
-        property: el.querySelector(".declaration-name").textContent,
-        value: el.querySelector(".declaration-value").textContent,
+        property: el.querySelector(".changes__declaration-name").textContent,
+        value: el.querySelector(".changes__declaration-value").textContent,
       };
     });
 }
 
 function getAddedDeclarations(panelDoc, containerNode) {
   return getDeclarations(panelDoc, ".diff-add", containerNode);
 }
 
--- a/devtools/client/inspector/rules/test/browser_rules_copy_styles.js
+++ b/devtools/client/inspector/rules/test/browser_rules_copy_styles.js
@@ -23,73 +23,73 @@ add_task(async function() {
   const data = [
     {
       desc: "Test Copy Property Name",
       node: ruleEditor.rule.textProps[0].editor.nameSpan,
       menuItemLabel: "styleinspector.contextmenu.copyPropertyName",
       expectedPattern: "color",
       visible: {
         copyLocation: false,
-        copyPropertyDeclaration: true,
+        copyDeclaration: true,
         copyPropertyName: true,
         copyPropertyValue: false,
         copySelector: false,
         copyRule: true,
       },
     },
     {
       desc: "Test Copy Property Value",
       node: ruleEditor.rule.textProps[2].editor.valueSpan,
       menuItemLabel: "styleinspector.contextmenu.copyPropertyValue",
       expectedPattern: "12px",
       visible: {
         copyLocation: false,
-        copyPropertyDeclaration: true,
+        copyDeclaration: true,
         copyPropertyName: false,
         copyPropertyValue: true,
         copySelector: false,
         copyRule: true,
       },
     },
     {
       desc: "Test Copy Property Value with Priority",
       node: ruleEditor.rule.textProps[3].editor.valueSpan,
       menuItemLabel: "styleinspector.contextmenu.copyPropertyValue",
       expectedPattern: "#00F !important",
       visible: {
         copyLocation: false,
-        copyPropertyDeclaration: true,
+        copyDeclaration: true,
         copyPropertyName: false,
         copyPropertyValue: true,
         copySelector: false,
         copyRule: true,
       },
     },
     {
       desc: "Test Copy Property Declaration",
       node: ruleEditor.rule.textProps[2].editor.nameSpan,
-      menuItemLabel: "styleinspector.contextmenu.copyPropertyDeclaration",
+      menuItemLabel: "styleinspector.contextmenu.copyDeclaration",
       expectedPattern: "font-size: 12px;",
       visible: {
         copyLocation: false,
-        copyPropertyDeclaration: true,
+        copyDeclaration: true,
         copyPropertyName: true,
         copyPropertyValue: false,
         copySelector: false,
         copyRule: true,
       },
     },
     {
       desc: "Test Copy Property Declaration with Priority",
       node: ruleEditor.rule.textProps[3].editor.nameSpan,
-      menuItemLabel: "styleinspector.contextmenu.copyPropertyDeclaration",
+      menuItemLabel: "styleinspector.contextmenu.copyDeclaration",
       expectedPattern: "border-color: #00F !important;",
       visible: {
         copyLocation: false,
-        copyPropertyDeclaration: true,
+        copyDeclaration: true,
         copyPropertyName: true,
         copyPropertyValue: false,
         copySelector: false,
         copyRule: true,
       },
     },
     {
       desc: "Test Copy Rule",
@@ -99,46 +99,46 @@ add_task(async function() {
                        "\tcolor: #F00;[\\r\\n]+" +
                        "\tbackground-color: #00F;[\\r\\n]+" +
                        "\tfont-size: 12px;[\\r\\n]+" +
                        "\tborder-color: #00F !important;[\\r\\n]+" +
                        "\t--var: \"\\*/\";[\\r\\n]+" +
                        "}",
       visible: {
         copyLocation: false,
-        copyPropertyDeclaration: true,
+        copyDeclaration: true,
         copyPropertyName: true,
         copyPropertyValue: false,
         copySelector: false,
         copyRule: true,
       },
     },
     {
       desc: "Test Copy Selector",
       node: ruleEditor.selectorText,
       menuItemLabel: "styleinspector.contextmenu.copySelector",
       expectedPattern: "html, body, #testid",
       visible: {
         copyLocation: false,
-        copyPropertyDeclaration: false,
+        copyDeclaration: false,
         copyPropertyName: false,
         copyPropertyValue: false,
         copySelector: true,
         copyRule: true,
       },
     },
     {
       desc: "Test Copy Location",
       node: ruleEditor.source,
       menuItemLabel: "styleinspector.contextmenu.copyLocation",
       expectedPattern: "http://example.com/browser/devtools/client/" +
                        "inspector/rules/test/doc_copystyles.css",
       visible: {
         copyLocation: true,
-        copyPropertyDeclaration: false,
+        copyDeclaration: false,
         copyPropertyName: false,
         copyPropertyValue: false,
         copySelector: false,
         copyRule: true,
       },
     },
     {
       setup: async function() {
@@ -151,17 +151,17 @@ add_task(async function() {
                        "\t\/\\* color: #F00; \\*\/[\\r\\n]+" +
                        "\tbackground-color: #00F;[\\r\\n]+" +
                        "\tfont-size: 12px;[\\r\\n]+" +
                        "\tborder-color: #00F !important;[\\r\\n]+" +
                        "\t--var: \"\\*/\";[\\r\\n]+" +
                        "}",
       visible: {
         copyLocation: false,
-        copyPropertyDeclaration: true,
+        copyDeclaration: true,
         copyPropertyName: true,
         copyPropertyValue: false,
         copySelector: false,
         copyRule: true,
       },
     },
     {
       setup: async function() {
@@ -174,31 +174,31 @@ add_task(async function() {
                        "\t\/\\* color: #F00; \\*\/[\\r\\n]+" +
                        "\tbackground-color: #00F;[\\r\\n]+" +
                        "\tfont-size: 12px;[\\r\\n]+" +
                        "\tborder-color: #00F !important;[\\r\\n]+" +
                        "\t/\\* --var: \"\\*\\\\\/\"; \\*\/[\\r\\n]+" +
                        "}",
       visible: {
         copyLocation: false,
-        copyPropertyDeclaration: true,
+        copyDeclaration: true,
         copyPropertyName: true,
         copyPropertyValue: false,
         copySelector: false,
         copyRule: true,
       },
     },
     {
       desc: "Test Copy Property Declaration with Disabled Property",
       node: ruleEditor.rule.textProps[0].editor.nameSpan,
-      menuItemLabel: "styleinspector.contextmenu.copyPropertyDeclaration",
+      menuItemLabel: "styleinspector.contextmenu.copyDeclaration",
       expectedPattern: "\/\\* color: #F00; \\*\/",
       visible: {
         copyLocation: false,
-        copyPropertyDeclaration: true,
+        copyDeclaration: true,
         copyPropertyName: true,
         copyPropertyValue: false,
         copySelector: false,
         copyRule: true,
       },
     },
   ];
 
@@ -215,18 +215,18 @@ add_task(async function() {
 async function checkCopyStyle(view, node, menuItemLabel, expectedPattern, visible) {
   const allMenuItems = openStyleContextMenuAndGetAllItems(view, node);
   const menuItem = allMenuItems.find(item =>
     item.label === STYLE_INSPECTOR_L10N.getStr(menuItemLabel));
   const menuitemCopy = allMenuItems.find(item => item.label ===
     STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copy"));
   const menuitemCopyLocation = allMenuItems.find(item => item.label ===
     STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyLocation"));
-  const menuitemCopyPropertyDeclaration = allMenuItems.find(item => item.label ===
-    STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyPropertyDeclaration"));
+  const menuitemCopyDeclaration = allMenuItems.find(item => item.label ===
+    STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyDeclaration"));
   const menuitemCopyPropertyName = allMenuItems.find(item => item.label ===
     STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyPropertyName"));
   const menuitemCopyPropertyValue = allMenuItems.find(item => item.label ===
     STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyPropertyValue"));
   const menuitemCopySelector = allMenuItems.find(item => item.label ===
     STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copySelector"));
   const menuitemCopyRule = allMenuItems.find(item => item.label ===
     STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyRule"));
@@ -236,20 +236,20 @@ async function checkCopyStyle(view, node
   ok(menuitemCopy.visible,
     "Copy visible is as expected: true");
 
   is(menuitemCopyLocation.visible,
      visible.copyLocation,
      "Copy Location visible attribute is as expected: " +
      visible.copyLocation);
 
-  is(menuitemCopyPropertyDeclaration.visible,
-     visible.copyPropertyDeclaration,
+  is(menuitemCopyDeclaration.visible,
+     visible.copyDeclaration,
      "Copy Property Declaration visible attribute is as expected: " +
-     visible.copyPropertyDeclaration);
+     visible.copyDeclaration);
 
   is(menuitemCopyPropertyName.visible,
      visible.copyPropertyName,
      "Copy Property Name visible attribute is as expected: " +
      visible.copyPropertyName);
 
   is(menuitemCopyPropertyValue.visible,
      visible.copyPropertyValue,
--- a/devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js
+++ b/devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js
@@ -53,16 +53,20 @@ const TEST_DATA = [
   {
     selector: "a",
     numUserRules: 3,
     numUARules: 0,
   },
 ];
 
 add_task(async function() {
+  // Bug 1517210: GC heuristics are broken for this test, so that the test ends up
+  // running out of memory if we don't force to reduce the GC side before/after the test.
+  Cu.forceShrinkingGC();
+
   requestLongerTimeout(4);
 
   info("Starting the test with the pref set to true before toolbox is opened");
   await setUserAgentStylesPref(true);
 
   await addTab(TEST_URI);
   const {inspector, view} = await openRuleView();
 
@@ -74,16 +78,20 @@ add_task(async function() {
   await userAgentStylesNotVisible(inspector, view);
 
   info("Making sure that resetting the pref to true shows UA styles again");
   await setUserAgentStylesPref(true);
   await userAgentStylesVisible(inspector, view);
 
   info("Resetting " + PREF_UA_STYLES);
   Services.prefs.clearUserPref(PREF_UA_STYLES);
+
+  // Bug 1517210: GC heuristics are broken for this test, so that the test ends up
+  // running out of memory if we don't force to reduce the GC side before/after the test.
+  Cu.forceShrinkingGC();
 });
 
 async function setUserAgentStylesPref(val) {
   info("Setting the pref " + PREF_UA_STYLES + " to: " + val);
 
   // Reset the pref and wait for PrefObserver to callback so UI
   // has a chance to get updated.
   const prefObserver = new PrefObserver("devtools.");
--- a/devtools/client/inspector/shared/style-inspector-menu.js
+++ b/devtools/client/inspector/shared/style-inspector-menu.js
@@ -41,17 +41,17 @@ function StyleInspectorMenu(view, option
 
   this.isRuleView = options.isRuleView;
 
   this._onAddNewRule = this._onAddNewRule.bind(this);
   this._onCopy = this._onCopy.bind(this);
   this._onCopyColor = this._onCopyColor.bind(this);
   this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
   this._onCopyLocation = this._onCopyLocation.bind(this);
-  this._onCopyPropertyDeclaration = this._onCopyPropertyDeclaration.bind(this);
+  this._onCopyDeclaration = this._onCopyDeclaration.bind(this);
   this._onCopyPropertyName = this._onCopyPropertyName.bind(this);
   this._onCopyPropertyValue = this._onCopyPropertyValue.bind(this);
   this._onCopyRule = this._onCopyRule.bind(this);
   this._onCopySelector = this._onCopySelector.bind(this);
   this._onCopyUrl = this._onCopyUrl.bind(this);
   this._onSelectAll = this._onSelectAll.bind(this);
   this._onToggleOrigSources = this._onToggleOrigSources.bind(this);
 }
@@ -126,21 +126,21 @@ StyleInspectorMenu.prototype = {
     const menuitemCopyImageDataUrl = new MenuItem({
       label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyImageDataUrl"),
       accesskey: STYLE_INSPECTOR_L10N.getStr(copyImageAccessKey),
       click: () => {
         this._onCopyImageDataUrl();
       },
       visible: this._isImageUrl(),
     });
-    const copyPropDeclarationLabel = "styleinspector.contextmenu.copyPropertyDeclaration";
-    const menuitemCopyPropertyDeclaration = new MenuItem({
-      label: STYLE_INSPECTOR_L10N.getStr(copyPropDeclarationLabel),
+    const copyDeclarationLabel = "styleinspector.contextmenu.copyDeclaration";
+    const menuitemCopyDeclaration = new MenuItem({
+      label: STYLE_INSPECTOR_L10N.getStr(copyDeclarationLabel),
       click: () => {
-        this._onCopyPropertyDeclaration();
+        this._onCopyDeclaration();
       },
       visible: false,
     });
     const menuitemCopyPropertyName = new MenuItem({
       label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyPropertyName"),
       click: () => {
         this._onCopyPropertyName();
       },
@@ -160,21 +160,21 @@ StyleInspectorMenu.prototype = {
       },
       visible: false,
     });
 
     this._clickedNodeInfo = this._getClickedNodeInfo();
     if (this.isRuleView && this._clickedNodeInfo) {
       switch (this._clickedNodeInfo.type) {
         case VIEW_NODE_PROPERTY_TYPE :
-          menuitemCopyPropertyDeclaration.visible = true;
+          menuitemCopyDeclaration.visible = true;
           menuitemCopyPropertyName.visible = true;
           break;
         case VIEW_NODE_VALUE_TYPE :
-          menuitemCopyPropertyDeclaration.visible = true;
+          menuitemCopyDeclaration.visible = true;
           menuitemCopyPropertyValue.visible = true;
           break;
         case VIEW_NODE_SELECTOR_TYPE :
           menuitemCopySelector.visible = true;
           break;
         case VIEW_NODE_LOCATION_TYPE :
           menuitemCopyLocation.visible = true;
           break;
@@ -182,17 +182,17 @@ StyleInspectorMenu.prototype = {
     }
 
     menu.append(menuitemCopy);
     menu.append(menuitemCopyLocation);
     menu.append(menuitemCopyRule);
     menu.append(menuitemCopyColor);
     menu.append(menuitemCopyUrl);
     menu.append(menuitemCopyImageDataUrl);
-    menu.append(menuitemCopyPropertyDeclaration);
+    menu.append(menuitemCopyDeclaration);
     menu.append(menuitemCopyPropertyName);
     menu.append(menuitemCopyPropertyValue);
     menu.append(menuitemCopySelector);
 
     menu.append(new MenuItem({
       type: "separator",
     }));
 
@@ -404,19 +404,19 @@ StyleInspectorMenu.prototype = {
     if (!this._clickedNodeInfo) {
       return;
     }
 
     clipboardHelper.copyString(this._clickedNodeInfo.value);
   },
 
   /**
-   * Copy the rule property declaration of the current clicked node.
+   * Copy the CSS declaration of the current clicked node.
    */
-  _onCopyPropertyDeclaration: function() {
+  _onCopyDeclaration: function() {
     if (!this._clickedNodeInfo) {
       return;
     }
 
     const textProp = this._clickedNodeInfo.value.textProperty;
     clipboardHelper.copyString(textProp.stringifyProperty());
   },
 
--- a/devtools/client/locales/en-US/changes.properties
+++ b/devtools/client/locales/en-US/changes.properties
@@ -38,16 +38,20 @@ changes.contextmenu.copy.accessKey=C
 # stylesheet
 changes.contextmenu.copyAllChanges=Copy All Changes
 
 # LOCALIZATION NOTE (changes.contextmenu.copyAllChangesDescription): Detailed explanation
 # for "Copy All Changes" option in Changes panel. Used as title attribute on "Copy All
 # Changes" button
 changes.contextmenu.copyAllChangesDescription=Copy a list of all CSS changes to clipboard.
 
+# LOCALIZATION NOTE (changes.contextmenu.copyDeclaration): Label for "Copy Declaration"
+# option in Changes panel context menu which copies the target CSS declaration.
+changes.contextmenu.copyDeclaration=Copy Declaration
+
 # LOCALIZATION NOTE (changes.contextmenu.copyRule): Label for "Copy Rule" option in
 # Changes panel context menu which copies the complete contents of a CSS rule.
 changes.contextmenu.copyRule=Copy Rule
 
 # LOCALIZATION NOTE (changes.contextmenu.copyRuleDescription): Detailed explanation for
 # "Copy Rule" option in Changes panel. Used as title attribute on "Copy Rule" button.
 changes.contextmenu.copyRuleDescription=Copy contents of this CSS rule to clipboard.
 
--- a/devtools/client/themes/changes.css
+++ b/devtools/client/themes/changes.css
@@ -152,17 +152,17 @@
 
 /* Show the Copy Rule button when hovering over the rule's selector elements */
 .changes__selector:hover + .changes__copy-rule-button,
 .changes__selector:hover + .changes__selector + .changes__copy-rule-button,
 .changes__copy-rule-button:hover {
   display: block;
 }
 
-#sidebar-panel-changes .declaration-name {
+.changes__declaration-name {
   margin-left: 10px;
 }
 
 .diff-add,
 .diff-remove {
   --diff-level-min-offset: 15px;
   position: relative;
 }
--- a/devtools/docs/frontend/telemetry.md
+++ b/devtools/docs/frontend/telemetry.md
@@ -333,52 +333,49 @@ This is best shown via an example:
 
 ```js
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const { Toolbox } = require("devtools/client/framework/toolbox");
+const { TelemetryTestUtils } = ChromeUtils.import("resource://testing-common/TelemetryTestUtils.jsm");
 
 const URL = "data:text/html;charset=utf8,browser_toolbox_telemetry_close.js";
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
-const { SIDE, BOTTOM } = Toolbox.HostType;
-const TELEMETRY_DATA = [
+const { RIGHT, BOTTOM } = Toolbox.HostType;
+const DATA = [
   {
-    timestamp: null,
     category: "devtools.main",
     method: "close",
     object: "tools",
     value: null,
     extra: {
       host: "right",
-      width: "1440"
+      width: w => w > 0,
     }
   },
   {
-    timestamp: null,
     category: "devtools.main",
     method: "close",
     object: "tools",
     value: null,
     extra: {
       host: "bottom",
-      width: "1440"
+      width: w => w > 0,
     }
   }
 ];
 
 add_task(async function() {
   // Let's reset the counts.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
-  ok(!snapshot.parent, "No events have been logged for the main process");
+  TelemetryTestUtils.assertNumberOfEvents(0);
 
   await openAndCloseToolbox("webconsole", SIDE);
   await openAndCloseToolbox("webconsole", BOTTOM);
 
   checkResults();
 });
 
 async function openAndCloseToolbox(toolId, host) {
@@ -386,37 +383,17 @@ async function openAndCloseToolbox(toolI
   const target = await TargetFactory.forTab(tab);
   const toolbox = await gDevTools.showToolbox(target, toolId);
 
   await toolbox.switchHost(host);
   await toolbox.destroy();
 }
 
 function checkResults() {
-  const snapshot = Services.telemetry.snapshotEvents(OPTOUT, true);
-  const events = snapshot.parent.filter(event => event[1] === "devtools.main" &&
-                                                 event[2] === "close" &&
-                                                 event[3] === "tools" &&
-                                                 event[4] === null
-  );
-
-  for (const i in TELEMETRY_DATA) {
-    const [ timestamp, category, method, object, value, extra ] = events[i];
-    const expected = TELEMETRY_DATA[i];
-
-    // ignore timestamp
-    ok(timestamp > 0, "timestamp is greater than 0");
-    is(category, expected.category, "category is correct");
-    is(method, expected.method, "method is correct");
-    is(object, expected.object, "object is correct");
-    is(value, expected.value, "value is correct");
-
-    is(extra.host, expected.extra.host, "host is correct");
-    ok(extra.width > 0, "width is greater than 0");
-  }
+  TelemetryTestUtils.assertEvents(DATA, {category: "devtools.main", method: "close", object: "tools"});
 }
 ```
 
 #### Compile it
 
 You need to do a full Firefox build if you have edited either `Histograms.json` or `Events.yaml`, as they are processed at build time, and various checks will be run on them to guarantee they are valid.
 
 ```bash
--- a/devtools/shared/base-loader.js
+++ b/devtools/shared/base-loader.js
@@ -97,19 +97,16 @@ function Sandbox(options) {
   options = {
     // Do not expose `Components` if you really need them (bad idea!) you
     // still can expose via prototype.
     wantComponents: false,
     sandboxName: options.name,
     sandboxPrototype: "prototype" in options ? options.prototype : {},
     invisibleToDebugger: "invisibleToDebugger" in options ?
                          options.invisibleToDebugger : false,
-    // For now create the sandbox in a new compartment. This is temporary until
-    // bug 1515290 fixes some devtools tests to not rely on this.
-    freshCompartment: true,
   };
 
   const sandbox = Cu.Sandbox(systemPrincipal, options);
 
   delete sandbox.Components;
 
   return sandbox;
 }
--- a/devtools/shared/locales/en-US/styleinspector.properties
+++ b/devtools/shared/locales/en-US/styleinspector.properties
@@ -201,19 +201,19 @@ styleinspector.contextmenu.copy=Copy
 # LOCALIZATION NOTE (styleinspector.contextmenu.copy.accessKey): Access key for
 # the computed view context menu "Copy" entry.
 styleinspector.contextmenu.copy.accessKey=C
 
 # LOCALIZATION NOTE (styleinspector.contextmenu.copyLocation): Text displayed in the
 # rule view context menu for copying the source location.
 styleinspector.contextmenu.copyLocation=Copy Location
 
-# LOCALIZATION NOTE (styleinspector.contextmenu.copyPropertyDeclaration): Text
-# displayed in the rule view context menu for copying the property declaration.
-styleinspector.contextmenu.copyPropertyDeclaration=Copy Property Declaration
+# LOCALIZATION NOTE (styleinspector.contextmenu.copyDeclaration): Text
+# displayed in the rule view context menu for copying the CSS declaration.
+styleinspector.contextmenu.copyDeclaration=Copy Declaration
 
 # LOCALIZATION NOTE (styleinspector.contextmenu.copyPropertyName): Text displayed in
 # the rule view context menu for copying the property name.
 styleinspector.contextmenu.copyPropertyName=Copy Property Name
 
 # LOCALIZATION NOTE (styleinspector.contextmenu.copyPropertyValue): Text displayed in
 # the rule view context menu for copying the property value.
 styleinspector.contextmenu.copyPropertyValue=Copy Property Value
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -23,16 +23,17 @@
 #include "mozilla/Logging.h"
 #include "mozilla/StaticPtr.h"
 
 #include "nsDocShell.h"
 #include "nsGlobalWindowOuter.h"
 #include "nsContentUtils.h"
 #include "nsScriptError.h"
 #include "nsThreadUtils.h"
+#include "xpcprivate.h"
 
 namespace mozilla {
 namespace dom {
 
 extern mozilla::LazyLogModule gUserInteractionPRLog;
 
 #define USER_ACTIVATION_LOG(msg, ...) \
   MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
@@ -542,19 +543,53 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(BrowsingContext)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(BrowsingContext, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(BrowsingContext, Release)
 
+class RemoteLocationProxy
+    : public RemoteObjectProxy<BrowsingContext::LocationProxy,
+                               Location_Binding::sCrossOriginAttributes,
+                               Location_Binding::sCrossOriginMethods> {
+ public:
+  typedef RemoteObjectProxy Base;
+
+  constexpr RemoteLocationProxy()
+      : RemoteObjectProxy(prototypes::id::Location) {}
+
+  void NoteChildren(JSObject* aProxy,
+                    nsCycleCollectionTraversalCallback& aCb) const override {
+    auto location =
+        static_cast<BrowsingContext::LocationProxy*>(GetNative(aProxy));
+    CycleCollectionNoteChild(aCb, location->GetBrowsingContext(),
+                             "js::GetObjectPrivate(obj)->GetBrowsingContext()");
+  }
+};
+
+static const RemoteLocationProxy sSingleton;
+
+// Give RemoteLocationProxy 2 reserved slots, like the other wrappers,
+// so JSObject::swap can swap it with CrossCompartmentWrappers without requiring
+// malloc.
+template <>
+const js::Class RemoteLocationProxy::Base::sClass =
+    PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
+
 void BrowsingContext::Location(JSContext* aCx,
                                JS::MutableHandle<JSObject*> aLocation,
-                               OOMReporter& aError) {}
+                               ErrorResult& aError) {
+  aError.MightThrowJSException();
+  sSingleton.GetProxyObject(aCx, &mLocation, aLocation);
+  if (!aLocation) {
+    aError.StealExceptionFromJSContext(aCx);
+  }
+}
 
 void BrowsingContext::Close(CallerType aCallerType, ErrorResult& aError) {
   // FIXME We need to set mClosed, but only once we're sending the
   //       DOMWindowClose event (which happens in the process where the
   //       document for this browsing context is loaded).
   //       See https://bugzilla.mozilla.org/show_bug.cgi?id=1516343.
   ContentChild* cc = ContentChild::GetSingleton();
   cc->SendWindowClose(this, aCallerType == CallerType::System);
@@ -668,16 +703,38 @@ void BrowsingContext::Transaction::Commi
       Unused << entry->GetKey()->SendCommitBrowsingContextTransaction(
           aBrowsingContext, *this);
     }
   }
 
   Apply(aBrowsingContext);
 }
 
+void BrowsingContext::LocationProxy::SetHref(const nsAString& aHref,
+                                             nsIPrincipal& aSubjectPrincipal,
+                                             ErrorResult& aError) {
+  nsPIDOMWindowOuter* win = GetBrowsingContext()->GetDOMWindow();
+  if (!win || !win->GetLocation()) {
+    aError.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+  win->GetLocation()->SetHref(aHref, aSubjectPrincipal, aError);
+}
+
+void BrowsingContext::LocationProxy::Replace(const nsAString& aUrl,
+                                             nsIPrincipal& aSubjectPrincipal,
+                                             ErrorResult& aError) {
+  nsPIDOMWindowOuter* win = GetBrowsingContext()->GetDOMWindow();
+  if (!win || !win->GetLocation()) {
+    aError.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+  win->GetLocation()->Replace(aUrl, aSubjectPrincipal, aError);
+}
+
 }  // namespace dom
 
 namespace ipc {
 
 void IPDLParamTraits<dom::BrowsingContext>::Write(
     IPC::Message* aMsg, IProtocol* aActor, dom::BrowsingContext* aParam) {
   uint64_t id = aParam ? aParam->Id() : 0;
   WriteIPDLParam(aMsg, aActor, id);
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -15,28 +15,28 @@
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIDocShell.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
 
 class nsGlobalWindowOuter;
+class nsIPrincipal;
 class nsOuterWindowProxy;
 class PickleIterator;
 
 namespace IPC {
 class Message;
 }  // namespace IPC
 
 namespace mozilla {
 
 class ErrorResult;
 class LogModule;
-class OOMReporter;
 
 namespace ipc {
 class IProtocol;
 
 template <typename T>
 struct IPDLParamTraits;
 }  // namespace ipc
 
@@ -262,17 +262,17 @@ class BrowsingContext : public nsWrapper
 
   using Children = nsTArray<RefPtr<BrowsingContext>>;
   const Children& GetChildren() { return mChildren; }
 
   // Window APIs that are cross-origin-accessible (from the HTML spec).
   BrowsingContext* Window() { return Self(); }
   BrowsingContext* Self() { return this; }
   void Location(JSContext* aCx, JS::MutableHandle<JSObject*> aLocation,
-                OOMReporter& aError);
+                ErrorResult& aError);
   void Close(CallerType aCallerType, ErrorResult& aError);
   bool GetClosed(ErrorResult&) { return mClosed; }
   void Focus(ErrorResult& aError);
   void Blur(ErrorResult& aError);
   BrowsingContext* GetFrames(ErrorResult& aError) { return Self(); }
   int32_t Length() const { return mChildren.Length(); }
   Nullable<WindowProxyHolder> GetTop(ErrorResult& aError);
   void GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aOpener,
@@ -324,32 +324,61 @@ class BrowsingContext : public nsWrapper
   }
   // Clear the window proxy object that corresponds to this browsing context.
   // This should be called if the window proxy object is finalized, or it can't
   // reach its browsing context anymore.
   void ClearWindowProxy() { mWindowProxy = nullptr; }
 
   BrowsingContext* TopLevelBrowsingContext();
 
+  friend class Location;
+  friend class RemoteLocationProxy;
+  /**
+   * LocationProxy is the class for the native object stored as a private in a
+   * RemoteLocationProxy proxy representing a Location object in a different
+   * process. It forwards all operations to its BrowsingContext and aggregates
+   * its refcount to that BrowsingContext.
+   */
+  class LocationProxy {
+   public:
+    MozExternalRefCountType AddRef() { return GetBrowsingContext()->AddRef(); }
+    MozExternalRefCountType Release() {
+      return GetBrowsingContext()->Release();
+    }
+
+    void SetHref(const nsAString& aHref, nsIPrincipal& aSubjectPrincipal,
+                 ErrorResult& aError);
+    void Replace(const nsAString& aUrl, nsIPrincipal& aSubjectPrincipal,
+                 ErrorResult& aError);
+
+   private:
+    friend class RemoteLocationProxy;
+    BrowsingContext* GetBrowsingContext() {
+      return reinterpret_cast<BrowsingContext*>(
+          uintptr_t(this) - offsetof(BrowsingContext, mLocation));
+    }
+  };
+
   // Type of BrowsingContent
   const Type mType;
 
   // Unique id identifying BrowsingContext
   const uint64_t mBrowsingContextId;
 
   RefPtr<BrowsingContextGroup> mGroup;
   RefPtr<BrowsingContext> mParent;
   Children mChildren;
   WeakPtr<BrowsingContext> mOpener;
   nsCOMPtr<nsIDocShell> mDocShell;
   // This is not a strong reference, but using a JS::Heap for that should be
   // fine. The JSObject stored in here should be a proxy with a
   // nsOuterWindowProxy handler, which will update the pointer from its
   // objectMoved hook and clear it from its finalize hook.
   JS::Heap<JSObject*> mWindowProxy;
+  LocationProxy mLocation;
 
   // This flag is only valid in the top level browsing context, it indicates
   // whether the corresponding document has been activated by user gesture.
   bool mIsActivatedByUserGesture;
 };
 
 /**
  * Gets a WindowProxy object for a BrowsingContext that lives in a different
--- a/docshell/base/moz.build
+++ b/docshell/base/moz.build
@@ -103,16 +103,17 @@ UNIFIED_SOURCES += [
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '/docshell/shistory',
     '/dom/base',
     '/dom/bindings',
+    '/js/xpconnect/src',
     '/layout/base',
     '/layout/generic',
     '/layout/style',
     '/layout/xul',
     '/netwerk/base',
     '/netwerk/protocol/viewsource',
     '/toolkit/components/browser',
     '/toolkit/components/find',
--- a/dom/base/Location.h
+++ b/dom/base/Location.h
@@ -24,17 +24,17 @@ namespace mozilla {
 namespace dom {
 
 //*****************************************************************************
 // Location: Script "location" object
 //*****************************************************************************
 
 class Location final : public nsISupports, public nsWrapperCache {
  public:
-  typedef Location RemoteProxy;
+  typedef BrowsingContext::LocationProxy RemoteProxy;
 
   Location(nsPIDOMWindowInner* aWindow, nsIDocShell* aDocShell);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Location)
 
   // WebIDL API:
   void Assign(const nsAString& aUrl, nsIPrincipal& aSubjectPrincipal,
--- a/dom/base/RemoteOuterWindowProxy.cpp
+++ b/dom/base/RemoteOuterWindowProxy.cpp
@@ -27,71 +27,56 @@ namespace dom {
  *       https://bugzilla.mozilla.org/show_bug.cgi?id=1516350.
  */
 
 class RemoteOuterWindowProxy
     : public RemoteObjectProxy<BrowsingContext,
                                Window_Binding::sCrossOriginAttributes,
                                Window_Binding::sCrossOriginMethods> {
  public:
+  typedef RemoteObjectProxy Base;
+
   constexpr RemoteOuterWindowProxy()
       : RemoteObjectProxy(prototypes::id::Window) {}
 
   // Standard internal methods
   bool getOwnPropertyDescriptor(
       JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
       JS::MutableHandle<JS::PropertyDescriptor> aDesc) const final;
   bool ownPropertyKeys(JSContext* aCx, JS::Handle<JSObject*> aProxy,
                        JS::AutoIdVector& aProps) const final;
 
   // SpiderMonkey extensions
   bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
                                     JS::AutoIdVector& props) const final;
-  void finalize(JSFreeOp* aFop, JSObject* aProxy) const final;
-  const char* className(JSContext* aCx,
-                        JS::Handle<JSObject*> aProxy) const final;
+
+  void NoteChildren(JSObject* aProxy,
+                    nsCycleCollectionTraversalCallback& aCb) const override {
+    CycleCollectionNoteChild(aCb,
+                             static_cast<BrowsingContext*>(GetNative(aProxy)),
+                             "js::GetObjectPrivate(obj)");
+  }
 };
 
 static const RemoteOuterWindowProxy sSingleton;
 
-// Give RemoteOuterWindowProxyClass 2 reserved slots, like the other wrappers,
+// Give RemoteOuterWindowProxy 2 reserved slots, like the other wrappers,
 // so JSObject::swap can swap it with CrossCompartmentWrappers without requiring
 // malloc.
-const js::Class RemoteOuterWindowProxyClass =
+template <>
+const js::Class RemoteOuterWindowProxy::Base::sClass =
     PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
 
 bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
                                JS::MutableHandle<JSObject*> aRetVal) {
   MOZ_ASSERT(!aContext->GetDocShell(),
              "Why are we creating a RemoteOuterWindowProxy?");
 
-  xpc::CompartmentPrivate* priv =
-      xpc::CompartmentPrivate::Get(JS::CurrentGlobalOrNull(aCx));
-  xpc::CompartmentPrivate::RemoteProxyMap& map = priv->GetRemoteProxyMap();
-  auto result = map.lookupForAdd(aContext);
-  if (result) {
-    aRetVal.set(result->value());
-    return true;
-  }
-
-  JS::Rooted<JSObject*> obj(
-      aCx, sSingleton.CreateProxyObject(aCx, aContext,
-                                        &RemoteOuterWindowProxyClass));
-  if (!obj) {
-    return false;
-  }
-  NS_ADDREF(aContext);
-
-  if (!map.add(result, aContext, obj)) {
-    JS_ReportOutOfMemory(aCx);
-    return false;
-  }
-
-  aRetVal.set(obj);
-  return true;
+  sSingleton.GetProxyObject(aCx, aContext, aRetVal);
+  return !!aRetVal;
 }
 
 static BrowsingContext* GetBrowsingContext(JSObject* aProxy) {
   MOZ_ASSERT(IsRemoteObjectProxy(aProxy, prototypes::id::Window));
   return static_cast<BrowsingContext*>(
       RemoteObjectProxyBase::GetNative(aProxy));
 }
 
@@ -172,22 +157,10 @@ bool RemoteOuterWindowProxy::ownProperty
 }
 
 bool RemoteOuterWindowProxy::getOwnEnumerablePropertyKeys(
     JSContext* aCx, JS::Handle<JSObject*> aProxy,
     JS::AutoIdVector& aProps) const {
   return AppendIndexedPropertyNames(aCx, GetBrowsingContext(aProxy), aProps);
 }
 
-void RemoteOuterWindowProxy::finalize(JSFreeOp* aFop, JSObject* aProxy) const {
-  BrowsingContext* bc = GetBrowsingContext(aProxy);
-  RefPtr<BrowsingContext> self(dont_AddRef(bc));
-}
-
-const char* RemoteOuterWindowProxy::className(
-    JSContext* aCx, JS::Handle<JSObject*> aProxy) const {
-  MOZ_ASSERT(js::IsProxy(aProxy));
-
-  return "Object";
-}
-
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -9127,17 +9127,16 @@ class CGSpecializedGetter(CGAbstractStat
         type = self.attr.type
         if self.attr.getExtendedAttribute("CrossOriginReadable"):
             remoteType = type
             extendedAttributes = self.descriptor.getExtendedAttributes(self.attr, getter=True)
             if remoteType.isGeckoInterface() and not remoteType.unroll().inner.isExternal():
                 # We'll use a JSObject. It might make more sense to use remoteType's
                 # RemoteProxy, but it's not easy to construct a type for that from here.
                 remoteType = BuiltinTypes[IDLBuiltinType.Types.object]
-                extendedAttributes.append('canOOM')
                 extendedAttributes.remove('infallible')
             prototypeID, _ = PrototypeIDAndDepth(self.descriptor)
             prefix = fill("""
                 if (IsRemoteObjectProxy(obj, ${prototypeID})) {
                     ${nativeType}::RemoteProxy* self = static_cast<${nativeType}::RemoteProxy*>(void_self);
                     $*{call}
                 }
                 ${nativeType}* self = static_cast<${nativeType}*>(void_self);
--- a/dom/bindings/RemoteObjectProxy.cpp
+++ b/dom/bindings/RemoteObjectProxy.cpp
@@ -6,22 +6,16 @@
 
 #include "RemoteObjectProxy.h"
 #include "AccessCheck.h"
 #include "jsfriendapi.h"
 
 namespace mozilla {
 namespace dom {
 
-// Give RemoteObjectProxy 2 reserved slots, like the other wrappers, so
-// JSObject::swap can swap it with CrossCompartmentWrappers without requiring
-// malloc.
-const js::Class RemoteObjectProxyClass =
-    PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
-
 bool RemoteObjectProxyBase::getOwnPropertyDescriptor(
     JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
     JS::MutableHandle<JS::PropertyDescriptor> aDesc) const {
   bool ok = CrossOriginGetOwnPropertyHelper(aCx, aProxy, aId, aDesc);
   if (!ok || aDesc.object()) {
     return ok;
   }
 
@@ -164,20 +158,49 @@ bool RemoteObjectProxyBase::hasOwn(JSCon
 }
 
 bool RemoteObjectProxyBase::getOwnEnumerablePropertyKeys(
     JSContext* aCx, JS::Handle<JSObject*> aProxy,
     JS::AutoIdVector& aProps) const {
   return true;
 }
 
-JSObject* RemoteObjectProxyBase::CreateProxyObject(
-    JSContext* aCx, void* aNative, const js::Class* aClasp) const {
+const char* RemoteObjectProxyBase::className(
+    JSContext* aCx, JS::Handle<JSObject*> aProxy) const {
+  MOZ_ASSERT(js::IsProxy(aProxy));
+
+  return "Object";
+}
+
+void RemoteObjectProxyBase::GetOrCreateProxyObject(
+    JSContext* aCx, void* aNative, const js::Class* aClasp,
+    JS::MutableHandle<JSObject*> aProxy, bool& aNewObjectCreated) const {
+  xpc::CompartmentPrivate* priv =
+      xpc::CompartmentPrivate::Get(JS::CurrentGlobalOrNull(aCx));
+  xpc::CompartmentPrivate::RemoteProxyMap& map = priv->GetRemoteProxyMap();
+  auto result = map.lookupForAdd(aNative);
+  if (result) {
+    aProxy.set(result->value());
+    return;
+  }
+
   js::ProxyOptions options;
   options.setClass(aClasp);
   JS::Rooted<JS::Value> native(aCx, JS::PrivateValue(aNative));
-  return js::NewProxyObject(aCx, this, native, nullptr, options);
+  JS::Rooted<JSObject*> obj(
+      aCx, js::NewProxyObject(aCx, this, native, nullptr, options));
+  if (!obj) {
+    return;
+  }
+
+  aNewObjectCreated = true;
+
+  if (!map.add(result, aNative, obj)) {
+    return;
+  }
+
+  aProxy.set(obj);
 }
 
 const char RemoteObjectProxyBase::sCrossOriginProxyFamily = 0;
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/bindings/RemoteObjectProxy.h
+++ b/dom/bindings/RemoteObjectProxy.h
@@ -65,20 +65,25 @@ class RemoteObjectProxyBase : public js:
            JS::ObjectOpResult& aResult) const final;
 
   // SpiderMonkey extensions
   bool hasOwn(JSContext* aCx, JS::Handle<JSObject*> aProxy,
               JS::Handle<jsid> aId, bool* aBp) const override;
   bool getOwnEnumerablePropertyKeys(JSContext* aCx,
                                     JS::Handle<JSObject*> aProxy,
                                     JS::AutoIdVector& aProps) const override;
+  const char* className(JSContext* aCx,
+                        JS::Handle<JSObject*> aProxy) const final;
 
   bool isCallable(JSObject* aObj) const final { return false; }
   bool isConstructor(JSObject* aObj) const final { return false; }
 
+  virtual void NoteChildren(JSObject* aProxy,
+                            nsCycleCollectionTraversalCallback& aCb) const = 0;
+
   static void* GetNative(JSObject* aProxy) {
     return js::GetProxyPrivate(aProxy).toPrivate();
   }
 
   /**
    * Returns true if aProxy is a cross-process proxy that represents
    * an object implementing the WebIDL interface for aProtoID. aProxy
    * should be a proxy object.
@@ -96,18 +101,27 @@ class RemoteObjectProxyBase : public js:
    * interface it represents.  aProxy should be a proxy object.
    */
   static inline bool IsRemoteObjectProxy(JSObject* aProxy) {
     const js::BaseProxyHandler* handler = js::GetProxyHandler(aProxy);
     return handler->family() == &sCrossOriginProxyFamily;
   }
 
  protected:
-  JSObject* CreateProxyObject(JSContext* aCx, void* aNative,
-                              const js::Class* aClasp) const;
+  /**
+   * Gets an existing cached proxy object, or creates a new one and caches it.
+   * aProxy will be null on failure. aNewObjectCreated is set to true if a new
+   * object was created, callers probably need to addref the native in that
+   * case. aNewObjectCreated can be true even if aProxy is null, if something
+   * failed after creating the object.
+   */
+  void GetOrCreateProxyObject(JSContext* aCx, void* aNative,
+                              const js::Class* aClasp,
+                              JS::MutableHandle<JSObject*> aProxy,
+                              bool& aNewObjectCreated) const;
 
   const prototypes::ID mPrototypeID;
 
   static const char sCrossOriginProxyFamily;
 };
 
 /**
  * Proxy handler for proxy objects that represent an object implementing a
@@ -121,30 +135,41 @@ class RemoteObjectProxyBase : public js:
  *
  * The proxy objects that use a handler derived from this one are stored in a
  * hash map in the JS compartment's private (@see
  * xpc::CompartmentPrivate::GetRemoteProxyMap).
  */
 template <class Native, JSPropertySpec* P, JSFunctionSpec* F>
 class RemoteObjectProxy : public RemoteObjectProxyBase {
  public:
-  JSObject* CreateProxyObject(JSContext* aCx, Native* aNative,
-                              const js::Class* aClasp) const {
-    return RemoteObjectProxyBase::CreateProxyObject(aCx, aNative, aClasp);
+  void finalize(JSFreeOp* aFop, JSObject* aProxy) const final {
+    auto native = static_cast<Native*>(GetNative(aProxy));
+    RefPtr<Native> self(dont_AddRef(native));
+  }
+
+  void GetProxyObject(JSContext* aCx, Native* aNative,
+                      JS::MutableHandle<JSObject*> aProxy) const {
+    bool objectCreated = false;
+    GetOrCreateProxyObject(aCx, aNative, &sClass, aProxy, objectCreated);
+    if (objectCreated) {
+      NS_ADDREF(aNative);
+    }
   }
 
  protected:
   using RemoteObjectProxyBase::RemoteObjectProxyBase;
 
  private:
   bool EnsureHolder(JSContext* aCx, JS::Handle<JSObject*> aProxy,
                     JS::MutableHandle<JSObject*> aHolder) const final {
     return MaybeCrossOriginObjectMixins::EnsureHolder(
         aCx, aProxy, /* slot = */ 0, P, F, aHolder);
   }
+
+  static const js::Class sClass;
 };
 
 /**
  * Returns true if aObj is a cross-process proxy object that
  * represents an object implementing the WebIDL interface for
  * aProtoID.
  */
 static inline bool IsRemoteObjectProxy(JSObject* aObj,
--- a/dom/cache/DBSchema.cpp
+++ b/dom/cache/DBSchema.cpp
@@ -2491,17 +2491,17 @@ nsresult ReadResponse(mozIStorageConnect
 
     nsCString origin;
     url->Origin(origin);
 
     // CSP is recovered from the headers, no need to initialise it here.
     nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
     aSavedResponseOut->mValue.principalInfo() =
         mozilla::ipc::ContentPrincipalInfo(attrs, origin, specNoSuffix,
-                                           std::move(policies));
+                                           Nothing(), std::move(policies));
   }
 
   bool nullPadding = false;
   rv = state->GetIsNull(6, &nullPadding);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
--- a/dom/canvas/CanvasImageCache.cpp
+++ b/dom/canvas/CanvasImageCache.cpp
@@ -22,47 +22,42 @@ namespace mozilla {
 using namespace dom;
 using namespace gfx;
 
 /**
  * Used for images specific to this one canvas. Required
  * due to CORS security.
  */
 struct ImageCacheKey {
-  ImageCacheKey(imgIContainer* aImage, HTMLCanvasElement* aCanvas,
-                bool aIsAccelerated)
-      : mImage(aImage), mCanvas(aCanvas), mIsAccelerated(aIsAccelerated) {}
+  ImageCacheKey(imgIContainer* aImage, HTMLCanvasElement* aCanvas)
+      : mImage(aImage), mCanvas(aCanvas) {}
   nsCOMPtr<imgIContainer> mImage;
   HTMLCanvasElement* mCanvas;
-  bool mIsAccelerated;
 };
 
 /**
  * Cache data needs to be separate from the entry
  * for nsExpirationTracker.
  */
 struct ImageCacheEntryData {
   ImageCacheEntryData(const ImageCacheEntryData& aOther)
       : mImage(aOther.mImage),
         mCanvas(aOther.mCanvas),
-        mIsAccelerated(aOther.mIsAccelerated),
         mSourceSurface(aOther.mSourceSurface),
         mSize(aOther.mSize) {}
   explicit ImageCacheEntryData(const ImageCacheKey& aKey)
       : mImage(aKey.mImage),
-        mCanvas(aKey.mCanvas),
-        mIsAccelerated(aKey.mIsAccelerated) {}
+        mCanvas(aKey.mCanvas) {}
 
   nsExpirationState* GetExpirationState() { return &mState; }
   size_t SizeInBytes() { return mSize.width * mSize.height * 4; }
 
   // Key
   nsCOMPtr<imgIContainer> mImage;
   HTMLCanvasElement* mCanvas;
-  bool mIsAccelerated;
   // Value
   RefPtr<SourceSurface> mSourceSurface;
   IntSize mSize;
   nsExpirationState mState;
 };
 
 class ImageCacheEntry : public PLDHashEntryHdr {
  public:
@@ -71,67 +66,63 @@ class ImageCacheEntry : public PLDHashEn
 
   explicit ImageCacheEntry(const KeyType* aKey)
       : mData(new ImageCacheEntryData(*aKey)) {}
   ImageCacheEntry(const ImageCacheEntry& toCopy)
       : mData(new ImageCacheEntryData(*toCopy.mData)) {}
   ~ImageCacheEntry() {}
 
   bool KeyEquals(KeyTypePointer key) const {
-    return mData->mImage == key->mImage && mData->mCanvas == key->mCanvas &&
-           mData->mIsAccelerated == key->mIsAccelerated;
+    return mData->mImage == key->mImage && mData->mCanvas == key->mCanvas;
   }
 
   static KeyTypePointer KeyToPointer(KeyType& key) { return &key; }
   static PLDHashNumber HashKey(KeyTypePointer key) {
-    return HashGeneric(key->mImage.get(), key->mCanvas, key->mIsAccelerated);
+    return HashGeneric(key->mImage.get(), key->mCanvas);
   }
   enum { ALLOW_MEMMOVE = true };
 
   nsAutoPtr<ImageCacheEntryData> mData;
 };
 
 /**
  * Used for all images across all canvases.
  */
 struct AllCanvasImageCacheKey {
-  AllCanvasImageCacheKey(imgIContainer* aImage, bool aIsAccelerated)
-      : mImage(aImage), mIsAccelerated(aIsAccelerated) {}
+  explicit AllCanvasImageCacheKey(imgIContainer* aImage)
+      : mImage(aImage) {}
 
   nsCOMPtr<imgIContainer> mImage;
-  bool mIsAccelerated;
 };
 
 class AllCanvasImageCacheEntry : public PLDHashEntryHdr {
  public:
   typedef AllCanvasImageCacheKey KeyType;
   typedef const AllCanvasImageCacheKey* KeyTypePointer;
 
   explicit AllCanvasImageCacheEntry(const KeyType* aKey)
-      : mImage(aKey->mImage), mIsAccelerated(aKey->mIsAccelerated) {}
+      : mImage(aKey->mImage) {}
 
   AllCanvasImageCacheEntry(const AllCanvasImageCacheEntry& toCopy)
       : mImage(toCopy.mImage),
-        mIsAccelerated(toCopy.mIsAccelerated),
         mSourceSurface(toCopy.mSourceSurface) {}
 
   ~AllCanvasImageCacheEntry() {}
 
   bool KeyEquals(KeyTypePointer key) const {
-    return mImage == key->mImage && mIsAccelerated == key->mIsAccelerated;
+    return mImage == key->mImage;
   }
 
   static KeyTypePointer KeyToPointer(KeyType& key) { return &key; }
   static PLDHashNumber HashKey(KeyTypePointer key) {
-    return HashGeneric(key->mImage.get(), key->mIsAccelerated);
+    return HashGeneric(key->mImage.get());
   }
   enum { ALLOW_MEMMOVE = true };
 
   nsCOMPtr<imgIContainer> mImage;
-  bool mIsAccelerated;
   RefPtr<SourceSurface> mSourceSurface;
 };
 
 static bool sPrefsInitialized = false;
 static int32_t sCanvasImageCacheLimit = 0;
 
 class ImageCacheObserver;
 
@@ -144,21 +135,20 @@ class ImageCache final : public nsExpira
 
   virtual void NotifyExpired(ImageCacheEntryData* aObject) override {
     mTotal -= aObject->SizeInBytes();
     RemoveObject(aObject);
 
     // Remove from the all canvas cache entry first since nsExpirationTracker
     // will delete aObject.
     mAllCanvasCache.RemoveEntry(
-        AllCanvasImageCacheKey(aObject->mImage, aObject->mIsAccelerated));
+        AllCanvasImageCacheKey(aObject->mImage));
 
     // Deleting the entry will delete aObject since the entry owns aObject.
-    mCache.RemoveEntry(ImageCacheKey(aObject->mImage, aObject->mCanvas,
-                                     aObject->mIsAccelerated));
+    mCache.RemoveEntry(ImageCacheKey(aObject->mImage, aObject->mCanvas));
   }
 
   nsTHashtable<ImageCacheEntry> mCache;
   nsTHashtable<AllCanvasImageCacheEntry> mAllCanvasCache;
   size_t mTotal;
   RefPtr<ImageCacheObserver> mImageCacheObserver;
 };
 
@@ -268,31 +258,30 @@ static already_AddRefed<imgIContainer> G
   }
 
   return imgContainer.forget();
 }
 
 void CanvasImageCache::NotifyDrawImage(Element* aImage,
                                        HTMLCanvasElement* aCanvas,
                                        SourceSurface* aSource,
-                                       const IntSize& aSize,
-                                       bool aIsAccelerated) {
+                                       const IntSize& aSize) {
   if (!gImageCache) {
     gImageCache = new ImageCache();
     nsContentUtils::RegisterShutdownObserver(
         new CanvasImageCacheShutdownObserver());
   }
 
   nsCOMPtr<imgIContainer> imgContainer = GetImageContainer(aImage);
   if (!imgContainer) {
     return;
   }
 
-  AllCanvasImageCacheKey allCanvasCacheKey(imgContainer, aIsAccelerated);
-  ImageCacheKey canvasCacheKey(imgContainer, aCanvas, aIsAccelerated);
+  AllCanvasImageCacheKey allCanvasCacheKey(imgContainer);
+  ImageCacheKey canvasCacheKey(imgContainer, aCanvas);
   ImageCacheEntry* entry = gImageCache->mCache.PutEntry(canvasCacheKey);
 
   if (entry) {
     if (entry->mData->mSourceSurface) {
       // We are overwriting an existing entry.
       gImageCache->mTotal -= entry->mData->SizeInBytes();
       gImageCache->RemoveObject(entry->mData);
       gImageCache->mAllCanvasCache.RemoveEntry(allCanvasCacheKey);
@@ -312,51 +301,49 @@ void CanvasImageCache::NotifyDrawImage(E
 
   if (!sCanvasImageCacheLimit) return;
 
   // Expire the image cache early if its larger than we want it to be.
   while (gImageCache->mTotal > size_t(sCanvasImageCacheLimit))
     gImageCache->AgeOneGeneration();
 }
 
-SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage,
-                                                 bool aIsAccelerated) {
+SourceSurface* CanvasImageCache::LookupAllCanvas(Element* aImage) {
   if (!gImageCache) {
     return nullptr;
   }
 
   nsCOMPtr<imgIContainer> imgContainer = GetImageContainer(aImage);
   if (!imgContainer) {
     return nullptr;
   }
 
   AllCanvasImageCacheEntry* entry = gImageCache->mAllCanvasCache.GetEntry(
-      AllCanvasImageCacheKey(imgContainer, aIsAccelerated));
+      AllCanvasImageCacheKey(imgContainer));
   if (!entry) {
     return nullptr;
   }
 
   return entry->mSourceSurface;
 }
 
 SourceSurface* CanvasImageCache::LookupCanvas(Element* aImage,
                                               HTMLCanvasElement* aCanvas,
-                                              IntSize* aSizeOut,
-                                              bool aIsAccelerated) {
+                                              IntSize* aSizeOut) {
   if (!gImageCache) {
     return nullptr;
   }
 
   nsCOMPtr<imgIContainer> imgContainer = GetImageContainer(aImage);
   if (!imgContainer) {
     return nullptr;
   }
 
   ImageCacheEntry* entry = gImageCache->mCache.GetEntry(
-      ImageCacheKey(imgContainer, aCanvas, aIsAccelerated));
+      ImageCacheKey(imgContainer, aCanvas));
   if (!entry) {
     return nullptr;
   }
 
   MOZ_ASSERT(aSizeOut);
 
   gImageCache->MarkUsed(entry->mData);
   *aSizeOut = entry->mData->mSize;
--- a/dom/canvas/CanvasImageCache.h
+++ b/dom/canvas/CanvasImageCache.h
@@ -28,31 +28,28 @@ class CanvasImageCache {
  public:
   /**
    * Notify that image element aImage was drawn to aCanvas element
    * using the first frame of aRequest's image. The data for the surface is
    * in aSurface, and the image size is in aSize.
    */
   static void NotifyDrawImage(dom::Element* aImage,
                               dom::HTMLCanvasElement* aCanvas,
-                              SourceSurface* aSource, const gfx::IntSize& aSize,
-                              bool aIsAccelerated);
+                              SourceSurface* aSource, const gfx::IntSize& aSize);
 
   /**
    * Check whether aImage has recently been drawn any canvas. If we return
    * a non-null surface, then the same image was recently drawn into a canvas.
    */
-  static SourceSurface* LookupAllCanvas(dom::Element* aImage,
-                                        bool aIsAccelerated);
+  static SourceSurface* LookupAllCanvas(dom::Element* aImage);
 
   /**
    * Like the top above, but restricts the lookup to only aCanvas. This is
    * required for CORS security.
    */
   static SourceSurface* LookupCanvas(dom::Element* aImage,
                                      dom::HTMLCanvasElement* aCanvas,
-                                     gfx::IntSize* aSizeOut,
-                                     bool aIsAccelerated);
+                                     gfx::IntSize* aSizeOut);
 };
 
 }  // namespace mozilla
 
 #endif /* CANVASIMAGECACHE_H_ */
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -101,18 +101,16 @@
 #include "mozilla/dom/HTMLImageElement.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "mozilla/dom/SVGImageElement.h"
 #include "mozilla/dom/SVGMatrix.h"
 #include "mozilla/dom/TextMetrics.h"
 #include "mozilla/dom/SVGMatrix.h"
 #include "mozilla/FloatingPoint.h"
 #include "nsGlobalWindow.h"
-#include "GLContext.h"
-#include "GLContextProvider.h"
 #include "nsIScreenManager.h"
 #include "nsFilterInstance.h"
 #include "nsSVGLength2.h"
 #include "nsDeviceContext.h"
 #include "nsFontMetrics.h"
 #include "Units.h"
 #include "CanvasUtils.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
@@ -120,26 +118,16 @@
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/SVGContentUtils.h"
 #include "mozilla/layers/CanvasClient.h"
 #include "mozilla/layers/WebRenderUserData.h"
 #include "mozilla/layers/WebRenderCanvasRenderer.h"
 
 #undef free  // apparently defined by some windows header, clashing with a
              // free() method in SkTypes.h
-#include "SkiaGLGlue.h"
-#ifdef USE_SKIA
-#  include "SurfaceTypes.h"
-#  include "GLBlitHelper.h"
-#  include "ScopedGLHelpers.h"
-#endif
-
-using mozilla::gl::GLContext;
-using mozilla::gl::GLContextProvider;
-using mozilla::gl::SkiaGLGlue;
 
 #ifdef XP_WIN
 #  include "gfxWindowsPlatform.h"
 #endif
 
 // windows.h (included by chromium code) defines this, in its infinite wisdom
 #undef DrawText
 
@@ -755,115 +743,16 @@ CanvasShutdownObserver::Observe(nsISuppo
   if (mCanvas && strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
     mCanvas->OnShutdown();
     OnShutdown();
   }
 
   return NS_OK;
 }
 
-class CanvasDrawObserver {
- public:
-  explicit CanvasDrawObserver(CanvasRenderingContext2D* aCanvasContext);
-
-  // Only enumerate draw calls that could affect the heuristic
-  enum DrawCallType { PutImageData, GetImageData, DrawImage };
-
-  // This is the one that we call on relevant draw calls and count
-  // GPU vs. CPU preferrable calls...
-  void DidDrawCall(DrawCallType aType);
-
-  // When this returns true, the observer is done making the decisions.
-  // Right now, we expect to get rid of the observer after the FrameEnd
-  // returns true, though the decision could eventually change if the
-  // function calls shift.  If we change to monitor the functions called
-  // and make decisions to change more than once, we would probably want
-  // FrameEnd to reset the timer and counters as it returns true.
-  bool FrameEnd();
-
- private:
-  // These values will be picked up from preferences:
-  int32_t mMinFramesBeforeDecision;
-  float mMinSecondsBeforeDecision;
-  int32_t mMinCallsBeforeDecision;
-
-  CanvasRenderingContext2D* mCanvasContext;
-  int32_t mSoftwarePreferredCalls;
-  int32_t mGPUPreferredCalls;
-  int32_t mFramesRendered;
-  TimeStamp mCreationTime;
-};
-
-// We are not checking for the validity of the preference values.  For example,
-// negative values will have an effect of a quick exit, so no harm done.
-CanvasDrawObserver::CanvasDrawObserver(CanvasRenderingContext2D* aCanvasContext)
-    : mMinFramesBeforeDecision(gfxPrefs::CanvasAutoAccelerateMinFrames()),
-      mMinSecondsBeforeDecision(gfxPrefs::CanvasAutoAccelerateMinSeconds()),
-      mMinCallsBeforeDecision(gfxPrefs::CanvasAutoAccelerateMinCalls()),
-      mCanvasContext(aCanvasContext),
-      mSoftwarePreferredCalls(0),
-      mGPUPreferredCalls(0),
-      mFramesRendered(0),
-      mCreationTime(TimeStamp::NowLoRes()) {}
-
-void CanvasDrawObserver::DidDrawCall(DrawCallType aType) {
-  switch (aType) {
-    case PutImageData:
-    case GetImageData:
-      if (mGPUPreferredCalls == 0 && mSoftwarePreferredCalls == 0) {
-        mCreationTime = TimeStamp::NowLoRes();
-      }
-      mSoftwarePreferredCalls++;
-      break;
-    case DrawImage:
-      if (mGPUPreferredCalls == 0 && mSoftwarePreferredCalls == 0) {
-        mCreationTime = TimeStamp::NowLoRes();
-      }
-      mGPUPreferredCalls++;
-      break;
-  }
-}
-
-// If we return true, the observer is done making the decisions...
-bool CanvasDrawObserver::FrameEnd() {
-  mFramesRendered++;
-
-  // We log the first mMinFramesBeforeDecision frames of any
-  // canvas object then make a call to determine whether it should
-  // be GPU or CPU backed
-  if ((mFramesRendered >= mMinFramesBeforeDecision) ||
-      ((TimeStamp::NowLoRes() - mCreationTime).ToSeconds()) >
-          mMinSecondsBeforeDecision) {
-    // If we don't have enough data, don't bother changing...
-    if (mGPUPreferredCalls > mMinCallsBeforeDecision ||
-        mSoftwarePreferredCalls > mMinCallsBeforeDecision) {
-      CanvasRenderingContext2D::RenderingMode switchToMode;
-      if (mGPUPreferredCalls >= mSoftwarePreferredCalls) {
-        switchToMode =
-            CanvasRenderingContext2D::RenderingMode::OpenGLBackendMode;
-      } else {
-        switchToMode =
-            CanvasRenderingContext2D::RenderingMode::SoftwareBackendMode;
-      }
-      if (switchToMode != mCanvasContext->mRenderingMode) {
-        if (!mCanvasContext->SwitchRenderingMode(switchToMode)) {
-          gfxDebug() << "Canvas acceleration failed mode switch to "
-                     << switchToMode;
-        }
-      }
-    }
-
-    // If we ever redesign this class to constantly monitor the functions
-    // and keep making decisions, we would probably want to reset the counters
-    // and the timers here...
-    return true;
-  }
-  return false;
-}
-
 class CanvasRenderingContext2DUserData : public LayerUserData {
  public:
   explicit CanvasRenderingContext2DUserData(CanvasRenderingContext2D* aContext)
       : mContext(aContext) {
     aContext->mUserDatas.AppendElement(this);
   }
   ~CanvasRenderingContext2DUserData() {
     if (mContext) {
@@ -879,22 +768,16 @@ class CanvasRenderingContext2DUserData :
     context->OnStableState();
   }
 
   static void DidTransactionCallback(void* aData) {
     CanvasRenderingContext2D* context =
         static_cast<CanvasRenderingContext2D*>(aData);
     if (context) {
       context->MarkContextClean();
-      if (context->mDrawObserver) {
-        if (context->mDrawObserver->FrameEnd()) {
-          // Note that this call deletes and nulls out mDrawObserver:
-          context->RemoveDrawObserver();
-        }
-      }
     }
   }
   bool IsForContext(CanvasRenderingContext2D* aContext) {
     return mContext == aContext;
   }
   void Forget() { mContext = nullptr; }
 
  private:
@@ -904,17 +787,16 @@ class CanvasRenderingContext2DUserData :
 NS_IMPL_CYCLE_COLLECTING_ADDREF(CanvasRenderingContext2D)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(CanvasRenderingContext2D)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(CanvasRenderingContext2D)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CanvasRenderingContext2D)
   // Make sure we remove ourselves from the list of demotable contexts (raw
   // pointers), since we're logically destructed at this point.
-  CanvasRenderingContext2D::RemoveDemotableContext(tmp);
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCanvasElement)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)
   for (uint32_t i = 0; i < tmp->mStyleStack.Length(); i++) {
     ImplCycleCollectionUnlink(tmp->mStyleStack[i].patternStyles[Style::STROKE]);
     ImplCycleCollectionUnlink(tmp->mStyleStack[i].patternStyles[Style::FILL]);
     ImplCycleCollectionUnlink(
         tmp->mStyleStack[i].gradientStyles[Style::STROKE]);
     ImplCycleCollectionUnlink(tmp->mStyleStack[i].gradientStyles[Style::FILL]);
@@ -995,74 +877,54 @@ NS_INTERFACE_MAP_END
 
 /**
  ** CanvasRenderingContext2D impl
  **/
 
 // Initialize our static variables.
 uintptr_t CanvasRenderingContext2D::sNumLivingContexts = 0;
 DrawTarget* CanvasRenderingContext2D::sErrorTarget = nullptr;
-static bool sMaxContextsInitialized = false;
-static int32_t sMaxContexts = 0;
 
 CanvasRenderingContext2D::CanvasRenderingContext2D(
     layers::LayersBackend aCompositorBackend)
-    : mRenderingMode(RenderingMode::OpenGLBackendMode),
-      mCompositorBackend(aCompositorBackend)
-      // these are the default values from the Canvas spec
-      ,
+    : // these are the default values from the Canvas spec
       mWidth(0),
       mHeight(0),
       mZero(false),
       mOpaqueAttrValue(false),
       mContextAttributesHasAlpha(true),
       mOpaque(false),
       mResetLayer(true),
       mIPC(false),
-      mIsSkiaGL(false),
       mHasPendingStableStateCallback(false),
-      mDrawObserver(nullptr),
       mIsEntireFrameInvalid(false),
       mPredictManyRedrawCalls(false),
       mIsCapturedFrameInvalid(false),
       mPathTransformWillUpdate(false),
       mInvalidateCount(0),
       mWriteOnly(false) {
-  if (!sMaxContextsInitialized) {
-    sMaxContexts = gfxPrefs::CanvasAzureAcceleratedLimit();
-    sMaxContextsInitialized = true;
-  }
 
   sNumLivingContexts++;
 
   mShutdownObserver = new CanvasShutdownObserver(this);
   nsContentUtils::RegisterShutdownObserver(mShutdownObserver);
-
-  // The default is to use OpenGL mode
-  if (AllowOpenGLCanvas()) {
-    mDrawObserver = new CanvasDrawObserver(this);
-  } else {
-    mRenderingMode = RenderingMode::SoftwareBackendMode;
-  }
 }
 
 CanvasRenderingContext2D::~CanvasRenderingContext2D() {
-  RemoveDrawObserver();
   RemovePostRefreshObserver();
   RemoveShutdownObserver();
   Reset();
   // Drop references from all CanvasRenderingContext2DUserData to this context
   for (uint32_t i = 0; i < mUserDatas.Length(); ++i) {
     mUserDatas[i]->Forget();
   }
   sNumLivingContexts--;
   if (!sNumLivingContexts) {
     NS_IF_RELEASE(sErrorTarget);
   }
-  RemoveDemotableContext(this);
 }
 
 JSObject* CanvasRenderingContext2D::WrapObject(
     JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
   return CanvasRenderingContext2D_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 bool CanvasRenderingContext2D::ParseColor(const nsAString& aString,
@@ -1223,229 +1085,45 @@ void CanvasRenderingContext2D::Redraw(co
   }
 
   SVGObserverUtils::InvalidateDirectRenderingObservers(mCanvasElement);
 
   mCanvasElement->InvalidateCanvasContent(&aR);
 }
 
 void CanvasRenderingContext2D::DidRefresh() {
-  if (IsTargetValid() && mIsSkiaGL) {
-    SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
-    MOZ_ASSERT(glue);
-
-    auto gl = glue->GetGLContext();
-    gl->FlushIfHeavyGLCallsSinceLastFlush();
-  }
 }
 
 void CanvasRenderingContext2D::RedrawUser(const gfxRect& aR) {
   mIsCapturedFrameInvalid = true;
 
   if (mIsEntireFrameInvalid) {
     ++mInvalidateCount;
     return;
   }
 
   gfx::Rect newr = mTarget->GetTransform().TransformBounds(ToRect(aR));
   Redraw(newr);
 }
 
-bool CanvasRenderingContext2D::AllowOpenGLCanvas() const {
-  // If we somehow didn't have the correct compositor in the constructor,
-  // we could do something like this to get it:
-  //
-  // HTMLCanvasElement* el = GetCanvas();
-  // if (el) {
-  //   mCompositorBackend = el->GetCompositorBackendType();
-  // }
-  //
-  // We could have LAYERS_NONE if there was no widget at the time of
-  // canvas creation, but in that case the
-  // HTMLCanvasElement::GetCompositorBackendType would return LAYERS_NONE
-  // as well, so it wouldn't help much.
-  //
-  // XXX Disable SkiaGL on WebRender, since there is a case that R8G8B8X8
-  // is used, but WebRender does not support R8G8B8X8.
-
-  return (mCompositorBackend == LayersBackend::LAYERS_OPENGL) &&
-         gfxPlatform::GetPlatform()->AllowOpenGLCanvas();
-}
-
-bool CanvasRenderingContext2D::SwitchRenderingMode(
-    RenderingMode aRenderingMode) {
-  if (!(IsTargetValid() || mBufferProvider) ||
-      mRenderingMode == aRenderingMode) {
-    return false;
-  }
-
-  MOZ_ASSERT(mBufferProvider);
-
-#ifdef USE_SKIA_GPU
-  // Do not attempt to switch into GL mode if the platform doesn't allow it.
-  if ((aRenderingMode == RenderingMode::OpenGLBackendMode) &&
-      !AllowOpenGLCanvas()) {
-    return false;
-  }
-#endif
-
-  RefPtr<PersistentBufferProvider> oldBufferProvider = mBufferProvider;
-
-  // Return the old target to the buffer provider.
-  // We need to do this before calling EnsureTarget.
-  ReturnTarget();
-  mTarget = nullptr;
-  mBufferProvider = nullptr;
-  mResetLayer = true;
-
-  // Recreate mTarget using the new rendering mode
-  RenderingMode attemptedMode = EnsureTarget(nullptr, aRenderingMode);
-  if (!IsTargetValid()) {
-    return false;
-  }
-
-  if (oldBufferProvider && mTarget) {
-    CopyBufferProvider(*oldBufferProvider, *mTarget,
-                       IntRect(0, 0, mWidth, mHeight));
-  }
-
-  // We succeeded, so update mRenderingMode to reflect reality
-  mRenderingMode = attemptedMode;
-
-  return true;
-}
-
 bool CanvasRenderingContext2D::CopyBufferProvider(
     PersistentBufferProvider& aOld, DrawTarget& aTarget, IntRect aCopyRect) {
   // Borrowing the snapshot must be done after ReturnTarget.
   RefPtr<SourceSurface> snapshot = aOld.BorrowSnapshot();
 
   if (!snapshot) {
     return false;
   }
 
   aTarget.CopySurface(snapshot, aCopyRect, IntPoint());
   aOld.ReturnSnapshot(snapshot.forget());
   return true;
 }
 
 void CanvasRenderingContext2D::Demote() {
-  if (SwitchRenderingMode(RenderingMode::SoftwareBackendMode)) {
-    RemoveDemotableContext(this);
-  }
-}
-
-std::vector<CanvasRenderingContext2D*>&
-CanvasRenderingContext2D::DemotableContexts() {
-  // This is a list of raw pointers to cycle-collected objects. We need to
-  // ensure that we remove elements from it during UNLINK (which can happen
-  // considerably before the actual destructor) since the object is logically
-  // destroyed at that point and will be in an inconsistant state.
-  static std::vector<CanvasRenderingContext2D*> contexts;
-  return contexts;
-}
-
-void CanvasRenderingContext2D::DemoteOldestContextIfNecessary() {
-  MOZ_ASSERT(sMaxContextsInitialized);
-  if (sMaxContexts <= 0) {
-    return;
-  }
-
-  std::vector<CanvasRenderingContext2D*>& contexts = DemotableContexts();
-  if (contexts.size() < (size_t)sMaxContexts) return;
-
-  CanvasRenderingContext2D* oldest = contexts.front();
-  if (oldest->SwitchRenderingMode(RenderingMode::SoftwareBackendMode)) {
-    RemoveDemotableContext(oldest);
-  }
-}
-
-void CanvasRenderingContext2D::AddDemotableContext(
-    CanvasRenderingContext2D* aContext) {
-  MOZ_ASSERT(sMaxContextsInitialized);
-  if (sMaxContexts <= 0) return;
-
-  std::vector<CanvasRenderingContext2D*>::iterator iter = std::find(
-      DemotableContexts().begin(), DemotableContexts().end(), aContext);
-  if (iter != DemotableContexts().end()) return;
-
-  DemotableContexts().push_back(aContext);
-}
-
-void CanvasRenderingContext2D::RemoveDemotableContext(
-    CanvasRenderingContext2D* aContext) {
-  MOZ_ASSERT(sMaxContextsInitialized);
-  if (sMaxContexts <= 0) return;
-
-  std::vector<CanvasRenderingContext2D*>::iterator iter = std::find(
-      DemotableContexts().begin(), DemotableContexts().end(), aContext);
-  if (iter != DemotableContexts().end()) DemotableContexts().erase(iter);
-}
-
-#define MIN_SKIA_GL_DIMENSION 16
-
-bool CanvasRenderingContext2D::CheckSizeForSkiaGL(IntSize aSize) {
-  MOZ_ASSERT(NS_IsMainThread());
-
-  int minsize = Preferences::GetInt("gfx.canvas.min-size-for-skia-gl", 128);
-  if (aSize.width < MIN_SKIA_GL_DIMENSION ||
-      aSize.height < MIN_SKIA_GL_DIMENSION ||
-      (aSize.width * aSize.height < minsize * minsize)) {
-    return false;
-  }
-
-  // Maximum pref allows 3 different options:
-  //  0   means unlimited size
-  //  > 0 means use value as an absolute threshold
-  //  < 0 means use the number of screen pixels as a threshold
-  int maxsize = Preferences::GetInt("gfx.canvas.max-size-for-skia-gl", 0);
-
-  // unlimited max size
-  if (!maxsize) {
-    return true;
-  }
-
-  // absolute max size threshold
-  if (maxsize > 0) {
-    return aSize.width <= maxsize && aSize.height <= maxsize;
-  }
-
-  // Cache the number of pixels on the primary screen
-  static int32_t gScreenPixels = -1;
-  if (gScreenPixels < 0) {
-    // Default to historical mobile screen size of 980x480, like FishIEtank.
-    // In addition, allow skia use up to this size even if the screen is
-    // smaller. A lot content expects this size to work well. See Bug 999841
-    if (gfxPlatform::GetPlatform()->HasEnoughTotalSystemMemoryForSkiaGL()) {
-      gScreenPixels = 980 * 480;
-    }
-
-    nsCOMPtr<nsIScreenManager> screenManager =
-        do_GetService("@mozilla.org/gfx/screenmanager;1");
-    if (screenManager) {
-      nsCOMPtr<nsIScreen> primaryScreen;
-      screenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen));
-      if (primaryScreen) {
-        int32_t x, y, width, height;
-        primaryScreen->GetRect(&x, &y, &width, &height);
-
-        gScreenPixels = std::max(gScreenPixels, width * height);
-      }
-    }
-  }
-
-  // Just always use a scale of 1.0. It can be changed if a lot of contents need
-  // it.
-  static double gDefaultScale = 1.0;
-
-  double scale = gDefaultScale > 0 ? gDefaultScale : 1.0;
-  int32_t threshold = ceil(scale * scale * gScreenPixels);
-
-  // screen size acts as max threshold
-  return threshold < 0 || (aSize.width * aSize.height) <= threshold;
 }
 
 void CanvasRenderingContext2D::ScheduleStableStateCallback() {
   if (mHasPendingStableStateCallback) {
     return;
   }
   mHasPendingStableStateCallback = true;
 
@@ -1484,40 +1162,32 @@ void CanvasRenderingContext2D::RestoreCl
         mTarget->PushClip(clipOrTransform.clip);
       } else {
         mTarget->SetTransform(clipOrTransform.transform);
       }
     }
   }
 }
 
-CanvasRenderingContext2D::RenderingMode CanvasRenderingContext2D::EnsureTarget(
-    const gfx::Rect* aCoveredRect, RenderingMode aRenderingMode) {
+bool CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect) {
   if (AlreadyShutDown()) {
     gfxCriticalError() << "Attempt to render into a Canvas2d after shutdown.";
     SetErrorState();
-    return aRenderingMode;
-  }
-
-  // This would make no sense, so make sure we don't get ourselves in a mess
-  MOZ_ASSERT(mRenderingMode != RenderingMode::DefaultBackendMode);
-
-  RenderingMode mode = (aRenderingMode == RenderingMode::DefaultBackendMode)
-                           ? mRenderingMode
-                           : aRenderingMode;
-
-  if (mTarget && mode == mRenderingMode) {
-    return mRenderingMode;
+    return false;
+  }
+
+  if (mTarget) {
+    return true;
   }
 
   // Check that the dimensions are sane
   if (mWidth > gfxPrefs::MaxCanvasSize() ||
       mHeight > gfxPrefs::MaxCanvasSize() || mWidth < 0 || mHeight < 0) {
     SetErrorState();
-    return aRenderingMode;
+    return false;
   }
 
   // If the next drawing command covers the entire canvas, we can skip copying
   // from the previous frame and/or clearing the canvas.
   gfx::Rect canvasRect(0, 0, mWidth, mHeight);
   bool canDiscardContent =
       aCoveredRect && CurrentState()
                           .transform.TransformBounds(*aCoveredRect)
@@ -1537,46 +1207,39 @@ CanvasRenderingContext2D::RenderingMode 
     }
   }
 
   ScheduleStableStateCallback();
 
   IntRect persistedRect =
       canDiscardContent ? IntRect() : IntRect(0, 0, mWidth, mHeight);
 
-  if (mBufferProvider && mode == mRenderingMode) {
+  if (mBufferProvider) {
     mTarget = mBufferProvider->BorrowDrawTarget(persistedRect);
 
     if (mTarget && !mBufferProvider->PreservesDrawingState()) {
       RestoreClipsAndTransformToTarget();
     }
 
     if (mTarget) {
-      return mode;
+      return true;
     }
   }
 
   RefPtr<DrawTarget> newTarget;
   RefPtr<PersistentBufferProvider> newProvider;
 
-  if (mode == RenderingMode::OpenGLBackendMode &&
-      !TrySkiaGLTarget(newTarget, newProvider)) {
-    // Fall back to software.
-    mode = RenderingMode::SoftwareBackendMode;
-  }
-
-  if (mode == RenderingMode::SoftwareBackendMode &&
-      !TrySharedTarget(newTarget, newProvider) &&
+  if (!TrySharedTarget(newTarget, newProvider) &&
       !TryBasicTarget(newTarget, newProvider)) {
     gfxCriticalError(
         CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(GetSize())))
         << "Failed borrow shared and basic targets.";
 
     SetErrorState();
-    return mode;
+    return false;
   }
 
   MOZ_ASSERT(newTarget);
   MOZ_ASSERT(newProvider);
 
   bool needsClear = !canDiscardContent;
   if (newTarget->GetBackendType() == gfx::BackendType::SKIA) {
     // Skia expects the unused X channel to contains 0xFF even for opaque
@@ -1607,17 +1270,17 @@ CanvasRenderingContext2D::RenderingMode 
   // and now we might need one.
   if (mCanvasElement) {
     mCanvasElement->InvalidateCanvas();
   }
   // Calling Redraw() tells our invalidation machinery that the entire
   // canvas is already invalid, which can speed up future drawing.
   Redraw();
 
-  return mode;
+  return true;
 }
 
 void CanvasRenderingContext2D::SetInitialState() {
   // Set up the initial canvas defaults
   mPathBuilder = nullptr;
   mPath = nullptr;
   mDSPathBuilder = nullptr;
   mPathTransformWillUpdate = false;
@@ -1667,67 +1330,16 @@ static already_AddRefed<LayerManager> La
   if (!aCanvasElement) {
     return nullptr;
   }
 
   return nsContentUtils::PersistentLayerManagerForDocument(
       aCanvasElement->OwnerDoc());
 }
 
-bool CanvasRenderingContext2D::TrySkiaGLTarget(
-    RefPtr<gfx::DrawTarget>& aOutDT,
-    RefPtr<layers::PersistentBufferProvider>& aOutProvider) {
-  aOutDT = nullptr;
-  aOutProvider = nullptr;
-
-  mIsSkiaGL = false;
-
-  IntSize size(mWidth, mHeight);
-  if (!AllowOpenGLCanvas() || !CheckSizeForSkiaGL(size)) {
-    return false;
-  }
-
-  RefPtr<LayerManager> layerManager =
-      LayerManagerFromCanvasElement(mCanvasElement);
-
-  if (!layerManager) {
-    return false;
-  }
-
-  DemoteOldestContextIfNecessary();
-  mBufferProvider = nullptr;
-
-#ifdef USE_SKIA_GPU
-  SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
-  if (!glue || !glue->GetGrContext() || !glue->GetGLContext()) {
-    return false;
-  }
-
-  SurfaceFormat format = GetSurfaceFormat();
-  aOutDT = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(),
-                                                      size, format);
-  if (!aOutDT) {
-    gfxCriticalNote
-        << "Failed to create a SkiaGL DrawTarget, falling back to software\n";
-    return false;
-  }
-
-  MOZ_ASSERT(aOutDT->GetType() == DrawTargetType::HARDWARE_RASTER);
-
-  AddDemotableContext(this);
-  aOutProvider = new PersistentBufferProviderBasic(aOutDT);
-  mIsSkiaGL = true;
-  // Drop a note in the debug builds if we ever use accelerated Skia canvas.
-  gfxWarningOnce() << "Using SkiaGL canvas.";
-#endif
-
-  // could still be null if USE_SKIA_GPU is not #defined.
-  return !!aOutDT;
-}
-
 bool CanvasRenderingContext2D::TrySharedTarget(
     RefPtr<gfx::DrawTarget>& aOutDT,
     RefPtr<layers::PersistentBufferProvider>& aOutProvider) {
   aOutDT = nullptr;
   aOutProvider = nullptr;
 
   if (!mCanvasElement) {
     return false;
@@ -1907,26 +1519,16 @@ CanvasRenderingContext2D::SetContextOpti
   MOZ_ASSERT(!mTarget);
 
   ContextAttributes2D attributes;
   if (!attributes.Init(aCx, aOptions)) {
     aRvForDictionaryInit.Throw(NS_ERROR_UNEXPECTED);
     return NS_ERROR_UNEXPECTED;
   }
 
-  if (Preferences::GetBool("gfx.canvas.willReadFrequently.enable", false)) {
-    // Use software when there is going to be a lot of readback
-    if (attributes.mWillReadFrequently) {
-      // We want to lock into software, so remove the observer that
-      // may potentially change that...
-      RemoveDrawObserver();
-      mRenderingMode = RenderingMode::SoftwareBackendMode;
-    }
-  }
-
   mContextAttributesHasAlpha = attributes.mAlpha;
   UpdateIsOpaque();
 
   return NS_OK;
 }
 
 UniquePtr<uint8_t[]> CanvasRenderingContext2D::GetImageBuffer(
     int32_t* aFormat) {
@@ -4532,17 +4134,17 @@ CanvasRenderingContext2D::CachedSurfaceF
   }
 
   nsCOMPtr<nsIPrincipal> principal;
   if (NS_FAILED(imgRequest->GetImagePrincipal(getter_AddRefs(principal))) ||
       !principal) {
     return res;
   }
 
-  res.mSourceSurface = CanvasImageCache::LookupAllCanvas(aElement, mIsSkiaGL);
+  res.mSourceSurface = CanvasImageCache::LookupAllCanvas(aElement);
   if (!res.mSourceSurface) {
     return res;
   }
 
   int32_t corsmode = imgIRequest::CORS_NONE;
   if (NS_SUCCEEDED(imgRequest->GetCORSMode(&corsmode))) {
     res.mCORSUsed = corsmode != imgIRequest::CORS_NONE;
   }
@@ -4571,20 +4173,16 @@ CanvasRenderingContext2D::CachedSurfaceF
 // are all passed in.
 
 void CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
                                          double aSx, double aSy, double aSw,
                                          double aSh, double aDx, double aDy,
                                          double aDw, double aDh,
                                          uint8_t aOptional_argc,
                                          ErrorResult& aError) {
-  if (mDrawObserver) {
-    mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::DrawImage);
-  }
-
   MOZ_ASSERT(aOptional_argc == 0 || aOptional_argc == 2 || aOptional_argc == 6);
 
   if (!ValidateRect(aDx, aDy, aDw, aDh, true)) {
     return;
   }
   if (aOptional_argc == 6) {
     if (!ValidateRect(aSx, aSy, aSw, aSh, true)) {
       return;
@@ -4635,18 +4233,17 @@ void CanvasRenderingContext2D::DrawImage
       element = img;
     } else {
       HTMLVideoElement* video = &aImage.GetAsHTMLVideoElement();
       video->MarkAsContentSource(
           mozilla::dom::HTMLVideoElement::CallerAPI::DRAW_IMAGE);
       element = video;
     }
 
-    srcSurf = CanvasImageCache::LookupCanvas(element, mCanvasElement, &imgSize,
-                                             mIsSkiaGL);
+    srcSurf = CanvasImageCache::LookupCanvas(element, mCanvasElement, &imgSize);
   }
 
   nsLayoutUtils::DirectDrawInfo drawInfo;
 
   if (!srcSurf) {
     // The canvas spec says that drawImage should draw the first frame
     // of animated images. We also don't want to rasterize vector images.
     uint32_t sfeFlags = nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE |
@@ -4687,17 +4284,17 @@ void CanvasRenderingContext2D::DrawImage
     if (mCanvasElement) {
       CanvasUtils::DoDrawImageSecurityCheck(mCanvasElement, res.mPrincipal,
                                             res.mIsWriteOnly, res.mCORSUsed);
     }
 
     if (res.mSourceSurface) {
       if (res.mImageRequest) {
         CanvasImageCache::NotifyDrawImage(
-            element, mCanvasElement, res.mSourceSurface, imgSize, mIsSkiaGL);
+            element, mCanvasElement, res.mSourceSurface, imgSize);
       }
       srcSurf = res.mSourceSurface;
     } else {
       drawInfo = res.mDrawInfo;
     }
   }
 
   if (aOptional_argc == 0) {
@@ -5113,20 +4710,16 @@ void CanvasRenderingContext2D::DrawWindo
 
 //
 // device pixel getting/setting
 //
 
 already_AddRefed<ImageData> CanvasRenderingContext2D::GetImageData(
     JSContext* aCx, double aSx, double aSy, double aSw, double aSh,
     nsIPrincipal& aSubjectPrincipal, ErrorResult& aError) {
-  if (mDrawObserver) {
-    mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::GetImageData);
-  }
-
   if (!mCanvasElement && !mDocShell) {
     NS_ERROR("No canvas element and no docshell in GetImageData!!!");
     aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   // Check only if we have a canvas element; if we were created with a docshell,
   // then it's special internal use.
@@ -5185,20 +4778,16 @@ already_AddRefed<ImageData> CanvasRender
 
   RefPtr<ImageData> imageData = new ImageData(w, h, *array);
   return imageData.forget();
 }
 
 nsresult CanvasRenderingContext2D::GetImageDataArray(
     JSContext* aCx, int32_t aX, int32_t aY, uint32_t aWidth, uint32_t aHeight,
     nsIPrincipal& aSubjectPrincipal, JSObject** aRetval) {
-  if (mDrawObserver) {
-    mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::GetImageData);
-  }
-
   MOZ_ASSERT(aWidth && aHeight);
 
   CheckedInt<uint32_t> len = CheckedInt<uint32_t>(aWidth) * aHeight * 4;
   if (!len.isValid()) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
 
   CheckedInt<int32_t> rightMost = CheckedInt<int32_t>(aX) + aWidth;
@@ -5344,20 +4933,16 @@ void CanvasRenderingContext2D::PutImageD
                                  JS::ToInt32(aDirtyY), JS::ToInt32(aDirtyWidth),
                                  JS::ToInt32(aDirtyHeight));
 }
 
 nsresult CanvasRenderingContext2D::PutImageData_explicit(
     int32_t aX, int32_t aY, uint32_t aW, uint32_t aH,
     dom::Uint8ClampedArray* aArray, bool aHasDirtyRect, int32_t aDirtyX,
     int32_t aDirtyY, int32_t aDirtyWidth, int32_t aDirtyHeight) {
-  if (mDrawObserver) {
-    mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::PutImageData);
-  }
-
   if (aW == 0 || aH == 0) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   IntRect dirtyRect;
   IntRect imageDataRect(0, 0, aW, aH);
 
   if (aHasDirtyRect) {
@@ -5515,39 +5100,21 @@ already_AddRefed<ImageData> CanvasRender
 already_AddRefed<ImageData> CanvasRenderingContext2D::CreateImageData(
     JSContext* aCx, ImageData& aImagedata, ErrorResult& aError) {
   return mozilla::dom::CreateImageData(aCx, this, aImagedata.Width(),
                                        aImagedata.Height(), aError);
 }
 
 static uint8_t g2DContextLayerUserData;
 
-uint32_t CanvasRenderingContext2D::SkiaGLTex() const {
-  if (!mTarget) {
-    return 0;
-  }
-  MOZ_ASSERT(IsTargetValid());
-  return (uint32_t)(uintptr_t)mTarget->GetNativeSurface(
-      NativeSurfaceType::OPENGL_TEXTURE);
-}
-
-void CanvasRenderingContext2D::RemoveDrawObserver() {
-  if (mDrawObserver) {
-    delete mDrawObserver;
-    mDrawObserver = nullptr;
-  }
-}
-
 already_AddRefed<Layer> CanvasRenderingContext2D::GetCanvasLayer(
     nsDisplayListBuilder* aBuilder, Layer* aOldLayer, LayerManager* aManager) {
-  if (mOpaque || mIsSkiaGL) {
+  if (mOpaque) {
     // If we're opaque then make sure we have a surface so we paint black
     // instead of transparent.
-    // If we're using SkiaGL, then SkiaGLTex() below needs the target to
-    // be accessible.
     EnsureTarget();
   }
 
   // Don't call EnsureTarget() ... if there isn't already a surface, then
   // we have nothing to paint and there is no need to create a surface just
   // to paint nothing. Also, EnsureTarget() can cause creation of a persistent
   // layer manager which must NOT happen during a paint.
   if (!mBufferProvider && !IsTargetValid()) {
@@ -5558,26 +5125,16 @@ already_AddRefed<Layer> CanvasRenderingC
   }
 
   if (!mResetLayer && aOldLayer) {
     auto userData = static_cast<CanvasRenderingContext2DUserData*>(
         aOldLayer->GetUserData(&g2DContextLayerUserData));
 
     CanvasInitializeData data;
 
-    if (mIsSkiaGL) {
-      GLuint skiaGLTex = SkiaGLTex();
-      if (skiaGLTex) {
-        SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
-        MOZ_ASSERT(glue);
-        data.mGLContext = glue->GetGLContext();
-        data.mFrontbufferGLTex = skiaGLTex;
-      }
-    }
-
     data.mBufferProvider = mBufferProvider;
 
     if (userData && userData->IsForContext(this) &&
         static_cast<CanvasLayer*>(aOldLayer)
             ->CreateOrGetCanvasRenderer()
             ->IsDataValid(data)) {
       RefPtr<Layer> ret = aOldLayer;
       return ret.forget();
@@ -5614,21 +5171,19 @@ already_AddRefed<Layer> CanvasRenderingC
 
   mResetLayer = false;
 
   return canvasLayer.forget();
 }
 
 bool CanvasRenderingContext2D::UpdateWebRenderCanvasData(
     nsDisplayListBuilder* aBuilder, WebRenderCanvasData* aCanvasData) {
-  if (mOpaque || mIsSkiaGL) {
+  if (mOpaque) {
     // If we're opaque then make sure we have a surface so we paint black
     // instead of transparent.
-    // If we're using SkiaGL, then SkiaGLTex() below needs the target to
-    // be accessible.
     EnsureTarget();
   }
 
   // Don't call EnsureTarget() ... if there isn't already a surface, then
   // we have nothing to paint and there is no need to create a surface just
   // to paint nothing. Also, EnsureTarget() can cause creation of a persistent
   // layer manager which must NOT happen during a paint.
   if (!mBufferProvider && !IsTargetValid()) {
@@ -5640,25 +5195,16 @@ bool CanvasRenderingContext2D::UpdateWeb
     return false;
   }
 
   CanvasRenderer* renderer = aCanvasData->GetCanvasRenderer();
 
   if (!mResetLayer && renderer) {
     CanvasInitializeData data;
 
-    if (mIsSkiaGL) {
-      GLuint skiaGLTex = SkiaGLTex();
-      if (skiaGLTex) {
-        SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
-        MOZ_ASSERT(glue);
-        data.mGLContext = glue->GetGLContext();
-        data.mFrontbufferGLTex = skiaGLTex;
-      }
-    }
     data.mBufferProvider = mBufferProvider;
 
     if (renderer->IsDataValid(data)) {
       return true;
     }
   }
 
   renderer = aCanvasData->CreateCanvasRenderer();
@@ -5690,26 +5236,16 @@ bool CanvasRenderingContext2D::Initializ
     EnsureTarget();
     ReturnTarget();
     if (!mBufferProvider) {
       MarkContextClean();
       return false;
     }
   }
 
-  if (mIsSkiaGL) {
-    GLuint skiaGLTex = SkiaGLTex();
-    if (skiaGLTex) {
-      SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
-      MOZ_ASSERT(glue);
-      data.mGLContext = glue->GetGLContext();
-      data.mFrontbufferGLTex = skiaGLTex;
-    }
-  }
-
   data.mBufferProvider = mBufferProvider;
 
   aRenderer->Initialize(data);
   aRenderer->SetDirty();
   return true;
 }
 
 void CanvasRenderingContext2D::MarkContextClean() {
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -371,24 +371,16 @@ class CanvasRenderingContext2D final : p
       CurrentState().imageSmoothingEnabled = aImageSmoothingEnabled;
     }
   }
 
   void DrawWindow(nsGlobalWindowInner& aWindow, double aX, double aY, double aW,
                   double aH, const nsAString& aBgColor, uint32_t aFlags,
                   mozilla::ErrorResult& aError);
 
-  enum RenderingMode {
-    SoftwareBackendMode,
-    OpenGLBackendMode,
-    DefaultBackendMode
-  };
-
-  bool SwitchRenderingMode(RenderingMode aRenderingMode);
-
   // Eventually this should be deprecated. Keeping for now to keep the binding
   // functional.
   void Demote();
 
   nsresult Redraw();
 
   gfx::IntSize GetSize() const { return gfx::IntSize(mWidth, mHeight); }
   virtual int32_t GetWidth() override { return GetSize().width; }
@@ -504,19 +496,16 @@ class CanvasRenderingContext2D final : p
   // Given a point, return hit region ID if it exists
   nsString GetHitRegion(const mozilla::gfx::Point& aPoint) override;
 
   // return true and fills in the bound rect if element has a hit region.
   bool GetHitRegionRect(Element* aElement, nsRect& aRect) override;
 
   void OnShutdown();
 
-  // Check the global setup, as well as the compositor type:
-  bool AllowOpenGLCanvas() const;
-
   /**
    * Update CurrentState().filter with the filter description for
    * CurrentState().filterChain.
    * Flushes the PresShell, so the world can change if you call this function.
    */
   void UpdateFilter();
 
  protected:
@@ -611,27 +600,22 @@ class CanvasRenderingContext2D final : p
   void FillRuleChanged();
 
   /**
    * Create the backing surfacing, if it doesn't exist. If there is an error
    * in creating the target then it will put sErrorTarget in place. If there
    * is in turn an error in creating the sErrorTarget then they would both
    * be null so IsTargetValid() would still return null.
    *
-   * Returns the actual rendering mode being used by the created target.
+   * Returns true on success.
    */
-  RenderingMode EnsureTarget(
-      const gfx::Rect* aCoveredRect = nullptr,
-      RenderingMode aRenderMode = RenderingMode::DefaultBackendMode);
+  bool EnsureTarget(const gfx::Rect* aCoveredRect = nullptr);
 
   void RestoreClipsAndTransformToTarget();
 
-  bool TrySkiaGLTarget(RefPtr<gfx::DrawTarget>& aOutDT,
-                       RefPtr<layers::PersistentBufferProvider>& aOutProvider);
-
   bool TrySharedTarget(RefPtr<gfx::DrawTarget>& aOutDT,
                        RefPtr<layers::PersistentBufferProvider>& aOutProvider);
 
   bool TryBasicTarget(RefPtr<gfx::DrawTarget>& aOutDT,
                       RefPtr<layers::PersistentBufferProvider>& aOutProvider);
 
   void RegisterAllocation();
 
@@ -699,29 +683,16 @@ class CanvasRenderingContext2D final : p
 
   nsString& GetFont() {
     /* will initilize the value if not set, else does nothing */
     GetCurrentFontStyle();
 
     return CurrentState().font;
   }
 
-  // This function maintains a list of raw pointers to cycle-collected
-  // objects. We need to ensure that no entries persist beyond unlink,
-  // since the objects are logically destructed at that point.
-  static std::vector<CanvasRenderingContext2D*>& DemotableContexts();
-  static void DemoteOldestContextIfNecessary();
-
-  static void AddDemotableContext(CanvasRenderingContext2D* aContext);
-  static void RemoveDemotableContext(CanvasRenderingContext2D* aContext);
-
-  RenderingMode mRenderingMode;
-
-  layers::LayersBackend mCompositorBackend;
-
   // Member vars
   int32_t mWidth, mHeight;
 
   // This is true when the canvas is valid, but of zero size, this requires
   // specific behavior on some operations.
   bool mZero;
 
   // The two ways to set the opaqueness of the canvas.
@@ -737,42 +708,31 @@ class CanvasRenderingContext2D final : p
   // mContextAttributesHasAlpha in UpdateIsOpaque().
   bool mOpaque;
 
   // This is true when the next time our layer is retrieved we need to
   // recreate it (i.e. our backing surface changed)
   bool mResetLayer;
   // This is needed for drawing in drawAsyncXULElement
   bool mIPC;
-  // True if the current DrawTarget is using skia-gl, used so we can avoid
-  // requesting the DT from mBufferProvider to check.
-  bool mIsSkiaGL;
 
   bool mHasPendingStableStateCallback;
 
   nsTArray<CanvasRenderingContext2DUserData*> mUserDatas;
 
   // If mCanvasElement is not provided, then a docshell is
   nsCOMPtr<nsIDocShell> mDocShell;
 
   // This is created lazily so it is necessary to call EnsureTarget before
   // accessing it. In the event of an error it will be equal to
   // sErrorTarget.
   RefPtr<mozilla::gfx::DrawTarget> mTarget;
 
   RefPtr<mozilla::layers::PersistentBufferProvider> mBufferProvider;
 
-  uint32_t SkiaGLTex() const;
-
-  // This observes our draw calls at the beginning of the canvas
-  // lifetime and switches to software or GPU mode depending on
-  // what it thinks is best
-  CanvasDrawObserver* mDrawObserver;
-  void RemoveDrawObserver();
-
   RefPtr<CanvasShutdownObserver> mShutdownObserver;
   void RemoveShutdownObserver();
   bool AlreadyShutDown() const { return !mShutdownObserver; }
 
   /**
    * Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever
    * Redraw is called, reset to false when Render is called.
    */
@@ -914,18 +874,16 @@ class CanvasRenderingContext2D final : p
   /**
    * Implementation of the fillText, strokeText, and measure functions with
    * the operation abstracted to a flag.
    */
   nsresult DrawOrMeasureText(const nsAString& aText, float aX, float aY,
                              const Optional<double>& aMaxWidth,
                              TextDrawOperation aOp, float* aWidth);
 
-  bool CheckSizeForSkiaGL(mozilla::gfx::IntSize aSize);
-
   // A clip or a transform, recorded and restored in order.
   struct ClipState {
     explicit ClipState(mozilla::gfx::Path* aClip) : clip(aClip) {}
 
     explicit ClipState(const mozilla::gfx::Matrix& aTransform)
         : transform(aTransform) {}
 
     bool IsClip() const { return !!clip; }
--- a/dom/canvas/OffscreenCanvas.cpp
+++ b/dom/canvas/OffscreenCanvas.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "mozilla/layers/AsyncCanvasRenderer.h"
 #include "mozilla/layers/CanvasClient.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/Telemetry.h"
 #include "CanvasRenderingContext2D.h"
 #include "CanvasUtils.h"
+#include "GLContext.h"
 #include "GLScreenBuffer.h"
 #include "WebGL1Context.h"
 #include "WebGL2Context.h"
 
 namespace mozilla {
 namespace dom {
 
 OffscreenCanvasCloneData::OffscreenCanvasCloneData(
--- a/dom/canvas/test/test_canvas.html
+++ b/dom/canvas/test/test_canvas.html
@@ -38,27 +38,16 @@ function IsAzureSkia() {
   try {
     var backend = Cc["@mozilla.org/gfx/info;1"].getService(SpecialPowers.Ci.nsIGfxInfo).getInfo().AzureCanvasBackend;
     enabled = (backend == "skia");
   } catch (e) { }
 
   return enabled;
 }
 
-function IsAcceleratedSkia() {
-  var enabled = false;
-
-  try {
-    var props = Cc["@mozilla.org/gfx/info;1"].getService(SpecialPowers.Ci.nsIGfxInfo).getInfo();
-    enabled = props.AzureCanvasBackend == "skia" && props.AzureCanvasAccelerated;
-  } catch(e) { }
-
-  return enabled;
-}
-
 function IsAzureCairo() {
   var enabled = false;
   
   try {
     var backend = Cc["@mozilla.org/gfx/info;1"].getService(SpecialPowers.Ci.nsIGfxInfo).getInfo().AzureCanvasBackend;
     enabled = (backend == "cairo");
   } catch (e) { }
 
@@ -6580,19 +6569,16 @@ isPixel(ctx, 98,48, 0,255,0,255, 0);
 
 <p>Canvas test: 2d.gradient.radial.inside1</p>
 <canvas id="c240" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
 <script>
 
 
 function test_2d_gradient_radial_inside1() {
 
-if (IsAcceleratedSkia())
-  return;
-
 var canvas = document.getElementById('c240');
 var ctx = canvas.getContext('2d');
 
 ctx.fillStyle = '#f00';
 ctx.fillRect(0, 0, 100, 50);
 
 var g = ctx.createRadialGradient(50, 25, 100, 50, 25, 200);
 g.addColorStop(0, '#0f0');
--- a/dom/html/HTMLAudioElement.cpp
+++ b/dom/html/HTMLAudioElement.cpp
@@ -15,22 +15,41 @@
 #include "nsJSUtils.h"
 #include "AudioSampleFormat.h"
 #include <algorithm>
 #include "nsComponentManagerUtils.h"
 #include "nsIHttpChannel.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "AudioStream.h"
 
-NS_IMPL_NS_NEW_HTML_ELEMENT(Audio)
+nsGenericHTMLElement* NS_NewHTMLAudioElement(
+    already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
+    mozilla::dom::FromParser aFromParser) {
+  mozilla::dom::HTMLAudioElement* element =
+      new mozilla::dom::HTMLAudioElement(std::move(aNodeInfo));
+  element->Init();
+  return element;
+}
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_ELEMENT_CLONE(HTMLAudioElement)
+nsresult HTMLAudioElement::Clone(mozilla::dom::NodeInfo* aNodeInfo,
+                                 nsINode** aResult) const {
+  *aResult = nullptr;
+  RefPtr<mozilla::dom::NodeInfo> ni(aNodeInfo);
+  HTMLAudioElement* it = new HTMLAudioElement(ni.forget());
+  it->Init();
+  nsCOMPtr<nsINode> kungFuDeathGrip = it;
+  nsresult rv = const_cast<HTMLAudioElement*>(this)->CopyInnerTo(it);
+  if (NS_SUCCEEDED(rv)) {
+    kungFuDeathGrip.swap(*aResult);
+  }
+  return rv;
+}
 
 HTMLAudioElement::HTMLAudioElement(already_AddRefed<NodeInfo>&& aNodeInfo)
     : HTMLMediaElement(std::move(aNodeInfo)) {
   DecoderDoctorLogger::LogConstruction(this);
 }
 
 HTMLAudioElement::~HTMLAudioElement() {
   DecoderDoctorLogger::LogDestruction(this);
@@ -49,17 +68,18 @@ already_AddRefed<HTMLAudioElement> HTMLA
   if (!win || !(doc = win->GetExtantDoc())) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   RefPtr<mozilla::dom::NodeInfo> nodeInfo = doc->NodeInfoManager()->GetNodeInfo(
       nsGkAtoms::audio, nullptr, kNameSpaceID_XHTML, ELEMENT_NODE);
 
-  RefPtr<HTMLAudioElement> audio = new HTMLAudioElement(nodeInfo.forget());
+  RefPtr<HTMLAudioElement> audio =
+      static_cast<HTMLAudioElement*>(NS_NewHTMLAudioElement(nodeInfo.forget()));
   audio->SetHTMLAttr(nsGkAtoms::preload, NS_LITERAL_STRING("auto"), aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   if (aSrc.WasPassed()) {
     audio->SetSrc(aSrc.Value(), aRv);
   }
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3494,23 +3494,37 @@ HTMLMediaElement::HTMLMediaElement(
       mWatchManager(this,
                     OwnerDoc()->AbstractMainThreadFor(TaskCategory::Other)),
       mMainThreadEventTarget(OwnerDoc()->EventTargetFor(TaskCategory::Other)),
       mAbstractMainThread(
           OwnerDoc()->AbstractMainThreadFor(TaskCategory::Other)),
       mShutdownObserver(new ShutdownObserver),
       mPlayed(new TimeRanges(ToSupports(OwnerDoc()))),
       mPaused(true, "HTMLMediaElement::mPaused"),
-      mAudioTrackList(new AudioTrackList(OwnerDoc()->GetParentObject(), this)),
-      mVideoTrackList(new VideoTrackList(OwnerDoc()->GetParentObject(), this)),
       mErrorSink(new ErrorSink(this)),
       mAudioChannelWrapper(new AudioChannelAgentCallback(this)),
       mSink(MakePair(nsString(), RefPtr<AudioDeviceInfo>())) {
   MOZ_ASSERT(mMainThreadEventTarget);
   MOZ_ASSERT(mAbstractMainThread);
+  // Please don't add anything to this constructor or the initialization
+  // list that can cause AddRef to be called. This prevents subclasses
+  // from overriding AddRef in a way that works with our refcount
+  // logging mechanisms. Put these things inside of the ::Init method
+  // instead.
+}
+
+void HTMLMediaElement::Init() {
+  MOZ_ASSERT(mRefCnt == 0 && !mRefCnt.IsPurple(),
+             "HTMLMediaElement::Init called when AddRef has been called "
+             "at least once already, probably in the constructor. Please "
+             "see the documentation in the HTMLMediaElement constructor.");
+  MOZ_ASSERT(!mRefCnt.IsPurple());
+
+  mAudioTrackList = new AudioTrackList(OwnerDoc()->GetParentObject(), this);
+  mVideoTrackList = new VideoTrackList(OwnerDoc()->GetParentObject(), this);
 
   DecoderDoctorLogger::LogConstruction(this);
 
   mWatchManager.Watch(mPaused, &HTMLMediaElement::UpdateWakeLock);
 
   ErrorResult rv;
 
   double defaultVolume = Preferences::GetFloat("media.default_volume", 1.0);
@@ -3521,19 +3535,22 @@ HTMLMediaElement::HTMLMediaElement(
 
   // We initialize the MediaShutdownManager as the HTMLMediaElement is always
   // constructed on the main thread, and not during stable state.
   // (MediaShutdownManager make use of nsIAsyncShutdownClient which is written
   // in JS)
   MediaShutdownManager::InitStatics();
 
   mShutdownObserver->Subscribe(this);
+  mInitialized = true;
 }
 
 HTMLMediaElement::~HTMLMediaElement() {
+  MOZ_ASSERT(mInitialized,
+             "HTMLMediaElement must be initialized before it is destroyed.");
   NS_ASSERTION(
       !mHasSelfReference,
       "How can we be destroyed if we're still holding a self reference?");
 
   mShutdownObserver->Unsubscribe();
 
   if (mVideoFrameContainer) {
     mVideoFrameContainer->ForgetElement();
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -112,16 +112,17 @@ class HTMLMediaElement : public nsGeneri
 
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(HTMLMediaElement)
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
   CORSMode GetCORSMode() { return mCORSMode; }
 
   explicit HTMLMediaElement(
       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
+  void Init();
 
   void ReportCanPlayTelemetry();
 
   /**
    * This is used when the browser is constructing a video element to play
    * a channel that we've already started loading. The src attribute and
    * <source> children are ignored.
    * @param aChannel the channel to use
@@ -1745,16 +1746,19 @@ class HTMLMediaElement : public nsGeneri
 
   // True if media has ever been blocked by autoplay policy before.
   bool mHasPlayEverBeenBlocked = false;
 
   // Report the Telemetry about whether media played over the specific time
   // threshold.
   void ReportPlayedTimeAfterBlockedTelemetry();
 
+  // True if Init() has been called after construction
+  bool mInitialized = false;
+
   // True if user has called load(), seek() or element has started playing
   // before. It's *only* use for checking autoplay policy
   bool mIsBlessed = false;
 
   // True if the first frame has been successfully loaded.
   bool mFirstFrameLoaded = false;
 
   // Media elements also have a default playback start position, which must
--- a/dom/html/HTMLVideoElement.cpp
+++ b/dom/html/HTMLVideoElement.cpp
@@ -30,24 +30,43 @@
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/Performance.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "mozilla/dom/VideoPlaybackQuality.h"
 
 #include <algorithm>
 #include <limits>
 
-NS_IMPL_NS_NEW_HTML_ELEMENT(Video)
+nsGenericHTMLElement* NS_NewHTMLVideoElement(
+    already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
+    mozilla::dom::FromParser aFromParser) {
+  mozilla::dom::HTMLVideoElement* element =
+      new mozilla::dom::HTMLVideoElement(std::move(aNodeInfo));
+  element->Init();
+  return element;
+}
 
 namespace mozilla {
 namespace dom {
 
 static bool sVideoStatsEnabled;
 
-NS_IMPL_ELEMENT_CLONE(HTMLVideoElement)
+nsresult HTMLVideoElement::Clone(mozilla::dom::NodeInfo* aNodeInfo,
+                                 nsINode** aResult) const {
+  *aResult = nullptr;
+  RefPtr<mozilla::dom::NodeInfo> ni(aNodeInfo);
+  HTMLVideoElement* it = new HTMLVideoElement(ni.forget());
+  it->Init();
+  nsCOMPtr<nsINode> kungFuDeathGrip = it;
+  nsresult rv = const_cast<HTMLVideoElement*>(this)->CopyInnerTo(it);
+  if (NS_SUCCEEDED(rv)) {
+    kungFuDeathGrip.swap(*aResult);
+  }
+  return rv;
+}
 
 HTMLVideoElement::HTMLVideoElement(already_AddRefed<NodeInfo>&& aNodeInfo)
     : HTMLMediaElement(std::move(aNodeInfo)), mIsOrientationLocked(false) {
   DecoderDoctorLogger::LogConstruction(this);
 }
 
 HTMLVideoElement::~HTMLVideoElement() {
   DecoderDoctorLogger::LogDestruction(this);
@@ -303,17 +322,18 @@ void HTMLVideoElement::ReleaseVideoWakeL
     ErrorResult rv;
     mScreenWakeLock->Unlock(rv);
     rv.SuppressException();
     mScreenWakeLock = nullptr;
     return;
   }
 }
 
-void HTMLVideoElement::Init() {
+/* static */
+void HTMLVideoElement::InitStatics() {
   Preferences::AddBoolVarCache(&sVideoStatsEnabled,
                                "media.video_stats.enabled");
 }
 
 /* static */
 bool HTMLVideoElement::IsVideoStatsEnabled() { return sVideoStatsEnabled; }
 
 double HTMLVideoElement::TotalPlayTime() const {
--- a/dom/html/HTMLVideoElement.h
+++ b/dom/html/HTMLVideoElement.h
@@ -33,17 +33,17 @@ class HTMLVideoElement final : public HT
   virtual bool IsVideo() const override { return true; }
 
   virtual bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
                               const nsAString& aValue,
                               nsIPrincipal* aMaybeScriptedPrincipal,
                               nsAttrValue& aResult) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
 
-  static void Init();
+  static void InitStatics();
 
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction()
       const override;
 
   virtual nsresult Clone(NodeInfo*, nsINode** aResult) const override;
 
   // Set size with the current video frame's height and width.
   // If there is no video frame, returns NS_ERROR_FAILURE.
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -1631,16 +1631,17 @@ void nsTextEditorState::SetSelectionRang
     }
     SelectionProperties& props = GetSelectionProperties();
     changed = props.GetStart() != aStart || props.GetEnd() != aEnd ||
               props.GetDirection() != aDirection;
     props.SetStart(aStart);
     props.SetEnd(aEnd);
     props.SetDirection(aDirection);
   } else {
+    MOZ_ASSERT(mBoundFrame, "Our frame should still be valid");
     WeakPtr<nsTextEditorState> self(this);
     aRv = mBoundFrame->SetSelectionRange(aStart, aEnd, aDirection);
     if (aRv.Failed() || !self.get()) {
       return;
     }
     if (mBoundFrame) {
       rv = mBoundFrame->ScrollSelectionIntoView();
     }
@@ -2456,19 +2457,18 @@ bool nsTextEditorState::SetValue(const n
 
     // If we've reached the point where the root node has been created, we
     // can assume that it's safe to notify.
     ValueWasChanged(!!mBoundFrame);
   }
 
   // TODO(emilio): It seems wrong to pass ValueChangeKind::Script if
   // BySetUserInput is in aFlags.
-  auto changeKind = (aFlags & eSetValue_Internal)
-    ? ValueChangeKind::Internal
-    : ValueChangeKind::Script;
+  auto changeKind = (aFlags & eSetValue_Internal) ? ValueChangeKind::Internal
+                                                  : ValueChangeKind::Script;
 
   // XXX Should we stop notifying "value changed" if mTextCtrlElement has
   //     been cleared?
   textControlElement->OnValueChanged(/* aNotify = */ !!mBoundFrame, changeKind);
   return true;
 }
 
 bool nsTextEditorState::HasNonEmptyValue() {
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1268,17 +1268,18 @@ void ContentChild::InitXPCOM(
   // Set the dynamic scalar definitions for this process.
   TelemetryIPC::AddDynamicScalarDefinitions(aXPCOMInit.dynamicScalarDefs());
 
   DOMPrefs::Initialize();
 }
 
 mozilla::ipc::IPCResult ContentChild::RecvRequestMemoryReport(
     const uint32_t& aGeneration, const bool& aAnonymize,
-    const bool& aMinimizeMemoryUsage, const MaybeFileDesc& aDMDFile) {
+    const bool& aMinimizeMemoryUsage,
+    const Maybe<mozilla::ipc::FileDescriptor>& aDMDFile) {
   nsCString process;
   GetProcessName(process);
   AppendProcessId(process);
 
   MemoryReportRequestClient::Start(
       aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, process,
       [&](const MemoryReport& aReport) {
         Unused << GetSingleton()->SendAddMemoryReport(aReport);
@@ -1606,17 +1607,17 @@ static bool StartMacOSContentSandbox() {
     MOZ_CRASH("sandbox_init() failed");
   }
 
   return true;
 }
 #endif
 
 mozilla::ipc::IPCResult ContentChild::RecvSetProcessSandbox(
-    const MaybeFileDesc& aBroker) {
+    const Maybe<mozilla::ipc::FileDescriptor>& aBroker) {
   // We may want to move the sandbox initialization somewhere else
   // at some point; see bug 880808.
 #if defined(MOZ_CONTENT_SANDBOX)
   bool sandboxEnabled = true;
 #  if defined(XP_LINUX)
   // On Linux, we have to support systems that can't use any sandboxing.
   if (!SandboxInfo::Get().CanSandboxContent()) {
     sandboxEnabled = false;
@@ -3913,9 +3914,9 @@ nsresult GetRepoDir(nsIFile** aRepoDir) 
 }
 
 nsresult GetObjDir(nsIFile** aObjDir) {
   MOZ_ASSERT(IsDevelopmentBuild());
   return GetDirFromBundlePlist(NS_LITERAL_STRING(MAC_DEV_OBJ_KEY), aObjDir);
 }
 #endif /* XP_MACOSX */
 
-}  // namespace mozilla
\ No newline at end of file
+}  // namespace mozilla
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -183,22 +183,22 @@ class ContentChild final : public PConte
 
   mozilla::ipc::IPCResult RecvReinitRendering(
       Endpoint<PCompositorManagerChild>&& aCompositor,
       Endpoint<PImageBridgeChild>&& aImageBridge,
       Endpoint<PVRManagerChild>&& aVRBridge,
       Endpoint<PVideoDecoderManagerChild>&& aVideoManager,
       nsTArray<uint32_t>&& namespaces);
 
-  virtual mozilla::ipc::IPCResult RecvAudioDefaultDeviceChange();
+  mozilla::ipc::IPCResult RecvAudioDefaultDeviceChange();
 
   mozilla::ipc::IPCResult RecvReinitRenderingForDeviceReset();
 
-  virtual mozilla::ipc::IPCResult RecvSetProcessSandbox(
-      const MaybeFileDesc& aBroker);
+  mozilla::ipc::IPCResult RecvSetProcessSandbox(
+      const Maybe<FileDescriptor>& aBroker);
 
   PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
                                     const TabId& aSameTabGroupAs,
                                     const IPCTabContext& aContext,
                                     const uint32_t& aChromeFlags,
                                     const ContentParentId& aCpID,
                                     const bool& aIsForBrowser);
 
@@ -356,17 +356,17 @@ class ContentChild final : public PConte
                                                 const nsCString& aKey,
                                                 const DataStorageType& aType);
 
   mozilla::ipc::IPCResult RecvDataStorageClear(const nsString& aFilename);
 
   mozilla::ipc::IPCResult RecvNotifyAlertsObserver(const nsCString& aType,
                                                    const nsString& aData);
 
-  virtual mozilla::ipc::IPCResult RecvLoadProcessScript(const nsString& aURL);
+  mozilla::ipc::IPCResult RecvLoadProcessScript(const nsString& aURL);
 
   mozilla::ipc::IPCResult RecvAsyncMessage(const nsString& aMsg,
                                            InfallibleTArray<CpowEntry>&& aCpows,
                                            const IPC::Principal& aPrincipal,
                                            const ClonedMessageData& aData);
 
   mozilla::ipc::IPCResult RecvRegisterStringBundles(
       nsTArray<StringBundleDescriptor>&& stringBundles);
@@ -571,17 +571,17 @@ class ContentChild final : public PConte
 
   mozilla::ipc::IPCResult RecvBlobURLUnregistration(const nsCString& aURI);
 
   mozilla::ipc::IPCResult RecvFileCreationResponse(
       const nsID& aUUID, const FileCreationResult& aResult);
 
   mozilla::ipc::IPCResult RecvRequestMemoryReport(
       const uint32_t& generation, const bool& anonymize,
-      const bool& minimizeMemoryUsage, const MaybeFileDesc& DMDFile);
+      const bool& minimizeMemoryUsage, const Maybe<FileDescriptor>& DMDFile);
 
   mozilla::ipc::IPCResult RecvSetXPCOMProcessAttributes(
       const XPCOMInitData& aXPCOMInit, const StructuredCloneData& aInitialData,
       nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache,
       nsTArray<SystemFontListEntry>&& aFontList);
 
   mozilla::ipc::IPCResult RecvProvideAnonymousTemporaryFile(
       const uint64_t& aID, const FileDescOrError& aFD);
@@ -817,9 +817,9 @@ class ContentChild final : public PConte
   DISALLOW_EVIL_CONSTRUCTORS(ContentChild);
 };
 
 uint64_t NextWindowID();
 
 }  // namespace dom
 }  // namespace mozilla
 
-#endif  // mozilla_dom_ContentChild_h
\ No newline at end of file
+#endif  // mozilla_dom_ContentChild_h
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2563,39 +2563,39 @@ void ContentParent::InitInternal(Process
   if (NS_SUCCEEDED(
           mozilla::widget::GetAudioSessionData(id, sessionName, iconPath))) {
     Unused << SendSetAudioSessionData(id, sessionName, iconPath);
   }
 #endif
 
 #ifdef MOZ_CONTENT_SANDBOX
   bool shouldSandbox = true;
-  MaybeFileDesc brokerFd = void_t();
+  Maybe<FileDescriptor> brokerFd;
   // XXX: Checking the pref here makes it possible to enable/disable sandboxing
   // during an active session. Currently the pref is only used for testing
   // purpose. If the decision is made to permanently rely on the pref, this
   // should be changed so that it is required to restart firefox for the change
   // of value to take effect.
   shouldSandbox = IsContentSandboxEnabled();
 
 #  ifdef XP_LINUX
   if (shouldSandbox) {
     MOZ_ASSERT(!mSandboxBroker);
     bool isFileProcess = mRemoteType.EqualsLiteral(FILE_REMOTE_TYPE);
     UniquePtr<SandboxBroker::Policy> policy =
         sSandboxBrokerPolicyFactory->GetContentPolicy(Pid(), isFileProcess);
     if (policy) {
-      brokerFd = FileDescriptor();
+      brokerFd = Some(FileDescriptor());
       mSandboxBroker =
-          SandboxBroker::Create(std::move(policy), Pid(), brokerFd);
+          SandboxBroker::Create(std::move(policy), Pid(), brokerFd.ref());
       if (!mSandboxBroker) {
         KillHard("SandboxBroker::Create failed");
         return;
       }
-      MOZ_ASSERT(static_cast<const FileDescriptor&>(brokerFd).IsValid());
+      MOZ_ASSERT(brokerFd.ref().IsValid());
     }
   }
 #  endif
   if (shouldSandbox && !SendSetProcessSandbox(brokerFd)) {
     KillHard("SandboxInitFailed");
   }
 #endif
 
@@ -3450,20 +3450,19 @@ ContentParent::AllocPHeapSnapshotTempFil
 }
 
 bool ContentParent::DeallocPHeapSnapshotTempFileHelperParent(
     devtools::PHeapSnapshotTempFileHelperParent* aHeapSnapshotHelper) {
   delete aHeapSnapshotHelper;
   return true;
 }
 
-bool ContentParent::SendRequestMemoryReport(const uint32_t& aGeneration,
-                                            const bool& aAnonymize,
-                                            const bool& aMinimizeMemoryUsage,
-                                            const MaybeFileDesc& aDMDFile) {
+bool ContentParent::SendRequestMemoryReport(
+    const uint32_t& aGeneration, const bool& aAnonymize,
+    const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile) {
   // This automatically cancels the previous request.
   mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
   Unused << PContentParent::SendRequestMemoryReport(
       aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult ContentParent::RecvAddMemoryReport(
@@ -5918,9 +5917,9 @@ mozilla::ipc::IPCResult ContentParent::R
 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
 
 NS_IMETHODIMP
 ParentIdleListener::Observe(nsISupports*, const char* aTopic,
                             const char16_t* aData) {
   mozilla::Unused << mParent->SendNotifyIdleObserver(
       mObserver, nsDependentCString(aTopic), nsDependentString(aData));
   return NS_OK;
-}
\ No newline at end of file
+}
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1165,17 +1165,17 @@ class ContentParent final : public PCont
 
  public:
   void SendGetFilesResponseAndForget(const nsID& aID,
                                      const GetFilesResponseResult& aResult);
 
   bool SendRequestMemoryReport(const uint32_t& aGeneration,
                                const bool& aAnonymize,
                                const bool& aMinimizeMemoryUsage,
-                               const MaybeFileDesc& aDMDFile) override;
+                               const Maybe<FileDescriptor>& aDMDFile) override;
 
   nsresult SaveRecording(nsIFile* aFile, bool* aRetval);
 
   bool IsRecordingOrReplaying() const {
     return mRecordReplayState != eNotRecordingOrReplaying;
   }
 
   void OnBrowsingContextGroupSubscribe(BrowsingContextGroup* aGroup);
--- a/dom/ipc/MemoryReportRequest.cpp
+++ b/dom/ipc/MemoryReportRequest.cpp
@@ -45,23 +45,21 @@ MemoryReportRequestHost::~MemoryReportRe
   if (mReporterManager) {
     mReporterManager->EndProcessReport(mGeneration, mSuccess);
     mReporterManager = nullptr;
   }
 }
 
 NS_IMPL_ISUPPORTS(MemoryReportRequestClient, nsIRunnable)
 
-/* static */
-void MemoryReportRequestClient::Start(uint32_t aGeneration, bool aAnonymize,
-                                      bool aMinimizeMemoryUsage,
-                                      const MaybeFileDesc& aDMDFile,
-                                      const nsACString& aProcessString,
-                                      const ReportCallback& aReportCallback,
-                                      const FinishCallback& aFinishCallback) {
+/* static */ void MemoryReportRequestClient::Start(
+    uint32_t aGeneration, bool aAnonymize, bool aMinimizeMemoryUsage,
+    const Maybe<FileDescriptor>& aDMDFile, const nsACString& aProcessString,
+    const ReportCallback& aReportCallback,
+    const FinishCallback& aFinishCallback) {
   RefPtr<MemoryReportRequestClient> request = new MemoryReportRequestClient(
       aGeneration, aAnonymize, aDMDFile, aProcessString, aReportCallback,
       aFinishCallback);
 
   DebugOnly<nsresult> rv;
   if (aMinimizeMemoryUsage) {
     nsCOMPtr<nsIMemoryReporterManager> mgr =
         do_GetService("@mozilla.org/memory-reporter-manager;1");
@@ -70,26 +68,27 @@ void MemoryReportRequestClient::Start(ui
   } else {
     rv = request->Run();
   }
 
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "actor operation failed");
 }
 
 MemoryReportRequestClient::MemoryReportRequestClient(
-    uint32_t aGeneration, bool aAnonymize, const MaybeFileDesc& aDMDFile,
-    const nsACString& aProcessString, const ReportCallback& aReportCallback,
+    uint32_t aGeneration, bool aAnonymize,
+    const Maybe<FileDescriptor>& aDMDFile, const nsACString& aProcessString,
+    const ReportCallback& aReportCallback,
     const FinishCallback& aFinishCallback)
     : mGeneration(aGeneration),
       mAnonymize(aAnonymize),
       mProcessString(aProcessString),
       mReportCallback(aReportCallback),
       mFinishCallback(aFinishCallback) {
-  if (aDMDFile.type() == MaybeFileDesc::TFileDescriptor) {
-    mDMDFile = aDMDFile.get_FileDescriptor();
+  if (aDMDFile.isSome()) {
+    mDMDFile = aDMDFile.value();
   }
 }
 
 MemoryReportRequestClient::~MemoryReportRequestClient() {}
 
 class HandleReportCallback final : public nsIHandleReportCallback {
  public:
   using ReportCallback = typename MemoryReportRequestClient::ReportCallback;
--- a/dom/ipc/MemoryReportRequest.h
+++ b/dom/ipc/MemoryReportRequest.h
@@ -13,17 +13,16 @@
 
 #include <functional>
 
 class nsMemoryReporterManager;
 
 namespace mozilla {
 namespace dom {
 
-class MaybeFileDesc;
 class MemoryReport;
 
 class MemoryReportRequestHost final {
  public:
   explicit MemoryReportRequestHost(uint32_t aGeneration);
   ~MemoryReportRequestHost();
 
   void RecvReport(const MemoryReport& aReport);
@@ -39,26 +38,27 @@ class MemoryReportRequestHost final {
 class MemoryReportRequestClient final : public nsIRunnable {
  public:
   using ReportCallback = std::function<void(const MemoryReport&)>;
   using FinishCallback = std::function<bool(const uint32_t&)>;
 
   NS_DECL_ISUPPORTS
 
   static void Start(uint32_t aGeneration, bool aAnonymize,
-                    bool aMinimizeMemoryUsage, const MaybeFileDesc& aDMDFile,
+                    bool aMinimizeMemoryUsage,
+                    const Maybe<mozilla::ipc::FileDescriptor>& aDMDFile,
                     const nsACString& aProcessString,
                     const ReportCallback& aReportCallback,
                     const FinishCallback& aFinishCallback);
 
   NS_IMETHOD Run() override;
 
  private:
   MemoryReportRequestClient(uint32_t aGeneration, bool aAnonymize,
-                            const MaybeFileDesc& aDMDFile,
+                            const Maybe<mozilla::ipc::FileDescriptor>& aDMDFile,
                             const nsACString& aProcessString,
                             const ReportCallback& aReportCallback,
                             const FinishCallback& aFinishCallback);
 
  private:
   ~MemoryReportRequestClient();
 
   uint32_t mGeneration;
--- a/dom/ipc/MemoryReportTypes.ipdlh
+++ b/dom/ipc/MemoryReportTypes.ipdlh
@@ -13,15 +13,10 @@ struct MemoryReport {
   nsCString path;
   int32_t kind;
   int32_t units;
   int64_t amount;
   uint32_t generation;
   nsCString desc;
 };
 
-union MaybeFileDesc {
-    FileDescriptor;
-    void_t;
-};
-
 }
 }
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -430,22 +430,22 @@ child:
     // Re-create the rendering stack for a device reset.
     async ReinitRenderingForDeviceReset();
 
     /**
      * Enable system-level sandboxing features, if available.  Can
      * usually only be performed zero or one times.  The child may
      * abnormally exit if this fails; the details are OS-specific.
      */
-    async SetProcessSandbox(MaybeFileDesc aBroker);
+    async SetProcessSandbox(FileDescriptor? aBroker);
 
     async RequestMemoryReport(uint32_t generation,
                               bool anonymize,
                               bool minimizeMemoryUsage,
-                              MaybeFileDesc DMDFile);
+                              FileDescriptor? DMDFile);
     async RequestPerformanceMetrics(nsID aID);
 
     /**
      * Communication between the PuppetBidiKeyboard and the actual
      * BidiKeyboard hosted by the parent
      */
     async BidiKeyboardNotify(bool isLangRTL, bool haveBidiKeyboards);
 
@@ -1289,9 +1289,9 @@ both:
     async WindowClose(BrowsingContext aContext, bool aTrustedCaller);
     async WindowFocus(BrowsingContext aContext);
     async WindowBlur(BrowsingContext aContext);
     async WindowPostMessage(BrowsingContext aContext, ClonedMessageData aMessage,
                             PostMessageData aData);
 };
 
 }
-}
\ No newline at end of file
+}
--- a/dom/ipc/PermissionMessageUtils.cpp
+++ b/dom/ipc/PermissionMessageUtils.cpp
@@ -1,59 +1,42 @@
 /* -*- 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 "mozilla/dom/PermissionMessageUtils.h"
-#include "nsISerializable.h"
-#include "nsSerializationHelper.h"
+#include "mozilla/ipc/BackgroundUtils.h"
 
-namespace IPC {
+namespace mozilla {
+namespace ipc {
 
-void ParamTraits<nsIPrincipal>::Write(Message* aMsg, nsIPrincipal* aParam) {
-  bool isNull = !aParam;
-  WriteParam(aMsg, isNull);
-  if (isNull) {
-    return;
+void IPDLParamTraits<nsIPrincipal>::Write(IPC::Message* aMsg, IProtocol* aActor,
+                                          nsIPrincipal* aParam) {
+  MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
+
+  Maybe<PrincipalInfo> info;
+  if (aParam) {
+    info.emplace();
+    nsresult rv = PrincipalToPrincipalInfo(aParam, info.ptr());
+    MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
   }
 
-  nsCString principalString;
-  nsresult rv = NS_SerializeToString(aParam, principalString);
-  if (NS_FAILED(rv)) {
-    MOZ_CRASH("Unable to serialize principal.");
-    return;
-  }
-
-  WriteParam(aMsg, principalString);
+  WriteIPDLParam(aMsg, aActor, info);
 }
 
-bool ParamTraits<nsIPrincipal>::Read(const Message* aMsg, PickleIterator* aIter,
-                                     RefPtr<nsIPrincipal>* aResult) {
-  bool isNull;
-  if (!ReadParam(aMsg, aIter, &isNull)) {
+bool IPDLParamTraits<nsIPrincipal>::Read(const IPC::Message* aMsg,
+                                         PickleIterator* aIter,
+                                         IProtocol* aActor,
+                                         RefPtr<nsIPrincipal>* aResult) {
+  Maybe<PrincipalInfo> info;
+  if (!ReadIPDLParam(aMsg, aIter, aActor, &info)) {
     return false;
   }
 
-  if (isNull) {
-    *aResult = nullptr;
-    return true;
-  }
-
-  nsCString principalString;
-  if (!ReadParam(aMsg, aIter, &principalString)) {
-    return false;
-  }
-
-  nsCOMPtr<nsISupports> iSupports;
-  nsresult rv =
-      NS_DeserializeObject(principalString, getter_AddRefs(iSupports));
-  NS_ENSURE_SUCCESS(rv, false);
-
-  nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(iSupports);
-  NS_ENSURE_TRUE(principal, false);
-
-  *aResult = principal.forget();
-  return true;
+  nsresult rv = NS_OK;
+  *aResult = info ? PrincipalInfoToPrincipal(info.ref(), &rv) : nullptr;
+  return NS_SUCCEEDED(rv);
 }
 
-}  // namespace IPC
+}  // namespace ipc
+}  // namespace mozilla
--- a/dom/ipc/PermissionMessageUtils.h
+++ b/dom/ipc/PermissionMessageUtils.h
@@ -2,34 +2,28 @@
 /* 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_dom_permission_message_utils_h__
 #define mozilla_dom_permission_message_utils_h__
 
+#include "mozilla/ipc/IPDLParamTraits.h"
 #include "ipc/IPCMessageUtils.h"
 #include "nsCOMPtr.h"
 #include "nsIPrincipal.h"
 
 namespace IPC {
 
-template <>
-struct ParamTraits<nsIPrincipal> {
-  static void Write(Message* aMsg, nsIPrincipal* aParam);
-  static bool Read(const Message* aMsg, PickleIterator* aIter,
-                   RefPtr<nsIPrincipal>* aResult);
-};
-
 /**
  * Legacy IPC::Principal type. Use nsIPrincipal directly in new IPDL code.
  */
 class Principal {
-  friend struct ParamTraits<Principal>;
+  friend struct mozilla::ipc::IPDLParamTraits<Principal>;
 
  public:
   Principal() : mPrincipal(nullptr) {}
 
   explicit Principal(nsIPrincipal* aPrincipal) : mPrincipal(aPrincipal) {}
 
   operator nsIPrincipal*() const { return mPrincipal.get(); }
 
@@ -37,23 +31,49 @@ class Principal {
     mPrincipal = aOther.mPrincipal;
     return *this;
   }
 
  private:
   RefPtr<nsIPrincipal> mPrincipal;
 };
 
+}  // namespace IPC
+
+namespace mozilla {
+namespace ipc {
+
 template <>
-struct ParamTraits<Principal> {
-  typedef Principal paramType;
-  static void Write(Message* aMsg, const paramType& aParam) {
-    WriteParam(aMsg, aParam.mPrincipal);
-  }
-  static bool Read(const Message* aMsg, PickleIterator* aIter,
-                   paramType* aResult) {
-    return ReadParam(aMsg, aIter, &aResult->mPrincipal);
+struct IPDLParamTraits<nsIPrincipal> {
+  static void Write(IPC::Message* aMsg, IProtocol* aActor,
+                    nsIPrincipal* aParam);
+  static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
+                   IProtocol* aActor, RefPtr<nsIPrincipal>* aResult);
+
+  // Overload to support deserializing nsCOMPtr<nsIPrincipal> directly.
+  static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
+                   IProtocol* aActor, nsCOMPtr<nsIPrincipal>* aResult) {
+    RefPtr<nsIPrincipal> result;
+    if (!Read(aMsg, aIter, aActor, &result)) {
+      return false;
+    }
+    *aResult = result.forget();
+    return true;
   }
 };
 
-}  // namespace IPC
+template <>
+struct IPDLParamTraits<IPC::Principal> {
+  typedef IPC::Principal paramType;
+  static void Write(IPC::Message* aMsg, IProtocol* aActor,
+                    const paramType& aParam) {
+    WriteIPDLParam(aMsg, aActor, aParam.mPrincipal);
+  }
+  static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
+                   IProtocol* aActor, paramType* aResult) {
+    return ReadIPDLParam(aMsg, aIter, aActor, &aResult->mPrincipal);
+  }
+};
+
+}  // namespace ipc
+}  // namespace mozilla
 
 #endif  // mozilla_dom_permission_message_utils_h__
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "MediaFormatReader.h"
 
 #include "AllocationPolicy.h"
+#include "GeckoProfiler.h"
 #include "MediaData.h"
 #include "MediaInfo.h"
 #include "VideoFrameContainer.h"
 #include "VideoUtils.h"
 #include "mozilla/AbstractThread.h"
 #include "mozilla/CDMProxy.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/NotNull.h"
@@ -2626,16 +2627,17 @@ void MediaFormatReader::SkipVideoDemuxTo
   mVideo.mTrackDemuxer->SkipToNextRandomAccessPoint(aTimeThreshold)
       ->Then(OwnerThread(), __func__, this,
              &MediaFormatReader::OnVideoSkipCompleted,
              &MediaFormatReader::OnVideoSkipFailed)
       ->Track(mSkipRequest);
 }
 
 void MediaFormatReader::VideoSkipReset(uint32_t aSkipped) {
+  PROFILER_ADD_MARKER("SkippedVideoDecode", GRAPHICS);
   MOZ_ASSERT(OnTaskQueue());
 
   // Some frames may have been output by the decoder since we initiated the
   // videoskip process and we know they would be late.
   DropDecodedSamples(TrackInfo::kVideoTrack);
   // Report the pending frames as dropped.
   if (mFrameStats) {
     mFrameStats->Accumulate({0, 0, SizeOfVideoQueueInFrames(), 0});
--- a/dom/media/ipc/PRDD.ipdl
+++ b/dom/media/ipc/PRDD.ipdl
@@ -16,27 +16,27 @@ namespace mozilla {
 // (RemoteDataDecoder) process. There is one instance of this protocol,
 // with the RDDParent living on the main thread of the RDD process and
 // the RDDChild living on the main thread of the UI process.
 protocol PRDD
 {
 parent:
 
   // args TBD, sent by UI process to initiate core settings
-  async Init(MaybeFileDesc sandboxBroker);
+  async Init(FileDescriptor? sandboxBroker);
 
   async InitProfiler(Endpoint<PProfilerChild> endpoint);
 
   async NewContentRemoteDecoderManager(
             Endpoint<PRemoteDecoderManagerParent> endpoint);
 
   async RequestMemoryReport(uint32_t generation,
                             bool anonymize,
                             bool minimizeMemoryUsage,
-                            MaybeFileDesc DMDFile);
+                            FileDescriptor? DMDFile);
 
 child:
   // args TBD, sent when init complete. Occurs once, after Init().
   async InitComplete();
 
   async InitCrashReporter(Shmem shmem, NativeThreadId threadId);
 
   async AddMemoryReport(MemoryReport aReport);
--- a/dom/media/ipc/RDDChild.cpp
+++ b/dom/media/ipc/RDDChild.cpp
@@ -24,30 +24,30 @@ using namespace layers;
 
 RDDChild::RDDChild(RDDProcessHost* aHost) : mHost(aHost), mRDDReady(false) {
   MOZ_COUNT_CTOR(RDDChild);
 }
 
 RDDChild::~RDDChild() { MOZ_COUNT_DTOR(RDDChild); }
 
 bool RDDChild::Init() {
-  MaybeFileDesc brokerFd = void_t();
+  Maybe<FileDescriptor> brokerFd;
 
 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
   auto policy = SandboxBrokerPolicyFactory::GetUtilityPolicy(OtherPid());
   if (policy != nullptr) {
-    brokerFd = FileDescriptor();
+    brokerFd = Some(FileDescriptor());
     mSandboxBroker =
-        SandboxBroker::Create(std::move(policy), OtherPid(), brokerFd);
+        SandboxBroker::Create(std::move(policy), OtherPid(), brokerFd.ref());
     // This is unlikely to fail and probably indicates OS resource
     // exhaustion, but we can at least try to recover.
     if (NS_WARN_IF(mSandboxBroker == nullptr)) {
       return false;
     }
-    MOZ_ASSERT(static_cast<const FileDescriptor&>(brokerFd).IsValid());
+    MOZ_ASSERT(brokerFd.ref().IsValid());
   }
 #endif  // XP_LINUX && MOZ_SANDBOX
 
   SendInit(brokerFd);
 
 #ifdef MOZ_GECKO_PROFILER
   Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
 #endif
@@ -80,17 +80,17 @@ mozilla::ipc::IPCResult RDDChild::RecvIn
                                                       aShmem, aThreadId);
 
   return IPC_OK();
 }
 
 bool RDDChild::SendRequestMemoryReport(const uint32_t& aGeneration,
                                        const bool& aAnonymize,
                                        const bool& aMinimizeMemoryUsage,
-                                       const MaybeFileDesc& aDMDFile) {
+                                       const Maybe<FileDescriptor>& aDMDFile) {
   mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
   Unused << PRDDChild::SendRequestMemoryReport(aGeneration, aAnonymize,
                                                aMinimizeMemoryUsage, aDMDFile);
   return true;
 }
 
 mozilla::ipc::IPCResult RDDChild::RecvAddMemoryReport(
     const MemoryReport& aReport) {
--- a/dom/media/ipc/RDDChild.h
+++ b/dom/media/ipc/RDDChild.h
@@ -44,17 +44,17 @@ class RDDChild final : public PRDDChild 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   mozilla::ipc::IPCResult RecvAddMemoryReport(const MemoryReport& aReport);
   mozilla::ipc::IPCResult RecvFinishMemoryReport(const uint32_t& aGeneration);
 
   bool SendRequestMemoryReport(const uint32_t& aGeneration,
                                const bool& aAnonymize,
                                const bool& aMinimizeMemoryUsage,
-                               const MaybeFileDesc& aDMDFile);
+                               const Maybe<ipc::FileDescriptor>& aDMDFile);
 
   static void Destroy(UniquePtr<RDDChild>&& aChild);
 
  private:
   RDDProcessHost* mHost;
   UniquePtr<ipc::CrashReporterHost> mCrashReporter;
   UniquePtr<MemoryReportRequestHost> mMemoryReportRequest;
 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
--- a/dom/media/ipc/RDDParent.cpp
+++ b/dom/media/ipc/RDDParent.cpp
@@ -123,25 +123,26 @@ static void StartRDDMacSandbox() {
   bool rv = mozilla::StartMacSandbox(info, err);
   if (!rv) {
     NS_WARNING(err.c_str());
     MOZ_CRASH("mozilla::StartMacSandbox failed");
   }
 }
 #endif
 
-mozilla::ipc::IPCResult RDDParent::RecvInit(const MaybeFileDesc& aBrokerFd) {
+mozilla::ipc::IPCResult RDDParent::RecvInit(
+    const Maybe<FileDescriptor>& aBrokerFd) {
   Unused << SendInitComplete();
 #if defined(MOZ_SANDBOX)
 #  if defined(XP_MACOSX)
   StartRDDMacSandbox();
 #  elif defined(XP_LINUX)
   int fd = -1;
-  if (aBrokerFd.type() == MaybeFileDesc::TFileDescriptor) {
-    fd = aBrokerFd.get_FileDescriptor().ClonePlatformHandle().release();
+  if (aBrokerFd.isSome()) {
+    fd = aBrokerFd.value().ClonePlatformHandle().release();
   }
   SetRemoteDataDecoderSandbox(fd);
 #  endif  // XP_MACOSX/XP_LINUX
 #endif    // MOZ_SANDBOX
 
   return IPC_OK();
 }
 
@@ -158,17 +159,17 @@ mozilla::ipc::IPCResult RDDParent::RecvN
   if (!RemoteDecoderManagerParent::CreateForContent(std::move(aEndpoint))) {
     return IPC_FAIL_NO_REASON(this);
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult RDDParent::RecvRequestMemoryReport(
     const uint32_t& aGeneration, const bool& aAnonymize,
-    const bool& aMinimizeMemoryUsage, const MaybeFileDesc& aDMDFile) {
+    const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile) {
   nsPrintfCString processName("RDD (pid %u)", (unsigned)getpid());
 
   mozilla::dom::MemoryReportRequestClient::Start(
       aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, processName,
       [&](const MemoryReport& aReport) {
         Unused << GetSingleton()->SendAddMemoryReport(aReport);
       },
       [&](const uint32_t& aGeneration) {
--- a/dom/media/ipc/RDDParent.h
+++ b/dom/media/ipc/RDDParent.h
@@ -19,25 +19,26 @@ class RDDParent final : public PRDDParen
   RDDParent();
   ~RDDParent();
 
   static RDDParent* GetSingleton();
 
   bool Init(base::ProcessId aParentPid, const char* aParentBuildID,
             MessageLoop* aIOLoop, IPC::Channel* aChannel);
 
-  mozilla::ipc::IPCResult RecvInit(const MaybeFileDesc& aBrokerFd);
+  mozilla::ipc::IPCResult RecvInit(const Maybe<ipc::FileDescriptor>& aBrokerFd);
   mozilla::ipc::IPCResult RecvInitProfiler(
       Endpoint<PProfilerChild>&& aEndpoint);
 
   mozilla::ipc::IPCResult RecvNewContentRemoteDecoderManager(
       Endpoint<PRemoteDecoderManagerParent>&& aEndpoint);
   mozilla::ipc::IPCResult RecvRequestMemoryReport(
       const uint32_t& generation, const bool& anonymize,
-      const bool& minimizeMemoryUsage, const MaybeFileDesc& DMDFile);
+      const bool& minimizeMemoryUsage,
+      const Maybe<ipc::FileDescriptor>& DMDFile);
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
  private:
   const TimeStamp mLaunchTime;
 #ifdef MOZ_GECKO_PROFILER
   RefPtr<ChildProfilerController> mProfilerController;
 #endif
--- a/dom/media/ipc/RDDProcessManager.cpp
+++ b/dom/media/ipc/RDDProcessManager.cpp
@@ -216,20 +216,20 @@ base::ProcessId RDDProcessManager::RDDPr
 }
 
 class RDDMemoryReporter : public MemoryReportingProcess {
  public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RDDMemoryReporter, override)
 
   bool IsAlive() const override { return !!GetChild(); }
 
-  bool SendRequestMemoryReport(const uint32_t& aGeneration,
-                               const bool& aAnonymize,
-                               const bool& aMinimizeMemoryUsage,
-                               const dom::MaybeFileDesc& aDMDFile) override {
+  bool SendRequestMemoryReport(
+      const uint32_t& aGeneration, const bool& aAnonymize,
+      const bool& aMinimizeMemoryUsage,
+      const Maybe<ipc::FileDescriptor>& aDMDFile) override {
     RDDChild* child = GetChild();
     if (!child) {
       return false;
     }
 
     return child->SendRequestMemoryReport(aGeneration, aAnonymize,
                                           aMinimizeMemoryUsage, aDMDFile);
   }
--- a/dom/media/mediasink/VideoSink.cpp
+++ b/dom/media/mediasink/VideoSink.cpp
@@ -5,18 +5,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifdef XP_WIN
 // Include Windows headers required for enabling high precision timers.
 #  include "windows.h"
 #  include "mmsystem.h"
 #endif
 
+#include "VideoSink.h"
+
+#include "GeckoProfiler.h"
 #include "MediaQueue.h"
-#include "VideoSink.h"
 #include "VideoUtils.h"
 
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/StaticPrefs.h"
 
 namespace mozilla {
 
 extern LazyLogModule gMediaDecoderLog;
@@ -446,16 +448,20 @@ void VideoSink::UpdateRenderedVideoFrame
     } else {
       droppedCount++;
       VSINK_LOG_V("discarding video frame mTime=%" PRId64
                   " clock_time=%" PRId64,
                   frame->mTime.ToMicroseconds(), clockTime.ToMicroseconds());
     }
   }
 
+  if (droppedCount > 0) {
+    PROFILER_ADD_MARKER("DroppedUncompositedVideoFrames", GRAPHICS);
+  }
+
   if (droppedCount || sentToCompositorCount) {
     uint32_t totalCompositorDroppedCount = mContainer->GetDroppedImageCount();
     uint32_t compositorDroppedCount =
         totalCompositorDroppedCount - mOldCompositorDroppedCount;
     if (compositorDroppedCount > 0) {
       mOldCompositorDroppedCount = totalCompositorDroppedCount;
       VSINK_LOG_V("%u video frame previously discarded by compositor",
                   compositorDroppedCount);
--- a/dom/media/platforms/android/AndroidDecoderModule.cpp
+++ b/dom/media/platforms/android/AndroidDecoderModule.cpp
@@ -21,17 +21,16 @@
   MOZ_LOG(                                                \
       sAndroidDecoderModuleLog, mozilla::LogLevel::Debug, \
       ("AndroidDecoderModule(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
 #define SLOG(arg, ...)                                        \
   MOZ_LOG(sAndroidDecoderModuleLog, mozilla::LogLevel::Debug, \
           ("%s: " arg, __func__, ##__VA_ARGS__))
 
 using namespace mozilla;
-using namespace mozilla::gl;
 using namespace mozilla::java::sdk;
 using media::TimeUnit;
 
 namespace mozilla {
 
 mozilla::LazyLogModule sAndroidDecoderModuleLog("AndroidDecoderModule");
 
 const nsCString TranslateMimeType(const nsACString& aMimeType) {
--- a/dom/serviceworkers/ServiceWorkerRegistrar.cpp
+++ b/dom/serviceworkers/ServiceWorkerRegistrar.cpp
@@ -109,17 +109,17 @@ nsresult CreatePrincipalInfo(nsILineInpu
   rv = GetOrigin(aEntry->scope(), origin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // CSP will be applied during the script load.
   nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
   aEntry->principal() = mozilla::ipc::ContentPrincipalInfo(
-      attrs, origin, aEntry->scope(), std::move(policies));
+      attrs, origin, aEntry->scope(), Nothing(), std::move(policies));
 
   return NS_OK;
 }
 
 }  // namespace
 
 NS_IMPL_ISUPPORTS(ServiceWorkerRegistrar, nsIObserver, nsIAsyncShutdownBlocker)
 
--- a/dom/serviceworkers/ServiceWorkerScriptCache.h
+++ b/dom/serviceworkers/ServiceWorkerScriptCache.h
@@ -40,17 +40,16 @@ class CompareCallback {
                                 const nsACString& aMaxScope,
                                 nsLoadFlags aLoadFlags) = 0;
 
   NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
 };
 
 nsresult Compare(ServiceWorkerRegistrationInfo* aRegistration,
                  nsIPrincipal* aPrincipal, const nsAString& aCacheName,
-                 const nsAString& aURL, CompareCallback* aCallback,
-                 nsILoadGroup* aLoadGroup);
+                 const nsAString& aURL, CompareCallback* aCallback);
 
 }  // namespace serviceWorkerScriptCache
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_ServiceWorkerScriptCache_h
--- a/dom/serviceworkers/test/gtest/TestReadWrite.cpp
+++ b/dom/serviceworkers/test/gtest/TestReadWrite.cpp
@@ -269,17 +269,18 @@ TEST(ServiceWorkerRegistrar, TestWriteDa
       reg.currentWorkerActivatedTime() = PR_Now();
       reg.lastUpdateTime() = PR_Now();
 
       nsAutoCString spec;
       spec.AppendPrintf("spec write %d", i);
 
       nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
       reg.principal() = mozilla::ipc::ContentPrincipalInfo(
-          mozilla::OriginAttributes(i, i % 2), spec, spec, std::move(policies));
+          mozilla::OriginAttributes(i, i % 2), spec, spec, mozilla::Nothing(),
+          std::move(policies));
 
       swr->TestRegisterServiceWorker(reg);
     }
 
     nsresult rv = swr->TestWriteData();
     ASSERT_EQ(NS_OK, rv) << "WriteData() should not fail";
   }
 
@@ -858,17 +859,18 @@ TEST(ServiceWorkerRegistrar, TestDedupeW
       reg.updateViaCache() =
           nsIServiceWorkerRegistrationInfo::UPDATE_VIA_CACHE_IMPORTS;
 
       nsAutoCString spec;
       spec.AppendPrintf("spec write dedupe/%d", i);
 
       nsTArray<mozilla::ipc::ContentSecurityPolicy> policies;
       reg.principal() = mozilla::ipc::ContentPrincipalInfo(
-          mozilla::OriginAttributes(0, false), spec, spec, std::move(policies));
+          mozilla::OriginAttributes(0, false), spec, spec, mozilla::Nothing(),
+          std::move(policies));
 
       swr->TestRegisterServiceWorker(reg);
     }
 
     nsresult rv = swr->TestWriteData();
     ASSERT_EQ(NS_OK, rv) << "WriteData() should not fail";
   }
 
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -61,17 +61,16 @@ struct ID3D11Texture2D;
 struct ID3D11Device;
 struct ID2D1Device;
 struct ID2D1DeviceContext;
 struct IDWriteFactory;
 struct IDWriteRenderingParams;
 struct IDWriteFontFace;
 struct IDWriteFontCollection;
 
-class GrContext;
 class SkCanvas;
 struct gfxFontStyle;
 
 struct CGContext;
 typedef struct CGContext *CGContextRef;
 
 struct CGFont;
 typedef CGFont *CGFontRef;
@@ -1503,23 +1502,16 @@ class DrawTarget : public external::Atom
    * This can be useful if the DrawTarget is wrapped around data that it does
    * not own, and for some reason the owner of the data has to make it
    * temporarily unavailable without the DrawTarget knowing about it. This can
    * cause costly surface copies, so it should not be used without a a good
    * reason.
    */
   virtual void DetachAllSnapshots() = 0;
 
-#ifdef USE_SKIA_GPU
-  virtual bool InitWithGrContext(GrContext *aGrContext, const IntSize &aSize,
-                                 SurfaceFormat aFormat) {
-    MOZ_CRASH("GFX: InitWithGrContext");
-  }
-#endif
-
  protected:
   UserData mUserData;
   Matrix mTransform;
   IntRect mOpaqueRect;
   bool mTransformDirty : 1;
   bool mPermitSubpixelAA : 1;
 
   SurfaceFormat mFormat;
@@ -1744,21 +1736,16 @@ class GFX2D_API Factory {
   static LogForwarder *GetLogForwarder() {
     return sConfig ? sConfig->mLogForwarder : nullptr;
   }
 
  private:
   static Config *sConfig;
 
  public:
-#ifdef USE_SKIA_GPU
-  static already_AddRefed<DrawTarget> CreateDrawTargetSkiaWithGrContext(
-      GrContext *aGrContext, const IntSize &aSize, SurfaceFormat aFormat);
-#endif
-
   static void PurgeAllCaches();
 
   static already_AddRefed<DrawTarget> CreateDualDrawTarget(DrawTarget *targetA,
                                                            DrawTarget *targetB);
 
   static already_AddRefed<SourceSurface> CreateDualSourceSurface(
       SourceSurface *sourceA, SourceSurface *sourceB);
 
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -24,23 +24,16 @@
 #include "Logging.h"
 #include "Tools.h"
 #include "DataSurfaceHelpers.h"
 #include "PathHelpers.h"
 #include "SourceSurfaceCapture.h"
 #include "Swizzle.h"
 #include <algorithm>
 
-#ifdef USE_SKIA_GPU
-#  include "GLDefs.h"
-#  include "skia/include/gpu/GrContext.h"
-#  include "skia/include/gpu/GrTexture.h"
-#  include "skia/include/gpu/gl/GrGLInterface.h"
-#endif
-
 #ifdef MOZ_WIDGET_COCOA
 #  include "BorrowedContext.h"
 #  include <ApplicationServices/ApplicationServices.h>
 #  include "ScaledFontMac.h"
 #  include "CGTextDrawing.h"
 #endif
 
 #ifdef XP_WIN
@@ -644,21 +637,16 @@ void DrawTargetSkia::DrawSurface(SourceS
   if (aSurfOptions.mSamplingFilter == SamplingFilter::POINT) {
     paint.mPaint.setFilterQuality(kNone_SkFilterQuality);
   }
 
   mCanvas->drawImageRect(image, sourceRect, destRect, &paint.mPaint);
 }
 
 DrawTargetType DrawTargetSkia::GetType() const {
-#ifdef USE_SKIA_GPU
-  if (mGrContext) {
-    return DrawTargetType::HARDWARE_RASTER;
-  }
-#endif
   return DrawTargetType::SOFTWARE_RASTER;
 }
 
 void DrawTargetSkia::DrawFilter(FilterNode* aNode, const Rect& aSourceRect,
                                 const Point& aDestPoint,
                                 const DrawOptions& aOptions) {
   FilterNodeSoftware* filter = static_cast<FilterNodeSoftware*>(aNode);
   filter->Draw(this, aSourceRect, aDestPoint, aOptions);
@@ -695,20 +683,19 @@ void DrawTargetSkia::DrawSurfaceWithShad
   // to blur the image ourselves.
 
   SkPaint shadowPaint;
   shadowPaint.setBlendMode(GfxOpToSkiaOp(aOperator));
 
   auto shadowDest = IntPoint::Round(aDest + aOffset);
 
   SkBitmap blurMask;
-  if (!UsingSkiaGPU() && ExtractAlphaBitmap(image, &blurMask)) {
-    // Prefer using our own box blur instead of Skia's when we're
-    // not using the GPU. It currently performs much better than
-    // SkBlurImageFilter or SkBlurMaskFilter on the CPU.
+  if (ExtractAlphaBitmap(image, &blurMask)) {
+    // Prefer using our own box blur instead of Skia's. It currently performs
+    // much better than SkBlurImageFilter or SkBlurMaskFilter on the CPU.
     AlphaBoxBlur blur(Rect(0, 0, blurMask.width(), blurMask.height()),
                       int32_t(blurMask.rowBytes()), aSigma, aSigma);
     blur.Blur(reinterpret_cast<uint8_t*>(blurMask.getPixels()));
     blurMask.notifyPixelsChanged();
 
     shadowPaint.setColor(ColorToSkColor(aColor, 1.0f));
 
     mCanvas->drawBitmap(blurMask, shadowDest.x, shadowDest.y, &shadowPaint);
@@ -1582,28 +1569,16 @@ already_AddRefed<SourceSurface> DrawTarg
   }
 
   return newSurf.forget();
 }
 
 already_AddRefed<DrawTarget> DrawTargetSkia::CreateSimilarDrawTarget(
     const IntSize& aSize, SurfaceFormat aFormat) const {
   RefPtr<DrawTargetSkia> target = new DrawTargetSkia();
-#ifdef USE_SKIA_GPU
-  if (UsingSkiaGPU()) {
-    // Try to create a GPU draw target first if we're currently using the GPU.
-    // Mark the DT as cached so that shadow DTs, extracted subrects, and similar
-    // can be reused.
-    if (target->InitWithGrContext(mGrContext.get(), aSize, aFormat, true)) {
-      return target.forget();
-    }
-    // Otherwise, just fall back to a software draw target.
-  }
-#endif
-
 #ifdef DEBUG
   if (!IsBackedByPixels(mCanvas)) {
     // If our canvas is backed by vector storage such as PDF then we want to
     // create a new DrawTarget with similar storage to avoid losing fidelity
     // (fidelity will be lost if the returned DT is Snapshot()'ed and drawn
     // back onto us since a raster will be drawn instead of vector commands).
     NS_WARNING("Not backed by pixels - we need to handle PDF backed SkCanvas");
   }
@@ -1615,67 +1590,19 @@ already_AddRefed<DrawTarget> DrawTargetS
   return target.forget();
 }
 
 bool DrawTargetSkia::CanCreateSimilarDrawTarget(const IntSize& aSize,
                                                 SurfaceFormat aFormat) const {
   return size_t(std::max(aSize.width, aSize.height)) < GetMaxSurfaceSize();
 }
 
-bool DrawTargetSkia::UsingSkiaGPU() const {
-#ifdef USE_SKIA_GPU
-  return !!mGrContext;
-#else
-  return false;
-#endif
-}
-
-#ifdef USE_SKIA_GPU
-already_AddRefed<SourceSurface> DrawTargetSkia::OptimizeGPUSourceSurface(
-    SourceSurface* aSurface) const {
-  // Check if the underlying SkImage already has an associated GrTexture.
-  sk_sp<SkImage> image = GetSkImageForSurface(aSurface);
-  if (!image || image->isTextureBacked()) {
-    RefPtr<SourceSurface> surface(aSurface);
-    return surface.forget();
-  }
-
-  // Upload the SkImage to a GrTexture otherwise.
-  sk_sp<SkImage> texture = image->makeTextureImage(mGrContext.get(), nullptr);
-  if (texture) {
-    // Create a new SourceSurfaceSkia whose SkImage contains the GrTexture.
-    RefPtr<SourceSurfaceSkia> surface = new SourceSurfaceSkia();
-    if (surface->InitFromImage(texture, aSurface->GetFormat())) {
-      return surface.forget();
-    }
-  }
-
-  // The data was too big to fit in a GrTexture.
-  if (aSurface->GetType() == SurfaceType::SKIA) {
-    // It is already a Skia source surface, so just reuse it as-is.
-    RefPtr<SourceSurface> surface(aSurface);
-    return surface.forget();
-  }
-
-  // Wrap it in a Skia source surface so that can do tiled uploads on-demand.
-  RefPtr<SourceSurfaceSkia> surface = new SourceSurfaceSkia();
-  surface->InitFromImage(image);
-  return surface.forget();
-}
-#endif
-
 already_AddRefed<SourceSurface>
 DrawTargetSkia::OptimizeSourceSurfaceForUnknownAlpha(
     SourceSurface* aSurface) const {
-#ifdef USE_SKIA_GPU
-  if (UsingSkiaGPU()) {
-    return OptimizeGPUSourceSurface(aSurface);
-  }
-#endif
-
   if (aSurface->GetType() == SurfaceType::SKIA) {
     RefPtr<SourceSurface> surface(aSurface);
     return surface.forget();
   }
 
   RefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface();
   DataSourceSurface::ScopedMap map(dataSurface, DataSourceSurface::READ_WRITE);
 
@@ -1685,22 +1612,16 @@ DrawTargetSkia::OptimizeSourceSurfaceFor
   // writes some bad data. Luckily, this only happens on plugins.
   WriteRGBXFormat(map.GetData(), dataSurface->GetSize(), map.GetStride(),
                   dataSurface->GetFormat());
   return dataSurface.forget();
 }
 
 already_AddRefed<SourceSurface> DrawTargetSkia::OptimizeSourceSurface(
     SourceSurface* aSurface) const {
-#ifdef USE_SKIA_GPU
-  if (UsingSkiaGPU()) {
-    return OptimizeGPUSourceSurface(aSurface);
-  }
-#endif
-
   if (aSurface->GetType() == SurfaceType::SKIA) {
     RefPtr<SourceSurface> surface(aSurface);
     return surface.forget();
   }
 
   // If we're not using skia-gl then drawing doesn't require any
   // uploading, so any data surface is fine. Call GetDataSurface
   // to trigger any required readback so that it only happens
@@ -1709,58 +1630,19 @@ already_AddRefed<SourceSurface> DrawTarg
 #ifdef DEBUG
   DataSourceSurface::ScopedMap map(dataSurface, DataSourceSurface::READ);
   MOZ_ASSERT(VerifyRGBXFormat(map.GetData(), dataSurface->GetSize(),
                               map.GetStride(), dataSurface->GetFormat()));
 #endif
   return dataSurface.forget();
 }
 
-#ifdef USE_SKIA_GPU
-static inline GrGLenum GfxFormatToGrGLFormat(SurfaceFormat format) {
-  switch (format) {
-    case SurfaceFormat::B8G8R8A8:
-      return LOCAL_GL_BGRA8_EXT;
-    case SurfaceFormat::B8G8R8X8:
-      // We probably need to do something here.
-      return LOCAL_GL_BGRA8_EXT;
-    case SurfaceFormat::R5G6B5_UINT16:
-      return LOCAL_GL_RGB565;
-    case SurfaceFormat::A8:
-      return LOCAL_GL_ALPHA8;
-    default:
-      return LOCAL_GL_RGBA8;
-  }
-}
-#endif
-
 already_AddRefed<SourceSurface>
 DrawTargetSkia::CreateSourceSurfaceFromNativeSurface(
     const NativeSurface& aSurface) const {
-#ifdef USE_SKIA_GPU
-  if (aSurface.mType == NativeSurfaceType::OPENGL_TEXTURE && UsingSkiaGPU()) {
-    // Wrap the OpenGL texture id in a Skia texture handle.
-    GrGLTextureInfo texInfo;
-    texInfo.fTarget = LOCAL_GL_TEXTURE_2D;
-    texInfo.fID = (GrGLuint)(uintptr_t)aSurface.mSurface;
-    texInfo.fFormat = GfxFormatToGrGLFormat(aSurface.mFormat);
-    GrBackendTexture texDesc(aSurface.mSize.width, aSurface.mSize.height,
-                             GrMipMapped::kNo, texInfo);
-    sk_sp<SkImage> texture = SkImage::MakeFromAdoptedTexture(
-        mGrContext.get(), texDesc, kTopLeft_GrSurfaceOrigin,
-        GfxFormatToSkiaColorType(aSurface.mFormat),
-        GfxFormatToSkiaAlphaType(aSurface.mFormat));
-    RefPtr<SourceSurfaceSkia> newSurf = new SourceSurfaceSkia();
-    if (texture && newSurf->InitFromImage(texture, aSurface.mFormat)) {
-      return newSurf.forget();
-    }
-    return nullptr;
-  }
-#endif
-
   return nullptr;
 }
 
 void DrawTargetSkia::CopySurface(SourceSurface* aSurface,
                                  const IntRect& aSourceRect,
                                  const IntPoint& aDestination) {
   MarkChanged();
 
@@ -1833,65 +1715,16 @@ bool DrawTargetSkia::Init(SkCanvas* aCan
   mSize.width = size.width();
   mSize.height = size.height();
   mFormat =
       SkiaColorTypeToGfxFormat(imageInfo.colorType(), imageInfo.alphaType());
   SetPermitSubpixelAA(IsOpaque(mFormat));
   return true;
 }
 
-#ifdef USE_SKIA_GPU
-/** Indicating a DT should be cached means that space will be reserved in Skia's
- * cache for the render target at creation time, with any unused resources
- * exceeding the cache limits being purged. When the DT is freed, it will then
- * be guaranteed to be kept around for subsequent allocations until it gets
- * incidentally purged.
- *
- * If it is not marked as cached, no space will be purged to make room for the
- * render target in the cache. When the DT is freed, If there is space within
- * the resource limits it may be added to the cache, otherwise it will be freed
- * immediately if the cache is already full.
- *
- * If you want to ensure that the resources will be kept around for reuse, it is
- * better to mark them as cached. Such resources should be short-lived to ensure
- * they don't permanently tie up cache resource limits. Long-lived resources
- * should generally be left as uncached.
- *
- * In neither case will cache resource limits affect whether the resource
- * allocation succeeds. The amount of in-use GPU resources is allowed to exceed
- * the size of the cache. Thus, only hard GPU out-of-memory conditions will
- * cause resource allocation to fail.
- */
-bool DrawTargetSkia::InitWithGrContext(GrContext* aGrContext,
-                                       const IntSize& aSize,
-                                       SurfaceFormat aFormat, bool aCached) {
-  MOZ_ASSERT(aGrContext, "null GrContext");
-
-  if (size_t(std::max(aSize.width, aSize.height)) > GetMaxSurfaceSize()) {
-    return false;
-  }
-
-  // Create a GPU rendertarget/texture using the supplied GrContext.
-  // MakeRenderTarget also implicitly clears the underlying texture on creation.
-  mSurface = SkSurface::MakeRenderTarget(aGrContext, SkBudgeted(aCached),
-                                         MakeSkiaImageInfo(aSize, aFormat));
-  if (!mSurface) {
-    return false;
-  }
-
-  mGrContext = sk_ref_sp(aGrContext);
-  mSize = aSize;
-  mFormat = aFormat;
-  mCanvas = mSurface->getCanvas();
-  SetPermitSubpixelAA(IsOpaque(mFormat));
-  return true;
-}
-
-#endif
-
 bool DrawTargetSkia::Init(unsigned char* aData, const IntSize& aSize,
                           int32_t aStride, SurfaceFormat aFormat,
                           bool aUninitialized) {
   MOZ_ASSERT((aFormat != SurfaceFormat::B8G8R8X8) || aUninitialized ||
              VerifyRGBXFormat(aData, aSize, aStride, aFormat));
 
   mSurface = SkSurface::MakeRasterDirect(MakeSkiaImageInfo(aSize, aFormat),
                                          aData, aStride);
@@ -1909,26 +1742,16 @@ bool DrawTargetSkia::Init(unsigned char*
 void DrawTargetSkia::SetTransform(const Matrix& aTransform) {
   SkMatrix mat;
   GfxMatrixToSkiaMatrix(aTransform, mat);
   mCanvas->setMatrix(mat);
   mTransform = aTransform;
 }
 
 void* DrawTargetSkia::GetNativeSurface(NativeSurfaceType aType) {
-#ifdef USE_SKIA_GPU
-  if (aType == NativeSurfaceType::OPENGL_TEXTURE && mSurface) {
-    GrBackendTexture tex =
-        mSurface->getBackendTexture(SkSurface::kFlushRead_BackendHandleAccess);
-    GrGLTextureInfo info;
-    if (tex.getGLTextureInfo(&info)) {
-      return (void*)(uintptr_t)info.fID;
-    }
-  }
-#endif
   return nullptr;
 }
 
 already_AddRefed<PathBuilder> DrawTargetSkia::CreatePathBuilder(
     FillRule aFillRule) const {
   return MakeAndAddRef<PathBuilderSkia>(aFillRule);
 }
 
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -125,28 +125,16 @@ class DrawTargetSkia : public DrawTarget
   virtual void *GetNativeSurface(NativeSurfaceType aType) override;
   virtual void DetachAllSnapshots() override { MarkChanged(); }
 
   bool Init(const IntSize &aSize, SurfaceFormat aFormat);
   bool Init(unsigned char *aData, const IntSize &aSize, int32_t aStride,
             SurfaceFormat aFormat, bool aUninitialized = false);
   bool Init(SkCanvas *aCanvas);
 
-#ifdef USE_SKIA_GPU
-  bool InitWithGrContext(GrContext *aGrContext, const IntSize &aSize,
-                         SurfaceFormat aFormat, bool aCached);
-  virtual bool InitWithGrContext(GrContext *aGrContext, const IntSize &aSize,
-                                 SurfaceFormat aFormat) override {
-    return InitWithGrContext(aGrContext, aSize, aFormat, false);
-  }
-
-  already_AddRefed<SourceSurface> OptimizeGPUSourceSurface(
-      SourceSurface *aSurface) const;
-#endif
-
   // Skia assumes that texture sizes fit in 16-bit signed integers.
   static size_t GetMaxSurfaceSize() { return 32767; }
 
   operator std::string() const {
     std::stringstream stream;
     stream << "DrawTargetSkia(" << this << ")";
     return stream.str();
   }
@@ -158,30 +146,24 @@ class DrawTargetSkia : public DrawTarget
 
   bool ShouldLCDRenderText(FontType aFontType, AntialiasMode aAntialiasMode);
 
   void DrawGlyphs(ScaledFont *aFont, const GlyphBuffer &aBuffer,
                   const Pattern &aPattern,
                   const StrokeOptions *aStrokeOptions = nullptr,
                   const DrawOptions &aOptions = DrawOptions());
 
-  bool UsingSkiaGPU() const;
-
   struct PushedLayer {
     PushedLayer(bool aOldPermitSubpixelAA, SourceSurface *aMask)
         : mOldPermitSubpixelAA(aOldPermitSubpixelAA), mMask(aMask) {}
     bool mOldPermitSubpixelAA;
     RefPtr<SourceSurface> mMask;
   };
   std::vector<PushedLayer> mPushedLayers;
 
-#ifdef USE_SKIA_GPU
-  sk_sp<GrContext> mGrContext;
-#endif
-
   IntSize mSize;
   sk_sp<SkSurface> mSurface;
   SkCanvas *mCanvas;
   RefPtr<SourceSurfaceSkia> mSnapshot;
   Mutex mSnapshotLock;
 
 #ifdef MOZ_WIDGET_COCOA
   friend class BorrowedCGContext;
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -915,28 +915,16 @@ already_AddRefed<ScaledFont> Factory::Cr
     IDWriteRenderingParams* aParams, Float aGamma, Float aContrast) {
   return MakeAndAddRef<ScaledFontDWrite>(aFontFace, aUnscaledFont, aSize,
                                          aUseEmbeddedBitmap, aForceGDIMode,
                                          aParams, aGamma, aContrast, aStyle);
 }
 
 #endif  // WIN32
 
-#ifdef USE_SKIA_GPU
-already_AddRefed<DrawTarget> Factory::CreateDrawTargetSkiaWithGrContext(
-    GrContext* aGrContext, const IntSize& aSize, SurfaceFormat aFormat) {
-  RefPtr<DrawTarget> newTarget = new DrawTargetSkia();
-  if (!newTarget->InitWithGrContext(aGrContext, aSize, aFormat)) {
-    return nullptr;
-  }
-  return newTarget.forget();
-}
-
-#endif  // USE_SKIA_GPU
-
 #ifdef USE_SKIA
 already_AddRefed<DrawTarget> Factory::CreateDrawTargetWithSkCanvas(
     SkCanvas* aCanvas) {
   RefPtr<DrawTargetSkia> newTarget = new DrawTargetSkia();
   if (!newTarget->Init(aCanvas)) {
     return nullptr;
   }
   return newTarget.forget();
--- a/gfx/2d/SourceSurfaceSkia.cpp
+++ b/gfx/2d/SourceSurfaceSkia.cpp
@@ -120,26 +120,16 @@ bool SourceSurfaceSkia::InitFromImage(co
 
   return true;
 }
 
 uint8_t* SourceSurfaceSkia::GetData() {
   if (!mImage) {
     return nullptr;
   }
-#ifdef USE_SKIA_GPU
-  if (mImage->isTextureBacked()) {
-    if (sk_sp<SkImage> raster =
-            ReadSkImage(mImage, MakeSkiaImageInfo(mSize, mFormat), mStride)) {
-      mImage = raster;
-    } else {
-      gfxCriticalError() << "Failed making Skia raster image for GPU surface";
-    }
-  }
-#endif
   SkPixmap pixmap;
   if (!mImage->peekPixels(&pixmap)) {
     gfxCriticalError() << "Failed accessing pixels for Skia raster image";
   }
   return reinterpret_cast<uint8_t*>(pixmap.writable_addr());
 }
 
 bool SourceSurfaceSkia::Map(MapType, MappedSurface* aMappedSurface) {
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -1442,17 +1442,17 @@ void GLContext::LoadMoreSymbols(const Sy
     fnLoadForExt(symbols, APPLE_framebuffer_multisample);
   }
 
   // Load developer symbols, don't fail if we can't find them.
   const SymLoadStruct devSymbols[] = {CORE_SYMBOL(GetTexImage),
                                       CORE_SYMBOL(GetTexLevelParameteriv),
                                       END_SYMBOLS};
   const bool warnOnFailures = ShouldSpew();
-  loader.LoadSymbols(devSymbols, warnOnFailures);
+  (void)loader.LoadSymbols(devSymbols, warnOnFailures);
 }
 
 #undef CORE_SYMBOL
 #undef CORE_EXT_SYMBOL2
 #undef EXT_SYMBOL2
 #undef EXT_SYMBOL3
 #undef END_SYMBOLS
 
deleted file mode 100644
--- a/gfx/gl/SkiaGLGlue.cpp
+++ /dev/null
@@ -1,375 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 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 "skia/include/gpu/GrContext.h"
-#include "skia/include/gpu/gl/GrGLInterface.h"
-#include "mozilla/gfx/2D.h"
-#include "mozilla/ThreadLocal.h"
-#include "mozilla/DebugOnly.h"
-
-/* SkPostConfig.h includes windows.h, which includes windef.h
- * which redefines min/max. We don't want that. */
-#ifdef _WIN32
-#  undef min
-#  undef max
-#endif
-
-#include "GLContext.h"
-#include "SkiaGLGlue.h"
-
-using mozilla::gl::GLContext;
-using mozilla::gl::GLFeature;
-using mozilla::gl::SkiaGLGlue;
-
-template <typename R, typename... A>
-static inline GrGLFunction<R (*)(A...)> WrapGL(RefPtr<GLContext> aContext,
-                                               R (GLContext::*aFunc)(A...)) {
-  return [aContext, aFunc](A... args) -> R {
-    aContext->MakeCurrent();
-    return (aContext->*aFunc)(args...);
-  };
-}
-
-template <typename R, typename... A>
-static inline GrGLFunction<R (*)(A...)> WrapGL(RefPtr<GLContext> aContext,
-                                               R (*aFunc)(GLContext*, A...)) {
-  return [aContext, aFunc](A... args) -> R {
-    aContext->MakeCurrent();
-    return (*aFunc)(aContext, args...);
-  };
-}
-
-// Core GL functions required by Ganesh
-
-static const GLubyte* glGetString_mozilla(GLContext* aContext, GrGLenum aName) {
-  // GLContext only exposes a OpenGL 2.0 style API, so we have to intercept a
-  // bunch of checks that Ganesh makes to determine which capabilities are
-  // present on the GL implementation and change them to match what GLContext
-  // actually exposes.
-
-  if (aName == LOCAL_GL_VERSION) {
-    if (aContext->IsGLES()) {
-      return reinterpret_cast<const GLubyte*>("OpenGL ES 2.0");
-    }
-    return reinterpret_cast<const GLubyte*>("2.0");
-  } else if (aName == LOCAL_GL_EXTENSIONS) {
-    // Only expose the bare minimum extensions we want to support to ensure a
-    // functional Ganesh as GLContext only exposes certain extensions
-    static bool extensionsStringBuilt = false;
-    static char extensionsString[1024];
-
-    if (!extensionsStringBuilt) {
-      extensionsString[0] = '\0';
-
-      if (aContext->IsGLES()) {
-        // OES is only applicable to GLES2
-        if (aContext->IsExtensionSupported(
-                GLContext::OES_packed_depth_stencil)) {
-          strcat(extensionsString, "GL_OES_packed_depth_stencil ");
-        }
-
-        if (aContext->IsExtensionSupported(GLContext::OES_rgb8_rgba8)) {
-          strcat(extensionsString, "GL_OES_rgb8_rgba8 ");
-        }
-
-        if (aContext->IsExtensionSupported(GLContext::OES_texture_npot)) {
-          strcat(extensionsString, "GL_OES_texture_npot ");
-        }
-
-        if (aContext->IsExtensionSupported(
-                GLContext::OES_vertex_array_object)) {
-          strcat(extensionsString, "GL_OES_vertex_array_object ");
-        }
-
-        if (aContext->IsSupported(GLFeature::standard_derivatives)) {
-          strcat(extensionsString, "GL_OES_standard_derivatives ");
-        }
-      } else {
-        if (aContext->IsSupported(GLFeature::framebuffer_object)) {
-          strcat(extensionsString, "GL_ARB_framebuffer_object ");
-        } else if (aContext->IsExtensionSupported(
-                       GLContext::EXT_framebuffer_object)) {
-          strcat(extensionsString, "GL_EXT_framebuffer_object ");
-        }
-
-        if (aContext->IsSupported(GLFeature::texture_rg)) {
-          strcat(extensionsString, "GL_ARB_texture_rg ");
-        }
-      }
-
-      if (aContext->IsExtensionSupported(
-              GLContext::EXT_texture_format_BGRA8888)) {
-        strcat(extensionsString, "GL_EXT_texture_format_BGRA8888 ");
-      }
-
-      if (aContext->IsExtensionSupported(GLContext::EXT_packed_depth_stencil)) {
-        strcat(extensionsString, "GL_EXT_packed_depth_stencil ");
-      }
-
-      if (aContext->IsExtensionSupported(GLContext::EXT_bgra)) {
-        strcat(extensionsString, "GL_EXT_bgra ");
-      }
-
-      if (aContext->IsExtensionSupported(GLContext::EXT_read_format_bgra)) {
-        strcat(extensionsString, "GL_EXT_read_format_bgra ");
-      }
-
-      extensionsStringBuilt = true;
-#ifdef DEBUG
-      printf_stderr("Exported SkiaGL extensions: %s\n", extensionsString);
-#endif
-    }
-
-    return reinterpret_cast<const GLubyte*>(extensionsString);
-
-  } else if (aName == LOCAL_GL_SHADING_LANGUAGE_VERSION) {
-    if (aContext->IsGLES()) {
-      return reinterpret_cast<const GLubyte*>("OpenGL ES GLSL ES 1.0");
-    }
-    return reinterpret_cast<const GLubyte*>("1.10");
-  }
-
-  return aContext->fGetString(aName);
-}
-
-static GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context) {
-  auto* i = new GrGLInterface();
-
-  context->MakeCurrent();
-
-  // We support both desktop GL and GLES2
-  if (context->IsGLES()) {
-    i->fStandard = kGLES_GrGLStandard;
-  } else {
-    i->fStandard = kGL_GrGLStandard;
-  }
-
-  GrGLFunction<GrGLGetStringFn> getString =
-      WrapGL(context, &glGetString_mozilla);
-  GrGLFunction<GrGLGetIntegervFn> getIntegerv =
-      WrapGL(context, &GLContext::fGetIntegerv);
-
-  GrGLExtensions extensions;
-  if (!extensions.init(i->fStandard, getString, nullptr, getIntegerv)) {
-    delete i;
-    return nullptr;
-  }
-
-  i->fExtensions.swap(&extensions);
-
-  // Core GL functions required by Ganesh
-  i->fFunctions.fActiveTexture = WrapGL(context, &GLContext::fActiveTexture);
-  i->fFunctions.fAttachShader = WrapGL(context, &GLContext::fAttachShader);
-  i->fFunctions.fBindAttribLocation =
-      WrapGL(context, &GLContext::fBindAttribLocation);
-  i->fFunctions.fBindBuffer = WrapGL(context, &GLContext::fBindBuffer);
-  i->fFunctions.fBindFramebuffer =
-      WrapGL(context, &GLContext::fBindFramebuffer);
-  i->fFunctions.fBindRenderbuffer =
-      WrapGL(context, &GLContext::fBindRenderbuffer);
-  i->fFunctions.fBindTexture = WrapGL(context, &GLContext::fBindTexture);
-  i->fFunctions.fBlendFunc = WrapGL(context, &GLContext::fBlendFunc);
-  i->fFunctions.fBlendColor = WrapGL(context, &GLContext::fBlendColor);
-  i->fFunctions.fBlendEquation = WrapGL(context, &GLContext::fBlendEquation);
-  i->fFunctions.fBufferData = WrapGL(context, &GLContext::fBufferData);
-  i->fFunctions.fBufferSubData = WrapGL(context, &GLContext::fBufferSubData);
-  i->fFunctions.fCheckFramebufferStatus =
-      WrapGL(context, &GLContext::fCheckFramebufferStatus);
-  i->fFunctions.fClear = WrapGL(context, &GLContext::fClear);
-  i->fFunctions.fClearColor = WrapGL(context, &GLContext::fClearColor);
-  i->fFunctions.fClearStencil = WrapGL(context, &GLContext::fClearStencil);
-  i->fFunctions.fColorMask = WrapGL(context, &GLContext::fColorMask);
-  i->fFunctions.fCompileShader = WrapGL(context, &GLContext::fCompileShader);
-  i->fFunctions.fCompressedTexImage2D =
-      WrapGL(context, &GLContext::fCompressedTexImage2D);
-  i->fFunctions.fCompressedTexSubImage2D =
-      WrapGL(context, &GLContext::fCompressedTexSubImage2D);
-  i->fFunctions.fCopyTexSubImage2D =
-      WrapGL(context, &GLContext::fCopyTexSubImage2D);
-  i->fFunctions.fCreateProgram = WrapGL(context, &GLContext::fCreateProgram);
-  i->fFunctions.fCreateShader = WrapGL(context, &GLContext::fCreateShader);
-  i->fFunctions.fCullFace = WrapGL(context, &GLContext::fCullFace);
-  i->fFunctions.fDeleteBuffers = WrapGL(context, &GLContext::fDeleteBuffers);
-  i->fFunctions.fDeleteFramebuffers =
-      WrapGL(context, &GLContext::fDeleteFramebuffers);
-  i->fFunctions.fDeleteProgram = WrapGL(context, &GLContext::fDeleteProgram);
-  i->fFunctions.fDeleteRenderbuffers =
-      WrapGL(context, &GLContext::fDeleteRenderbuffers);
-  i->fFunctions.fDeleteShader = WrapGL(context, &GLContext::fDeleteShader);
-  i->fFunctions.fDeleteTextures = WrapGL(context, &GLContext::fDeleteTextures);
-  i->fFunctions.fDepthMask = WrapGL(context, &GLContext::fDepthMask);
-  i->fFunctions.fDisable = WrapGL(context, &GLContext::fDisable);
-  i->fFunctions.fDisableVertexAttribArray =
-      WrapGL(context, &GLContext::fDisableVertexAttribArray);
-  i->fFunctions.fDrawArrays = WrapGL(context, &GLContext::fDrawArrays);
-  i->fFunctions.fDrawElements = WrapGL(context, &GLContext::fDrawElements);
-  i->fFunctions.fDrawRangeElements =
-      WrapGL(context, &GLContext::fDrawRangeElements);
-  i->fFunctions.fEnable = WrapGL(context, &GLContext::fEnable);
-  i->fFunctions.fEnableVertexAttribArray =
-      WrapGL(context, &GLContext::fEnableVertexAttribArray);
-  i->fFunctions.fFinish = WrapGL(context, &GLContext::fFinish);
-  i->fFunctions.fFlush = WrapGL(context, &GLContext::fFlush);
-  i->fFunctions.fFramebufferRenderbuffer =
-      WrapGL(context, &GLContext::fFramebufferRenderbuffer);
-  i->fFunctions.fFramebufferTexture2D =
-      WrapGL(context, &GLContext::fFramebufferTexture2D);
-  i->fFunctions.fFrontFace = WrapGL(context, &GLContext::fFrontFace);
-  i->fFunctions.fGenBuffers = WrapGL(context, &GLContext::fGenBuffers);
-  i->fFunctions.fGenFramebuffers =
-      WrapGL(context, &GLContext::fGenFramebuffers);
-  i->fFunctions.fGenRenderbuffers =
-      WrapGL(context, &GLContext::fGenRenderbuffers);
-  i->fFunctions.fGetFramebufferAttachmentParameteriv =
-      WrapGL(context, &GLContext::fGetFramebufferAttachmentParameteriv);
-  i->fFunctions.fGenTextures = WrapGL(context, &GLContext::fGenTextures);
-  i->fFunctions.fGenerateMipmap = WrapGL(context, &GLContext::fGenerateMipmap);
-  i->fFunctions.fGetBufferParameteriv =
-      WrapGL(context, &GLContext::fGetBufferParameteriv);
-  i->fFunctions.fGetError = WrapGL(context, &GLContext::fGetError);
-  i->fFunctions.fGetIntegerv = getIntegerv;
-  i->fFunctions.fGetProgramInfoLog =
-      WrapGL(context, &GLContext::fGetProgramInfoLog);
-  i->fFunctions.fGetProgramiv = WrapGL(context, &GLContext::fGetProgramiv);
-  i->fFunctions.fGetRenderbufferParameteriv =
-      WrapGL(context, &GLContext::fGetRenderbufferParameteriv);
-  i->fFunctions.fGetShaderInfoLog =
-      WrapGL(context, &GLContext::fGetShaderInfoLog);
-  i->fFunctions.fGetShaderiv = WrapGL(context, &GLContext::fGetShaderiv);
-  i->fFunctions.fGetShaderPrecisionFormat =
-      WrapGL(context, &GLContext::fGetShaderPrecisionFormat);
-  i->fFunctions.fGetString = getString;
-  i->fFunctions.fGetUniformLocation =
-      WrapGL(context, &GLContext::fGetUniformLocation);
-  i->fFunctions.fIsTexture = WrapGL(context, &GLContext::fIsTexture);
-  i->fFunctions.fLineWidth = WrapGL(context, &GLContext::fLineWidth);
-  i->fFunctions.fLinkProgram = WrapGL(context, &GLContext::fLinkProgram);
-  i->fFunctions.fPixelStorei = WrapGL(context, &GLContext::fPixelStorei);
-  i->fFunctions.fPolygonMode = WrapGL(context, &GLContext::fPolygonMode);
-  i->fFunctions.fReadPixels = WrapGL(context, &GLContext::fReadPixels);
-  i->fFunctions.fRenderbufferStorage =
-      WrapGL(context, &GLContext::fRenderbufferStorage);
-  i->fFunctions.fScissor = WrapGL(context, &GLContext::fScissor);
-  i->fFunctions.fShaderSource = WrapGL(context, &GLContext::fShaderSource);
-  i->fFunctions.fStencilFunc = WrapGL(context, &GLContext::fStencilFunc);
-  i->fFunctions.fStencilFuncSeparate =
-      WrapGL(context, &GLContext::fStencilFuncSeparate);
-  i->fFunctions.fStencilMask = WrapGL(context, &GLContext::fStencilMask);
-  i->fFunctions.fStencilMaskSeparate =
-      WrapGL(context, &GLContext::fStencilMaskSeparate);
-  i->fFunctions.fStencilOp = WrapGL(context, &GLContext::fStencilOp);
-  i->fFunctions.fStencilOpSeparate =
-      WrapGL(context, &GLContext::fStencilOpSeparate);
-  i->fFunctions.fTexImage2D = WrapGL(context, &GLContext::fTexImage2D);
-  i->fFunctions.fTexParameteri = WrapGL(context, &GLContext::fTexParameteri);
-  i->fFunctions.fTexParameteriv = WrapGL(context, &GLContext::fTexParameteriv);
-  i->fFunctions.fTexSubImage2D = WrapGL(context, &GLContext::fTexSubImage2D);
-  i->fFunctions.fUniform1f = WrapGL(context, &GLContext::fUniform1f);
-  i->fFunctions.fUniform1i = WrapGL(context, &GLContext::fUniform1i);
-  i->fFunctions.fUniform1fv = WrapGL(context, &GLContext::fUniform1fv);
-  i->fFunctions.fUniform1iv = WrapGL(context, &GLContext::fUniform1iv);
-  i->fFunctions.fUniform2f = WrapGL(context, &GLContext::fUniform2f);
-  i->fFunctions.fUniform2i = WrapGL(context, &GLContext::fUniform2i);
-  i->fFunctions.fUniform2fv = WrapGL(context, &GLContext::fUniform2fv);
-  i->fFunctions.fUniform2iv = WrapGL(context, &GLContext::fUniform2iv);
-  i->fFunctions.fUniform3f = WrapGL(context, &GLContext::fUniform3f);
-  i->fFunctions.fUniform3i = WrapGL(context, &GLContext::fUniform3i);
-  i->fFunctions.fUniform3fv = WrapGL(context, &GLContext::fUniform3fv);
-  i->fFunctions.fUniform3iv = WrapGL(context, &GLContext::fUniform3iv);
-  i->fFunctions.fUniform4f = WrapGL(context, &GLContext::fUniform4f);
-  i->fFunctions.fUniform4i = WrapGL(context, &GLContext::fUniform4i);
-  i->fFunctions.fUniform4fv = WrapGL(context, &GLContext::fUniform4fv);
-  i->fFunctions.fUniform4iv = WrapGL(context, &GLContext::fUniform4iv);
-  i->fFunctions.fUniformMatrix2fv =
-      WrapGL(context, &GLContext::fUniformMatrix2fv);
-  i->fFunctions.fUniformMatrix3fv =
-      WrapGL(context, &GLContext::fUniformMatrix3fv);
-  i->fFunctions.fUniformMatrix4fv =
-      WrapGL(context, &GLContext::fUniformMatrix4fv);
-  i->fFunctions.fUseProgram = WrapGL(context, &GLContext::fUseProgram);
-  i->fFunctions.fVertexAttrib1f = WrapGL(context, &GLContext::fVertexAttrib1f);
-  i->fFunctions.fVertexAttrib2fv =
-      WrapGL(context, &GLContext::fVertexAttrib2fv);
-  i->fFunctions.fVertexAttrib3fv =
-      WrapGL(context, &GLContext::fVertexAttrib3fv);
-  i->fFunctions.fVertexAttrib4fv =
-      WrapGL(context, &GLContext::fVertexAttrib4fv);
-  i->fFunctions.fVertexAttribPointer =
-      WrapGL(context, &GLContext::fVertexAttribPointer);
-  i->fFunctions.fViewport = WrapGL(context, &GLContext::fViewport);
-
-  // Required for either desktop OpenGL 2.0 or OpenGL ES 2.0
-  i->fFunctions.fStencilFuncSeparate =
-      WrapGL(context, &GLContext::fStencilFuncSeparate);
-  i->fFunctions.fStencilMaskSeparate =
-      WrapGL(context, &GLContext::fStencilMaskSeparate);
-  i->fFunctions.fStencilOpSeparate =
-      WrapGL(context, &GLContext::fStencilOpSeparate);
-
-  // GLContext supports glMapBuffer
-  i->fFunctions.fMapBuffer = WrapGL(context, &GLContext::fMapBuffer);
-  i->fFunctions.fUnmapBuffer = WrapGL(context, &GLContext::fUnmapBuffer);
-
-  // GLContext supports glRenderbufferStorageMultisample/glBlitFramebuffer
-  i->fFunctions.fRenderbufferStorageMultisample =
-      WrapGL(context, &GLContext::fRenderbufferStorageMultisample);
-  i->fFunctions.fBlitFramebuffer =
-      WrapGL(context, &GLContext::fBlitFramebuffer);
-
-  // GLContext supports glCompressedTexImage2D
-  i->fFunctions.fCompressedTexImage2D =
-      WrapGL(context, &GLContext::fCompressedTexImage2D);
-
-  // GL_OES_vertex_array_object
-  i->fFunctions.fBindVertexArray =
-      WrapGL(context, &GLContext::fBindVertexArray);
-  i->fFunctions.fDeleteVertexArrays =
-      WrapGL(context, &GLContext::fDeleteVertexArrays);
-  i->fFunctions.fGenVertexArrays =
-      WrapGL(context, &GLContext::fGenVertexArrays);
-
-  // Desktop GL
-  i->fFunctions.fGetTexLevelParameteriv =
-      WrapGL(context, &GLContext::fGetTexLevelParameteriv);
-  i->fFunctions.fDrawBuffer = WrapGL(context, &GLContext::fDrawBuffer);
-  i->fFunctions.fReadBuffer = WrapGL(context, &GLContext::fReadBuffer);
-
-  // Desktop OpenGL > 1.5
-  i->fFunctions.fGenQueries = WrapGL(context, &GLContext::fGenQueries);
-  i->fFunctions.fDeleteQueries = WrapGL(context, &GLContext::fDeleteQueries);
-  i->fFunctions.fBeginQuery = WrapGL(context, &GLContext::fBeginQuery);
-  i->fFunctions.fEndQuery = WrapGL(context, &GLContext::fEndQuery);
-  i->fFunctions.fGetQueryiv = WrapGL(context, &GLContext::fGetQueryiv);
-  i->fFunctions.fGetQueryObjectiv =
-      WrapGL(context, &GLContext::fGetQueryObjectiv);
-  i->fFunctions.fGetQueryObjectuiv =
-      WrapGL(context, &GLContext::fGetQueryObjectuiv);
-
-  // Desktop OpenGL > 2.0
-  i->fFunctions.fDrawBuffers = WrapGL(context, &GLContext::fDrawBuffers);
-
-  return i;
-}
-
-SkiaGLGlue::SkiaGLGlue(GLContext* context) : mGLContext(context) {
-  mGrGLInterface.reset(CreateGrGLInterfaceFromGLContext(mGLContext));
-  mGrContext = GrContext::MakeGL(mGrGLInterface);
-}
-
-SkiaGLGlue::~SkiaGLGlue() {
-  /*
-   * These members have inter-dependencies, but do not keep each other alive, so
-   * destruction order is very important here: mGrContext uses mGrGLInterface,
-   * and through it, uses mGLContext
-   */
-  mGrContext = nullptr;
-  if (mGrGLInterface) {
-    // Ensure that no references to the GLContext remain, even if the GrContext
-    // still lives.
-    mGrGLInterface->fFunctions = GrGLInterface::Functions();
-    mGrGLInterface = nullptr;
-  }
-  mGLContext = nullptr;
-}
deleted file mode 100644
--- a/gfx/gl/SkiaGLGlue.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 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/. */
-
-#ifndef SKIA_GL_GLUE_H_
-#define SKIA_GL_GLUE_H_
-
-#ifdef USE_SKIA_GPU
-
-#  include "skia/include/core/SkRefCnt.h"
-#  include "mozilla/RefPtr.h"
-
-struct GrGLInterface;
-class GrContext;
-
-namespace mozilla {
-namespace gl {
-
-class GLContext;
-
-class SkiaGLGlue : public GenericAtomicRefCounted {
- public:
-  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SkiaGLGlue, override)
-
-  explicit SkiaGLGlue(GLContext* context);
-  GLContext* GetGLContext() const { return mGLContext.get(); }
-  GrContext* GetGrContext() const { return mGrContext.get(); }
-
- protected:
-  virtual ~SkiaGLGlue();
-
- private:
-  RefPtr<GLContext> mGLContext;
-  sk_sp<GrGLInterface> mGrGLInterface;
-  sk_sp<GrContext> mGrContext;
-};
-
-}  // namespace gl
-}  // namespace mozilla
-
-#else  // USE_SKIA_GPU
-
-class GrContext;
-
-namespace mozilla {
-namespace gl {
-
-class GLContext;
-
-class SkiaGLGlue : public GenericAtomicRefCounted {
- public:
-  SkiaGLGlue(GLContext* context);
-  GLContext* GetGLContext() const { return nullptr; }
-  GrContext* GetGrContext() const { return nullptr; }
-};
-
-}  // namespace gl
-}  // namespace mozilla
-
-#endif  // USE_SKIA_GPU
-
-#endif  // SKIA_GL_GLUE_H_
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -69,24 +69,16 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'wind
         'WGLLibrary.h',
     ]
     UNIFIED_SOURCES += [
         'GLBlitHelperD3D.cpp',
         'GLContextProviderWGL.cpp',
         'SharedSurfaceANGLE.cpp',
         'SharedSurfaceD3D11Interop.cpp',
     ]
-if CONFIG['MOZ_ENABLE_SKIA_GPU']:
-    EXPORTS += ['SkiaGLGlue.h']
-    SOURCES += [
-        'SkiaGLGlue.cpp',
-    ]
-    if CONFIG['CC_TYPE'] == 'clang':
-        # Suppress warnings from Skia header files.
-        SOURCES['SkiaGLGlue.cpp'].flags += ['-Wno-implicit-fallthrough']
 
 if gl_provider == 'CGL':
     # These files include Mac headers that are unfriendly to unified builds
     SOURCES += [
         "GLContextProviderCGL.mm",
     ]
     EXPORTS += [
         'GLContextCGL.h',
--- a/gfx/ipc/GPUChild.cpp
+++ b/gfx/ipc/GPUChild.cpp
@@ -235,17 +235,17 @@ mozilla::ipc::IPCResult GPUChild::RecvNo
   gfxPlatform::GetPlatform()->ImportGPUDeviceData(aData);
   mHost->mListener->OnRemoteProcessDeviceReset(mHost);
   return IPC_OK();
 }
 
 bool GPUChild::SendRequestMemoryReport(const uint32_t& aGeneration,
                                        const bool& aAnonymize,
                                        const bool& aMinimizeMemoryUsage,
-                                       const MaybeFileDesc& aDMDFile) {
+                                       const Maybe<FileDescriptor>& aDMDFile) {
   mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
   Unused << PGPUChild::SendRequestMemoryReport(aGeneration, aAnonymize,
                                                aMinimizeMemoryUsage, aDMDFile);
   return true;
 }
 
 mozilla::ipc::IPCResult GPUChild::RecvAddMemoryReport(
     const MemoryReport& aReport) {
--- a/gfx/ipc/GPUChild.h
+++ b/gfx/ipc/GPUChild.h
@@ -73,17 +73,17 @@ class GPUChild final : public PGPUChild,
                                             const FeatureFailure& aChange);
   mozilla::ipc::IPCResult RecvUsedFallback(const Fallback& aFallback,
                                            const nsCString& aMessage);
   mozilla::ipc::IPCResult RecvBHRThreadHang(const HangDetails& aDetails);
 
   bool SendRequestMemoryReport(const uint32_t& aGeneration,
                                const bool& aAnonymize,
                                const bool& aMinimizeMemoryUsage,
-                               const MaybeFileDesc& aDMDFile);
+                               const Maybe<ipc::FileDescriptor>& aDMDFile);
 
   static void Destroy(UniquePtr<GPUChild>&& aChild);
 
  private:
   GPUProcessHost* mHost;
   UniquePtr<ipc::CrashReporterHost> mCrashReporter;
   UniquePtr<MemoryReportRequestHost> mMemoryReportRequest;
   bool mGPUReady;
--- a/gfx/ipc/GPUParent.cpp
+++ b/gfx/ipc/GPUParent.cpp
@@ -439,17 +439,17 @@ void GPUParent::GetGPUProcessName(nsACSt
   }
 
   nsPrintfCString processName("GPU (pid %u)", pid);
   aStr.Assign(processName);
 }
 
 mozilla::ipc::IPCResult GPUParent::RecvRequestMemoryReport(
     const uint32_t& aGeneration, const bool& aAnonymize,
-    const bool& aMinimizeMemoryUsage, const MaybeFileDesc& aDMDFile) {
+    const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile) {
   nsAutoCString processName;
   GetGPUProcessName(processName);
 
   mozilla::dom::MemoryReportRequestClient::Start(
       aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, processName,
       [&](const MemoryReport& aReport) {
         Unused << GetSingleton()->SendAddMemoryReport(aReport);
       },
--- a/gfx/ipc/GPUParent.h
+++ b/gfx/ipc/GPUParent.h
@@ -69,17 +69,18 @@ class GPUParent final : public PGPUParen
   mozilla::ipc::IPCResult RecvSimulateDeviceReset(GPUDeviceData* aOutStatus);
   mozilla::ipc::IPCResult RecvAddLayerTreeIdMapping(
       const LayerTreeIdMapping& aMapping);
   mozilla::ipc::IPCResult RecvRemoveLayerTreeIdMapping(
       const LayerTreeIdMapping& aMapping);
   mozilla::ipc::IPCResult RecvNotifyGpuObservers(const nsCString& aTopic);
   mozilla::ipc::IPCResult RecvRequestMemoryReport(
       const uint32_t& generation, const bool& anonymize,
-      const bool& minimizeMemoryUsage, const MaybeFileDesc& DMDFile);
+      const bool& minimizeMemoryUsage,
+      const Maybe<ipc::FileDescriptor>& DMDFile);
   mozilla::ipc::IPCResult RecvShutdownVR();
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
  private:
   const TimeStamp mLaunchTime;
   RefPtr<VsyncBridgeParent> mVsyncBridge;
 #ifdef MOZ_GECKO_PROFILER
--- a/gfx/ipc/GPUProcessManager.cpp
+++ b/gfx/ipc/GPUProcessManager.cpp
@@ -1032,17 +1032,17 @@ class GPUMemoryReporter : public MemoryR
       return !!gpm->GetGPUChild();
     }
     return false;
   }
 
   bool SendRequestMemoryReport(const uint32_t& aGeneration,
                                const bool& aAnonymize,
                                const bool& aMinimizeMemoryUsage,
-                               const dom::MaybeFileDesc& aDMDFile) override {
+                               const Maybe<FileDescriptor>& aDMDFile) override {
     GPUChild* child = GetChild();
     if (!child) {
       return false;
     }
 
     return child->SendRequestMemoryReport(aGeneration, aAnonymize,
                                           aMinimizeMemoryUsage, aDMDFile);
   }
--- a/gfx/ipc/PGPU.ipdl
+++ b/gfx/ipc/PGPU.ipdl
@@ -86,17 +86,17 @@ parent:
 
   // Have a message be broadcasted to the GPU process by the GPU process
   // observer service.
   async NotifyGpuObservers(nsCString aTopic);
 
   async RequestMemoryReport(uint32_t generation,
                             bool anonymize,
                             bool minimizeMemoryUsage,
-                            MaybeFileDesc DMDFile);
+                            FileDescriptor? DMDFile);
   async ShutdownVR();
 
 child:
   // Sent when the GPU process has initialized devices. This occurs once, after
   // Init().
   async InitComplete(GPUDeviceData data);
 
   // Sent when APZ detects checkerboarding and apz checkerboard reporting is enabled.
--- a/gfx/layers/CanvasRenderer.h
+++ b/gfx/layers/CanvasRenderer.h
@@ -32,36 +32,32 @@ struct CanvasInitializeData {
   CanvasInitializeData()
       : mBufferProvider(nullptr),
         mGLContext(nullptr),
         mRenderer(nullptr),
         mPreTransCallback(nullptr),
         mPreTransCallbackData(nullptr),
         mDidTransCallback(nullptr),
         mDidTransCallbackData(nullptr),
-        mFrontbufferGLTex(0),
         mSize(0, 0),
         mHasAlpha(false),
         mIsGLAlphaPremult(true) {}
 
   // One of these three must be specified for Canvas2D, but never more than one
   PersistentBufferProvider*
       mBufferProvider;  // A BufferProvider for the Canvas contents
   mozilla::gl::GLContext* mGLContext;  // or this, for GL.
   AsyncCanvasRenderer* mRenderer;      // or this, for OffscreenCanvas
 
   typedef void (*TransactionCallback)(void* closureData);
   TransactionCallback mPreTransCallback;
   void* mPreTransCallbackData;
   TransactionCallback mDidTransCallback;
   void* mDidTransCallbackData;
 
-  // Frontbuffer override
-  uint32_t mFrontbufferGLTex;
-
   // The size of the canvas content
   gfx::IntSize mSize;
 
   // Whether the canvas drawingbuffer has an alpha channel.
   bool mHasAlpha;
 
   // Whether mGLContext contains data that is alpha-premultiplied.
   bool mIsGLAlphaPremult;
--- a/gfx/layers/CopyableCanvasRenderer.cpp
+++ b/gfx/layers/CopyableCanvasRenderer.cpp
@@ -31,17 +31,16 @@ namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
 CopyableCanvasRenderer::CopyableCanvasRenderer()
     : mGLContext(nullptr),
       mBufferProvider(nullptr),
-      mGLFrontbuffer(nullptr),
       mAsyncRenderer(nullptr),
       mIsAlphaPremultiplied(true),
       mOriginPos(gl::OriginPos::TopLeft),
       mOpaque(true),
       mCachedTempSurface(nullptr) {
   MOZ_COUNT_CTOR(CopyableCanvasRenderer);
 }
 
@@ -55,22 +54,16 @@ void CopyableCanvasRenderer::Initialize(
 
   if (aData.mGLContext) {
     mGLContext = aData.mGLContext;
     mIsAlphaPremultiplied = aData.mIsGLAlphaPremult;
     mOriginPos = gl::OriginPos::BottomLeft;
 
     MOZ_ASSERT(mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
 
-    if (aData.mFrontbufferGLTex) {
-      gfx::IntSize size(aData.mSize.width, aData.mSize.height);
-      mGLFrontbuffer = SharedSurface_Basic::Wrap(
-          aData.mGLContext, size, aData.mHasAlpha, aData.mFrontbufferGLTex);
-      mBufferProvider = aData.mBufferProvider;
-    }
   } else if (aData.mBufferProvider) {
     mBufferProvider = aData.mBufferProvider;
   } else if (aData.mRenderer) {
     mAsyncRenderer = aData.mRenderer;
     mOriginPos = gl::OriginPos::BottomLeft;
   } else {
     MOZ_CRASH(
         "GFX: CanvasRenderer created without BufferProvider, DrawTarget or "
@@ -125,19 +118,17 @@ already_AddRefed<SourceSurface> Copyable
     return mAsyncRenderer->GetSurface();
   }
 
   if (!mGLContext) {
     return nullptr;
   }
 
   SharedSurface* frontbuffer = nullptr;
-  if (mGLFrontbuffer) {
-    frontbuffer = mGLFrontbuffer.get();
-  } else if (mGLContext->Screen()) {
+  if (mGLContext->Screen()) {
     const auto& front = mGLContext->Screen()->Front();
     if (front) {
       frontbuffer = front->Surf();
     }
   }
 
   if (!frontbuffer) {
     NS_WARNING("Null frame received.");
--- a/gfx/layers/CopyableCanvasRenderer.h
+++ b/gfx/layers/CopyableCanvasRenderer.h
@@ -52,17 +52,16 @@ class CopyableCanvasRenderer : public Ca
 
   PersistentBufferProvider* GetBufferProvider() { return mBufferProvider; }
 
   already_AddRefed<gfx::SourceSurface> ReadbackSurface();
 
  protected:
   RefPtr<gl::GLContext> mGLContext;
   RefPtr<PersistentBufferProvider> mBufferProvider;
-  UniquePtr<gl::SharedSurface> mGLFrontbuffer;
   RefPtr<AsyncCanvasRenderer> mAsyncRenderer;
 
   bool mIsAlphaPremultiplied;
   gl::OriginPos mOriginPos;
 
   bool mOpaque;
 
   RefPtr<gfx::DataSourceSurface> mCachedTempSurface;
--- a/gfx/layers/ShareableCanvasRenderer.cpp
+++ b/gfx/layers/ShareableCanvasRenderer.cpp
@@ -36,47 +36,30 @@ ShareableCanvasRenderer::~ShareableCanva
 void ShareableCanvasRenderer::Initialize(const CanvasInitializeData& aData) {
   CopyableCanvasRenderer::Initialize(aData);
 
   mCanvasClient = nullptr;
 
   if (!mGLContext) return;
 
   gl::GLScreenBuffer* screen = mGLContext->Screen();
-
-  gl::SurfaceCaps caps;
-  if (mGLFrontbuffer) {
-    // The screen caps are irrelevant if we're using a separate frontbuffer.
-    caps = mGLFrontbuffer->mHasAlpha ? gl::SurfaceCaps::ForRGBA()
-                                     : gl::SurfaceCaps::ForRGB();
-  } else {
-    MOZ_ASSERT(screen);
-    caps = screen->mCaps;
-  }
+  MOZ_ASSERT(screen);
+  gl::SurfaceCaps caps = screen->mCaps;
 
   auto forwarder = GetForwarder();
 
   mFlags = TextureFlags::ORIGIN_BOTTOM_LEFT;
   if (!aData.mIsGLAlphaPremult) {
     mFlags |= TextureFlags::NON_PREMULTIPLIED;
   }
 
   UniquePtr<gl::SurfaceFactory> factory =
       gl::GLScreenBuffer::CreateFactory(mGLContext, caps, forwarder, mFlags);
-
-  if (mGLFrontbuffer) {
-    // We're using a source other than the one in the default screen.
-    // (SkiaGL)
-    mFactory = std::move(factory);
-    if (!mFactory) {
-      // Absolutely must have a factory here, so create a basic one
-      mFactory = MakeUnique<gl::SurfaceFactory_Basic>(mGLContext, caps, mFlags);
-    }
-  } else {
-    if (factory) screen->Morph(std::move(factory));
+  if (factory) {
+    screen->Morph(std::move(factory));
   }
 }
 
 void ShareableCanvasRenderer::ClearCachedResources() {
   CopyableCanvasRenderer::ClearCachedResources();
 
   if (mCanvasClient) {
     mCanvasClient->Clear();
@@ -117,24 +100,21 @@ bool ShareableCanvasRenderer::UpdateTarg
     }
 
     aDestTarget->CopySurface(surface, IntRect(0, 0, mSize.width, mSize.height),
                              IntPoint(0, 0));
     return true;
   }
 
   gl::SharedSurface* frontbuffer = nullptr;
-  if (mGLFrontbuffer) {
-    frontbuffer = mGLFrontbuffer.get();
-  } else {
-    gl::GLScreenBuffer* screen = mGLContext->Screen();
-    const auto& front = screen->Front();
-    if (front) {
-      frontbuffer = front->Surf();
-    }
+
+  gl::GLScreenBuffer* screen = mGLContext->Screen();
+  const auto& front = screen->Front();
+  if (front) {
+    frontbuffer = front->Surf();
   }
 
   if (!frontbuffer) {
     NS_WARNING("Null frame received.");
     return false;
   }
 
   IntSize readSize(frontbuffer->mSize);
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -381,24 +381,17 @@ void CanvasClientSharedSurface::UpdateRe
     asyncRenderer = aRenderer.ref<AsyncCanvasRenderer*>();
     gl = asyncRenderer->mGLContext;
   }
   if (!gl->MakeCurrent()) return;
 
   RefPtr<TextureClient> newFront;
 
   mShSurfClient = nullptr;
-  if (canvasRenderer && canvasRenderer->mGLFrontbuffer) {
-    mShSurfClient = CloneSurface(canvasRenderer->mGLFrontbuffer.get(),
-                                 canvasRenderer->mFactory.get());
-    if (!mShSurfClient) {
-      gfxCriticalError() << "Invalid canvas front buffer";
-      return;
-    }
-  } else if (gl->Screen()) {
+  if (gl->Screen()) {
     mShSurfClient = gl->Screen()->Front();
     if (mShSurfClient && mShSurfClient->GetAllocator() &&
         mShSurfClient->GetAllocator() !=
             GetForwarder()->GetTextureForwarder()) {
       mShSurfClient =
           CloneSurface(mShSurfClient->Surf(), gl->Screen()->Factory());
     }
   }
--- a/gfx/skia/generate_mozbuild.py
+++ b/gfx/skia/generate_mozbuild.py
@@ -48,20 +48,16 @@ LOCAL_INCLUDES += [
     'skia/include/gpu',
     'skia/include/pathops',
     'skia/include/ports',
     'skia/include/private',
     'skia/include/utils',
     'skia/include/utils/mac',
     'skia/src/codec',
     'skia/src/core',
-    'skia/src/gpu',
-    'skia/src/gpu/effects',
-    'skia/src/gpu/gl',
-    'skia/src/gpu/glsl',
     'skia/src/image',
     'skia/src/lazy',
     'skia/src/opts',
     'skia/src/sfnt',
     'skia/src/shaders',
     'skia/src/shaders/gradients',
     'skia/src/sksl',
     'skia/src/utils',
@@ -93,19 +89,16 @@ elif CONFIG['CPU_ARCH'] == 'arm' and CON
 elif CONFIG['CPU_ARCH'] == 'aarch64' and CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     SOURCES['skia/src/opts/SkOpts_crc32.cpp'].flags += ['-march=armv8-a+crc']
 
 DEFINES['SKIA_IMPLEMENTATION'] = 1
 
 if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY']:
     DEFINES['SK_PDF_USE_SFNTLY'] = 1
 
-if not CONFIG['MOZ_ENABLE_SKIA_GPU']:
-    DEFINES['SK_SUPPORT_GPU'] = 0
-
 if CONFIG['MOZ_TREE_FREETYPE']:
     DEFINES['SK_CAN_USE_DLOPEN'] = 0
 
 # Suppress warnings in third-party code.
 CXXFLAGS += [
     '-Wno-deprecated-declarations',
     '-Wno-overloaded-virtual',
     '-Wno-shadow',
@@ -167,45 +160,39 @@ def generate_platform_sources():
     'win' : 'win_vc="C:/" win_sdk_version="00.0.00000.0"'
   }
   for plat in platforms:
     args = platform_args.get(plat, '')
     output = subprocess.check_output('cd skia && bin/gn gen out/{0} --args=\'target_os="{0}" {1}\' > /dev/null && bin/gn desc out/{0} :skia sources'.format(plat, args), shell=True)
     if output:
       sources[plat] = parse_sources(output)
 
-  deps = {':effects' : 'common', ':gpu' : 'gpu', ':pdf' : 'pdf'}
+  deps = {':effects' : 'common', ':pdf' : 'pdf'}
   for dep, key in deps.items():
     output = subprocess.check_output('cd skia && bin/gn desc out/linux {} sources'.format(dep), shell=True)
     if output:
       sources[key] = parse_sources(output)
 
   return dict(sources.items() + generate_opt_sources().items())
 
 
 def generate_separated_sources(platform_sources):
   blacklist = [
-    'GrGLMakeNativeInterface',
-    'GrGLCreateNullInterface',
-    'GrGLAssembleInterface',
-    'GrGLTestInterface',
     'skia/src/android/',
     'skia/src/atlastext/',
     'skia/src/c/',
     'skia/src/effects/',
     'skia/src/fonts/',
     'skia/src/ports/SkImageEncoder',
     'skia/src/ports/SkImageGenerator',
-    'skia/src/gpu/vk/',
     'SkBitmapRegion',
     'SkLite',
     'SkLight',
     'SkNormal',
     'codec',
-    'SkWGL',
     'SkMemory_malloc',
     'third_party',
     'Sk3D',
     'SkAnimCodecPlayer',
     'SkCamera',
     'SkCanvasStack',
     'SkCanvasStateUtils',
     'SkFrontBufferedStream',
@@ -231,17 +218,16 @@ def generate_separated_sources(platform_
 
     return False
 
   separated = defaultdict(set, {
     'common': {
       'skia/src/codec/SkMasks.cpp',
       'skia/src/effects/imagefilters/SkBlurImageFilter.cpp',
       'skia/src/effects/SkDashPathEffect.cpp',
-      'skia/src/gpu/gl/GrGLMakeNativeInterface_none.cpp',
       'skia/src/ports/SkDiscardableMemory_none.cpp',
       'skia/src/ports/SkGlobalInitialization_default.cpp',
       'skia/src/ports/SkGlobalInitialization_default_imagefilters.cpp',
       'skia/src/ports/SkMemory_mozalloc.cpp',
       'skia/src/ports/SkImageGenerator_none.cpp',
       'skia/third_party/skcms/skcms.cc',
     },
     'android': {
@@ -255,18 +241,17 @@ def generate_separated_sources(platform_
     'linux': {
       'skia/src/ports/SkFontHost_cairo.cpp',
       'skia/src/ports/SkFontHost_FreeType_common.cpp',
     },
     'intel': set(),
     'arm': set(),
     'arm64': set(),
     'none': set(),
-    'pdf': set(),
-    'gpu': set()
+    'pdf': set()
   })
 
   for plat in platform_sources.keys():
     for value in platform_sources[plat]:
       if isblacklisted(value):
         continue
 
       if value in separated['common']:
@@ -336,28 +321,16 @@ unified_blacklist = [
   'SkBlitter_RGB16.cpp',
   'SkBlitter_Sprite.cpp',
   'SkScan_Antihair.cpp',
   'SkScan_AntiPath.cpp',
   'SkScan_DAAPath.cpp',
   'SkParse.cpp',
   'SkPDFFont.cpp',
   'SkPictureData.cpp',
-  'skia/src/gpu/effects/',
-  'skia/src/gpu/gradients/',
-  'GrResourceCache',
-  'GrResourceProvider',
-  'GrAA',
-  'GrGL',
-  'GrCCPathProcessor',
-  'GrCCStrokeGeometry',
-  'GrMSAAPathRenderer.cpp',
-  'GrNonAAFillRect',
-  'GrPathUtils',
-  'GrShadowRRectOp',
   'SkColorSpace',
   'SkImage_Gpu.cpp',
   'SkPathOpsDebug.cpp',
   'SkParsePath.cpp',
   'SkRecorder.cpp',
   'SkMiniRecorder.cpp',
   'SkXfermode',
   'SkMatrix44.cpp',
@@ -416,19 +389,16 @@ def write_mozbuild(sources):
   f.write(header)
 
   write_sources(f, sources['common'], 0)
   write_cflags(f, sources['common'], opt_whitelist, 'skia_opt_flags', 0)
 
   f.write("if CONFIG['MOZ_ENABLE_SKIA_PDF']:\n")
   write_sources(f, sources['pdf'], 4)
 
-  f.write("if CONFIG['MOZ_ENABLE_SKIA_GPU']:\n")
-  write_sources(f, sources['gpu'], 4)
-
   f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':\n")
   write_sources(f, sources['android'], 4)
 
   f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'uikit'):\n")
   write_sources(f, sources['mac'], 4)
 
   f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk3':\n")
   write_sources(f, sources['linux'], 4)
--- a/gfx/skia/moz.build
+++ b/gfx/skia/moz.build
@@ -295,17 +295,16 @@ SOURCES += [
     'skia/src/core/SkScan_Antihair.cpp',
     'skia/src/core/SkScan_AntiPath.cpp',
     'skia/src/core/SkScan_DAAPath.cpp',
     'skia/src/core/SkSpriteBlitter_ARGB32.cpp',
     'skia/src/core/SkSpriteBlitter_RGB565.cpp',
     'skia/src/core/SkVertices.cpp',
     'skia/src/core/SkXfermode.cpp',
     'skia/src/core/SkXfermodeInterpretation.cpp',
-    'skia/src/gpu/gl/GrGLMakeNativeInterface_none.cpp',
     'skia/src/jumper/SkJumper.cpp',
     'skia/src/pathops/SkPathOpsDebug.cpp',
     'skia/src/utils/SkParse.cpp',
     'skia/src/utils/SkParsePath.cpp',
     'skia/third_party/skcms/skcms.cc',
 ]
 SOURCES['skia/src/core/SkBitmapProcState.cpp'].flags += skia_opt_flags
 SOURCES['skia/src/core/SkBitmapProcState_matrixProcs.cpp'].flags += skia_opt_flags
@@ -343,271 +342,16 @@ if CONFIG['MOZ_ENABLE_SKIA_PDF']:
         'skia/src/pdf/SkPDFShader.cpp',
         'skia/src/pdf/SkPDFTag.cpp',
         'skia/src/pdf/SkPDFTypes.cpp',
         'skia/src/pdf/SkPDFUtils.cpp',
     ]
     SOURCES += [
         'skia/src/pdf/SkPDFFont.cpp',
     ]
-if CONFIG['MOZ_ENABLE_SKIA_GPU']:
-    UNIFIED_SOURCES += [
-        'skia/src/gpu/ccpr/GrCCAtlas.cpp',
-        'skia/src/gpu/ccpr/GrCCClipPath.cpp',
-        'skia/src/gpu/ccpr/GrCCClipProcessor.cpp',
-        'skia/src/gpu/ccpr/GrCCConicShader.cpp',
-        'skia/src/gpu/ccpr/GrCCCoverageProcessor.cpp',
-        'skia/src/gpu/ccpr/GrCCCoverageProcessor_GSImpl.cpp',
-        'skia/src/gpu/ccpr/GrCCCoverageProcessor_VSImpl.cpp',
-        'skia/src/gpu/ccpr/GrCCCubicShader.cpp',
-        'skia/src/gpu/ccpr/GrCCDrawPathsOp.cpp',
-        'skia/src/gpu/ccpr/GrCCFiller.cpp',
-        'skia/src/gpu/ccpr/GrCCFillGeometry.cpp',
-        'skia/src/gpu/ccpr/GrCCPathCache.cpp',
-        'skia/src/gpu/ccpr/GrCCPerFlushResources.cpp',
-        'skia/src/gpu/ccpr/GrCCQuadraticShader.cpp',
-        'skia/src/gpu/ccpr/GrCCStroker.cpp',
-        'skia/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp',
-        'skia/src/gpu/GrAHardwareBufferImageGenerator.cpp',
-        'skia/src/gpu/GrAuditTrail.cpp',
-        'skia/src/gpu/GrBackendSurface.cpp',
-        'skia/src/gpu/GrBackendTextureImageGenerator.cpp',
-        'skia/src/gpu/GrBitmapTextureMaker.cpp',
-        'skia/src/gpu/GrBlurUtils.cpp',
-        'skia/src/gpu/GrBuffer.cpp',
-        'skia/src/gpu/GrBufferAllocPool.cpp',
-        'skia/src/gpu/GrCaps.cpp',
-        'skia/src/gpu/GrClipStackClip.cpp',
-        'skia/src/gpu/GrColorSpaceInfo.cpp',
-        'skia/src/gpu/GrColorSpaceXform.cpp',
-        'skia/src/gpu/GrContext.cpp',
-        'skia/src/gpu/GrDDLContext.cpp',
-        'skia/src/gpu/GrDefaultGeoProcFactory.cpp',
-        'skia/src/gpu/GrDirectContext.cpp',
-        'skia/src/gpu/GrDistanceFieldGenFromVector.cpp',
-        'skia/src/gpu/GrDrawingManager.cpp',
-        'skia/src/gpu/GrDrawOpAtlas.cpp',
-        'skia/src/gpu/GrDrawOpTest.cpp',
-        'skia/src/gpu/GrDriverBugWorkarounds.cpp',
-        'skia/src/gpu/GrFixedClip.cpp',
-        'skia/src/gpu/GrFragmentProcessor.cpp',
-        'skia/src/gpu/GrGpu.cpp',
-        'skia/src/gpu/GrGpuCommandBuffer.cpp',
-        'skia/src/gpu/GrGpuResource.cpp',
-        'skia/src/gpu/GrImageTextureMaker.cpp',
-        'skia/src/gpu/GrMemoryPool.cpp',
-        'skia/src/gpu/GrOnFlushResourceProvider.cpp',
-        'skia/src/gpu/GrOpFlushState.cpp',
-        'skia/src/gpu/GrOpList.cpp',
-        'skia/src/gpu/GrPaint.cpp',
-        'skia/src/gpu/GrPath.cpp',
-        'skia/src/gpu/GrPathProcessor.cpp',
-        'skia/src/gpu/GrPathRenderer.cpp',
-        'skia/src/gpu/GrPathRendererChain.cpp',
-        'skia/src/gpu/GrPathRendering.cpp',
-        'skia/src/gpu/GrPipeline.cpp',
-        'skia/src/gpu/GrPrimitiveProcessor.cpp',
-        'skia/src/gpu/GrProcessor.cpp',
-        'skia/src/gpu/GrProcessorAnalysis.cpp',
-        'skia/src/gpu/GrProcessorSet.cpp',
-        'skia/src/gpu/GrProcessorUnitTest.cpp',
-        'skia/src/gpu/GrProgramDesc.cpp',
-        'skia/src/gpu/GrProxyProvider.cpp',
-        'skia/src/gpu/GrQuad.cpp',
-        'skia/src/gpu/GrRectanizer_pow2.cpp',
-        'skia/src/gpu/GrRectanizer_skyline.cpp',
-        'skia/src/gpu/GrReducedClip.cpp',
-        'skia/src/gpu/GrRenderTarget.cpp',
-        'skia/src/gpu/GrRenderTargetContext.cpp',
-        'skia/src/gpu/GrRenderTargetOpList.cpp',
-        'skia/src/gpu/GrRenderTargetProxy.cpp',
-        'skia/src/gpu/GrResourceAllocator.cpp',
-        'skia/src/gpu/GrShaderCaps.cpp',
-        'skia/src/gpu/GrShaderVar.cpp',
-        'skia/src/gpu/GrShape.cpp',
-        'skia/src/gpu/GrSKSLPrettyPrint.cpp',
-        'skia/src/gpu/GrSoftwarePathRenderer.cpp',
-        'skia/src/gpu/GrStencilAttachment.cpp',
-        'skia/src/gpu/GrStencilSettings.cpp',
-        'skia/src/gpu/GrStyle.cpp',
-        'skia/src/gpu/GrSurface.cpp',
-        'skia/src/gpu/GrSurfaceContext.cpp',
-        'skia/src/gpu/GrSurfaceProxy.cpp',
-        'skia/src/gpu/GrSWMaskHelper.cpp',
-        'skia/src/gpu/GrTessellator.cpp',
-        'skia/src/gpu/GrTestUtils.cpp',
-        'skia/src/gpu/GrTexture.cpp',
-        'skia/src/gpu/GrTextureAdjuster.cpp',
-        'skia/src/gpu/GrTextureContext.cpp',
-        'skia/src/gpu/GrTextureMaker.cpp',
-        'skia/src/gpu/GrTextureOpList.cpp',
-        'skia/src/gpu/GrTextureProducer.cpp',
-        'skia/src/gpu/GrTextureProxy.cpp',
-        'skia/src/gpu/GrTextureRenderTargetProxy.cpp',
-        'skia/src/gpu/GrUninstantiateProxyTracker.cpp',
-        'skia/src/gpu/GrXferProcessor.cpp',
-        'skia/src/gpu/GrYUVProvider.cpp',
-        'skia/src/gpu/mock/GrMockGpu.cpp',
-        'skia/src/gpu/ops/GrAtlasTextOp.cpp',
-        'skia/src/gpu/ops/GrClearOp.cpp',
-        'skia/src/gpu/ops/GrClearStencilClipOp.cpp',
-        'skia/src/gpu/ops/GrCopySurfaceOp.cpp',
-        'skia/src/gpu/ops/GrDashLinePathRenderer.cpp',
-        'skia/src/gpu/ops/GrDashOp.cpp',
-        'skia/src/gpu/ops/GrDebugMarkerOp.cpp',
-        'skia/src/gpu/ops/GrDefaultPathRenderer.cpp',
-        'skia/src/gpu/ops/GrDrawAtlasOp.cpp',
-        'skia/src/gpu/ops/GrDrawPathOp.cpp',
-        'skia/src/gpu/ops/GrDrawVerticesOp.cpp',
-        'skia/src/gpu/ops/GrLatticeOp.cpp',
-        'skia/src/gpu/ops/GrMeshDrawOp.cpp',
-        'skia/src/gpu/ops/GrNonAAStrokeRectOp.cpp',
-        'skia/src/gpu/ops/GrOp.cpp',
-        'skia/src/gpu/ops/GrOvalOpFactory.cpp',
-        'skia/src/gpu/ops/GrRegionOp.cpp',
-        'skia/src/gpu/ops/GrSemaphoreOp.cpp',
-        'skia/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp',
-        'skia/src/gpu/ops/GrSmallPathRenderer.cpp',
-        'skia/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp',
-        'skia/src/gpu/ops/GrStencilPathOp.cpp',
-        'skia/src/gpu/ops/GrTessellatingPathRenderer.cpp',
-        'skia/src/gpu/ops/GrTextureOp.cpp',
-        'skia/src/gpu/SkGpuDevice.cpp',
-        'skia/src/gpu/SkGpuDevice_drawTexture.cpp',
-        'skia/src/gpu/SkGr.cpp',
-        'skia/src/gpu/text/GrAtlasManager.cpp',
-        'skia/src/gpu/text/GrDistanceFieldAdjustTable.cpp',
-        'skia/src/gpu/text/GrGlyphCache.cpp',
-        'skia/src/gpu/text/GrSDFMaskFilter.cpp',
-        'skia/src/gpu/text/GrTextBlob.cpp',
-        'skia/src/gpu/text/GrTextBlobCache.cpp',
-        'skia/src/gpu/text/GrTextBlobVertexRegenerator.cpp',
-        'skia/src/gpu/text/GrTextContext.cpp',
-        'skia/src/image/SkImage_GpuBase.cpp',
-        'skia/src/image/SkImage_GpuYUVA.cpp',
-        'skia/src/image/SkSurface_Gpu.cpp',
-        'skia/src/sksl/ir/SkSLSetting.cpp',
-        'skia/src/sksl/ir/SkSLSymbolTable.cpp',
-        'skia/src/sksl/ir/SkSLType.cpp',
-        'skia/src/sksl/ir/SkSLVariableReference.cpp',
-        'skia/src/sksl/SkSLCFGGenerator.cpp',
-        'skia/src/sksl/SkSLCompiler.cpp',
-        'skia/src/sksl/SkSLCPPCodeGenerator.cpp',
-        'skia/src/sksl/SkSLCPPUniformCTypes.cpp',
-        'skia/src/sksl/SkSLGLSLCodeGenerator.cpp',
-        'skia/src/sksl/SkSLInterpreter.cpp',
-        'skia/src/sksl/SkSLIRGenerator.cpp',
-        'skia/src/sksl/SkSLJIT.cpp',
-        'skia/src/sksl/SkSLMetalCodeGenerator.cpp',
-        'skia/src/sksl/SkSLParser.cpp',
-        'skia/src/sksl/SkSLPipelineStageCodeGenerator.cpp',
-        'skia/src/sksl/SkSLSPIRVCodeGenerator.cpp',
-        'skia/src/sksl/SkSLString.cpp',
-        'skia/src/sksl/SkSLUtil.cpp',
-    ]
-    SOURCES += [
-        'skia/src/gpu/ccpr/GrCCPathProcessor.cpp',
-        'skia/src/gpu/ccpr/GrCCStrokeGeometry.cpp',
-        'skia/src/gpu/effects/GrAARectEffect.cpp',
-        'skia/src/gpu/effects/GrAlphaThresholdFragmentProcessor.cpp',
-        'skia/src/gpu/effects/GrBezierEffect.cpp',
-        'skia/src/gpu/effects/GrBicubicEffect.cpp',
-        'skia/src/gpu/effects/GrBitmapTextGeoProc.cpp',
-        'skia/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp',
-        'skia/src/gpu/effects/GrCircleBlurFragmentProcessor.cpp',
-        'skia/src/gpu/effects/GrCircleEffect.cpp',
-        'skia/src/gpu/effects/GrConfigConversionEffect.cpp',
-        'skia/src/gpu/effects/GrConstColorProcessor.cpp',
-        'skia/src/gpu/effects/GrConvexPolyEffect.cpp',
-        'skia/src/gpu/effects/GrCoverageSetOpXP.cpp',
-        'skia/src/gpu/effects/GrCustomXfermode.cpp',
-        'skia/src/gpu/effects/GrDisableColorXP.cpp',
-        'skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp',
-        'skia/src/gpu/effects/GrEllipseEffect.cpp',
-        'skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp',
-        'skia/src/gpu/effects/GrLumaColorFilterEffect.cpp',
-        'skia/src/gpu/effects/GrMagnifierEffect.cpp',
-        'skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp',
-        'skia/src/gpu/effects/GrOvalEffect.cpp',
-        'skia/src/gpu/effects/GrPorterDuffXferProcessor.cpp',
-        'skia/src/gpu/effects/GrPremulInputFragmentProcessor.cpp',
-        'skia/src/gpu/effects/GrRectBlurEffect.cpp',
-        'skia/src/gpu/effects/GrRRectBlurEffect.cpp',
-        'skia/src/gpu/effects/GrRRectEffect.cpp',
-        'skia/src/gpu/effects/GrShadowGeoProc.cpp',
-        'skia/src/gpu/effects/GrSimpleTextureEffect.cpp',
-        'skia/src/gpu/effects/GrSkSLFP.cpp',
-        'skia/src/gpu/effects/GrSRGBEffect.cpp',
-        'skia/src/gpu/effects/GrTextureDomain.cpp',
-        'skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp',
-        'skia/src/gpu/effects/GrYUVtoRGBEffect.cpp',
-        'skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp',
-        'skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp',
-        'skia/src/gpu/gl/GrGLBuffer.cpp',
-        'skia/src/gpu/gl/GrGLCaps.cpp',
-        'skia/src/gpu/gl/GrGLContext.cpp',
-        'skia/src/gpu/gl/GrGLExtensions.cpp',
-        'skia/src/gpu/gl/GrGLGLSL.cpp',
-        'skia/src/gpu/gl/GrGLGpu.cpp',
-        'skia/src/gpu/gl/GrGLGpuCommandBuffer.cpp',
-        'skia/src/gpu/gl/GrGLGpuProgramCache.cpp',
-        'skia/src/gpu/gl/GrGLInterface.cpp',
-        'skia/src/gpu/gl/GrGLPath.cpp',
-        'skia/src/gpu/gl/GrGLPathRendering.cpp',
-        'skia/src/gpu/gl/GrGLProgram.cpp',
-        'skia/src/gpu/gl/GrGLProgramDataManager.cpp',
-        'skia/src/gpu/gl/GrGLRenderTarget.cpp',
-        'skia/src/gpu/gl/GrGLSemaphore.cpp',
-        'skia/src/gpu/gl/GrGLStencilAttachment.cpp',
-        'skia/src/gpu/gl/GrGLTexture.cpp',
-        'skia/src/gpu/gl/GrGLTextureRenderTarget.cpp',
-        'skia/src/gpu/gl/GrGLUniformHandler.cpp',
-        'skia/src/gpu/gl/GrGLUtil.cpp',
-        'skia/src/gpu/gl/GrGLVaryingHandler.cpp',
-        'skia/src/gpu/gl/GrGLVertexArray.cpp',
-        'skia/src/gpu/glsl/GrGLSL.cpp',
-        'skia/src/gpu/glsl/GrGLSLBlend.cpp',
-        'skia/src/gpu/glsl/GrGLSLFragmentProcessor.cpp',
-        'skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp',
-        'skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp',
-        'skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp',
-        'skia/src/gpu/glsl/GrGLSLProgramBuilder.cpp',
-        'skia/src/gpu/glsl/GrGLSLProgramDataManager.cpp',
-        'skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp',
-        'skia/src/gpu/glsl/GrGLSLUtil.cpp',
-        'skia/src/gpu/glsl/GrGLSLVarying.cpp',
-        'skia/src/gpu/glsl/GrGLSLVertexGeoBuilder.cpp',
-        'skia/src/gpu/glsl/GrGLSLXferProcessor.cpp',
-        'skia/src/gpu/gradients/GrClampedGradientEffect.cpp',
-        'skia/src/gpu/gradients/GrDualIntervalGradientColorizer.cpp',
-        'skia/src/gpu/gradients/GrGradientBitmapCache.cpp',
-        'skia/src/gpu/gradients/GrGradientShader.cpp',
-        'skia/src/gpu/gradients/GrLinearGradientLayout.cpp',
-        'skia/src/gpu/gradients/GrRadialGradientLayout.cpp',
-        'skia/src/gpu/gradients/GrSingleIntervalGradientColorizer.cpp',
-        'skia/src/gpu/gradients/GrSweepGradientLayout.cpp',
-        'skia/src/gpu/gradients/GrTextureGradientColorizer.cpp',
-        'skia/src/gpu/gradients/GrTiledGradientEffect.cpp',
-        'skia/src/gpu/gradients/GrTwoPointConicalGradientLayout.cpp',
-        'skia/src/gpu/gradients/GrUnrolledBinaryGradientColorizer.cpp',
-        'skia/src/gpu/GrPathUtils.cpp',
-        'skia/src/gpu/GrResourceCache.cpp',
-        'skia/src/gpu/GrResourceProvider.cpp',
-        'skia/src/gpu/ops/GrAAConvexPathRenderer.cpp',
-        'skia/src/gpu/ops/GrAAConvexTessellator.cpp',
-        'skia/src/gpu/ops/GrAAFillRectOp.cpp',
-        'skia/src/gpu/ops/GrAAHairLinePathRenderer.cpp',
-        'skia/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp',
-        'skia/src/gpu/ops/GrAAStrokeRectOp.cpp',
-        'skia/src/gpu/ops/GrNonAAFillRectOp.cpp',
-        'skia/src/gpu/ops/GrShadowRRectOp.cpp',
-        'skia/src/image/SkImage_Gpu.cpp',
-        'skia/src/sksl/SkSLHCodeGenerator.cpp',
-        'skia/src/sksl/SkSLLexer.cpp',
-    ]
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     UNIFIED_SOURCES += [
         'skia/src/ports/SkDebug_android.cpp',
         'skia/src/ports/SkOSFile_posix.cpp',
         'skia/src/ports/SkOSLibrary_posix.cpp',
         'skia/src/ports/SkTLS_pthread.cpp',
     ]
     SOURCES += [
@@ -728,20 +472,16 @@ LOCAL_INCLUDES += [
     'skia/include/gpu',
     'skia/include/pathops',
     'skia/include/ports',
     'skia/include/private',
     'skia/include/utils',
     'skia/include/utils/mac',
     'skia/src/codec',
     'skia/src/core',
-    'skia/src/gpu',
-    'skia/src/gpu/effects',
-    'skia/src/gpu/gl',
-    'skia/src/gpu/glsl',
     'skia/src/image',
     'skia/src/lazy',
     'skia/src/opts',
     'skia/src/sfnt',
     'skia/src/shaders',
     'skia/src/shaders/gradients',
     'skia/src/sksl',
     'skia/src/utils',
@@ -773,19 +513,16 @@ elif CONFIG['CPU_ARCH'] == 'arm' and CON
 elif CONFIG['CPU_ARCH'] == 'aarch64' and CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     SOURCES['skia/src/opts/SkOpts_crc32.cpp'].flags += ['-march=armv8-a+crc']
 
 DEFINES['SKIA_IMPLEMENTATION'] = 1
 
 if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY']:
     DEFINES['SK_PDF_USE_SFNTLY'] = 1
 
-if not CONFIG['MOZ_ENABLE_SKIA_GPU']:
-    DEFINES['SK_SUPPORT_GPU'] = 0
-
 if CONFIG['MOZ_TREE_FREETYPE']:
     DEFINES['SK_CAN_USE_DLOPEN'] = 0
 
 # Suppress warnings in third-party code.
 CXXFLAGS += [
     '-Wno-deprecated-declarations',
     '-Wno-overloaded-virtual',
     '-Wno-shadow',
--- a/gfx/skia/skia/include/config/SkUserConfig.h
+++ b/gfx/skia/skia/include/config/SkUserConfig.h
@@ -149,17 +149,11 @@
 #    define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
 #  else
 #    define MOZ_IMPLICIT
 #  endif
 #endif
 
 #define MOZ_SKIA
 
-#ifndef SK_SUPPORT_GPU
-#  ifdef USE_SKIA_GPU
-#    define SK_SUPPORT_GPU 1
-#  else
-#    define SK_SUPPORT_GPU 0
-#  endif
-#endif
+#define SK_SUPPORT_GPU 0
 
 #endif
--- a/gfx/tests/gtest/TestGfxPrefs.cpp
+++ b/gfx/tests/gtest/TestGfxPrefs.cpp
@@ -40,19 +40,16 @@ TEST(GfxPrefs, OnceValues) {
   ASSERT_TRUE(gfxPrefs::SingletonExists());
 
   // Once boolean, default true
   ASSERT_TRUE(gfxPrefs::WorkAroundDriverBugs());
 
   // Once boolean, default false
   ASSERT_FALSE(gfxPrefs::LayersDump());
 
-  // Once int32_t, default 95
-  ASSERT_TRUE(gfxPrefs::CanvasSkiaGLCacheSize() == 96);
-
   // Once uint32_t, default 5
   ASSERT_TRUE(gfxPrefs::APZMaxVelocityQueueSize() == 5);
 
   // Once float, default -1 (should be OK with ==)
   ASSERT_TRUE(gfxPrefs::APZMaxVelocity() == -1.0f);
 }
 
 TEST(GfxPrefs, Set) {
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -104,36 +104,27 @@
 #include "mozilla/gfx/Logging.h"
 
 #ifdef USE_SKIA
 #  ifdef __GNUC__
 #    pragma GCC diagnostic push
 #    pragma GCC diagnostic ignored "-Wshadow"
 #  endif
 #  include "skia/include/core/SkGraphics.h"
-#  ifdef USE_SKIA_GPU
-#    include "skia/include/gpu/GrContext.h"
-#    include "skia/include/gpu/gl/GrGLInterface.h"
-#    include "SkiaGLGlue.h"
-#  endif
 #  ifdef MOZ_ENABLE_FREETYPE
 #    include "skia/include/ports/SkTypeface_cairo.h"
 #  endif
 #  include "mozilla/gfx/SkMemoryReporter.h"
 #  ifdef __GNUC__
 #    pragma GCC diagnostic pop  // -Wshadow
 #  endif
 static const uint32_t kDefaultGlyphCacheSize = -1;
 
 #endif
 
-#if !defined(USE_SKIA) || !defined(USE_SKIA_GPU)
-class mozilla::gl::SkiaGLGlue : public GenericAtomicRefCounted {};
-#endif
-
 #include "mozilla/Preferences.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Mutex.h"
 
 #include "nsAlgorithm.h"
 #include "nsIGfxInfo.h"
@@ -443,17 +434,16 @@ static void FontPrefChanged(const char* 
   gfxPlatform::GetPlatform()->FontsPrefsChanged(aPref);
 }
 
 void gfxPlatform::OnMemoryPressure(layers::MemoryPressureReason aWhy) {
   Factory::PurgeAllCaches();
   gfxGradientCache::PurgeAllCaches();
   gfxFontMissingGlyphs::Purge();
   PurgeSkiaFontCache();
-  PurgeSkiaGPUCache();
   if (XRE_IsParentProcess()) {
     layers::CompositorManagerChild* manager =
         CompositorManagerChild::GetInstance();
     if (manager) {
       manager->SendNotifyMemoryPressure();
     }
   }
 }
@@ -470,18 +460,16 @@ gfxPlatform::gfxPlatform()
   mFallbackUsesCmaps = UNINITIALIZED_VALUE;
 
   mWordCacheCharLimit = UNINITIALIZED_VALUE;
   mWordCacheMaxEntries = UNINITIALIZED_VALUE;
   mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
   mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
   mBidiNumeralOption = UNINITIALIZED_VALUE;
 
-  mSkiaGlue = nullptr;
-
   InitBackendPrefs(GetBackendPrefs());
 
   mTotalSystemMemory = PR_GetPhysicalMemorySize();
 
   VRManager::ManagerInit();
 }
 
 gfxPlatform* gfxPlatform::GetPlatform() {
@@ -883,17 +871,17 @@ void gfxPlatform::Init() {
     forcedPrefs.AppendPrintf(
         "-W%d%d%d%d%d%d%d%d", gfxPrefs::WebGLANGLEForceD3D11(),
         gfxPrefs::WebGLANGLEForceWARP(), gfxPrefs::WebGLDisabled(),
         gfxPrefs::WebGLDisableANGLE(), gfxPrefs::WebGLDXGLEnabled(),
         gfxPrefs::WebGLForceEnabled(), gfxPrefs::WebGLForceLayersReadback(),
         gfxPrefs::WebGLForceMSAA());
     // Prefs that don't fit into any of the other sections
     forcedPrefs.AppendPrintf("-T%d%d%d) ", gfxPrefs::AndroidRGB16Force(),
-                             gfxPrefs::CanvasAzureAccelerated(),
+                             0, // SkiaGL canvas no longer supported
                              gfxPrefs::ForceShmemTiles());
     ScopedGfxFeatureReporter::AppNote(forcedPrefs);
   }
 
   InitMoz2DLogging();
 
   gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock");
 
@@ -1190,17 +1178,16 @@ void gfxPlatform::Shutdown() {
   Preferences::UnregisterPrefixCallbacks(FontPrefChanged, kObservedPrefs);
 
   NS_ASSERTION(gPlatform->mMemoryPressureObserver,
                "mMemoryPressureObserver has already gone");
   if (gPlatform->mMemoryPressureObserver) {
     gPlatform->mMemoryPressureObserver->Unregister();
     gPlatform->mMemoryPressureObserver = nullptr;
   }
-  gPlatform->mSkiaGlue = nullptr;
 
   if (XRE_IsParentProcess()) {
     gPlatform->mVsyncSource->Shutdown();
   }
 
   gPlatform->mVsyncSource = nullptr;
 
   // Shut down the default GL context provider.
@@ -1572,148 +1559,28 @@ void gfxPlatform::PopulateScreenInfo() {
   screen->GetRect(&left, &top, &mScreenSize.width, &mScreenSize.height);
 }
 
 bool gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget) {
   if (!aTarget || !aTarget->IsValid()) {
     return false;
   }
 
-#ifdef USE_SKIA_GPU
-  // Skia content rendering doesn't support GPU acceleration, so we can't
-  // use the same backend if the current backend is accelerated.
-  if ((aTarget->GetType() == DrawTargetType::HARDWARE_RASTER) &&
-      (aTarget->GetBackendType() == BackendType::SKIA)) {
-    return false;
-  }
-#endif
-
   return SupportsAzureContentForType(aTarget->GetBackendType());
 }
 
-bool gfxPlatform::AllowOpenGLCanvas() {
-  // For now, only allow Skia+OpenGL, unless it's blocked.
-  // Allow acceleration on Skia if the preference is set, unless it's blocked
-  // as long as we have the accelerated layers
-
-  // The compositor backend is only set correctly in the parent process,
-  // so we let content process always assume correct compositor backend.
-  // The callers have to do the right thing.
-  //
-  // XXX Disable SkiaGL on WebRender, since there is a case that R8G8B8X8
-  // is used, but WebRender does not support R8G8B8X8.
-  bool correctBackend =
-      !XRE_IsParentProcess() ||
-      (mCompositorBackend == LayersBackend::LAYERS_OPENGL &&
-       (GetContentBackendFor(mCompositorBackend) == BackendType::SKIA));
-
-  if (gfxPrefs::CanvasAzureAccelerated() && correctBackend) {
-    nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
-    int32_t status;
-    nsCString discardFailureId;
-    return !gfxInfo || (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(
-                            nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION,
-                            discardFailureId, &status)) &&
-                        status == nsIGfxInfo::FEATURE_STATUS_OK);
-  }
-  return false;
-}
-
-void gfxPlatform::InitializeSkiaCacheLimits() {
-  if (AllowOpenGLCanvas()) {
-#ifdef USE_SKIA_GPU
-    bool usingDynamicCache = gfxPrefs::CanvasSkiaGLDynamicCache();
-    int cacheItemLimit = gfxPrefs::CanvasSkiaGLCacheItems();
-    uint64_t cacheSizeLimit =
-        std::max(gfxPrefs::CanvasSkiaGLCacheSize(), (int32_t)0);
-
-    // Prefs are in megabytes, but we want the sizes in bytes
-    cacheSizeLimit *= 1024 * 1024;
-
-    if (usingDynamicCache) {
-      if (mTotalSystemMemory < 512 * 1024 * 1024) {
-        // We need a very minimal cache on anything smaller than 512mb.
-        // Note the large jump as we cross 512mb (from 2mb to 32mb).
-        cacheSizeLimit = 2 * 1024 * 1024;
-      } else if (mTotalSystemMemory > 0) {
-        cacheSizeLimit = mTotalSystemMemory / 16;
-      }
-    }
-
-    // Ensure cache size doesn't overflow on 32-bit platforms.
-    cacheSizeLimit = std::min(cacheSizeLimit, (uint64_t)SIZE_MAX);
-
-#  ifdef DEBUG
-    printf_stderr("Determined SkiaGL cache limits: Size %" PRIu64
-                  ", Items: %i\n",
-                  cacheSizeLimit, cacheItemLimit);
-#  endif
-
-    mSkiaGlue->GetGrContext()->setResourceCacheLimits(cacheItemLimit,
-                                                      (size_t)cacheSizeLimit);
-#endif
-  }
-}
-
-SkiaGLGlue* gfxPlatform::GetSkiaGLGlue() {
-#ifdef USE_SKIA_GPU
-  // Check the accelerated Canvas is enabled for the first time,
-  // because the callers should check it before using.
-  if (!mSkiaGlue && !AllowOpenGLCanvas()) {
-    return nullptr;
-  }
-
-  if (!mSkiaGlue) {
-    /* Dummy context. We always draw into a FBO.
-     *
-     * FIXME: This should be stored in TLS or something, since there needs to be
-     * one for each thread using it. As it stands, this only works on the main
-     * thread.
-     */
-    RefPtr<GLContext> glContext;
-    nsCString discardFailureId;
-    glContext = GLContextProvider::CreateHeadless(
-        CreateContextFlags::REQUIRE_COMPAT_PROFILE |
-            CreateContextFlags::ALLOW_OFFLINE_RENDERER,
-        &discardFailureId);
-    if (!glContext) {
-      printf_stderr("Failed to create GLContext for SkiaGL!\n");
-      return nullptr;
-    }
-    mSkiaGlue = new SkiaGLGlue(glContext);
-    MOZ_ASSERT(mSkiaGlue->GetGrContext(), "No GrContext");
-    InitializeSkiaCacheLimits();
-  }
-#endif
-
-  return mSkiaGlue;
-}
-
 void gfxPlatform::PurgeSkiaFontCache() {
 #ifdef USE_SKIA
   if (gfxPlatform::GetPlatform()->GetDefaultContentBackend() ==
       BackendType::SKIA) {
     SkGraphics::PurgeFontCache();
   }
 #endif
 }
 
-void gfxPlatform::PurgeSkiaGPUCache() {
-#ifdef USE_SKIA_GPU
-  if (!mSkiaGlue) return;
-
-  mSkiaGlue->GetGrContext()->freeGpuResources();
-  // GrContext::flush() doesn't call glFlush. Call it here.
-  mSkiaGlue->GetGLContext()->MakeCurrent();
-  mSkiaGlue->GetGLContext()->fFlush();
-#endif
-}
-
-bool gfxPlatform::HasEnoughTotalSystemMemoryForSkiaGL() { return true; }
-
 already_AddRefed<DrawTarget> gfxPlatform::CreateDrawTargetForBackend(
     BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat) {
   // There is a bunch of knowledge in the gfxPlatform heirarchy about how to
   // create the best offscreen surface for the current system and situation. We
   // can easily take advantage of this for the Cairo backend, so that's what we
   // do.
   // mozilla::gfx::Factory can get away without having all this knowledge for
   // now, but this might need to change in the future (using
@@ -3134,18 +3001,16 @@ void gfxPlatform::GetAzureBackendInfo(mo
     aObj.DefineProperty("AzureContentBackend", GetBackendName(contentBackend));
   } else {
     aObj.DefineProperty("AzureCanvasBackend",
                         GetBackendName(mPreferredCanvasBackend));
     aObj.DefineProperty("AzureFallbackCanvasBackend",
                         GetBackendName(mFallbackCanvasBackend));
     aObj.DefineProperty("AzureContentBackend", GetBackendName(mContentBackend));
   }
-
-  aObj.DefineProperty("AzureCanvasAccelerated", AllowOpenGLCanvas());
 }
 
 void gfxPlatform::GetApzSupportInfo(mozilla::widget::InfoObject& aObj) {
   if (!gfxPlatform::AsyncPanZoomEnabled()) {
     return;
   }
 
   if (SupportsApzWheelInput()) {
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -39,19 +39,16 @@ class gfxTextRun;
 class nsIURI;
 class nsAtom;
 class nsIObserver;
 class SRGBOverrideObserver;
 class gfxTextPerfMetrics;
 typedef struct FT_LibraryRec_* FT_Library;
 
 namespace mozilla {
-namespace gl {
-class SkiaGLGlue;
-}  // namespace gl
 namespace layers {
 class FrameStats;
 }
 namespace gfx {
 class DrawTarget;
 class SourceSurface;
 class DataSourceSurface;
 class ScaledFont;
@@ -271,25 +268,16 @@ class gfxPlatform : public mozilla::laye
    * will return false.
    */
   bool SupportsAzureContentForDrawTarget(mozilla::gfx::DrawTarget* aTarget);
 
   bool SupportsAzureContentForType(mozilla::gfx::BackendType aType) {
     return BackendTypeBit(aType) & mContentBackendBitmask;
   }
 
-  /// This function also lets us know if the current preferences/platform
-  /// combination allows for both accelerated and not accelerated canvas
-  /// implementations.  If it does, and other relevant preferences are
-  /// asking for it, we will examine the commands in the first few seconds
-  /// of the canvas usage, and potentially change to accelerated or
-  /// non-accelerated canvas.
-  virtual bool AllowOpenGLCanvas();
-  virtual void InitializeSkiaCacheLimits();
-
   static bool AsyncPanZoomEnabled();
 
   virtual void GetAzureBackendInfo(mozilla::widget::InfoObject& aObj);
   void GetApzSupportInfo(mozilla::widget::InfoObject& aObj);
   void GetTilesSupportInfo(mozilla::widget::InfoObject& aObj);
   void GetFrameStats(mozilla::widget::InfoObject& aObj);
 
   // Get the default content backend that will be used with the default
@@ -610,24 +598,20 @@ class gfxPlatform : public mozilla::laye
   int GetScreenDepth() const { return mScreenDepth; }
   mozilla::gfx::IntSize GetScreenSize() const { return mScreenSize; }
 
   /**
    * Return the layer debugging options to use browser-wide.
    */
   mozilla::layers::DiagnosticTypes GetLayerDiagnosticTypes();
 
-  mozilla::gl::SkiaGLGlue* GetSkiaGLGlue();
-  void PurgeSkiaGPUCache();
   static void PurgeSkiaFontCache();
 
   static bool UsesOffMainThreadCompositing();
 
-  bool HasEnoughTotalSystemMemoryForSkiaGL();
-
   /**
    * Whether we want to adjust gfx parameters (currently just
    * the framerate and whether we use software vs. hardware vsync)
    * down because we've determined we're on a low-end machine.
    * This will return false if the user has turned on fingerprinting
    * resistance (to ensure consistent behavior across devices).
    */
   static bool ShouldAdjustForLowEndMachine();
@@ -929,17 +913,16 @@ class gfxPlatform : public mozilla::laye
   mozilla::widget::GfxInfoCollector<gfxPlatform> mAzureCanvasBackendCollector;
   mozilla::widget::GfxInfoCollector<gfxPlatform> mApzSupportCollector;
   mozilla::widget::GfxInfoCollector<gfxPlatform> mTilesInfoCollector;
   mozilla::widget::GfxInfoCollector<gfxPlatform> mFrameStatsCollector;
 
   nsTArray<mozilla::layers::FrameStats> mFrameStats;
 
   RefPtr<mozilla::gfx::DrawEventRecorder> mRecorder;
-  RefPtr<mozilla::gl::SkiaGLGlue> mSkiaGlue;
 
   // Backend that we are compositing with. NONE, if no compositor has been
   // created yet.
   mozilla::layers::LayersBackend mCompositorBackend;
 
   int32_t mScreenDepth;
   mozilla::gfx::IntSize mScreenSize;
 
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -463,26 +463,18 @@ class gfxPrefs final {
   // Used for drawing a border around the content.
   DECL_GFX_PREF(Live, "gfx.compositor.override.clear-color.r", CompositorOverrideClearColorR, float, 0.0f);
   DECL_GFX_PREF(Live, "gfx.compositor.override.clear-color.g", CompositorOverrideClearColorG, float, 0.0f);
   DECL_GFX_PREF(Live, "gfx.compositor.override.clear-color.b", CompositorOverrideClearColorB, float, 0.0f);
   DECL_GFX_PREF(Live, "gfx.compositor.override.clear-color.a", CompositorOverrideClearColorA, float, 0.0f);
 #endif // defined(MOZ_WIDGET_ANDROID)
   DECL_GFX_PREF(Live, "gfx.compositor.clearstate",             CompositorClearState, bool, false);
   DECL_GFX_PREF(Live, "gfx.compositor.glcontext.opaque",       CompositorGLContextOpaque, bool, false);
-  DECL_GFX_PREF(Live, "gfx.canvas.auto_accelerate.min_calls",  CanvasAutoAccelerateMinCalls, int32_t, 4);
-  DECL_GFX_PREF(Live, "gfx.canvas.auto_accelerate.min_frames", CanvasAutoAccelerateMinFrames, int32_t, 30);
-  DECL_GFX_PREF(Live, "gfx.canvas.auto_accelerate.min_seconds", CanvasAutoAccelerateMinSeconds, float, 5.0f);
-  DECL_GFX_PREF(Live, "gfx.canvas.azure.accelerated",          CanvasAzureAccelerated, bool, false);
-  DECL_GFX_PREF(Once, "gfx.canvas.azure.accelerated.limit",    CanvasAzureAcceleratedLimit, int32_t, 0);
   // 0x7fff is the maximum supported xlib surface size and is more than enough for canvases.
   DECL_GFX_PREF(Live, "gfx.canvas.max-size",                   MaxCanvasSize, int32_t, 0x7fff);
-  DECL_GFX_PREF(Once, "gfx.canvas.skiagl.cache-items",         CanvasSkiaGLCacheItems, int32_t, 256);
-  DECL_GFX_PREF(Once, "gfx.canvas.skiagl.cache-size",          CanvasSkiaGLCacheSize, int32_t, 96);
-  DECL_GFX_PREF(Once, "gfx.canvas.skiagl.dynamic-cache",       CanvasSkiaGLDynamicCache, bool, false);
 
   DECL_GFX_PREF(Live, "gfx.color_management.enablev4",         CMSEnableV4, bool, false);
   DECL_GFX_PREF(Live, "gfx.color_management.mode",             CMSMode, int32_t,-1);
   // The zero default here should match QCMS_INTENT_DEFAULT from qcms.h
   DECL_GFX_PREF(Live, "gfx.color_management.rendering_intent", CMSRenderingIntent, int32_t, 0);
   DECL_GFX_PREF(Live, "gfx.content.always-paint",              AlwaysPaint, bool, false);
   // Size in megabytes
   DECL_GFX_PREF(Once, "gfx.content.skia-font-cache-size",      SkiaContentFontCacheSize, int32_t, 5);
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -580,21 +580,16 @@ void gfxWindowsPlatform::UpdateRenderMod
           << ", content:" << int(GetDefaultContentBackend())
           << ", compositor:" << int(GetCompositorBackend());
       MOZ_CRASH(
           "GFX: Failed to update reference draw target after device reset");
     }
   }
 }
 
-bool gfxWindowsPlatform::AllowOpenGLCanvas() {
-  // OpenGL canvas is not supported on windows
-  return false;
-}
-
 mozilla::gfx::BackendType gfxWindowsPlatform::GetContentBackendFor(
     mozilla::layers::LayersBackend aLayers) {
   mozilla::gfx::BackendType defaultBackend =
       gfxPlatform::GetDefaultContentBackend();
   if (aLayers == LayersBackend::LAYERS_D3D11) {
     return defaultBackend;
   }
 
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -162,18 +162,16 @@ class gfxWindowsPlatform : public gfxPla
 
   virtual void CompositorUpdated() override;
 
   bool DidRenderingDeviceReset(
       DeviceResetReason* aResetReason = nullptr) override;
   void SchedulePaintIfDeviceReset() override;
   void CheckForContentOnlyDeviceReset();
 
-  bool AllowOpenGLCanvas() override;
-
   mozilla::gfx::BackendType GetContentBackendFor(
       mozilla::layers::LayersBackend aLayers) override;
 
   mozilla::gfx::BackendType GetPreferredCanvasBackend() override;
 
   static void GetDLLVersion(char16ptr_t aDLLPath, nsAString& aVersion);
 
   // returns ClearType tuning information for each display
--- a/gfx/webrender_bindings/RenderCompositorEGL.cpp
+++ b/gfx/webrender_bindings/RenderCompositorEGL.cpp
@@ -77,16 +77,18 @@ RenderCompositorEGL::RenderCompositorEGL
   MOZ_ASSERT(mGL);
 }
 
 RenderCompositorEGL::~RenderCompositorEGL() { DestroyEGLSurface(); }
 
 bool RenderCompositorEGL::BeginFrame() {
   if (mWidget->AsX11() &&
       mWidget->AsX11()->WaylandRequestsUpdatingEGLSurface()) {
+    // Destroy EGLSurface if it exists.
+    DestroyEGLSurface();
     mEGLSurface = CreateEGLSurface(mWidget);
     gl::GLContextEGL::Cast(gl())->SetEGLSurfaceOverride(mEGLSurface);
   }
 
   if (!mGL->MakeCurrent()) {
     gfxCriticalNote << "Failed to make render context current, can't draw.";
     return false;
   }
--- a/gfx/wr/webrender/src/frame_builder.rs
+++ b/gfx/wr/webrender/src/frame_builder.rs
@@ -470,18 +470,21 @@ impl FrameBuilder {
 
         frame_state.pop_dirty_region();
 
         let child_tasks = frame_state
             .surfaces[ROOT_SURFACE_INDEX.0]
             .take_render_tasks();
 
         let root_render_task = RenderTask::new_picture(
-            RenderTaskLocation::Fixed(self.screen_rect.to_i32()),
-            self.screen_rect.size.to_f32(),
+            // The rect here is the whole window. If we were to use the screen_rect,
+            // any offset in that rect would doubly apply for cached pictures.
+            RenderTaskLocation::Fixed(DeviceIntRect::new(DeviceIntPoint::zero(),
+                                                         self.window_size).to_i32()),
+            self.window_size.to_f32(),
             self.root_pic_index,
             DeviceIntPoint::zero(),
             child_tasks,
             UvRectKind::Rect,
             root_spatial_node_index,
             global_device_pixel_scale,
         );
 
--- a/gfx/wr/webrender/src/renderer.rs
+++ b/gfx/wr/webrender/src/renderer.rs
@@ -2536,16 +2536,24 @@ impl Renderer {
         if self.active_documents.is_empty() {
             self.last_time = precise_time_ns();
             return Ok(results);
         }
 
         let mut frame_profiles = Vec::new();
         let mut profile_timers = RendererProfileTimers::new();
 
+        // The texture resolver scope should be outside of any rendering, including
+        // debug rendering. This ensures that when we return render targets to the
+        // pool via glInvalidateFramebuffer, we don't do any debug rendering after
+        // that point. Otherwise, the bind / invalidate / bind logic trips up the
+        // render pass logic in tiled / mobile GPUs, resulting in an extra copy /
+        // resolve step when the debug overlay is enabled.
+        self.texture_resolver.begin_frame();
+
         let profile_samplers = {
             let _gm = self.gpu_profile.start_marker("build samples");
             // Block CPU waiting for last frame's GPU profiles to arrive.
             // In general this shouldn't block unless heavily GPU limited.
             let (gpu_frame_id, timers, samplers) = self.gpu_profile.build_samples();
 
             if self.max_recorded_profiles > 0 {
                 while self.gpu_profiles.len() >= self.max_recorded_profiles {
@@ -2570,68 +2578,72 @@ impl Renderer {
             //self.update_shaders();
 
             self.update_texture_cache();
 
             frame_id
         });
 
         profile_timers.cpu_time.profile(|| {
-            let clear_depth_value = if self.are_documents_intersecting_depth() {
-                None
-            } else {
-                Some(1.0)
-            };
+            // If the documents don't intersect for depth, we can just do
+            // a single, global depth clear.
+            let clear_depth_per_doc = self.are_documents_intersecting_depth();
 
             //Note: another borrowck dance
             let mut active_documents = mem::replace(&mut self.active_documents, Vec::default());
             // sort by the document layer id
             active_documents.sort_by_key(|&(_, ref render_doc)| render_doc.frame.layer);
 
-            // don't clear the framebuffer if one of the rendered documents will overwrite it
-            if let Some(framebuffer_size) = framebuffer_size {
-                let needs_color_clear = !active_documents
-                    .iter()
-                    .any(|&(_, RenderedDocument { ref frame, .. })| {
-                        frame.background_color.is_some() &&
-                        frame.inner_rect.origin == DeviceIntPoint::zero() &&
-                        frame.inner_rect.size == framebuffer_size
-                    });
-
-                if needs_color_clear || clear_depth_value.is_some() {
-                    let clear_color = if needs_color_clear {
-                        self.clear_color.map(|color| color.to_array())
-                    } else {
-                        None
-                    };
-                    self.device.reset_draw_target();
-                    self.device.enable_depth_write();
-                    self.device.clear_target(clear_color, clear_depth_value, None);
-                    self.device.disable_depth_write();
-                }
-            }
-
             #[cfg(feature = "replay")]
             self.texture_resolver.external_images.extend(
                 self.owned_external_images.iter().map(|(key, value)| (*key, value.clone()))
             );
 
-            for &mut (_, RenderedDocument { ref mut frame, .. }) in &mut active_documents {
+            for (doc_index, (_, RenderedDocument { ref mut frame, .. })) in active_documents.iter_mut().enumerate() {
                 frame.profile_counters.reset_targets();
                 self.prepare_gpu_cache(frame);
                 assert!(frame.gpu_cache_frame_id <= self.gpu_cache_frame_id,
                     "Received frame depends on a later GPU cache epoch ({:?}) than one we received last via `UpdateGpuCache` ({:?})",
                     frame.gpu_cache_frame_id, self.gpu_cache_frame_id);
 
+                // Work out what color to clear the frame buffer for this document.
+                // The document's supplied clear color is used, unless:
+                //  (a) The document has no specified clear color AND
+                //  (b) We are rendering the first document.
+                // If both those conditions are true, the overall renderer
+                // clear color will be used, if specified.
+
+                // Get the default clear color from the renderer.
+                let mut fb_clear_color = if doc_index == 0 {
+                    self.clear_color
+                } else {
+                    None
+                };
+
+                // Override with document clear color if no overall clear
+                // color or not on the first document.
+                if fb_clear_color.is_none() {
+                    fb_clear_color = frame.background_color;
+                }
+
+                // Only clear the depth buffer for this document if this is
+                // the first document, or we need to clear depth per document.
+                let fb_clear_depth = if clear_depth_per_doc || doc_index == 0 {
+                    Some(1.0)
+                } else {
+                    None
+                };
+
                 self.draw_tile_frame(
                     frame,
                     framebuffer_size,
-                    clear_depth_value.is_some(),
                     cpu_frame_id,
-                    &mut results.stats
+                    &mut results.stats,
+                    fb_clear_color,
+                    fb_clear_depth,
                 );
 
                 if self.debug_flags.contains(DebugFlags::PROFILER_DBG) {
                     frame_profiles.push(frame.profile_counters.clone());
                 }
 
                 let dirty_regions =
                     mem::replace(&mut frame.recorded_dirty_regions, Vec::new());
@@ -2728,16 +2740,22 @@ impl Renderer {
         self.gpu_cache_upload_time = 0;
 
         profile_timers.cpu_time.profile(|| {
             let _gm = self.gpu_profile.start_marker("end frame");
             self.gpu_profile.end_frame();
             if let Some(debug_renderer) = self.debug.try_get_mut() {
                 debug_renderer.render(&mut self.device, framebuffer_size);
             }
+            // See comment for texture_resolver.begin_frame() for explanation
+            // of why this must be done after all rendering, including debug
+            // overlays. The end_frame() call implicitly calls end_pass(), which
+            // should ensure any left over render targets get invalidated and
+            // returned to the pool correctly.
+            self.texture_resolver.end_frame(&mut self.device, cpu_frame_id);
             self.device.end_frame();
         });
         if framebuffer_size.is_some() {
             self.last_time = current_time;
         }
 
         if self.renderer_errors.is_empty() {
             Ok(results)
@@ -3102,18 +3120,18 @@ impl Renderer {
         );
     }
 
     fn draw_color_target(
         &mut self,
         draw_target: DrawTarget,
         target: &ColorRenderTarget,
         framebuffer_target_rect: DeviceIntRect,
-        depth_is_ready: bool,
         clear_color: Option<[f32; 4]>,
+        clear_depth: Option<f32>,
         render_tasks: &RenderTaskTree,
         projection: &Transform3D<f32>,
         frame_id: GpuFrameId,
         stats: &mut RendererStats,
     ) {
         self.profile_counters.color_targets.inc();
         let _gm = self.gpu_profile.start_marker("color target");
 
@@ -3129,22 +3147,19 @@ impl Renderer {
         };
 
         {
             let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_TARGET);
             self.device.bind_draw_target(draw_target);
             self.device.disable_depth();
             self.set_blend(false, framebuffer_kind);
 
-            let depth_clear = if !depth_is_ready && target.needs_depth() {
+            if clear_depth.is_some() {
                 self.device.enable_depth_write();
-                Some(1.0)
-            } else {
-                None
-            };
+            }
 
             let clear_rect = if !draw_target.is_default() {
                 if self.enable_clear_scissor {
                     // TODO(gw): Applying a scissor rect and minimal clear here
                     // is a very large performance win on the Intel and nVidia
                     // GPUs that I have tested with. It's possible it may be a
                     // performance penalty on other GPU types - we should test this
                     // and consider different code paths.
@@ -3164,19 +3179,23 @@ impl Renderer {
                 let mut rect = framebuffer_target_rect.to_i32();
                 // Note: `framebuffer_target_rect` needs a Y-flip before going to GL
                 // Note: at this point, the target rectangle is not guaranteed to be within the main framebuffer bounds
                 // but `clear_target_rect` is totally fine with negative origin, as long as width & height are positive
                 rect.origin.y = draw_target.dimensions().height as i32 - rect.origin.y - rect.size.height;
                 Some(rect)
             };
 
-            self.device.clear_target(clear_color, depth_clear, clear_rect);
-
-            if depth_clear.is_some() {
+            self.device.clear_target(
+                clear_color,
+                clear_depth,
+                clear_rect,
+            );
+
+            if clear_depth.is_some() {
                 self.device.disable_depth_write();
             }
         }
 
         // Handle any blits from the texture cache to this target.
         self.handle_blits(&target.blits, render_tasks);
 
         // Draw any blurs for this target.
@@ -4037,77 +4056,74 @@ impl Renderer {
         debug_assert!(self.texture_resolver.prev_pass_alpha.is_none());
         debug_assert!(self.texture_resolver.prev_pass_color.is_none());
     }
 
     fn draw_tile_frame(
         &mut self,
         frame: &mut Frame,
         framebuffer_size: Option<DeviceIntSize>,
-        framebuffer_depth_is_ready: bool,
         frame_id: GpuFrameId,
         stats: &mut RendererStats,
+        fb_clear_color: Option<ColorF>,
+        fb_clear_depth: Option<f32>,
     ) {
         let _gm = self.gpu_profile.start_marker("tile frame draw");
 
         if frame.passes.is_empty() {
             frame.has_been_rendered = true;
             return;
         }
 
         self.device.disable_depth_write();
         self.set_blend(false, FramebufferKind::Other);
         self.device.disable_stencil();
 
         self.bind_frame_data(frame);
-        self.texture_resolver.begin_frame();
 
         for (pass_index, pass) in frame.passes.iter_mut().enumerate() {
             let _gm = self.gpu_profile.start_marker(&format!("pass {}", pass_index));
 
             self.texture_resolver.bind(
                 &TextureSource::PrevPassAlpha,
                 TextureSampler::PrevPassAlpha,
                 &mut self.device,
             );
             self.texture_resolver.bind(
                 &TextureSource::PrevPassColor,
                 TextureSampler::PrevPassColor,
                 &mut self.device,
             );
 
-            let (cur_alpha, cur_color) = match pass.kind {
+            match pass.kind {
                 RenderPassKind::MainFramebuffer(ref target) => {
                     if let Some(framebuffer_size) = framebuffer_size {
                         stats.color_target_count += 1;
 
-                        let clear_color = frame.background_color.map(|color| color.to_array());
                         let projection = Transform3D::ortho(
                             0.0,
                             framebuffer_size.width as f32,
                             framebuffer_size.height as f32,
                             0.0,
                             ORTHO_NEAR_PLANE,
                             ORTHO_FAR_PLANE,
                         );
 
                         self.draw_color_target(
                             DrawTarget::Default(framebuffer_size),
                             target,
                             frame.inner_rect,
-                            framebuffer_depth_is_ready,
-                            clear_color,
+                            fb_clear_color.map(|color| color.to_array()),
+                            fb_clear_depth,
                             &frame.render_tasks,
                             &projection,
                             frame_id,
                             stats,
                         );
                     }
-
-                    (None, None)
                 }
                 RenderPassKind::OffScreen { ref mut alpha, ref mut color, ref mut texture_cache } => {
                     let alpha_tex = self.allocate_target_texture(alpha, &mut frame.profile_counters);
                     let color_tex = self.allocate_target_texture(color, &mut frame.profile_counters);
 
                     // If this frame has already been drawn, then any texture
                     // cache targets have already been updated and can be
                     // skipped this time.
@@ -4161,42 +4177,49 @@ impl Renderer {
                             0.0,
                             draw_target.dimensions().width as f32,
                             0.0,
                             draw_target.dimensions().height as f32,
                             ORTHO_NEAR_PLANE,
                             ORTHO_FAR_PLANE,
                         );
 
+                        let clear_depth = if target.needs_depth() {
+                            Some(1.0)
+                        } else {
+                            None
+                        };
+
                         self.draw_color_target(
                             draw_target,
                             target,
                             frame.inner_rect,
-                            false,
                             Some([0.0, 0.0, 0.0, 0.0]),
+                            clear_depth,
                             &frame.render_tasks,
                             &projection,
                             frame_id,
                             stats,
                         );
                     }
 
-                    (alpha_tex, color_tex)
+                    // Only end the pass here and invalidate previous textures for
+                    // off-screen targets. Deferring return of the inputs to the
+                    // frame buffer until the implicit end_pass in end_frame allows
+                    // debug draw overlays to be added without triggering a copy
+                    // resolve stage in mobile / tiled GPUs.
+                    self.texture_resolver.end_pass(
+                        &mut self.device,
+                        alpha_tex,
+                        color_tex,
+                    );
                 }
-            };
-
-            self.texture_resolver.end_pass(
-                &mut self.device,
-                cur_alpha,
-                cur_color,
-            );
+            }
         }
 
-        self.texture_resolver.end_frame(&mut self.device, frame_id);
-
         if let Some(framebuffer_size) = framebuffer_size {
             self.draw_frame_debug_items(&frame.debug_items);
             self.draw_render_target_debug(framebuffer_size);
             self.draw_texture_cache_debug(framebuffer_size);
             self.draw_gpu_cache_debug(framebuffer_size);
             self.draw_zoom_debug(framebuffer_size);
         }
         self.draw_epoch_debug();
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -99,16 +99,29 @@ already_AddRefed<nsIPrincipal> Principal
       // Origin must match what the_new_principal.getOrigin returns.
       nsAutoCString originNoSuffix;
       rv = principal->GetOriginNoSuffix(originNoSuffix);
       if (NS_WARN_IF(NS_FAILED(rv)) ||
           !info.originNoSuffix().Equals(originNoSuffix)) {
         MOZ_CRASH("Origin must be available when deserialized");
       }
 
+      if (info.domain()) {
+        nsCOMPtr<nsIURI> domain;
+        rv = NS_NewURI(getter_AddRefs(domain), *info.domain());
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return nullptr;
+        }
+
+        rv = principal->SetDomain(domain);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return nullptr;
+        }
+      }
+
       if (info.securityPolicies().Length() > 0) {
         nsCOMPtr<nsIContentSecurityPolicy> csp =
             do_CreateInstance(NS_CSPCONTEXT_CONTRACTID, &rv);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return nullptr;
         }
 
         rv = csp->SetRequestContext(nullptr, principal);
@@ -271,30 +284,45 @@ nsresult PrincipalToPrincipalInfo(nsIPri
   }
 
   nsCString originNoSuffix;
   rv = aPrincipal->GetOriginNoSuffix(originNoSuffix);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
+  nsCOMPtr<nsIURI> domainUri;
+  rv = aPrincipal->GetDomain(getter_AddRefs(domainUri));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  Maybe<nsCString> domain;
+  if (domainUri) {
+    domain.emplace();
+    rv = domainUri->GetSpec(domain.ref());
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
   nsCOMPtr<nsIContentSecurityPolicy> csp;
   rv = aPrincipal->GetCsp(getter_AddRefs(csp));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsTArray<ContentSecurityPolicy> policies;
   if (csp) {
     PopulateContentSecurityPolicies(csp, policies);
   }
 
   *aPrincipalInfo =
       ContentPrincipalInfo(aPrincipal->OriginAttributesRef(), originNoSuffix,
-                           spec, std::move(policies));
+                           spec, domain, std::move(policies));
   return NS_OK;
 }
 
 bool IsPincipalInfoPrivate(const PrincipalInfo& aPrincipalInfo) {
   if (aPrincipalInfo.type() != ipc::PrincipalInfo::TContentPrincipalInfo) {
     return false;
   }
 
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -1014,27 +1014,29 @@ bool GeckoChildProcessHost::PerformAsync
 #  endif  // MOZ_WIDGET_COCOA
 
 //--------------------------------------------------
 #elif defined(OS_WIN)  // defined(OS_POSIX)
 
   FilePath exePath;
   BinaryPathType pathType = GetPathToBinary(exePath, mProcessType);
 
+#  if defined(MOZ_SANDBOX) || (defined(_ARM64_) && defined(XP_WIN))
   const bool isGMP = mProcessType == GeckoProcessType_GMPlugin;
   const bool isWidevine = isGMP && Contains(aExtraOpts, "gmp-widevinecdm");
-#  if defined(_ARM64_) && defined(XP_WIN)
+#    if defined(_ARM64_) && defined(XP_WIN)
   const bool isClearKey = isGMP && Contains(aExtraOpts, "gmp-clearkey");
   if (isGMP && (isClearKey || isWidevine)) {
     // On Windows on ARM64 for ClearKey and Widevine, we want to run the
     // x86 plugin-container.exe in the "i686" subdirectory, instead of the
     // aarch64 plugin-container.exe. So insert "i686" into the exePath.
     exePath = exePath.DirName().AppendASCII("i686").Append(exePath.BaseName());
   }
-#  endif
+#    endif
+#  endif  // defined(MOZ_SANDBOX) || (defined(_ARM64_) && defined(XP_WIN))
 
   CommandLine cmdLine(exePath.ToWStringHack());
 
   if (pathType == BinaryPathType::Self) {
     cmdLine.AppendLooseValue(UTF8ToWide("-contentproc"));
   }
 
   cmdLine.AppendSwitchWithValue(switches::kProcessChannelID, channel_id());
--- a/ipc/glue/PBackgroundSharedTypes.ipdlh
+++ b/ipc/glue/PBackgroundSharedTypes.ipdlh
@@ -25,16 +25,18 @@ struct ContentPrincipalInfo
   // on.
   // Another important reason why we have this attribute is that
   // ContentPrincipalInfo is used out of the main-thread. Having this value
   // here allows us to retrive the origin without creating a full nsIPrincipal.
   nsCString originNoSuffix;
 
   nsCString spec;
 
+  nsCString? domain;
+
   ContentSecurityPolicy[] securityPolicies;
 };
 
 struct SystemPrincipalInfo
 { };
 
 struct NullPrincipalInfo
 {
--- a/js/src/jit-test/tests/atomics/mutual-exclusion.js
+++ b/js/src/jit-test/tests/atomics/mutual-exclusion.js
@@ -1,9 +1,9 @@
-// |jit-test| skip-if: helperThreadCount() === 0
+// |jit-test| skip-if: helperThreadCount() === 0 || getBuildConfiguration()["arm64-simulator"] === true
 
 // Let a few threads hammer on memory with atomics to provoke errors
 // in exclusion work.  This test is not 100% fail-safe: the test may
 // pass despite a bug, but this is unlikely.
 
 // Map an Int32Array on shared memory.  The first location is used as
 // a counter, each worker counts up on exit and the main thread will
 // wait until the counter reaches the number of workers.  The other
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1473830.js
@@ -0,0 +1,18 @@
+
+y = [];
+y.forEach(function() {});
+
+x = [];
+for (var i = 0; i < 100; ++i) {
+    x.push(undefined, 1);
+}
+x.sort();
+x.reverse();
+
+x.forEach(function(j) {
+    "use strict";
+    assertEq(this, 4);
+    if (j) {
+        x.forEach(function(z) { });
+    }
+}, 4);
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/js/src/tests/non262/fields/unimplemented.js
@@ -0,0 +1,45 @@
+// Note: These tests should pass eventually (and this file deleted): this test
+// is just asserting that fields don't crash the engine, even if disabled.
+
+let source = `class C {
+    x
+}`;
+assertThrowsInstanceOf(() => Function(source), SyntaxError);
+
+source = `class C {
+    x = 0;
+}`;
+assertThrowsInstanceOf(() => Function(source), SyntaxError);
+
+source = `class C {
+    0 = 0;
+}`;
+assertThrowsInstanceOf(() => Function(source), SyntaxError);
+
+source = `class C {
+    [0] = 0;
+}`;
+assertThrowsInstanceOf(() => Function(source), SyntaxError);
+
+source = `class C {
+    "hi" = 0;
+}`;
+assertThrowsInstanceOf(() => Function(source), SyntaxError);
+
+source = `class C {
+    "hi" = 0;
+}`;
+assertThrowsInstanceOf(() => Function(source), SyntaxError);
+
+source = `class C {
+    d = function(){};
+}`;
+assertThrowsInstanceOf(() => Function(source), SyntaxError);
+
+source = `class C {
+    d = class D { x = 0; };
+}`;
+assertThrowsInstanceOf(() => Function(source), SyntaxError);
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -250,17 +250,17 @@ nsresult nsLayoutStatics::Initialize() {
   nsSVGUtils::Init();
 
   ProcessPriorityManager::Init();
 
   nsPermissionManager::ClearOriginDataObserverInit();
   nsCookieService::AppClearDataObserverInit();
   nsApplicationCacheService::AppClearDataObserverInit();
 
-  HTMLVideoElement::Init();
+  HTMLVideoElement::InitStatics();
   nsGenericHTMLFrameElement::InitStatics();
 
 #ifdef MOZ_XUL
   nsMenuBarListener::InitializeStatics();
 #endif
 
   CacheObserver::Init();
 
--- a/layout/tools/reftest/manifest.jsm
+++ b/layout/tools/reftest/manifest.jsm
@@ -421,23 +421,22 @@ function BuildConditionSandbox(aURL) {
     } catch (e) {
       sandbox.d2d = false;
       sandbox.dwrite = false;
     }
 
     var info = gfxInfo.getInfo();
     var canvasBackend = readGfxInfo(info, "AzureCanvasBackend");
     var contentBackend = readGfxInfo(info, "AzureContentBackend");
-    var canvasAccelerated = readGfxInfo(info, "AzureCanvasAccelerated");
 
     sandbox.gpuProcess = gfxInfo.usingGPUProcess;
     sandbox.azureCairo = canvasBackend == "cairo";
     sandbox.azureSkia = canvasBackend == "skia";
     sandbox.skiaContent = contentBackend == "skia";
-    sandbox.azureSkiaGL = canvasAccelerated; // FIXME: assumes GL right now
+    sandbox.azureSkiaGL = false;
     // true if we are using the same Azure backend for rendering canvas and content
     sandbox.contentSameGfxBackendAsCanvas = contentBackend == canvasBackend
                                             || (contentBackend == "none" && canvasBackend == "cairo");
 
     sandbox.layersGPUAccelerated =
       g.windowUtils.layerManagerType != "Basic";
     sandbox.d3d11 =
       g.windowUtils.layerManagerType == "Direct3D 11";
--- a/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.cpp
+++ b/media/webrtc/signaling/src/peerconnection/MediaTransportHandler.cpp
@@ -914,28 +914,34 @@ void MediaTransportHandlerSTS::ClearIceL
 
   RLogConnector* logs = RLogConnector::GetInstance();
   if (logs) {
     logs->Clear();
   }
 }
 
 void MediaTransportHandlerSTS::EnterPrivateMode() {
+  // Do this from calling thread, because that's what we do in CreateIceCtx...
+  RLogConnector::CreateInstance();
+
   if (!mStsThread->IsOnCurrentThread()) {
     mStsThread->Dispatch(
         WrapRunnable(RefPtr<MediaTransportHandlerSTS>(this),
                      &MediaTransportHandlerSTS::EnterPrivateMode),
         NS_DISPATCH_NORMAL);
     return;
   }
 
-  RLogConnector::CreateInstance()->EnterPrivateMode();
+  RLogConnector::GetInstance()->EnterPrivateMode();
 }
 
 void MediaTransportHandlerSTS::ExitPrivateMode() {
+  // Do this from calling thread, because that's what we do in CreateIceCtx...
+  RLogConnector::CreateInstance();
+
   if (!mStsThread->IsOnCurrentThread()) {
     mStsThread->Dispatch(
         WrapRunnable(RefPtr<MediaTransportHandlerSTS>(this),
                      &MediaTransportHandlerSTS::ExitPrivateMode),
         NS_DISPATCH_NORMAL);
     return;
   }
 
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -713,20 +713,17 @@ pref("browser.contentHandlers.types.3.ur
 pref("browser.contentHandlers.types.3.type", "application/vnd.mozilla.maybe.feed");
 
 // Shortnumber matching needed for e.g. Brazil:
 // 01187654321 can be found with 87654321
 pref("dom.phonenumber.substringmatching.BR", 8);
 pref("dom.phonenumber.substringmatching.CO", 10);
 pref("dom.phonenumber.substringmatching.VE", 7);
 
-// Support, but deprecate, hardware-accelerated Skia canvas
 pref("gfx.canvas.azure.backends", "skia");
-pref("gfx.canvas.azure.accelerated", false);
-pref("gfx.canvas.azure.accelerated.limit", 64);
 
 // See ua-update.json.in for the packaged UA override list
 pref("general.useragent.updates.enabled", true);
 pref("general.useragent.updates.url", "https://dynamicua.cdn.mozilla.net/0/%APP_ID%");
 pref("general.useragent.updates.interval", 604800); // 1 week
 pref("general.useragent.updates.retry", 86400); // 1 day
 
 // When true, phone number linkification is enabled.
--- a/mobile/android/geckoview/api.txt
+++ b/mobile/android/geckoview/api.txt
@@ -723,16 +723,20 @@ package org.mozilla.geckoview {
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoSessionSettings.Builder userAgentMode(int);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoSessionSettings.Builder userAgentOverride(@android.support.annotation.NonNull java.lang.String);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.GeckoSessionSettings.Builder viewportMode(int);
   }
 
   public static class GeckoSessionSettings.Key<T> {
   }
 
+  public class GeckoVRManager {
+    method @android.support.annotation.AnyThread public static synchronized void setExternalContext(long);
+  }
+
   @android.support.annotation.UiThread public class GeckoView extends android.widget.FrameLayout {
     ctor public GeckoView(android.content.Context);
     ctor public GeckoView(android.content.Context, android.util.AttributeSet);
     method public void coverUntilFirstPaint(int);
     method @android.support.annotation.NonNull public org.mozilla.geckoview.DynamicToolbarAnimator getDynamicToolbarAnimator();
     method @android.support.annotation.AnyThread @android.support.annotation.NonNull public org.mozilla.gecko.EventDispatcher getEventDispatcher();
     method @android.support.annotation.NonNull public org.mozilla.geckoview.PanZoomController getPanZoomController();
     method @android.support.annotation.AnyThread @android.support.annotation.Nullable public org.mozilla.geckoview.GeckoSession getSession();
deleted file mode 100644
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoVRManager.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * vim: ts=4 sw=4 expandtab:
- * 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/. */
-
-package org.mozilla.gecko;
-
-import org.mozilla.gecko.annotation.WrapForJNI;
-import org.mozilla.gecko.util.ThreadUtils;
-
-public class GeckoVRManager {
-    private static long mExternalContext;
-
-    @WrapForJNI
-    public static synchronized long getExternalContext() {
-      return mExternalContext;
-    }
-
-    public static synchronized void setExternalContext(final long externalContext) {
-        mExternalContext = externalContext;
-    }
-
-}
new file mode 100644
--- /dev/null
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoVRManager.java
@@ -0,0 +1,41 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * vim: ts=4 sw=4 expandtab:
+ * 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/. */
+
+package org.mozilla.geckoview;
+
+import android.support.annotation.AnyThread;
+
+import org.mozilla.gecko.annotation.WrapForJNI;
+
+/**
+ * Interface for registering the external VR context with WebVR.
+ * The context must be registered before Gecko is started. This API
+ * is not intended for external consumption. To see an example of
+ * how it is used please see the <a href="https://github.com/MozillaReality/FirefoxReality" target="_blank">Firefox Reality browser</a>.
+ * @see <a href="https://searchfox.org/mozilla-central/source/gfx/vr/external_api/moz_external_vr.h" target="_blank">External VR Context</a>
+ */
+public class GeckoVRManager {
+    private static long mExternalContext;
+
+    private GeckoVRManager() {}
+
+    @WrapForJNI
+    private static synchronized long getExternalContext() {
+      return mExternalContext;
+    }
+
+    /**
+     * Sets the external VR context.
+     * The external VR context is defined
+     * <a href="https://searchfox.org/mozilla-central/source/gfx/vr/external_api/moz_external_vr.h" target="_blank">here</a>.
+     * @param externalContext A pointer to the external VR context.
+     */
+    @AnyThread
+    public static synchronized void setExternalContext(final long externalContext) {
+        mExternalContext = externalContext;
+    }
+
+}
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md
@@ -58,17 +58,20 @@ exclude: true
   default user agent synchronously.
 
 - Changed `WebResponse.body` from a `ByteBuffer` to an `InputStream`. Apps that want access
   to the entire response body will now need to read the stream themselves.
 
 - Added `GeckoWebExecutor.FETCH_FLAGS_NO_REDIRECTS`, which will cause `GeckoWebExecutor.fetch()` to not
   automatically follow HTTP redirects (e.g., 302).
 
+- Moved [`GeckoVRManager`][67.2] into the org.mozilla.geckoview package.
+
 [67.1]: ../GeckoSession.html#getDefaultUserAgent--
+[67.2]: ../GeckoVRManager.html
 
 - Initial WebExtension support. [`GeckoRuntime#registerWebExtension`][67.15]
   allows embedders to register a local web extension.
 
 [67.15]: ../GeckoRuntime.html#registerWebExtension-org.mozilla.geckoview.WebExtension-
 
 ## v66
 - Removed redundant field `trackingMode` from [`SecurityInformation`][66.6].
@@ -184,9 +187,9 @@ exclude: true
 [65.23]: ../GeckoSession.FinderResult.html
 
 - Update [`CrashReporter#sendCrashReport`][65.24] to return the crash ID as a
   [`GeckoResult<String>`][65.25].
 
 [65.24]: ../CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
 [65.25]: ../GeckoResult.html
 
-[api-version]: b26e5e12a78512a9c18d1ba3441864ca66d3dde8
+[api-version]: df89fa914cfd095b37e696f3e767b55fc03a4835
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -891,18 +891,16 @@ pref("gfx.content.azure.backends", "dire
 pref("gfx.content.azure.backends", "skia");
 pref("gfx.canvas.azure.backends", "skia");
 #else
 pref("gfx.canvas.azure.backends", "skia");
 pref("gfx.content.azure.backends", "skia");
 #endif
 #endif
 
-pref("gfx.canvas.skiagl.dynamic-cache", true);
-
 pref("gfx.text.disable-aa", false);
 
 pref("gfx.work-around-driver-bugs", true);
 
 pref("gfx.draw-color-bars", false);
 
 pref("gfx.logging.painted-pixel-count.enabled", false);
 pref("gfx.logging.texture-usage.enabled", false);
@@ -1457,17 +1455,17 @@ pref("javascript.enabled",              
 pref("javascript.options.strict",           false);
 #ifdef DEBUG
 pref("javascript.options.strict.debug",     false);
 #endif
 pref("javascript.options.unboxed_objects",  false);
 pref("javascript.options.baselinejit",      true);
 //Duplicated in JitOptions - ensure both match.
 pref("javascript.options.baselinejit.threshold", 10);
-#ifdef _ARM64_
+#ifdef NO_ION
 pref("javascript.options.ion",              false);
 #else
 pref("javascript.options.ion",              true);
 #endif
 //Duplicated in JitOptions - ensure both match.
 pref("javascript.options.ion.threshold",    1000);
 //Duplicated in JitOptions - ensure both match.
 pref("javascript.options.ion.frequent_bailout_threshold", 10);
--- a/modules/libpref/moz.build
+++ b/modules/libpref/moz.build
@@ -44,11 +44,14 @@ include('/ipc/chromium/chromium-config.m
 
 FINAL_LIBRARY = 'xul'
 
 DEFINES['OS_ARCH'] = CONFIG['OS_ARCH']
 DEFINES['MOZ_WIDGET_TOOLKIT'] = CONFIG['MOZ_WIDGET_TOOLKIT']
 if CONFIG['MOZ_ENABLE_WEBRENDER']:
     DEFINES['MOZ_ENABLE_WEBRENDER'] = True
 
+if CONFIG['CPU_ARCH'] == 'aarch64':
+    DEFINES['NO_ION'] = True
+
 FINAL_TARGET_PP_FILES += [
     'greprefs.js',
 ]
--- a/netwerk/ipc/PSocketProcess.ipdl
+++ b/netwerk/ipc/PSocketProcess.ipdl
@@ -34,17 +34,17 @@ parent:
   async RecordChildEvents(ChildEventData[] events);
   async RecordDiscardedData(DiscardedData data);
 
 child:
   async PreferenceUpdate(Pref pref);
   async RequestMemoryReport(uint32_t generation,
                             bool anonymize,
                             bool minimizeMemoryUsage,
-                            MaybeFileDesc DMDFile);
+                            FileDescriptor? DMDFile);
   async SetOffline(bool offline);
   async InitSocketProcessBridgeParent(ProcessId processId, Endpoint<PSocketProcessBridgeParent> endpoint);
   async InitProfiler(Endpoint<PProfilerChild> aEndpoint);
   // test-only
   async SocketProcessTelemetryPing();
 };
 
 } // namespace net
--- a/netwerk/ipc/SocketProcessChild.cpp
+++ b/netwerk/ipc/SocketProcessChild.cpp
@@ -104,17 +104,18 @@ void SocketProcessChild::CleanUp() {
 
 IPCResult SocketProcessChild::RecvPreferenceUpdate(const Pref& aPref) {
   Preferences::SetPreference(aPref);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult SocketProcessChild::RecvRequestMemoryReport(
     const uint32_t& aGeneration, const bool& aAnonymize,
-    const bool& aMinimizeMemoryUsage, const MaybeFileDesc& aDMDFile) {
+    const bool& aMinimizeMemoryUsage,
+    const Maybe<ipc::FileDescriptor>& aDMDFile) {
   nsPrintfCString processName("SocketProcess");
 
   mozilla::dom::MemoryReportRequestClient::Start(
       aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, processName,
       [&](const MemoryReport& aReport) {
         Unused << GetSingleton()->SendAddMemoryReport(aReport);
       },
       [&](const uint32_t& aGeneration) {
--- a/netwerk/ipc/SocketProcessChild.h
+++ b/netwerk/ipc/SocketProcessChild.h
@@ -30,17 +30,18 @@ class SocketProcessChild final : public 
   bool Init(base::ProcessId aParentPid, const char* aParentBuildID,
             MessageLoop* aIOLoop, IPC::Channel* aChannel);
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   mozilla::ipc::IPCResult RecvPreferenceUpdate(const Pref& aPref);
   mozilla::ipc::IPCResult RecvRequestMemoryReport(
       const uint32_t& generation, const bool& anonymize,
-      const bool& minimizeMemoryUsage, const MaybeFileDesc& DMDFile);
+      const bool& minimizeMemoryUsage,
+      const Maybe<ipc::FileDescriptor>& DMDFile);
   mozilla::ipc::IPCResult RecvSetOffline(const bool& aOffline);
   mozilla::ipc::IPCResult RecvInitSocketProcessBridgeParent(
       const ProcessId& aContentProcessId,
       Endpoint<mozilla::net::PSocketProcessBridgeParent>&& aEndpoint);
   mozilla::ipc::IPCResult RecvInitProfiler(
       Endpoint<mozilla::PProfilerChild>&& aEndpoint);
   mozilla::ipc::IPCResult RecvSocketProcessTelemetryPing();
 
--- a/netwerk/ipc/SocketProcessHost.cpp
+++ b/netwerk/ipc/SocketProcessHost.cpp
@@ -302,17 +302,18 @@ bool SocketProcessMemoryReporter::IsAliv
     return false;
   }
 
   return gIOService->mSocketProcess->IsConnected();
 }
 
 bool SocketProcessMemoryReporter::SendRequestMemoryReport(
     const uint32_t& aGeneration, const bool& aAnonymize,
-    const bool& aMinimizeMemoryUsage, const dom::MaybeFileDesc& aDMDFile) {
+    const bool& aMinimizeMemoryUsage,
+    const Maybe<ipc::FileDescriptor>& aDMDFile) {
   MOZ_ASSERT(gIOService);
 
   if (!gIOService->mSocketProcess) {
     return false;
   }
 
   SocketProcessParent* actor = gIOService->mSocketProcess->GetActor();
   if (!actor) {
--- a/netwerk/ipc/SocketProcessHost.h
+++ b/netwerk/ipc/SocketProcessHost.h
@@ -108,20 +108,20 @@ class SocketProcessHost final : public m
 class SocketProcessMemoryReporter : public MemoryReportingProcess {
  public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SocketProcessMemoryReporter, override)
 
   SocketProcessMemoryReporter() = default;
 
   bool IsAlive() const override;
 
-  bool SendRequestMemoryReport(const uint32_t& aGeneration,
-                               const bool& aAnonymize,
-                               const bool& aMinimizeMemoryUsage,
-                               const dom::MaybeFileDesc& aDMDFile) override;
+  bool SendRequestMemoryReport(
+      const uint32_t& aGeneration, const bool& aAnonymize,
+      const bool& aMinimizeMemoryUsage,
+      const Maybe<mozilla::ipc::FileDescriptor>& aDMDFile) override;
 
   int32_t Pid() const override;
 
  protected:
   virtual ~SocketProcessMemoryReporter() = default;
 };
 
 }  // namespace net
--- a/netwerk/ipc/SocketProcessParent.cpp
+++ b/netwerk/ipc/SocketProcessParent.cpp
@@ -56,17 +56,18 @@ void SocketProcessParent::ActorDestroy(A
 
   if (mHost) {
     mHost->OnChannelClosed();
   }
 }
 
 bool SocketProcessParent::SendRequestMemoryReport(
     const uint32_t& aGeneration, const bool& aAnonymize,
-    const bool& aMinimizeMemoryUsage, const MaybeFileDesc& aDMDFile) {
+    const bool& aMinimizeMemoryUsage,
+    const Maybe<ipc::FileDescriptor>& aDMDFile) {
   mMemoryReportRequest = MakeUnique<dom::MemoryReportRequestHost>(aGeneration);
   Unused << PSocketProcessParent::SendRequestMemoryReport(
       aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile);
   return true;
 }
 
 mozilla::ipc::IPCResult SocketProcessParent::RecvAddMemoryReport(
     const MemoryReport& aReport) {
--- a/netwerk/ipc/SocketProcessParent.h
+++ b/netwerk/ipc/SocketProcessParent.h
@@ -51,17 +51,17 @@ class SocketProcessParent final : public
       nsTArray<ChildEventData>&& events);
   mozilla::ipc::IPCResult RecvRecordDiscardedData(
       const DiscardedData& aDiscardedData);
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
   bool SendRequestMemoryReport(const uint32_t& aGeneration,
                                const bool& aAnonymize,
                                const bool& aMinimizeMemoryUsage,
-                               const MaybeFileDesc& aDMDFile);
+                               const Maybe<ipc::FileDescriptor>& aDMDFile);
 
  private:
   SocketProcessHost* mHost;
   UniquePtr<ipc::CrashReporterHost> mCrashReporter;
   UniquePtr<dom::MemoryReportRequestHost> mMemoryReportRequest;
 
   static void Destroy(UniquePtr<SocketProcessParent>&& aParent);
 };
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -362,18 +362,17 @@ class AsmFlags(BaseCompileFlags):
         )
         BaseCompileFlags.__init__(self, context)
 
     def _debug_flags(self):
         debug_flags = []
         if (self._context.config.substs.get('MOZ_DEBUG') or
             self._context.config.substs.get('MOZ_DEBUG_SYMBOLS')):
             if self._context.get('USE_NASM'):
-                if (self._context.config.substs.get('OS_ARCH') == 'WINNT' and
-                    not self._context.config.substs.get('GNU_CC')):
+                if self._context.config.substs.get('OS_ARCH') == 'WINNT':
                     debug_flags += ['-F', 'cv8']
                 elif self._context.config.substs.get('OS_ARCH') != 'Darwin':
                     debug_flags += ['-F', 'dwarf']
             elif self._context.get('USE_YASM'):
                 if (self._context.config.substs.get('OS_ARCH') == 'WINNT' and
                     not self._context.config.substs.get('GNU_CC')):
                     debug_flags += ['-g', 'cv8']
                 elif self._context.config.substs.get('OS_ARCH') != 'Darwin':
--- a/security/manager/ssl/security-prefs.js
+++ b/security/manager/ssl/security-prefs.js
@@ -150,14 +150,18 @@ pref("security.pki.mitm_canary_issuer.en
 // Firefox update service's connection.
 // This value is set automatically.
 // The difference between security.pki.mitm_canary_issuer and this pref is that
 // here the root is trusted but not a built-in, whereas for
 // security.pki.mitm_canary_issuer.enabled, the root is not trusted.
 pref("security.pki.mitm_detected", false);
 
 // Intermediate CA Preloading settings
+#ifdef RELEASE_OR_BETA
 pref("security.remote_settings.intermediates.enabled", false);
+#else
+pref("security.remote_settings.intermediates.enabled", true);
+#endif
 pref("security.remote_settings.intermediates.bucket", "security-state");
 pref("security.remote_settings.intermediates.collection", "intermediates");
 pref("security.remote_settings.intermediates.checked", 0);
 pref("security.remote_settings.intermediates.downloads_per_poll", 100);
 pref("security.remote_settings.intermediates.signer", "onecrl.content-signature.mozilla.org");
--- a/security/sandbox/linux/Sandbox.h
+++ b/security/sandbox/linux/Sandbox.h
@@ -12,19 +12,19 @@
 #include <vector>
 
 // This defines the entry points for a content process to start
 // sandboxing itself.  See also SandboxInfo.h for what parts of
 // sandboxing are enabled/supported.
 
 namespace mozilla {
 
-namespace dom {
-class MaybeFileDesc;
-}  // namespace dom
+namespace ipc {
+class FileDescriptor;
+}  // namespace ipc
 
 // This must be called early, before glib creates any worker threads.
 // (See bug 1176099.)
 MOZ_EXPORT void SandboxEarlyInit();
 
 #ifdef MOZ_CONTENT_SANDBOX
 // A collection of sandbox parameters that have to be extracted from
 // prefs or other libxul facilities and passed down, because
@@ -41,17 +41,17 @@ struct ContentProcessSandboxParams {
   // Determines whether we allow reading all files, for processes that
   // render file:/// URLs.
   bool mFileProcess = false;
   // Syscall numbers to allow even if the seccomp-bpf policy otherwise
   // wouldn't.
   std::vector<int> mSyscallWhitelist;
 
   static ContentProcessSandboxParams ForThisProcess(
-      const dom::MaybeFileDesc& aBroker);
+      const Maybe<ipc::FileDescriptor>& aBroker);
 };
 
 // Call only if SandboxInfo::CanSandboxContent() returns true.
 // (No-op if the sandbox is disabled.)
 // isFileProcess determines whether we allow system wide file reads.
 MOZ_EXPORT bool SetContentProcessSandbox(ContentProcessSandboxParams&& aParams);
 #endif
 
--- a/security/sandbox/linux/glue/SandboxPrefBridge.cpp
+++ b/security/sandbox/linux/glue/SandboxPrefBridge.cpp
@@ -8,24 +8,24 @@
 
 #include "mozilla/Preferences.h"
 #include "mozilla/SandboxSettings.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"  // for FILE_REMOTE_TYPE
 
 namespace mozilla {
 
-/* static */
-ContentProcessSandboxParams ContentProcessSandboxParams::ForThisProcess(
-    const dom::MaybeFileDesc& aBroker) {
+/* static */ ContentProcessSandboxParams
+ContentProcessSandboxParams::ForThisProcess(
+    const Maybe<ipc::FileDescriptor>& aBroker) {
   ContentProcessSandboxParams params;
   params.mLevel = GetEffectiveContentSandboxLevel();
 
-  if (aBroker.type() == dom::MaybeFileDesc::TFileDescriptor) {
-    auto fd = aBroker.get_FileDescriptor().ClonePlatformHandle();
+  if (aBroker.isSome()) {
+    auto fd = aBroker.value().ClonePlatformHandle();
     params.mBrokerFd = fd.release();
     // brokerFd < 0 means to allow direct filesystem access, so
     // make absolutely sure that doesn't happen if the parent
     // didn't intend it.
     MOZ_RELEASE_ASSERT(params.mBrokerFd >= 0);
   }
   // (Otherwise, mBrokerFd will remain -1 from the default ctor.)
 
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -22,16 +22,17 @@ use crate::values::computed::transform::
 use crate::values::computed::url::ComputedImageUrl;
 use crate::values::computed::{Angle, Gradient, Image};
 use crate::values::computed::{Integer, LengthPercentage};
 use crate::values::computed::{Length, Percentage, TextAlign};
 use crate::values::generics::box_::VerticalAlign;
 use crate::values::generics::grid::{TrackListValue, TrackSize};
 use crate::values::generics::image::{CompatMode, GradientItem, Image as GenericImage};
 use crate::values::generics::rect::Rect;
+use crate::Zero;
 use app_units::Au;
 use std::f32::consts::PI;
 use style_traits::values::specified::AllowedNumericType;
 
 impl From<LengthPercentage> for nsStyleCoord_CalcValue {
     fn from(other: LengthPercentage) -> nsStyleCoord_CalcValue {
         debug_assert!(
             other.was_calc || !other.has_percentage || other.unclamped_length() == Length::zero()
@@ -698,17 +699,16 @@ pub mod basic_shape {
         fn from(other: &'a StyleBasicShape) -> Self {
             match other.mType {
                 StyleBasicShapeType::Inset => {
                     let t = LengthPercentage::from_gecko_style_coord(&other.mCoordinates[0]);
                     let r = LengthPercentage::from_gecko_style_coord(&other.mCoordinates[1]);
                     let b = LengthPercentage::from_gecko_style_coord(&other.mCoordinates[2]);
                     let l = LengthPercentage::from_gecko_style_coord(&other.mCoordinates[3]);
                     let round = other.mRadius;
-                    let round = if round.all_zero() { None } else { Some(round) };
                     let rect = Rect::new(
                         t.expect("inset() offset should be a length, percentage, or calc value"),
                         r.expect("inset() offset should be a length, percentage, or calc value"),
                         b.expect("inset() offset should be a length, percentage, or calc value"),
                         l.expect("inset() offset should be a length, percentage, or calc value"),
                     );
                     GenericBasicShape::Inset(InsetRect { rect, round })
                 },
--- a/servo/components/style/gecko/values.rs
+++ b/servo/components/style/gecko/values.rs
@@ -14,17 +14,17 @@ use crate::values::computed::basic_shape
 use crate::values::computed::{Angle, Length, LengthPercentage};
 use crate::values::computed::{Number, NumberOrPercentage, Percentage};
 use crate::values::generics::basic_shape::ShapeRadius;
 use crate::values::generics::gecko::ScrollSnapPoint;
 use crate::values::generics::grid::{TrackBreadth, TrackKeyword};
 use crate::values::generics::length::LengthPercentageOrAuto;
 use crate::values::generics::{CounterStyleOrNone, NonNegative};
 use crate::values::{Auto, Either, None_, Normal};
-use crate::Atom;
+use crate::{Atom, Zero};
 use app_units::Au;
 use cssparser::RGBA;
 use nsstring::{nsACString, nsCStr};
 use std::cmp::max;
 
 /// A trait that defines an interface to convert from and to `nsStyleCoord`s.
 ///
 /// TODO(emilio): Almost everything that is in this file should be somehow
--- a/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
@@ -5,16 +5,17 @@
 //! Little helpers for `nsCSSValue`.
 
 use crate::gecko_bindings::bindings;
 use crate::gecko_bindings::structs;
 use crate::gecko_bindings::structs::{nsCSSUnit, nsCSSValue};
 use crate::gecko_bindings::structs::{nsCSSValueList, nsCSSValue_Array};
 use crate::gecko_string_cache::Atom;
 use crate::values::computed::{Angle, Length, LengthPercentage, Percentage};
+use crate::Zero;
 use std::marker::PhantomData;
 use std::mem;
 use std::ops::{Index, IndexMut};
 use std::slice;
 
 impl nsCSSValue {
     /// Create a CSSValue with null unit, useful to be used as a return value.
     #[inline]
--- a/servo/components/style/lib.rs
+++ b/servo/components/style/lib.rs
@@ -239,8 +239,31 @@ pub trait CaseSensitivityExt {
 impl CaseSensitivityExt for selectors::attr::CaseSensitivity {
     fn eq_atom(self, a: &WeakAtom, b: &WeakAtom) -> bool {
         match self {
             selectors::attr::CaseSensitivity::CaseSensitive => a == b,
             selectors::attr::CaseSensitivity::AsciiCaseInsensitive => a.eq_ignore_ascii_case(b),
         }
     }
 }
+
+/// A trait pretty much similar to num_traits::Zero, but without the need of
+/// implementing `Add`.
+pub trait Zero {
+    /// Returns the zero value.
+    fn zero() -> Self;
+
+    /// Returns whether this value is zero.
+    fn is_zero(&self) -> bool;
+}
+
+impl<T> Zero for T
+where
+    T: num_traits::Zero,
+{
+    fn zero() -> Self {
+        <Self as num_traits::Zero>::zero()
+    }
+
+    fn is_zero(&self) -> bool {
+        <Self as num_traits::Zero>::is_zero(self)
+    }
+}
--- a/servo/components/style/media_queries/media_feature_expression.rs
+++ b/servo/components/style/media_queries/media_feature_expression.rs