merge mozilla-inbound to mozilla-central. r=merge a=merge FIREFOX_NIGHTLY_57_END
authorSebastian Hengst <archaeopteryx@coole-files.de>
Thu, 21 Sep 2017 15:23:43 +0200
changeset 382171 f7e9777221a3
parent 382143 9caeafcec998 (current diff)
parent 382170 e03b7dcc0311 (diff)
child 382172 1ca411f5e97b
child 382189 5d10000883d9
child 382279 27a12fb3e64b
push id32547
push userarchaeopteryx@coole-files.de
push dateThu, 21 Sep 2017 13:24:03 +0000
treeherdermozilla-central@f7e9777221a3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone57.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-inbound to mozilla-central. r=merge a=merge MozReview-Commit-ID: mr7OYuaLKE
browser/base/content/browser.js
browser/themes/linux/privatebrowsing-mask.png
browser/themes/osx/privatebrowsing-mask-short.png
browser/themes/osx/privatebrowsing-mask-short@2x.png
browser/themes/osx/privatebrowsing-mask.png
browser/themes/osx/privatebrowsing-mask@2x.png
browser/themes/windows/privatebrowsing-mask-tabstrip-win7.png
browser/themes/windows/privatebrowsing-mask-tabstrip.png
browser/themes/windows/privatebrowsing-mask-titlebar-win7-tall.png
browser/themes/windows/privatebrowsing-mask-titlebar-win7.png
browser/themes/windows/privatebrowsing-mask-titlebar.png
gfx/layers/wr/StackingContextHelper.cpp
gfx/layers/wr/StackingContextHelper.h
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/webrender_ffi_generated.h
layout/painting/nsCSSRendering.cpp
layout/painting/nsCSSRenderingBorders.cpp
layout/painting/nsCSSRenderingBorders.h
layout/painting/nsDisplayList.cpp
taskcluster/ci/test/tests.yml
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -668,16 +668,20 @@ pref("network.protocol-handler.expose.ne
 pref("network.protocol-handler.expose.snews", false);
 pref("network.protocol-handler.expose.nntp", false);
 
 pref("accessibility.typeaheadfind", false);
 pref("accessibility.typeaheadfind.timeout", 5000);
 pref("accessibility.typeaheadfind.linksonly", false);
 pref("accessibility.typeaheadfind.flashBar", 1);
 
+// Accessibility indicator preferences such as support URL, enabled flag.
+pref("accessibility.support.url", "https://support.mozilla.org/%LOCALE%/kb/accessibility-services");
+pref("accessibility.indicator.enabled", true);
+
 pref("plugins.click_to_play", true);
 pref("plugins.testmode", false);
 
 // Should plugins that are hidden show the infobar UI?
 pref("plugins.show_infobar", false);
 
 // Should dismissing the hidden plugin infobar suppress it permanently?
 pref("plugins.remember_infobar_dismissal", true);
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -295,17 +295,18 @@ toolbarpaletteitem {
 %else
 /* On non-OSX, these should be start-aligned */
 #titlebar-buttonbox-container {
   -moz-box-align: start;
 }
 %endif
 
 %if !defined(MOZ_WIDGET_GTK)
-#TabsToolbar > .private-browsing-indicator {
+#TabsToolbar > .private-browsing-indicator,
+#TabsToolbar > .accessibility-indicator {
   -moz-box-ordinal-group: 1000;
 }
 %endif
 
 %ifdef XP_WIN
 #main-window[sizemode="maximized"] #titlebar-buttonbox {
   -moz-appearance: -moz-window-button-box-maximized;
 }
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1357,16 +1357,17 @@ var gBrowserInit = {
       gURLBar.setAttribute("enablehistory", "false");
     }
 
     // Misc. inits.
     TabletModeUpdater.init();
     CombinedStopReload.init();
     gPrivateBrowsingUI.init();
     BrowserPageActions.init();
+    gAccessibilityServiceIndicator.init();
 
     if (window.matchMedia("(-moz-os-version: windows-win8)").matches &&
         window.matchMedia("(-moz-windows-default-theme)").matches) {
       let windowFrameColor = new Color(...Cu.import("resource:///modules/Windows8WindowFrameColor.jsm", {})
                                             .Windows8WindowFrameColor.get());
       // Default to black for foreground text.
       if (!windowFrameColor.isContrastRatioAcceptable(new Color(0, 0, 0))) {
         document.documentElement.setAttribute("darkwindowframe", "true");
@@ -1856,16 +1857,18 @@ var gBrowserInit = {
     TrackingProtection.uninit();
 
     CaptivePortalWatcher.uninit();
 
     SidebarUI.uninit();
 
     DownloadsButton.uninit();
 
+    gAccessibilityServiceIndicator.uninit();
+
     // Now either cancel delayedStartup, or clean up the services initialized from
     // it.
     if (this._boundDelayedStartup) {
       this._cancelDelayedStartup();
     } else {
       if (Win7Features)
         Win7Features.onCloseWindow();
 
@@ -8035,16 +8038,73 @@ function getTabModalPromptBox(aWindow) {
   return null;
 }
 
 /* DEPRECATED */
 function getBrowser() {
   return gBrowser;
 }
 
+const gAccessibilityServiceIndicator = {
+  init() {
+    // Pref to enable accessibility service indicator.
+    gPrefService.addObserver("accessibility.indicator.enabled", this);
+    // Accessibility service init/shutdown event.
+    Services.obs.addObserver(this, "a11y-init-or-shutdown");
+    this.update(Services.appinfo.accessibilityEnabled);
+  },
+
+  update(accessibilityEnabled = false) {
+    if (this.enabled && accessibilityEnabled) {
+      this._active = true;
+      document.documentElement.setAttribute("accessibilitymode", "true");
+      [...document.querySelectorAll(".accessibility-indicator")].forEach(
+        indicator => ["click", "keypress"].forEach(type =>
+          indicator.addEventListener(type, this)));
+      TabsInTitlebar.updateAppearance(true);
+    } else if (this._active) {
+      this._active = false;
+      document.documentElement.removeAttribute("accessibilitymode");
+      [...document.querySelectorAll(".accessibility-indicator")].forEach(
+        indicator => ["click", "keypress"].forEach(type =>
+          indicator.removeEventListener(type, this)));
+      TabsInTitlebar.updateAppearance(true);
+    }
+  },
+
+  observe(subject, topic, data) {
+    if (topic == "nsPref:changed" && data === "accessibility.indicator.enabled") {
+      this.update(Services.appinfo.accessibilityEnabled);
+    } else if (topic === "a11y-init-or-shutdown") {
+      // When "a11y-init-or-shutdown" event is fired, "1" indicates that
+      // accessibility service is started and "0" that it is shut down.
+      this.update(data === "1");
+    }
+  },
+
+  get enabled() {
+    return gPrefService.getBoolPref("accessibility.indicator.enabled");
+  },
+
+  handleEvent({ key, type }) {
+    if ((type === "keypress" && [" ", "Enter"].includes(key)) ||
+         type === "click") {
+      let a11yServicesSupportURL =
+        Services.urlFormatter.formatURLPref("accessibility.support.url");
+      gBrowser.selectedTab = gBrowser.addTab(a11yServicesSupportURL);
+    }
+  },
+
+  uninit() {
+    gPrefService.removeObserver("accessibility.indicator.enabled", this);
+    Services.obs.removeObserver(this, "a11y-init-or-shutdown");
+    this.update();
+  }
+};
+
 var gPrivateBrowsingUI = {
   init: function PBUI_init() {
     // Do nothing for normal windows
     if (!PrivateBrowsingUtils.isWindowPrivate(window)) {
       return;
     }
 
     // Disable the Clear Recent History... menu item when in PB mode
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -568,30 +568,30 @@
   <box id="appMenu-viewCache" hidden="true"/>
 
 #ifdef CAN_DRAW_IN_TITLEBAR
 <vbox id="titlebar">
   <hbox id="titlebar-content">
     <spacer id="titlebar-spacer" flex="1"/>
     <hbox id="titlebar-buttonbox-container">
 #ifdef XP_WIN
-      <hbox id="private-browsing-indicator-titlebar">
-        <hbox class="private-browsing-indicator"/>
-      </hbox>
+      <button class="accessibility-indicator" tooltiptext="&accessibilityIndicator.tooltip;" aria-live="polite"/>
+      <hbox class="private-browsing-indicator"/>
 #endif
       <hbox id="titlebar-buttonbox">
         <toolbarbutton class="titlebar-button" id="titlebar-min" oncommand="window.minimize();"/>
         <toolbarbutton class="titlebar-button" id="titlebar-max" oncommand="onTitlebarMaxClick();"/>
         <toolbarbutton class="titlebar-button" id="titlebar-close" command="cmd_closeWindow"/>
       </hbox>
     </hbox>
 #ifdef XP_MACOSX
     <!-- OS X does not natively support RTL for its titlebar items, so we prevent this secondary
          buttonbox from reversing order in RTL by forcing an LTR direction. -->
     <hbox id="titlebar-secondary-buttonbox" dir="ltr">
+      <button class="accessibility-indicator" tooltiptext="&accessibilityIndicator.tooltip;" aria-live="polite"/>
       <hbox class="private-browsing-indicator"/>
       <hbox id="titlebar-fullscreen-button"/>
     </hbox>
 #endif
   </hbox>
 </vbox>
 #endif
 
@@ -628,18 +628,22 @@
              customizable="true"
              mode="icons"
              iconsize="small"
              aria-label="&tabsToolbar.label;"
              context="toolbar-context-menu"
              collapsed="true">
 
 #if defined(MOZ_WIDGET_GTK)
-      <hbox id="private-browsing-indicator"
+      <hbox class="private-browsing-indicator"
             skipintoolbarset="true"/>
+      <button class="accessibility-indicator"
+              tooltiptext="&accessibilityIndicator.tooltip;"
+              aria-live="polite"
+              skipintoolbarset="true"/>
 #endif
 
       <tabs id="tabbrowser-tabs"
             class="tabbrowser-tabs"
             tabbrowser="content"
             flex="1"
             setfocus="false"
             tooltip="tabbrowser-tab-tooltip"
@@ -677,16 +681,18 @@
                 label="&newUserContext.label;">
             <menupopup id="alltabs_containersMenuTab" />
           </menu>
           <menuseparator id="alltabs-popup-separator-2"/>
         </menupopup>
       </toolbarbutton>
 
 #if !defined(MOZ_WIDGET_GTK)
+      <button class="accessibility-indicator" tooltiptext="&accessibilityIndicator.tooltip;"
+              aria-live="polite" skipintoolbarset="true"/>
       <hbox class="private-browsing-indicator" skipintoolbarset="true"/>
 #endif
 #ifdef CAN_DRAW_IN_TITLEBAR
       <hbox class="titlebar-placeholder" type="caption-buttons"
             id="titlebar-placeholder-on-TabsToolbar-for-captions-buttons" persist="width"
 #ifndef XP_MACOSX
             ordinal="1000"
 #endif
--- a/browser/base/content/test/performance/browser_urlbar_keyed_search_reflows.js
+++ b/browser/base/content/test/performance/browser_urlbar_keyed_search_reflows.js
@@ -20,16 +20,17 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
   {
     stack: [
       "_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
       "handleOverUnderflow@chrome://global/content/bindings/autocomplete.xml",
       "_onChanged@chrome://global/content/bindings/autocomplete.xml",
       "_appendCurrentResult/<@chrome://global/content/bindings/autocomplete.xml",
     ],
     times: 18, // This number should only ever go down - never up.
+    minTimes: 12,
   },
 
   {
     stack: [
       "_rebuild@chrome://browser/content/search/search.xml",
       "set_popup@chrome://browser/content/search/search.xml",
       "enableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
       "_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
--- a/browser/base/content/test/performance/browser_urlbar_search_reflows.js
+++ b/browser/base/content/test/performance/browser_urlbar_search_reflows.js
@@ -18,19 +18,16 @@ requestLongerTimeout(5);
 const EXPECTED_REFLOWS_FIRST_OPEN = [
   // Bug 1357054
   {
     stack: [
       "_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
       "handleOverUnderflow@chrome://global/content/bindings/autocomplete.xml",
       "_onChanged@chrome://global/content/bindings/autocomplete.xml",
       "_appendCurrentResult/<@chrome://global/content/bindings/autocomplete.xml",
-      "setTimeout handler*_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
-      "_invalidate@chrome://global/content/bindings/autocomplete.xml",
-      "invalidate@chrome://global/content/bindings/autocomplete.xml"
     ],
     times: 6, // This number should only ever go down - never up.
     minTimes: 0, // Sometimes this is not hit.
   },
 
   {
     stack: [
       "_rebuild@chrome://browser/content/search/search.xml",
--- a/browser/base/content/test/tabs/browser.ini
+++ b/browser/base/content/test/tabs/browser.ini
@@ -1,14 +1,15 @@
 [DEFAULT]
 support-files =
   dummy_page.html
   test_bug1358314.html
 
 [browser_abandonment_telemetry.js]
+[browser_accessibility_indicator.js]
 [browser_allow_process_switches_despite_related_browser.js]
 [browser_contextmenu_openlink_after_tabnavigated.js]
 [browser_isLocalAboutURI.js]
 [browser_tabCloseProbes.js]
 [browser_tabSpinnerProbe.js]
 skip-if = !e10s # Tab spinner is e10s only.
 [browser_tabSwitchPrintPreview.js]
 skip-if = os == 'mac'
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabs/browser_accessibility_indicator.js
@@ -0,0 +1,124 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const A11Y_INDICATOR_ENABLED_PREF = "accessibility.indicator.enabled";
+
+/**
+ * Test various pref and UI properties based on whether the accessibility
+ * indicator is enabled and the accessibility service is initialized.
+ * @param  {Object}  win      browser window to check the indicator in.
+ * @param  {Boolean} enabled  pref flag for accessibility indicator.
+ * @param  {Boolean} active   whether accessibility service is started or not.
+ */
+function testIndicatorState(win, enabled, active) {
+  is(Services.prefs.getBoolPref(A11Y_INDICATOR_ENABLED_PREF), enabled,
+    `Indicator is ${enabled ? "enabled" : "disabled"}.`);
+  is(Services.appinfo.accessibilityEnabled, active,
+    `Accessibility service is ${active ? "enabled" : "disabled"}.`);
+
+  let visible = enabled && active;
+  is(win.document.documentElement.hasAttribute("accessibilitymode"), visible,
+    `accessibilitymode flag is ${visible ? "set" : "unset"}.`);
+
+  // Browser UI has 2 indicators in markup for OSX and Windows but only 1 is
+  // shown depending on whether the titlebar is enabled.
+  let expectedVisibleCount = visible ? 1 : 0;
+  let visibleCount = 0;
+  [...win.document.querySelectorAll(".accessibility-indicator")].forEach(indicator =>
+    win.getComputedStyle(indicator).getPropertyValue("display") !== "none" &&
+    visibleCount++);
+  is(expectedVisibleCount, visibleCount,
+    `Indicator is ${visible ? "visible" : "invisible"}.`);
+}
+
+/**
+ * Instantiate accessibility service and wait for event associated with its
+ * startup, if necessary.
+ */
+async function initAccessibilityService() {
+  let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
+    Ci.nsIAccessibilityService);
+
+  if (!Services.appinfo.accessibilityEnabled) {
+    await new Promise(resolve => {
+      let observe = (subject, topic, data) => {
+        Services.obs.removeObserver(observe, "a11y-init-or-shutdown");
+        // "1" indicates that the accessibility service is initialized.
+        data === "1" && resolve();
+      };
+      Services.obs.addObserver(observe, "a11y-init-or-shutdown");
+    })
+  }
+
+  return accService;
+}
+
+/**
+ * If accessibility service is not yet disabled, wait for the event associated
+ * with its shutdown.
+ */
+async function shutdownAccessibilityService() {
+  if (Services.appinfo.accessibilityEnabled) {
+    await new Promise(resolve => {
+      let observe = (subject, topic, data) => {
+        Services.obs.removeObserver(observe, "a11y-init-or-shutdown");
+        // "1" indicates that the accessibility service is shutdown.
+        data === "0" && resolve();
+      };
+      Services.obs.addObserver(observe, "a11y-init-or-shutdown");
+    })
+  }
+}
+
+/**
+ * Force garbage collection.
+ */
+function forceGC() {
+  SpecialPowers.gc();
+  SpecialPowers.forceShrinkingGC();
+  SpecialPowers.forceCC();
+}
+
+add_task(async function test_accessibility_indicator() {
+  info("Test default accessibility indicator state.");
+  let newWin = await BrowserTestUtils.openNewBrowserWindow();
+  testIndicatorState(window, true, false);
+  testIndicatorState(newWin, true, false);
+
+  info("Enable accessibility and ensure the indicator is shown in all windows.");
+  let accService = await initAccessibilityService(); // eslint-disable-line no-unused-vars
+  testIndicatorState(window, true, true);
+  testIndicatorState(newWin, true, true);
+
+  info("Open a new window and ensure the indicator is shown there by default.");
+  let dynamicWin = await BrowserTestUtils.openNewBrowserWindow({ private: true });
+  testIndicatorState(dynamicWin, true, true);
+  await BrowserTestUtils.closeWindow(dynamicWin);
+
+  info("Preff off accessibility indicator.");
+  Services.prefs.setBoolPref(A11Y_INDICATOR_ENABLED_PREF, false);
+  testIndicatorState(window, false, true);
+  testIndicatorState(newWin, false, true);
+  dynamicWin = await BrowserTestUtils.openNewBrowserWindow({ private: true });
+  testIndicatorState(dynamicWin, false, true);
+
+  info("Preff on accessibility indicator.");
+  Services.prefs.setBoolPref(A11Y_INDICATOR_ENABLED_PREF, true);
+  testIndicatorState(window, true, true);
+  testIndicatorState(newWin, true, true);
+  testIndicatorState(dynamicWin, true, true);
+
+  info("Disable accessibility and ensure the indicator is hidden in all windows.");
+  accService = undefined;
+  forceGC();
+  await shutdownAccessibilityService();
+  testIndicatorState(window, true, false);
+  testIndicatorState(newWin, true, false);
+  testIndicatorState(dynamicWin, true, false);
+
+  Services.prefs.clearUserPref(A11Y_INDICATOR_ENABLED_PREF);
+  await BrowserTestUtils.closeWindow(newWin);
+  await BrowserTestUtils.closeWindow(dynamicWin);
+});
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -1636,18 +1636,17 @@ var gPrivacyPane = {
       case 0: // access allowed
         checkbox.checked = false;
         break;
     }
   },
 
   _initA11yString() {
     let a11yLearnMoreLink =
-      Services.urlFormatter.formatURLPref("app.support.baseURL") +
-      "accessibility";
+      Services.urlFormatter.formatURLPref("accessibility.support.url");
     document.getElementById("a11yLearnMoreLink")
       .setAttribute("href", a11yLearnMoreLink);
   },
 
   updateA11yPrefs(checked) {
     Services.prefs.setIntPref("accessibility.force_disabled", checked ? 1 : 0);
   }
 };
--- a/browser/extensions/formautofill/FormAutofillHeuristics.jsm
+++ b/browser/extensions/formautofill/FormAutofillHeuristics.jsm
@@ -471,33 +471,16 @@ this.FormAutofillHeuristics = {
       "cc-name",
       "cc-number",
       "cc-exp-month",
       "cc-exp-year",
       "cc-exp",
     ];
     let regexps = isAutoCompleteOff ? FIELDNAMES_IGNORING_AUTOCOMPLETE_OFF : Object.keys(this.RULES);
 
-    if (!FormAutofillUtils.isAutofillCreditCardsAvailable) {
-      if (isAutoCompleteOff) {
-        if (!this._regexpListOf_CcUnavailable_AcOff) {
-          this._regexpListOf_CcUnavailable_AcOff = regexps.filter(name => !FormAutofillUtils.isCreditCardField(name));
-        }
-        regexps = this._regexpListOf_CcUnavailable_AcOff;
-      } else {
-        if (!this._regexpListOf_CcUnavailable_AcOn) {
-          this._regexpListOf_CcUnavailable_AcOn = regexps.filter(name => !FormAutofillUtils.isCreditCardField(name));
-        }
-        regexps = this._regexpListOf_CcUnavailable_AcOn;
-      }
-    }
-    if (regexps.length == 0) {
-      return null;
-    }
-
     let labelStrings;
     let getElementStrings = {};
     getElementStrings[Symbol.iterator] = function* () {
       yield element.id;
       yield element.name;
       if (!labelStrings) {
         labelStrings = [];
         let labels = LabelUtils.findLabelElements(element);
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,5 +1,5 @@
 This is the PDF.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 1.9.562
+Current extension version is: 1.9.583
 
-Taken from upstream commit: 31a34335
+Taken from upstream commit: d7b37ae7
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -1454,17 +1454,17 @@ exports.unreachable = unreachable;
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
-exports.DOMSVGFactory = exports.DOMCMapReaderFactory = exports.DOMCanvasFactory = exports.DEFAULT_LINK_REL = exports.getDefaultSetting = exports.LinkTarget = exports.getFilenameFromUrl = exports.isValidUrl = exports.isExternalLinkTargetSet = exports.addLinkAttributes = exports.RenderingCancelledException = exports.CustomStyle = undefined;
+exports.SimpleXMLParser = exports.DOMSVGFactory = exports.DOMCMapReaderFactory = exports.DOMCanvasFactory = exports.DEFAULT_LINK_REL = exports.getDefaultSetting = exports.LinkTarget = exports.getFilenameFromUrl = exports.isValidUrl = exports.isExternalLinkTargetSet = exports.addLinkAttributes = exports.RenderingCancelledException = exports.CustomStyle = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
 var _global_scope = __w_pdfjs_require__(2);
 
 var _global_scope2 = _interopRequireDefault(_global_scope);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -1557,16 +1557,117 @@ class DOMSVGFactory {
     svg.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
     return svg;
   }
   createElement(type) {
     (0, _util.assert)(typeof type === 'string', 'Invalid SVG element type');
     return document.createElementNS(SVG_NS, type);
   }
 }
+class SimpleDOMNode {
+  constructor(nodeName, nodeValue) {
+    this.nodeName = nodeName;
+    this.nodeValue = nodeValue;
+    Object.defineProperty(this, 'parentNode', {
+      value: null,
+      writable: true
+    });
+  }
+  get firstChild() {
+    return this.childNodes[0];
+  }
+  get nextSibling() {
+    let index = this.parentNode.childNodes.indexOf(this);
+    return this.parentNode.childNodes[index + 1];
+  }
+  get textContent() {
+    if (!this.childNodes) {
+      return this.nodeValue || '';
+    }
+    return this.childNodes.map(function (child) {
+      return child.textContent;
+    }).join('');
+  }
+  hasChildNodes() {
+    return this.childNodes && this.childNodes.length > 0;
+  }
+}
+class SimpleXMLParser {
+  parseFromString(data) {
+    let nodes = [];
+    data = data.replace(/<\?[\s\S]*?\?>|<!--[\s\S]*?-->/g, '').trim();
+    data = data.replace(/<!DOCTYPE[^>\[]+(\[[^\]]+)?[^>]+>/g, '').trim();
+    data = data.replace(/>([^<][\s\S]*?)</g, (all, text) => {
+      let length = nodes.length;
+      let node = new SimpleDOMNode('#text', this._decodeXML(text));
+      nodes.push(node);
+      if (node.textContent.trim().length === 0) {
+        return '><';
+      }
+      return '>' + length + ',<';
+    });
+    data = data.replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g, function (all, text) {
+      let length = nodes.length;
+      let node = new SimpleDOMNode('#text', text);
+      nodes.push(node);
+      return length + ',';
+    });
+    let regex = /<([\w\:]+)((?:[\s\w:=]|'[^']*'|"[^"]*")*)(?:\/>|>([\d,]*)<\/[^>]+>)/g;
+    let lastLength;
+    do {
+      lastLength = nodes.length;
+      data = data.replace(regex, function (all, name, attrs, data) {
+        let length = nodes.length;
+        let node = new SimpleDOMNode(name);
+        let children = [];
+        if (data) {
+          data = data.split(',');
+          data.pop();
+          data.forEach(function (child) {
+            let childNode = nodes[+child];
+            childNode.parentNode = node;
+            children.push(childNode);
+          });
+        }
+        node.childNodes = children;
+        nodes.push(node);
+        return length + ',';
+      });
+    } while (lastLength < nodes.length);
+    return { documentElement: nodes.pop() };
+  }
+  _decodeXML(text) {
+    if (text.indexOf('&') < 0) {
+      return text;
+    }
+    return text.replace(/&(#(x[0-9a-f]+|\d+)|\w+);/gi, function (all, entityName, number) {
+      if (number) {
+        if (number[0] === 'x') {
+          number = parseInt(number.substring(1), 16);
+        } else {
+          number = +number;
+        }
+        return String.fromCharCode(number);
+      }
+      switch (entityName) {
+        case 'amp':
+          return '&';
+        case 'lt':
+          return '<';
+        case 'gt':
+          return '>';
+        case 'quot':
+          return '\"';
+        case 'apos':
+          return '\'';
+      }
+      return '&' + entityName + ';';
+    });
+  }
+}
 var CustomStyle = function CustomStyleClosure() {
   var prefixes = ['ms', 'Moz', 'Webkit', 'O'];
   var _cache = Object.create(null);
   function CustomStyle() {}
   CustomStyle.getProp = function get(propName, element) {
     if (arguments.length === 1 && typeof _cache[propName] === 'string') {
       return _cache[propName];
     }
@@ -1718,16 +1819,17 @@ exports.isExternalLinkTargetSet = isExte
 exports.isValidUrl = isValidUrl;
 exports.getFilenameFromUrl = getFilenameFromUrl;
 exports.LinkTarget = LinkTarget;
 exports.getDefaultSetting = getDefaultSetting;
 exports.DEFAULT_LINK_REL = DEFAULT_LINK_REL;
 exports.DOMCanvasFactory = DOMCanvasFactory;
 exports.DOMCMapReaderFactory = DOMCMapReaderFactory;
 exports.DOMSVGFactory = DOMSVGFactory;
+exports.SimpleXMLParser = SimpleXMLParser;
 
 /***/ }),
 /* 2 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
@@ -1906,17 +2008,18 @@ function _fetchDocument(worker, source, 
       length: source.length
     },
     maxImageSize: (0, _dom_utils.getDefaultSetting)('maxImageSize'),
     disableFontFace: (0, _dom_utils.getDefaultSetting)('disableFontFace'),
     disableCreateObjectURL: (0, _dom_utils.getDefaultSetting)('disableCreateObjectURL'),
     postMessageTransfers: (0, _dom_utils.getDefaultSetting)('postMessageTransfers') && !isPostMessageTransfersDisabled,
     docBaseUrl: source.docBaseUrl,
     nativeImageDecoderSupport: source.nativeImageDecoderSupport,
-    ignoreErrors: source.ignoreErrors
+    ignoreErrors: source.ignoreErrors,
+    isEvalSupported: (0, _dom_utils.getDefaultSetting)('isEvalSupported')
   }).then(function (workerId) {
     if (worker.destroyed) {
       throw new Error('Worker was destroyed');
     }
     return workerId;
   });
 }
 var PDFDocumentLoadingTask = function PDFDocumentLoadingTaskClosure() {
@@ -3201,18 +3304,18 @@ var _UnsupportedManager = function Unsup
       for (var i = 0, ii = listeners.length; i < ii; i++) {
         listeners[i](featureId);
       }
     }
   };
 }();
 var version, build;
 {
-  exports.version = version = '1.9.562';
-  exports.build = build = '31a34335';
+  exports.version = version = '1.9.583';
+  exports.build = build = 'd7b37ae7';
 }
 exports.getDocument = getDocument;
 exports.LoopbackPort = LoopbackPort;
 exports.PDFDataRangeTransport = PDFDataRangeTransport;
 exports.PDFWorker = PDFWorker;
 exports.PDFDocumentProxy = PDFDocumentProxy;
 exports.PDFPageProxy = PDFPageProxy;
 exports.setPDFNetworkStreamClass = setPDFNetworkStreamClass;
@@ -3592,84 +3695,89 @@ exports.WebGLUtils = WebGLUtils;
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
-function fixMetadata(meta) {
-  return meta.replace(/>\\376\\377([^<]+)/g, function (all, codes) {
-    var bytes = codes.replace(/\\([0-3])([0-7])([0-7])/g, function (code, d1, d2, d3) {
-      return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1);
+exports.Metadata = undefined;
+
+var _util = __w_pdfjs_require__(0);
+
+var _dom_utils = __w_pdfjs_require__(1);
+
+class Metadata {
+  constructor(data) {
+    (0, _util.assert)(typeof data === 'string', 'Metadata: input is not a string');
+    data = this._repair(data);
+    let parser = new _dom_utils.SimpleXMLParser();
+    data = parser.parseFromString(data);
+    this._metadata = Object.create(null);
+    this._parse(data);
+  }
+  _repair(data) {
+    return data.replace(/>\\376\\377([^<]+)/g, function (all, codes) {
+      let bytes = codes.replace(/\\([0-3])([0-7])([0-7])/g, function (code, d1, d2, d3) {
+        return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1);
+      });
+      let chars = '';
+      for (let i = 0, ii = bytes.length; i < ii; i += 2) {
+        let code = bytes.charCodeAt(i) * 256 + bytes.charCodeAt(i + 1);
+        if (code >= 32 && code < 127 && code !== 60 && code !== 62 && code !== 38) {
+          chars += String.fromCharCode(code);
+        } else {
+          chars += '&#x' + (0x10000 + code).toString(16).substring(1) + ';';
+        }
+      }
+      return '>' + chars;
     });
-    var chars = '';
-    for (var i = 0; i < bytes.length; i += 2) {
-      var code = bytes.charCodeAt(i) * 256 + bytes.charCodeAt(i + 1);
-      chars += code >= 32 && code < 127 && code !== 60 && code !== 62 && code !== 38 ? String.fromCharCode(code) : '&#x' + (0x10000 + code).toString(16).substring(1) + ';';
-    }
-    return '>' + chars;
-  });
-}
-function Metadata(meta) {
-  if (typeof meta === 'string') {
-    meta = fixMetadata(meta);
-    var parser = new DOMParser();
-    meta = parser.parseFromString(meta, 'application/xml');
-  } else if (!(meta instanceof Document)) {
-    throw new Error('Metadata: Invalid metadata object');
-  }
-  this.metaDocument = meta;
-  this.metadata = Object.create(null);
-  this.parse();
-}
-Metadata.prototype = {
-  parse: function Metadata_parse() {
-    var doc = this.metaDocument;
-    var rdf = doc.documentElement;
+  }
+  _parse(domDocument) {
+    let rdf = domDocument.documentElement;
     if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') {
       rdf = rdf.firstChild;
       while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf') {
         rdf = rdf.nextSibling;
       }
     }
-    var nodeName = rdf ? rdf.nodeName.toLowerCase() : null;
+    let nodeName = rdf ? rdf.nodeName.toLowerCase() : null;
     if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes()) {
       return;
     }
-    var children = rdf.childNodes,
-        desc,
-        entry,
-        name,
-        i,
-        ii,
-        length,
-        iLength;
-    for (i = 0, length = children.length; i < length; i++) {
-      desc = children[i];
+    let children = rdf.childNodes;
+    for (let i = 0, ii = children.length; i < ii; i++) {
+      let desc = children[i];
       if (desc.nodeName.toLowerCase() !== 'rdf:description') {
         continue;
       }
-      for (ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) {
-        if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text') {
-          entry = desc.childNodes[ii];
-          name = entry.nodeName.toLowerCase();
-          this.metadata[name] = entry.textContent.trim();
-        }
-      }
-    }
-  },
-  get: function Metadata_get(name) {
-    return this.metadata[name] || null;
-  },
-  has: function Metadata_has(name) {
-    return typeof this.metadata[name] !== 'undefined';
-  }
-};
+      for (let j = 0, jj = desc.childNodes.length; j < jj; j++) {
+        if (desc.childNodes[j].nodeName.toLowerCase() !== '#text') {
+          let entry = desc.childNodes[j];
+          let name = entry.nodeName.toLowerCase();
+          this._metadata[name] = entry.textContent.trim();
+        }
+      }
+    }
+  }
+  get(name) {
+    return this._metadata[name] || null;
+  }
+  getAll() {
+    return this._metadata;
+  }
+  has(name) {
+    return typeof this._metadata[name] !== 'undefined';
+  }
+  get metadata() {
+    (0, _util.deprecated)('`metadata` getter; use `getAll()` instead.');
+    return this.getAll();
+  }
+}
 exports.Metadata = Metadata;
 
 /***/ }),
 /* 6 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
@@ -3719,16 +3827,18 @@ class AnnotationElementFactory {
       case _util.AnnotationType.HIGHLIGHT:
         return new HighlightAnnotationElement(parameters);
       case _util.AnnotationType.UNDERLINE:
         return new UnderlineAnnotationElement(parameters);
       case _util.AnnotationType.SQUIGGLY:
         return new SquigglyAnnotationElement(parameters);
       case _util.AnnotationType.STRIKEOUT:
         return new StrikeOutAnnotationElement(parameters);
+      case _util.AnnotationType.STAMP:
+        return new StampAnnotationElement(parameters);
       case _util.AnnotationType.FILEATTACHMENT:
         return new FileAttachmentAnnotationElement(parameters);
       default:
         return new AnnotationElement(parameters);
     }
   }
 }
 class AnnotationElement {
@@ -4242,16 +4352,29 @@ class StrikeOutAnnotationElement extends
   render() {
     this.container.className = 'strikeoutAnnotation';
     if (!this.data.hasPopup) {
       this._createPopup(this.container, null, this.data);
     }
     return this.container;
   }
 }
+class StampAnnotationElement extends AnnotationElement {
+  constructor(parameters) {
+    let isRenderable = !!(parameters.data.hasPopup || parameters.data.title || parameters.data.contents);
+    super(parameters, isRenderable, true);
+  }
+  render() {
+    this.container.className = 'stampAnnotation';
+    if (!this.data.hasPopup) {
+      this._createPopup(this.container, null, this.data);
+    }
+    return this.container;
+  }
+}
 class FileAttachmentAnnotationElement extends AnnotationElement {
   constructor(parameters) {
     super(parameters, true);
     let file = this.data.file;
     this.filename = (0, _dom_utils.getFilenameFromUrl)(file.filename);
     this.content = file.content;
     this.linkService.onFileAttachmentAnnotation({
       id: (0, _util.stringToPDFString)(file.filename),
@@ -4877,18 +5000,18 @@ exports.SVGGraphics = SVGGraphics;
 
 /***/ }),
 /* 9 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '1.9.562';
-var pdfjsBuild = '31a34335';
+var pdfjsVersion = '1.9.583';
+var pdfjsBuild = 'd7b37ae7';
 var pdfjsSharedUtil = __w_pdfjs_require__(0);
 var pdfjsDisplayGlobal = __w_pdfjs_require__(13);
 var pdfjsDisplayAPI = __w_pdfjs_require__(3);
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(7);
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(6);
 var pdfjsDisplayDOMUtils = __w_pdfjs_require__(1);
 var pdfjsDisplaySVG = __w_pdfjs_require__(8);
 ;
@@ -8004,18 +8127,18 @@ var _svg = __w_pdfjs_require__(8);
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 var isWorker = typeof window === 'undefined';
 if (!_global_scope2.default.PDFJS) {
   _global_scope2.default.PDFJS = {};
 }
 var PDFJS = _global_scope2.default.PDFJS;
 {
-  PDFJS.version = '1.9.562';
-  PDFJS.build = '31a34335';
+  PDFJS.version = '1.9.583';
+  PDFJS.build = 'd7b37ae7';
 }
 PDFJS.pdfBug = false;
 if (PDFJS.verbosity !== undefined) {
   (0, _util.setVerbosityLevel)(PDFJS.verbosity);
 }
 delete PDFJS.verbosity;
 Object.defineProperty(PDFJS, 'verbosity', {
   get() {
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -2239,16 +2239,26 @@ var PredictorStream = function Predictor
     } else if (bits === 8) {
       for (i = 0; i < colors; ++i) {
         buffer[pos++] = rawBytes[i];
       }
       for (; i < rowBytes; ++i) {
         buffer[pos] = buffer[pos - colors] + rawBytes[i];
         pos++;
       }
+    } else if (bits === 16) {
+      var bytesPerPixel = colors * 2;
+      for (i = 0; i < bytesPerPixel; ++i) {
+        buffer[pos++] = rawBytes[i];
+      }
+      for (; i < rowBytes; i += 2) {
+        var sum = ((rawBytes[i] & 0xFF) << 8) + (rawBytes[i + 1] & 0xFF) + ((buffer[pos - bytesPerPixel] & 0xFF) << 8) + (buffer[pos - bytesPerPixel + 1] & 0xFF);
+        buffer[pos++] = sum >> 8 & 0xFF;
+        buffer[pos++] = sum & 0xFF;
+      }
     } else {
       var compArray = new Uint8Array(colors + 1);
       var bitMask = (1 << bits) - 1;
       var j = 0,
           k = bufferLength;
       var columns = this.columns;
       for (i = 0; i < columns; ++i) {
         for (var kk = 0; kk < colors; ++kk) {
@@ -2735,17 +2745,19 @@ var CCITTFaxStream = function CCITTFaxSt
   var whiteTable1 = [[-1, -1], [12, ccittEOL], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [11, 1792], [11, 1792], [12, 1984], [12, 2048], [12, 2112], [12, 2176], [12, 2240], [12, 2304], [11, 1856], [11, 1856], [11, 1920], [11, 1920], [12, 2368], [12, 2432], [12, 2496], [12, 2560]];
   var whiteTable2 = [[-1, -1], [-1, -1], [-1, -1], [-1, -1], [8, 29], [8, 29], [8, 30], [8, 30], [8, 45], [8, 45], [8, 46], [8, 46], [7, 22], [7, 22], [7, 22], [7, 22], [7, 23], [7, 23], [7, 23], [7, 23], [8, 47], [8, 47], [8, 48], [8, 48], [6, 13], [6, 13], [6, 13], [6, 13], [6, 13], [6, 13], [6, 13], [6, 13], [7, 20], [7, 20], [7, 20], [7, 20], [8, 33], [8, 33], [8, 34], [8, 34], [8, 35], [8, 35], [8, 36], [8, 36], [8, 37], [8, 37], [8, 38], [8, 38], [7, 19], [7, 19], [7, 19], [7, 19], [8, 31], [8, 31], [8, 32], [8, 32], [6, 1], [6, 1], [6, 1], [6, 1], [6, 1], [6, 1], [6, 1], [6, 1], [6, 12], [6, 12], [6, 12], [6, 12], [6, 12], [6, 12], [6, 12], [6, 12], [8, 53], [8, 53], [8, 54], [8, 54], [7, 26], [7, 26], [7, 26], [7, 26], [8, 39], [8, 39], [8, 40], [8, 40], [8, 41], [8, 41], [8, 42], [8, 42], [8, 43], [8, 43], [8, 44], [8, 44], [7, 21], [7, 21], [7, 21], [7, 21], [7, 28], [7, 28], [7, 28], [7, 28], [8, 61], [8, 61], [8, 62], [8, 62], [8, 63], [8, 63], [8, 0], [8, 0], [8, 320], [8, 320], [8, 384], [8, 384], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 10], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [5, 11], [7, 27], [7, 27], [7, 27], [7, 27], [8, 59], [8, 59], [8, 60], [8, 60], [9, 1472], [9, 1536], [9, 1600], [9, 1728], [7, 18], [7, 18], [7, 18], [7, 18], [7, 24], [7, 24], [7, 24], [7, 24], [8, 49], [8, 49], [8, 50], [8, 50], [8, 51], [8, 51], [8, 52], [8, 52], [7, 25], [7, 25], [7, 25], [7, 25], [8, 55], [8, 55], [8, 56], [8, 56], [8, 57], [8, 57], [8, 58], [8, 58], [6, 192], [6, 192], [6, 192], [6, 192], [6, 192], [6, 192], [6, 192], [6, 192], [6, 1664], [6, 1664], [6, 1664], [6, 1664], [6, 1664], [6, 1664], [6, 1664], [6, 1664], [8, 448], [8, 448], [8, 512], [8, 512], [9, 704], [9, 768], [8, 640], [8, 640], [8, 576], [8, 576], [9, 832], [9, 896], [9, 960], [9, 1024], [9, 1088], [9, 1152], [9, 1216], [9, 1280], [9, 1344], [9, 1408], [7, 256], [7, 256], [7, 256], [7, 256], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 2], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [4, 3], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 128], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 8], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [5, 9], [6, 16], [6, 16], [6, 16], [6, 16], [6, 16], [6, 16], [6, 16], [6, 16], [6, 17], [6, 17], [6, 17], [6, 17], [6, 17], [6, 17], [6, 17], [6, 17], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 4], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [4, 5], [6, 14], [6, 14], [6, 14], [6, 14], [6, 14], [6, 14], [6, 14], [6, 14], [6, 15], [6, 15], [6, 15], [6, 15], [6, 15], [6, 15], [6, 15], [6, 15], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [5, 64], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 6], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7], [4, 7]];
   var blackTable1 = [[-1, -1], [-1, -1], [12, ccittEOL], [12, ccittEOL], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [-1, -1], [11, 1792], [11, 1792], [11, 1792], [11, 1792], [12, 1984], [12, 1984], [12, 2048], [12, 2048], [12, 2112], [12, 2112], [12, 2176], [12, 2176], [12, 2240], [12, 2240], [12, 2304], [12, 2304], [11, 1856], [11, 1856], [11, 1856], [11, 1856], [11, 1920], [11, 1920], [11, 1920], [11, 1920], [12, 2368], [12, 2368], [12, 2432], [12, 2432], [12, 2496], [12, 2496], [12, 2560], [12, 2560], [10, 18], [10, 18], [10, 18], [10, 18], [10, 18], [10, 18], [10, 18], [10, 18], [12, 52], [12, 52], [13, 640], [13, 704], [13, 768], [13, 832], [12, 55], [12, 55], [12, 56], [12, 56], [13, 1280], [13, 1344], [13, 1408], [13, 1472], [12, 59], [12, 59], [12, 60], [12, 60], [13, 1536], [13, 1600], [11, 24], [11, 24], [11, 24], [11, 24], [11, 25], [11, 25], [11, 25], [11, 25], [13, 1664], [13, 1728], [12, 320], [12, 320], [12, 384], [12, 384], [12, 448], [12, 448], [13, 512], [13, 576], [12, 53], [12, 53], [12, 54], [12, 54], [13, 896], [13, 960], [13, 1024], [13, 1088], [13, 1152], [13, 1216], [10, 64], [10, 64], [10, 64], [10, 64], [10, 64], [10, 64], [10, 64], [10, 64]];
   var blackTable2 = [[8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [8, 13], [11, 23], [11, 23], [12, 50], [12, 51], [12, 44], [12, 45], [12, 46], [12, 47], [12, 57], [12, 58], [12, 61], [12, 256], [10, 16], [10, 16], [10, 16], [10, 16], [10, 17], [10, 17], [10, 17], [10, 17], [12, 48], [12, 49], [12, 62], [12, 63], [12, 30], [12, 31], [12, 32], [12, 33], [12, 40], [12, 41], [11, 22], [11, 22], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [8, 14], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 10], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [7, 11], [9, 15], [9, 15], [9, 15], [9, 15], [9, 15], [9, 15], [9, 15], [9, 15], [12, 128], [12, 192], [12, 26], [12, 27], [12, 28], [12, 29], [11, 19], [11, 19], [11, 20], [11, 20], [12, 34], [12, 35], [12, 36], [12, 37], [12, 38], [12, 39], [11, 21], [11, 21], [12, 42], [12, 43], [10, 0], [10, 0], [10, 0], [10, 0], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12], [7, 12]];
   var blackTable3 = [[-1, -1], [-1, -1], [-1, -1], [-1, -1], [6, 9], [6, 8], [5, 7], [5, 7], [4, 6], [4, 6], [4, 6], [4, 6], [4, 5], [4, 5], [4, 5], [4, 5], [3, 1], [3, 1], [3, 1], [3, 1], [3, 1], [3, 1], [3, 1], [3, 1], [3, 4], [3, 4], [3, 4], [3, 4], [3, 4], [3, 4], [3, 4], [3, 4], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2]];
   function CCITTFaxStream(str, maybeLength, params) {
     this.str = str;
     this.dict = str.dict;
-    params = params || _primitives.Dict.empty;
+    if (!(0, _primitives.isDict)(params)) {
+      params = _primitives.Dict.empty;
+    }
     this.encoding = params.get('K') || 0;
     this.eoline = params.get('EndOfLine') || false;
     this.byteAlign = params.get('EncodedByteAlign') || false;
     this.columns = params.get('Columns') || 1728;
     this.rows = params.get('Rows') || 0;
     var eoblock = params.get('EndOfBlock');
     if (eoblock === null || eoblock === undefined) {
       eoblock = true;
@@ -2756,16 +2768,17 @@ var CCITTFaxStream = function CCITTFaxSt
     this.refLine = new Uint32Array(this.columns + 2);
     this.codingLine[0] = this.columns;
     this.codingPos = 0;
     this.row = 0;
     this.nextLine2D = this.encoding < 0;
     this.inputBits = 0;
     this.inputBuf = 0;
     this.outputBits = 0;
+    this.rowsDone = false;
     var code1;
     while ((code1 = this.lookBits(12)) === 0) {
       this.eatBits(1);
     }
     if (code1 === 1) {
       this.eatBits(12);
     }
     if (this.encoding > 0) {
@@ -2825,16 +2838,19 @@ var CCITTFaxStream = function CCITTFaxSt
     this.codingPos = codingPos;
   };
   CCITTFaxStream.prototype.lookChar = function CCITTFaxStream_lookChar() {
     var refLine = this.refLine;
     var codingLine = this.codingLine;
     var columns = this.columns;
     var refPos, blackPixels, bits, i;
     if (this.outputBits === 0) {
+      if (this.rowsDone) {
+        this.eof = true;
+      }
       if (this.eof) {
         return null;
       }
       this.err = false;
       var code1, code2, code3;
       if (this.nextLine2D) {
         for (i = 0; codingLine[i] < columns; ++i) {
           refLine[i] = codingLine[i];
@@ -2990,17 +3006,17 @@ var CCITTFaxStream = function CCITTFaxSt
           blackPixels ^= 1;
         }
       }
       var gotEOL = false;
       if (this.byteAlign) {
         this.inputBits &= ~7;
       }
       if (!this.eoblock && this.row === this.rows - 1) {
-        this.eof = true;
+        this.rowsDone = true;
       } else {
         code1 = this.lookBits(12);
         if (this.eoline) {
           while (code1 !== ccittEOF && code1 !== 1) {
             this.eatBits(1);
             code1 = this.lookBits(12);
           }
         } else {
@@ -3011,17 +3027,17 @@ var CCITTFaxStream = function CCITTFaxSt
         }
         if (code1 === 1) {
           this.eatBits(12);
           gotEOL = true;
         } else if (code1 === ccittEOF) {
           this.eof = true;
         }
       }
-      if (!this.eof && this.encoding > 0) {
+      if (!this.eof && this.encoding > 0 && !this.rowsDone) {
         this.nextLine2D = !this.lookBits(1);
         this.eatBits(1);
       }
       if (this.eoblock && gotEOL && this.byteAlign) {
         code1 = this.lookBits(12);
         if (code1 === 1) {
           this.eatBits(12);
           if (this.encoding > 0) {
@@ -4791,17 +4807,17 @@ var Parser = function ParserClosure() {
       stream.dict = dict;
       return stream;
     },
     filter: function Parser_filter(stream, dict, length) {
       var filter = dict.get('Filter', 'F');
       var params = dict.get('DecodeParms', 'DP');
       if ((0, _primitives.isName)(filter)) {
         if (Array.isArray(params)) {
-          params = this.xref.fetchIfRef(params[0]);
+          (0, _util.warn)('/DecodeParms should not contain an Array, ' + 'when /Filter contains a Name.');
         }
         return this.makeFilter(stream, filter.name, length, params);
       }
       var maybeLength = length;
       if (Array.isArray(filter)) {
         var filterArray = filter;
         var paramsArray = params;
         for (var i = 0, ii = filterArray.length; i < ii; ++i) {
@@ -5328,22 +5344,31 @@ Object.defineProperty(exports, "__esModu
 exports.PostScriptCompiler = exports.PostScriptEvaluator = exports.PDFFunction = exports.isPDFFunction = undefined;
 
 var _util = __w_pdfjs_require__(0);
 
 var _primitives = __w_pdfjs_require__(1);
 
 var _ps_parser = __w_pdfjs_require__(26);
 
+let IsEvalSupportedCached = {
+  get value() {
+    return (0, _util.shadow)(this, 'value', (0, _util.isEvalSupported)());
+  }
+};
 var PDFFunction = function PDFFunctionClosure() {
   var CONSTRUCT_SAMPLED = 0;
   var CONSTRUCT_INTERPOLATED = 2;
   var CONSTRUCT_STICHED = 3;
   var CONSTRUCT_POSTSCRIPT = 4;
+  let isEvalSupported = true;
   return {
+    setIsEvalSupported(support = true) {
+      isEvalSupported = support !== false;
+    },
     getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps, str) {
       var i, ii;
       var length = 1;
       for (i = 0, ii = size.length; i < ii; i++) {
         length *= size[i];
       }
       length *= outputSize;
       var array = new Array(length);
@@ -5605,19 +5630,21 @@ var PDFFunction = function PDFFunctionCl
       var parser = new _ps_parser.PostScriptParser(lexer);
       var code = parser.parse();
       return [CONSTRUCT_POSTSCRIPT, domain, range, code];
     },
     constructPostScriptFromIR: function PDFFunction_constructPostScriptFromIR(IR) {
       var domain = IR[1];
       var range = IR[2];
       var code = IR[3];
-      var compiled = new PostScriptCompiler().compile(code, domain, range);
-      if (compiled) {
-        return new Function('src', 'srcOffset', 'dest', 'destOffset', compiled);
+      if (isEvalSupported && IsEvalSupportedCached.value) {
+        let compiled = new PostScriptCompiler().compile(code, domain, range);
+        if (compiled) {
+          return new Function('src', 'srcOffset', 'dest', 'destOffset', compiled);
+        }
       }
       (0, _util.info)('Unable to compile PS function');
       var numOutputs = range.length >> 1;
       var numInputs = domain.length >> 1;
       var evaluator = new PostScriptEvaluator(code);
       var cache = Object.create(null);
       var MAX_CACHE_SIZE = 2048 * 4;
       var cache_available = MAX_CACHE_SIZE;
@@ -16700,17 +16727,18 @@ var _murmurhash = __w_pdfjs_require__(35
 var _image = __w_pdfjs_require__(36);
 
 var PartialEvaluator = function PartialEvaluatorClosure() {
   const DefaultPartialEvaluatorOptions = {
     forceDataSchema: false,
     maxImageSize: -1,
     disableFontFace: false,
     nativeImageDecoderSupport: _util.NativeImageDecoding.DECODE,
-    ignoreErrors: false
+    ignoreErrors: false,
+    isEvalSupported: true
   };
   function NativeImageDecoder(xref, resources, handler, forceDataSchema) {
     this.xref = xref;
     this.resources = resources;
     this.handler = handler;
     this.forceDataSchema = forceDataSchema;
   }
   NativeImageDecoder.prototype = {
@@ -18265,17 +18293,17 @@ var PartialEvaluator = function PartialE
     extractWidths: function PartialEvaluator_extractWidths(dict, descriptor, properties) {
       var xref = this.xref;
       var glyphsWidths = [];
       var defaultWidth = 0;
       var glyphsVMetrics = [];
       var defaultVMetrics;
       var i, ii, j, jj, start, code, widths;
       if (properties.composite) {
-        defaultWidth = dict.get('DW') || 1000;
+        defaultWidth = dict.has('DW') ? dict.get('DW') : 1000;
         widths = dict.get('W');
         if (widths) {
           for (i = 0, ii = widths.length; i < ii; i++) {
             start = xref.fetchIfRef(widths[i++]);
             code = xref.fetchIfRef(widths[i]);
             if (Array.isArray(code)) {
               for (j = 0, jj = code.length; j < jj; j++) {
                 glyphsWidths[start++] = xref.fetchIfRef(code[j]);
@@ -23697,18 +23725,18 @@ exports.getUnicodeForGlyph = getUnicodeF
 
 /***/ }),
 /* 17 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '1.9.562';
-var pdfjsBuild = '31a34335';
+var pdfjsVersion = '1.9.583';
+var pdfjsBuild = 'd7b37ae7';
 var pdfjsCoreWorker = __w_pdfjs_require__(18);
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 18 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
@@ -24083,17 +24111,18 @@ var WorkerMessageHandler = {
         }, onFailure);
       }
       ensureNotTerminated();
       var evaluatorOptions = {
         forceDataSchema: data.disableCreateObjectURL,
         maxImageSize: data.maxImageSize === undefined ? -1 : data.maxImageSize,
         disableFontFace: data.disableFontFace,
         nativeImageDecoderSupport: data.nativeImageDecoderSupport,
-        ignoreErrors: data.ignoreErrors
+        ignoreErrors: data.ignoreErrors,
+        isEvalSupported: data.isEvalSupported
       };
       getPdfManager(data, evaluatorOptions).then(function (newPdfManager) {
         if (terminated) {
           newPdfManager.terminate();
           throw new Error('Worker was terminated');
         }
         pdfManager = newPdfManager;
         handler.send('PDFManagerReady', null);
@@ -27536,16 +27565,18 @@ var _stream = __w_pdfjs_require__(2);
 var _evaluator = __w_pdfjs_require__(13);
 
 var _annotation = __w_pdfjs_require__(37);
 
 var _crypto = __w_pdfjs_require__(12);
 
 var _parser = __w_pdfjs_require__(5);
 
+var _function = __w_pdfjs_require__(6);
+
 var Page = function PageClosure() {
   var DEFAULT_USER_UNIT = 1.0;
   var LETTER_SIZE_MEDIABOX = [0, 0, 612, 792];
   function isAnnotationRenderable(annotation, intent) {
     return intent === 'display' && annotation.viewable || intent === 'print' && annotation.printable;
   }
   function Page(pdfManager, xref, pageIndex, pageDict, ref, fontCache, builtInCMapCache) {
     this.pdfManager = pdfManager;
@@ -27943,16 +27974,18 @@ var PDFDocument = function PDFDocumentCl
     setup: function PDFDocument_setup(recoveryMode) {
       this.xref.parse(recoveryMode);
       var pageFactory = {
         createPage: (pageIndex, dict, ref, fontCache, builtInCMapCache) => {
           return new Page(this.pdfManager, this.xref, pageIndex, dict, ref, fontCache, builtInCMapCache);
         }
       };
       this.catalog = new _obj.Catalog(this.pdfManager, this.xref, pageFactory);
+      let evaluatorOptions = this.pdfManager.evaluatorOptions;
+      _function.PDFFunction.setIsEvalSupported(evaluatorOptions.isEvalSupported);
     },
     get numPages() {
       var linearization = this.linearization;
       var num = linearization ? linearization.numPages : this.catalog.numPages;
       return (0, _util.shadow)(this, 'numPages', num);
     },
     get documentInfo() {
       var docInfo = {
@@ -39517,16 +39550,18 @@ class AnnotationFactory {
       case 'Highlight':
         return new HighlightAnnotation(parameters);
       case 'Underline':
         return new UnderlineAnnotation(parameters);
       case 'Squiggly':
         return new SquigglyAnnotation(parameters);
       case 'StrikeOut':
         return new StrikeOutAnnotation(parameters);
+      case 'Stamp':
+        return new StampAnnotation(parameters);
       case 'FileAttachment':
         return new FileAttachmentAnnotation(parameters);
       default:
         if (!subtype) {
           (0, _util.warn)('Annotation is missing the required /Subtype.');
         } else {
           (0, _util.warn)('Unimplemented annotation type "' + subtype + '", ' + 'falling back to base annotation.');
         }
@@ -40043,16 +40078,23 @@ class SquigglyAnnotation extends Annotat
 }
 class StrikeOutAnnotation extends Annotation {
   constructor(parameters) {
     super(parameters);
     this.data.annotationType = _util.AnnotationType.STRIKEOUT;
     this._preparePopup(parameters.dict);
   }
 }
+class StampAnnotation extends Annotation {
+  constructor(parameters) {
+    super(parameters);
+    this.data.annotationType = _util.AnnotationType.STAMP;
+    this._preparePopup(parameters.dict);
+  }
+}
 class FileAttachmentAnnotation extends Annotation {
   constructor(parameters) {
     super(parameters);
     let file = new _obj.FileSpec(parameters.dict.get('FS'), parameters.xref);
     this.data.annotationType = _util.AnnotationType.FILEATTACHMENT;
     this.data.file = file.serializable;
     this._preparePopup(parameters.dict);
   }
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -244,16 +244,17 @@
 
 .annotationLayer .highlightAnnotation,
 .annotationLayer .underlineAnnotation,
 .annotationLayer .squigglyAnnotation,
 .annotationLayer .strikeoutAnnotation,
 .annotationLayer .lineAnnotation svg line,
 .annotationLayer .squareAnnotation svg rect,
 .annotationLayer .circleAnnotation svg ellipse,
+.annotationLayer .stampAnnotation,
 .annotationLayer .fileAttachmentAnnotation {
   cursor: pointer;
 }
 
 .pdfViewer .canvasWrapper {
   overflow: hidden;
 }
 
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -2001,20 +2001,17 @@ function webViewerHashchange(evt) {
     PDFViewerApplication.pdfLinkService.setHash(hash);
   }
 }
 let webViewerFileInputChange;
 ;
 function webViewerPresentationMode() {
   PDFViewerApplication.requestPresentationMode();
 }
-function webViewerOpenFile() {
-  let openFileInputName = PDFViewerApplication.appConfig.openFileInputName;
-  document.getElementById(openFileInputName).click();
-}
+function webViewerOpenFile() {}
 function webViewerPrint() {
   window.print();
 }
 function webViewerDownload() {
   PDFViewerApplication.download();
 }
 function webViewerFirstPage() {
   if (PDFViewerApplication.pdfDocument) {
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -977,8 +977,14 @@ you can use these alternative items. Oth
 <!ENTITY pageActionButton.tooltip "Page actions">
 <!ENTITY pageAction.addToUrlbar.label "Add to Address Bar">
 <!ENTITY pageAction.removeFromUrlbar.label "Remove from Address Bar">
 
 <!ENTITY pageAction.sendTabToDevice.label "Send Tab to Device">
 <!ENTITY sendToDevice.syncNotReady.label "Syncing Devices…">
 
 <!ENTITY libraryButton.tooltip "View history, saved bookmarks, and more">
+
+<!-- LOCALIZATION NOTE: (accessibilityIndicator.tooltip): This is used to
+     display a tooltip for accessibility indicator in toolbar/tabbar. It is also
+     used as a textual label for the indicator used by assistive technology
+     users. -->
+<!ENTITY accessibilityIndicator.tooltip "Accessibility Features Enabled">
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -712,22 +712,16 @@ html|span.ac-emphasize-text-url {
 }
 
 /* Customization mode */
 
 %include ../shared/customizableui/customizeMode.inc.css
 
 /* End customization mode */
 
-
-#main-window[privatebrowsingmode=temporary] #private-browsing-indicator {
-  background: url("chrome://browser/skin/privatebrowsing-mask.png") center no-repeat;
-  width: 40px;
-}
-
 %include ../shared/UITour.inc.css
 
 #UITourHighlight {
   /* Below are some fixes for people without an X compositor on Linux.
      This is why we can't have nice things: */
   /* Animations don't repaint properly without an X compositor. */
   animation-name: none !important;
   /* Opacity rounds to 0 or 1 on Linux without an X compositor, making the
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -17,17 +17,16 @@ browser.jar:
   skin/classic/browser/menuPanel-exit@2x.png
   skin/classic/browser/menuPanel-help.png
   skin/classic/browser/menuPanel-help@2x.png
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
 * skin/classic/browser/pageInfo.css
   skin/classic/browser/pageInfo.png
   skin/classic/browser/page-livemarks.png
-  skin/classic/browser/privatebrowsing-mask.png
   skin/classic/browser/searchbar.css
   skin/classic/browser/setDesktopBackground.css
   skin/classic/browser/slowStartup-16.png
   skin/classic/browser/webRTC-indicator.css  (../shared/webRTC-indicator.css)
 * skin/classic/browser/controlcenter/panel.css        (controlcenter/panel.css)
 * skin/classic/browser/customizableui/panelUI.css (customizableui/panelUI.css)
 * skin/classic/browser/downloads/allDownloadsViewOverlay.css   (downloads/allDownloadsViewOverlay.css)
 * skin/classic/browser/downloads/downloads.css        (downloads/downloads.css)
deleted file mode 100644
index 9eaf3aec7e71bd4d7f3e3d91b47fa3717a17a947..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -49,38 +49,45 @@
 
 #main-window {
   -moz-appearance: none;
   background-color: #eeeeee;
 }
 
 /** Begin titlebar **/
 
+#titlebar-content {
+  /* Ensure the the content part of the titlebar does not shrink. */
+  min-height: inherit;
+}
+
 #titlebar-buttonbox > .titlebar-button {
   display: none;
 }
 
 /* Making the toolbox position:relative (browser.inc.css) occludes titlebar indicators
  * if the toolbox has a background. Fix this by positioning the relevant elements, too: */
 #titlebar-secondary-buttonbox {
   position: relative;
   z-index: 1;
 }
 
+#titlebar-buttonbox-container {
+  -moz-box-align: center;
+}
+
 /* These would be margin-inline-start/end if it wasn't for the fact that OS X
  * doesn't reverse the order of the items in the titlebar in RTL mode. */
 .titlebar-placeholder[type="caption-buttons"],
 #titlebar-buttonbox {
   margin-left: 7px;
 }
 
-.titlebar-placeholder[type="fullscreen-button"],
-#titlebar-secondary-buttonbox {
-  margin-right: 7px;
-  margin-left: 7px;
+.titlebar-placeholder[type="fullscreen-button"] {
+  margin-right: 4px;
 }
 
 #main-window:not(:-moz-lwtheme) > #titlebar {
   -moz-appearance: -moz-window-titlebar;
 }
 
 #main-window:not([tabsintitlebar]) > #titlebar {
   -moz-appearance: -moz-window-titlebar;
@@ -1231,76 +1238,31 @@ html|*.addon-webext-perm-list {
 }
 
 /* Customization mode */
 
 %include ../shared/customizableui/customizeMode.inc.css
 
 /* End customization mode */
 
-.private-browsing-indicator {
-  background-image: url("chrome://browser/skin/privatebrowsing-mask.png");
-  background-repeat: no-repeat;
-  background-size: 100% auto;
-  width: 38px;
-  height: 28px;
-  /**
-   * The private browsing mask graphic has a 3px flare at the top. The distance
-   * we want between the mask and items on either side is 7px, so we use 4px,
-   * since the other 3px is accounted for by the empty space on either side.
-   */
-  margin-left: 4px;
-  margin-right: 4px;
-}
+/* Private browsing and accessibility indicators */
 
-#titlebar-secondary-buttonbox > .private-browsing-indicator {
-  position: relative;
-}
-
-#main-window[privatebrowsingmode=temporary]:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > .private-browsing-indicator {
-  background-image: url("chrome://browser/skin/privatebrowsing-mask-short.png");
-  height: 20px;
-}
-
-#main-window:not([privatebrowsingmode=temporary]) .private-browsing-indicator,
-#main-window[privatebrowsingmode=temporary][inFullscreen] > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > .private-browsing-indicator,
-#main-window[privatebrowsingmode=temporary]:not([inFullscreen]) > #tab-view-deck > #browser-panel > #navigator-toolbox > #TabsToolbar > .private-browsing-indicator {
+:root[accessibilitymode][tabsintitlebar]:not([inFullscreen]) > #tab-view-deck > #browser-panel > #navigator-toolbox > #TabsToolbar > .accessibility-indicator,
+:root[privatebrowsingmode=temporary][tabsintitlebar]:not([inFullscreen]) > #tab-view-deck > #browser-panel > #navigator-toolbox > #TabsToolbar > .private-browsing-indicator,
+:root[accessibilitymode]:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > .accessibility-indicator,
+:root[privatebrowsingmode=temporary]:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > .private-browsing-indicator {
   display: none;
 }
 
-@media (min-resolution: 2dppx) {
-  .private-browsing-indicator {
-    background-image: url("chrome://browser/skin/privatebrowsing-mask@2x.png");
-  }
-  #main-window[privatebrowsingmode=temporary]:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > .private-browsing-indicator {
-    background-image: url("chrome://browser/skin/privatebrowsing-mask-short@2x.png");
-  }
+#TabsToolbar > .private-browsing-indicator:-moz-locale-dir(rtl),
+#TabsToolbar > .accessibility-indicator:-moz-locale-dir(rtl) {
+  -moz-box-ordinal-group: 0;
 }
 
-#TabsToolbar > .private-browsing-indicator {
-  /* We offset by 38px for mask graphic, plus 4px to account for the
-   * margin-left, which sums to 42px.
-   */
-  margin-right: -42px;
-}
-
-#main-window[privatebrowsingmode=temporary] .titlebar-placeholder[type="fullscreen-button"],
-#main-window[privatebrowsingmode=temporary] > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > #titlebar-fullscreen-button {
-  margin-left: 0px;
-}
-
-#main-window[privatebrowsingmode=temporary][inFullscreen] .titlebar-placeholder[type="fullscreen-button"] {
-  /* Override display:none for .titlebar-placeholder in fullscreen so we can have consistent
-     position and padding for the private browsing indicator. */
-  display: -moz-box;
-}
-
-#TabsToolbar > .private-browsing-indicator:-moz-locale-dir(rtl) {
-  -moz-box-ordinal-group: 0;
-}
+/* End private browsing and accessibility indicators */
 
 %include ../shared/UITour.inc.css
 
 #UITourTooltipDescription {
   font-size: 1.18rem;
   line-height: 2rem;
 }
 
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -22,20 +22,16 @@ browser.jar:
   skin/classic/browser/panel-expander-closed.png
   skin/classic/browser/panel-expander-closed@2x.png
   skin/classic/browser/panel-expander-open.png
   skin/classic/browser/panel-expander-open@2x.png
   skin/classic/browser/panel-plus-sign.png
   skin/classic/browser/page-livemarks.png
   skin/classic/browser/page-livemarks@2x.png
   skin/classic/browser/pageInfo.css
-  skin/classic/browser/privatebrowsing-mask.png
-  skin/classic/browser/privatebrowsing-mask@2x.png
-  skin/classic/browser/privatebrowsing-mask-short.png
-  skin/classic/browser/privatebrowsing-mask-short@2x.png
   skin/classic/browser/searchbar.css
   skin/classic/browser/slowStartup-16.png
   skin/classic/browser/toolbarbutton-dropmarker.png
   skin/classic/browser/toolbarbutton-dropmarker@2x.png
   skin/classic/browser/webRTC-indicator.css
 * skin/classic/browser/controlcenter/panel.css        (controlcenter/panel.css)
 * skin/classic/browser/customizableui/panelUI.css    (customizableui/panelUI.css)
 * skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
deleted file mode 100644
index 92f60e29f9fd71ed62101b7f7f22ea37423387a0..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index ec1cf7452ef6e0251dad9113e8119793bfed4b6f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 586d3d9f0a4bda4175ea75f7c3725fa607875e7c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index efb6d9b8070f646a39b04a40ee556386fb5291f6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/shared/browser.inc.css
+++ b/browser/themes/shared/browser.inc.css
@@ -74,8 +74,52 @@
 #library-animatable-box {
   display: none;
 }
 
 #library-animatable-box[animate] {
   display: -moz-box;
 }
 
+/* Private browsing and accessibility indicators */
+
+.accessibility-indicator,
+.private-browsing-indicator {
+  background-repeat: no-repeat;
+  background-size: 100% auto;
+  background-position: center;
+  width: 24px;
+  height: 24px;
+  margin-left: 8px;
+  margin-right: 8px;
+  position: relative;
+  /* Need to ensure this gets positioned on top of the position:relative #navigator-toolbox
+   * in case the dark/light themes give that item a background. */
+  z-index: 1;
+}
+
+.accessibility-indicator {
+  background-image: url("chrome://browser/skin/accessibility.svg");
+  -moz-user-focus: normal;
+  /* Clear default button styling */
+  -moz-appearance: none;
+  margin-top: unset;
+  margin-bottom: unset;
+  min-width: unset;
+  color: unset;
+  text-shadow: unset;
+}
+
+.accessibility-indicator:-moz-any(:hover, :active, :focus, :-moz-focusring) {
+  background-image: url("chrome://browser/skin/accessibility-active.svg");
+  outline: 0;
+}
+
+.private-browsing-indicator {
+  background-image: url("chrome://browser/skin/private-browsing.svg");
+}
+
+:root:not([accessibilitymode]) .accessibility-indicator,
+:root:not([privatebrowsingmode=temporary]) .private-browsing-indicator {
+  display: none;
+}
+
+/* End private browsing and accessibility indicators */
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/icons/accessibility-active.svg
@@ -0,0 +1,10 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px">
+<path fill="#008EA4" fill-opacity="0.9886" d="M12,24L12,24C5.4,24,0,18.6,0,12l0,0C0,5.4,5.4,0,12,0l0,0c6.6,0,12,5.4,12,12l0,0  C24,18.6,18.6,24,12,24z"/>
+<g>
+	<circle fill="#FFFFFF" cx="12" cy="6" r="2"/>
+	<path fill="#FFFFFF" d="M18.1,8.5h-3.6l0,0h-5l0,0H6c-0.6,0-1,0.4-1,1s0.4,1,1,1h3.5v0.6l0,0v7.8c0,0.6,0.4,1.1,1,1.1s1-0.5,1-1.1   v-4.1h1v4.1c0,0.6,0.4,1.1,1,1.1s1-0.5,1-1.1v-4.1l0,0v-4.5H18c0.6,0,1-0.4,1-1C19,8.8,18.6,8.5,18.1,8.5z"/>
+</g>
+</svg>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/icons/accessibility.svg
@@ -0,0 +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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px">
+<path fill="#00C8D7" fill-opacity="0.9886" d="M12,24L12,24C5.4,24,0,18.6,0,12l0,0C0,5.4,5.4,0,12,0l0,0c6.6,0,12,5.4,12,12l0,0  C24,18.6,18.6,24,12,24z"/>
+<g>
+	<circle fill="#FFFFFF" cx="12" cy="6" r="2"/>
+	<path fill="#FFFFFF" d="M18.1,8.5h-3.6l0,0h-5l0,0H6c-0.6,0-1,0.4-1,1c0,0.6,0.4,1,1,1h3.5v0.6l0,0v7.8c0,0.6,0.4,1.1,1,1.1s1-0.5,1-1.1
+  v-4.1h1v4.1c0,0.6,0.4,1.1,1,1.1s1-0.5,1-1.1v-4.1l0,0v-4.5H18c0.6,0,1-0.4,1-1C19,8.8,18.6,8.5,18.1,8.5z"/>
+</g>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/icons/private-browsing.svg
@@ -0,0 +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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px">
+<path fill="#8000D7" d="M12,24L12,24C5.4,24,0,18.6,0,12l0,0C0,5.4,5.4,0,12,0l0,0c6.6,0,12,5.4,12,12l0,0
+	C24,18.6,18.6,24,12,24z"/>
+<path fill="#FFFFFF" d="M15.4,11c-1-0.1-1.9,0.5-2.1,1.5c0,0.3,1.2,0.7,2.3,0.7s2.1-0.7,2.1-0.9C17.7,12.1,17,11.1,15.4,11
+	L15.4,11z M8.6,11c-1.6,0.1-2.3,1-2.3,1.3c0,0.2,1.1,0.9,2.1,0.9c1,0,2.3-0.4,2.3-0.7C10.5,11.5,9.5,10.9,8.6,11L8.6,11z M16.4,16.5
+	c-1.7,0-2.8-2-4.4-2c-1.6,0-2.8,2-4.4,2c-2.1,0-3.6-1.9-3.6-5.3c0-2.1,0.6-2.7,3.3-2.7s3.4,1.1,4.7,1.1s2.1-1.1,4.7-1.1
+	S20,9.2,20,11.2C20,14.6,18.5,16.5,16.4,16.5L16.4,16.5z"/>
+</svg>
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -109,16 +109,18 @@
   skin/classic/browser/preferences/in-content/sync-devices.svg (../shared/incontentprefs/sync-devices.svg)
   skin/classic/browser/preferences/in-content/sync.svg         (../shared/incontentprefs/sync.svg)
 * skin/classic/browser/preferences/in-content/containers.css   (../shared/incontentprefs/containers.css)
 * skin/classic/browser/preferences/containers.css              (../shared/preferences/containers.css)
   skin/classic/browser/fxa/default-avatar.svg                  (../shared/fxa/default-avatar.svg)
   skin/classic/browser/fxa/sync-illustration.svg               (../shared/fxa/sync-illustration.svg)
 
 
+  skin/classic/browser/accessibility.svg              (../shared/icons/accessibility.svg)
+  skin/classic/browser/accessibility-active.svg       (../shared/icons/accessibility-active.svg)
   skin/classic/browser/arrow-left.svg                 (../shared/icons/arrow-left.svg)
   skin/classic/browser/back.svg                       (../shared/icons/back.svg)
   skin/classic/browser/back-12.svg                    (../shared/icons/back-12.svg)
   skin/classic/browser/bookmark.svg                   (../shared/icons/bookmark.svg)
   skin/classic/browser/bookmark-animation.svg         (../shared/icons/bookmark-animation.svg)
   skin/classic/browser/bookmark-hollow.svg            (../shared/icons/bookmark-hollow.svg)
   skin/classic/browser/bookmark-star-on-tray.svg      (../shared/icons/bookmark-star-on-tray.svg)
   skin/classic/browser/characterEncoding.svg          (../shared/icons/characterEncoding.svg)
@@ -150,16 +152,17 @@
   skin/classic/browser/mail.svg                       (../shared/icons/mail.svg)
   skin/classic/browser/menu.svg                       (../shared/icons/menu.svg)
   skin/classic/browser/menu-badged.svg                (../shared/icons/menu-badged.svg)
   skin/classic/browser/new-tab.svg                    (../shared/icons/new-tab.svg)
   skin/classic/browser/new-window.svg                 (../shared/icons/new-window.svg)
   skin/classic/browser/open.svg                       (../shared/icons/open.svg)
   skin/classic/browser/page-action.svg                (../shared/icons/page-action.svg)
   skin/classic/browser/print.svg                      (../shared/icons/print.svg)
+  skin/classic/browser/private-browsing.svg           (../shared/icons/private-browsing.svg)
   skin/classic/browser/privateBrowsing.svg            (../shared/icons/privateBrowsing.svg)
   skin/classic/browser/restore-session.svg            (../shared/icons/restore-session.svg)
   skin/classic/browser/quit.svg                       (../shared/icons/quit.svg)
   skin/classic/browser/reload.svg                     (../shared/icons/reload.svg)
   skin/classic/browser/reload-to-stop.svg             (../shared/icons/reload-to-stop.svg)
   skin/classic/browser/save.svg                       (../shared/icons/save.svg)
   skin/classic/browser/settings.svg                   (../shared/icons/settings.svg)
   skin/classic/browser/sidebars.svg                   (../shared/icons/sidebars.svg)
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -277,16 +277,27 @@
  * window state. Otherwise, elements in the navigator-toolbox, like the menubar,
  * can swallow those events. It will also place the buttons above the fog on
  * Windows 7 with Aero Glass.
  */
 #titlebar-buttonbox {
   z-index: 1;
 }
 
+#titlebar-buttonbox-container {
+  -moz-box-align: center;
+}
+
+@media (-moz-os-version: windows-win7) {
+  /* Preserve window control buttons position at the top of the button box. */
+  #titlebar-buttonbox-container {
+    -moz-box-align: start;
+  }
+}
+
 .titlebar-placeholder[type="caption-buttons"] {
   margin-left: 22px; /* space needed for Aero Snap */
 }
 
 /* titlebar command buttons */
 
 #titlebar-min {
   -moz-appearance: -moz-window-button-minimize;
@@ -1110,102 +1121,49 @@ notification[value="translation"] {
  * paint, so this hack is how we sidestep that performance bottleneck.
  */
 #main-window:-moz-any([customize-entering],[customize-exiting]) label {
   transform: perspective(0.01px);
 }
 
 /* End customization mode */
 
-/* Private browsing indicators */
-
-/**
- * Currently, we have two places where we put private browsing indicators on
- * Windows. When tabsintitlebar is enabled, we draw the indicator in the titlebar.
- * When tabsintitlebar is disabled, we draw the indicator at the end of the
- * tabstrip. The titlebar indicator is the fiddliest of the bunch, since we
- * want the bottom border of the image to line up with the bottom of the window
- * caption buttons. That's why there's so much special-casing going on in here.
- */
-.private-browsing-indicator {
-  display: none;
-  pointer-events: none;
-}
-
-#private-browsing-indicator-titlebar {
-  display: block;
-  position: absolute;
-  /* Need to ensure this gets positioned on top of the position:relative #navigator-toolbox
-   * in case the dark/light themes give that item a background. */
-  z-index: 1;
-}
-
-#main-window[privatebrowsingmode=temporary][tabsintitlebar] #private-browsing-indicator-titlebar > .private-browsing-indicator {
-  display: block;
-}
+/* Private browsing and accessibility indicators */
 
-#main-window[privatebrowsingmode=temporary]:-moz-any([inFullscreen],:not([tabsintitlebar])) #TabsToolbar > .private-browsing-indicator {
-  display: -moz-box;
-}
-
-#TabsToolbar > .private-browsing-indicator {
-  background: url("chrome://browser/skin/privatebrowsing-mask-tabstrip.png") no-repeat center -3px;
-  margin-inline-start: 4px;
-  width: 48px;
-}
+@media (-moz-os-version: windows-win7) {
+  /* Making sure that indicators take up all available vertical space. */
+  :root[tabsintitlebar]:not([inFullscreen]) .private-browsing-indicator,
+  :root[tabsintitlebar]:not([inFullscreen]) .accessibility-indicator {
+    height: var(--tab-min-height);
+  }
 
-/* Bug 1008183: We're intentionally using the titlebar asset here for fullscreen
- * mode, since the tabstrip "mimics" the titlebar in that case with its own
- * min/max/close window buttons.
- */
-#private-browsing-indicator-titlebar > .private-browsing-indicator,
-#main-window[inFullscreen] #TabsToolbar > .private-browsing-indicator {
-  background: url("chrome://browser/skin/privatebrowsing-mask-titlebar.png") no-repeat center 0px;
-  margin-inline-end: 4px;
-  width: 40px;
-  height: 20px;
-  position: relative;
-}
-
-@media (-moz-windows-classic) {
-  /**
-   * We have to use top instead of background-position in this case, otherwise
-   * the bottom of the indicator would get cut off by the bounds of the
-   * private-browsing-indicator element.
-   */
-  #main-window[sizemode="normal"] > #titlebar > #titlebar-content > #titlebar-buttonbox-container > #private-browsing-indicator-titlebar > .private-browsing-indicator {
-    top: 4px;
+  :root[tabsintitlebar][sizemode="normal"]:not([inFullscreen]) .private-browsing-indicator,
+  :root[tabsintitlebar][sizemode="normal"]:not([inFullscreen]) .accessibility-indicator {
+    height: calc(var(--tab-min-height) + 4px);
   }
 }
 
-@media (-moz-os-version: windows-win7) {
-  @media (-moz-windows-glass) {
-    #main-window[sizemode="normal"] > #titlebar > #titlebar-content > #titlebar-buttonbox-container > #private-browsing-indicator-titlebar > .private-browsing-indicator {
-      top: 1px;
-    }
-    #main-window[sizemode="maximized"] > #titlebar > #titlebar-content > #titlebar-buttonbox-container > #private-browsing-indicator-titlebar > .private-browsing-indicator {
-      top: -1px;
-    }
-  }
-
-  /**
-   * This next block targets Aero Basic, which has different positioning for the
-   * window caption buttons, and therefore needs to be special-cased.
-   */
-  @media (-moz-windows-default-theme) {
-    @media (-moz-windows-compositor: 0) {
-      #main-window[sizemode="normal"] > #titlebar > #titlebar-content > #titlebar-buttonbox-container > #private-browsing-indicator-titlebar > .private-browsing-indicator {
-        background-image: url("chrome://browser/skin/privatebrowsing-mask-titlebar-win7-tall.png");
-        height: 28px;
-      }
-    }
-  }
+:root:-moz-any([tabsintitlebar], [inFullscreen]):not([privatebrowsingmode=temporary]) .accessibility-indicator,
+:root:-moz-any([tabsintitlebar], [inFullscreen]) .private-browsing-indicator {
+  margin-inline-end: 12px;
 }
 
-/* End private browsing indicators */
+:root:not([accessibilitymode]) .private-browsing-indicator,
+.accessibility-indicator {
+  margin-inline-start: 12px;
+}
+
+:root[accessibilitymode][tabsintitlebar]:not([inFullscreen]) > #tab-view-deck > #browser-panel > #navigator-toolbox > #TabsToolbar > .accessibility-indicator,
+:root[privatebrowsingmode=temporary][tabsintitlebar]:not([inFullscreen]) > #tab-view-deck > #browser-panel > #navigator-toolbox > #TabsToolbar > .private-browsing-indicator,
+:root[accessibilitymode]:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > .accessibility-indicator,
+:root[privatebrowsingmode=temporary]:not([tabsintitlebar]) > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > .private-browsing-indicator {
+  display: none;
+}
+
+/* End private browsing and accessibility indicators */
 
 %include ../shared/UITour.inc.css
 
 #UITourTooltipButtons {
   /**
    * Override the --arrowpanel-padding so the background extends
    * to the sides and bottom of the panel.
    */
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -18,21 +18,16 @@ browser.jar:
   skin/classic/browser/menuPanel-exit.png
   skin/classic/browser/menuPanel-exit@2x.png
   skin/classic/browser/menuPanel-help.png
   skin/classic/browser/menuPanel-help@2x.png
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
   skin/classic/browser/pageInfo.css
   skin/classic/browser/pageInfo.png
-  skin/classic/browser/privatebrowsing-mask-tabstrip.png
-  skin/classic/browser/privatebrowsing-mask-tabstrip-win7.png
-  skin/classic/browser/privatebrowsing-mask-titlebar.png
-  skin/classic/browser/privatebrowsing-mask-titlebar-win7.png
-  skin/classic/browser/privatebrowsing-mask-titlebar-win7-tall.png
   skin/classic/browser/searchbar.css
   skin/classic/browser/setDesktopBackground.css
   skin/classic/browser/slowStartup-16.png
   skin/classic/browser/sync-desktopIcon.svg  (../shared/sync-desktopIcon.svg)
   skin/classic/browser/sync-mobileIcon.svg  (../shared/sync-mobileIcon.svg)
   skin/classic/browser/toolbarbutton-dropdown-arrow-win7.png
   skin/classic/browser/webRTC-indicator.css  (../shared/webRTC-indicator.css)
 * skin/classic/browser/controlcenter/panel.css                 (controlcenter/panel.css)
@@ -86,11 +81,9 @@ browser.jar:
 
 [extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
 % override chrome://browser/skin/page-livemarks.png                   chrome://browser/skin/feeds/feedIcon16.png
 % override chrome://browser/skin/feeds/audioFeedIcon.png              chrome://browser/skin/feeds/feedIcon.png
 % override chrome://browser/skin/feeds/audioFeedIcon16.png            chrome://browser/skin/feeds/feedIcon16.png
 % override chrome://browser/skin/feeds/videoFeedIcon.png              chrome://browser/skin/feeds/feedIcon.png
 % override chrome://browser/skin/feeds/videoFeedIcon16.png            chrome://browser/skin/feeds/feedIcon16.png
 
-% override chrome://browser/skin/privatebrowsing-mask-tabstrip.png    chrome://browser/skin/privatebrowsing-mask-tabstrip-win7.png  os=WINNT osversion<=6.1
-% override chrome://browser/skin/privatebrowsing-mask-titlebar.png    chrome://browser/skin/privatebrowsing-mask-titlebar-win7.png  os=WINNT osversion<=6.1
 % override chrome://browser/skin/toolbarbutton-dropdown-arrow.png     chrome://browser/skin/toolbarbutton-dropdown-arrow-win7.png   os=WINNT osversion<=6.1
deleted file mode 100644
index bd5d46a76a8def4a3d8db31aed36126f5b7b062b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index e2eba8b89e4fd2b1b9d33a5f93f6c1bbfdaf9889..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 4a723c54e2316e978062be38a7be8eaa1a0d11f2..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 835912b534b2d16ac01a52c44ff6f3548ac0032c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 111dc7d04167c3767538fb6b64e34717fb259ef0..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/gfx/layers/PaintThread.cpp
+++ b/gfx/layers/PaintThread.cpp
@@ -4,17 +4,16 @@
  * 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 "PaintThread.h"
 
 #include "base/task.h"
 #include "gfxPrefs.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
-#include "mozilla/layers/ContentClient.h"
 #include "mozilla/layers/ShadowLayers.h"
 #include "mozilla/layers/SyncObject.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/SyncRunnable.h"
 
 namespace mozilla {
 namespace layers {
@@ -141,47 +140,16 @@ PaintThread::Get()
 
 /* static */ bool
 PaintThread::IsOnPaintThread()
 {
   return sThreadId == PlatformThread::CurrentId();
 }
 
 void
-PaintThread::CopyFrontToBack(ContentClientRemoteBuffer* aContentClient,
-                             nsIntRegion aRegionToDraw)
-{
-  MOZ_ASSERT(PaintThread::IsOnPaintThread());
-  aContentClient->FinalizeFrameOnPaintThread(aRegionToDraw);
-}
-
-void
-PaintThread::CopyFrontBufferToBackBuffer(ContentClientRemoteBuffer* aContentClient,
-                                         nsIntRegion aRegionToDraw)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aContentClient);
-
-  RefPtr<ContentClientRemoteBuffer> cc(aContentClient);
-  RefPtr<PaintThread> self = this;
-
-  RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::CopyFrontToBack",
-    [self, cc, aRegionToDraw]() -> void
-  {
-    self->CopyFrontToBack(cc, aRegionToDraw);
-  });
-
-  if (!gfxPrefs::LayersOMTPForceSync()) {
-    sThread->Dispatch(task.forget());
-  } else {
-    SyncRunnable::DispatchToThread(sThread, task);
-  }
-}
-
-void
 PaintThread::PaintContents(CapturedPaintState* aState,
                            PrepDrawTargetForPaintingCallback aCallback)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aState);
 
   // If painting asynchronously, we need to acquire the compositor bridge which
   // owns the underlying MessageChannel. Otherwise we leave it null and use
--- a/gfx/layers/PaintThread.h
+++ b/gfx/layers/PaintThread.h
@@ -16,17 +16,16 @@
 
 namespace mozilla {
 namespace gfx {
 class DrawTarget;
 class DrawTargetCapture;
 };
 
 namespace layers {
-class ContentClientRemoteBuffer;
 
 // Holds the key parts from a RotatedBuffer::PaintState
 // required to draw the captured paint state
 class CapturedPaintState {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CapturedPaintState)
 public:
   CapturedPaintState(nsIntRegion& aRegionToDraw,
                      gfx::DrawTarget* aTarget,
@@ -67,19 +66,16 @@ class PaintThread final
 public:
   static void Start();
   static void Shutdown();
   static PaintThread* Get();
 
   // Helper for asserts.
   static bool IsOnPaintThread();
 
-  void CopyFrontBufferToBackBuffer(ContentClientRemoteBuffer* aContentClient,
-                                   nsIntRegion aRegionToDraw);
-
   void PaintContents(CapturedPaintState* aState,
                      PrepDrawTargetForPaintingCallback aCallback);
 
   // Must be called on the main thread. Signifies that the current
   // batch of CapturedPaintStates* for PaintContents have been recorded
   // and the main thread is finished recording this layer.
   void EndLayer();
 
@@ -97,18 +93,16 @@ public:
   // Override release/addref but don't do anything.
   void Release();
   void AddRef();
 
 private:
   bool Init();
   void ShutdownOnPaintThread();
   void InitOnPaintThread();
-  void CopyFrontToBack(ContentClientRemoteBuffer* aContentClient,
-                       nsIntRegion aRegionToDraw);
 
   void AsyncPaintContents(CompositorBridgeChild* aBridge,
                           CapturedPaintState* aState,
                           PrepDrawTargetForPaintingCallback aCallback);
   void AsyncEndLayer();
   void AsyncEndLayerTransaction(CompositorBridgeChild* aBridge,
                                 SyncObjectClient* aSyncObject);
 
--- a/gfx/layers/RotatedBuffer.cpp
+++ b/gfx/layers/RotatedBuffer.cpp
@@ -429,18 +429,17 @@ RotatedContentBuffer::FlushBuffers()
   }
   if (mDTBufferOnWhite) {
     mDTBufferOnWhite->Flush();
   }
 }
 
 RotatedContentBuffer::PaintState
 RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer,
-                                 uint32_t aFlags,
-                                 bool aCopyToBackBuffer)
+                                 uint32_t aFlags)
 {
   PaintState result;
   // We need to disable rotation if we're going to be resampled when
   // drawing, because we might sample across the rotation boundary.
   // Also disable buffer rotation when using webrender.
   bool canHaveRotation = gfxPlatform::BufferRotationEnabled() &&
                          !(aFlags & (PAINT_WILL_RESAMPLE | PAINT_NO_ROTATION)) &&
                          !(aLayer->Manager()->AsWebRenderLayerManager());
@@ -551,17 +550,17 @@ RotatedContentBuffer::BeginPaint(Painted
                "Destination rect doesn't contain what we need to paint");
 
   result.mRegionToDraw.Sub(neededRegion, validRegion);
 
   if (result.mRegionToDraw.IsEmpty())
     return result;
 
   if (HaveBuffer()) {
-    if (aCopyToBackBuffer && LockBuffers()) {
+    if (LockBuffers()) {
       // Do not modify result.mRegionToDraw or result.mContentType after this call.
       // Do not modify mBufferRect, mBufferRotation, or mDidSelfCopy,
       // or call CreateBuffer before this call.
       FinalizeFrame(result.mRegionToDraw);
     } else {
       // Abandon everything and redraw it all. Ideally we'd reallocate and copy
       // the old to the new and then call FinalizeFrame on the new buffer so that
       // we only need to draw the latest bits, but we need a big refactor to support
@@ -658,17 +657,16 @@ RotatedContentBuffer::BeginPaint(Painted
             mBufferRect = destBufferRect;
             mBufferRotation = IntPoint(0, 0);
           }
 
           if (!result.mDidSelfCopy) {
             destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
             CreateBuffer(result.mContentType, destBufferRect, bufferFlags,
                          &destDTBuffer, &destDTBufferOnWhite);
-            result.mFinalizeOnPaintThread = false;
             if (!destDTBuffer ||
                 (!destDTBufferOnWhite && (bufferFlags & BUFFER_COMPONENT_ALPHA))) {
               if (Factory::ReasonableSurfaceSize(IntSize(destBufferRect.Width(), destBufferRect.Height()))) {
                 gfxCriticalNote << "Failed 1 buffer db=" << hexa(destDTBuffer.get()) << " dw=" << hexa(destDTBufferOnWhite.get()) << " for " << destBufferRect.x << ", " << destBufferRect.y << ", " << destBufferRect.Width() << ", " << destBufferRect.Height();
               }
               return result;
             }
           }
@@ -683,17 +681,16 @@ RotatedContentBuffer::BeginPaint(Painted
       // set destBuffer.
       mBufferRect = destBufferRect;
       mBufferRotation = IntPoint(0,0);
     }
   } else {
     // The buffer's not big enough, so allocate a new one
     CreateBuffer(result.mContentType, destBufferRect, bufferFlags,
                  &destDTBuffer, &destDTBufferOnWhite);
-    result.mFinalizeOnPaintThread = false;
     if (!destDTBuffer ||
         (!destDTBufferOnWhite && (bufferFlags & BUFFER_COMPONENT_ALPHA))) {
       if (Factory::ReasonableSurfaceSize(IntSize(destBufferRect.Width(), destBufferRect.Height()))) {
         gfxCriticalNote << "Failed 2 buffer db=" << hexa(destDTBuffer.get()) << " dw=" << hexa(destDTBufferOnWhite.get()) << " for " << destBufferRect.x << ", " << destBufferRect.y << ", " << destBufferRect.Width() << ", " << destBufferRect.Height();
       }
       return result;
     }
   }
--- a/gfx/layers/RotatedBuffer.h
+++ b/gfx/layers/RotatedBuffer.h
@@ -220,37 +220,33 @@ public:
   /**
    * This is returned by BeginPaint. The caller should draw into mTarget.
    * mRegionToDraw must be drawn. mRegionToInvalidate has been invalidated
    * by RotatedContentBuffer and must be redrawn on the screen.
    * mRegionToInvalidate is set when the buffer has changed from
    * opaque to transparent or vice versa, since the details of rendering can
    * depend on the buffer type.  mDidSelfCopy is true if we kept our buffer
    * but used MovePixels() to shift its content.
-   * mFinalizeOnPaintThread is true if we need to copy the front
-   * to back buffer and we didn't destroy the buffer during BeginPaint.
    */
   struct PaintState {
     PaintState()
       : mRegionToDraw()
       , mRegionToInvalidate()
       , mMode(SurfaceMode::SURFACE_NONE)
       , mClip(DrawRegionClip::NONE)
       , mContentType(gfxContentType::SENTINEL)
       , mDidSelfCopy(false)
-      , mFinalizeOnPaintThread(true)
     {}
 
     nsIntRegion mRegionToDraw;
     nsIntRegion mRegionToInvalidate;
     SurfaceMode mMode;
     DrawRegionClip mClip;
     ContentType mContentType;
     bool mDidSelfCopy;
-    bool mFinalizeOnPaintThread;
   };
 
   enum {
     PAINT_WILL_RESAMPLE = 0x01,
     PAINT_NO_ROTATION = 0x02,
     PAINT_CAN_DRAW_ROTATED = 0x04
   };
   /**
@@ -267,23 +263,19 @@ public:
    * to resample across the rotation boundary) and will ensure that we
    * make the entire buffer contents valid (since we don't want to sample
    * invalid pixels outside the visible region, if the visible region doesn't
    * fill the buffer bounds).
    * PAINT_CAN_DRAW_ROTATED can be passed if the caller supports drawing
    * rotated content that crosses the physical buffer boundary. The caller
    * will need to call BorrowDrawTargetForPainting multiple times to achieve
    * this.
-   * @param aCopyToBackBuffer Whether to copy the front buffer to back buffer
-   * This should generally be true unless OMTP is enabled where we want to do
-   * this on the paint thread instead.
    */
   PaintState BeginPaint(PaintedLayer* aLayer,
-                        uint32_t aFlags,
-                        bool aCopyToBackbuffer = true);
+                        uint32_t aFlags);
 
   struct DrawIterator {
     friend class RotatedContentBuffer;
     DrawIterator()
       : mCount(0)
     {}
 
     nsIntRegion mDrawRegion;
--- a/gfx/layers/client/ClientPaintedLayer.cpp
+++ b/gfx/layers/client/ClientPaintedLayer.cpp
@@ -77,17 +77,17 @@ ClientPaintedLayer::CanRecordLayer(Readb
 void
 ClientPaintedLayer::UpdateContentClient(PaintState& aState)
 {
   Mutated();
 
   AddToValidRegion(aState.mRegionToDraw);
 
   ContentClientRemote *contentClientRemote =
-      static_cast<ContentClientRemote*>(mContentClient.get());
+      static_cast<ContentClientRemote *>(mContentClient.get());
   MOZ_ASSERT(contentClientRemote->GetIPCHandle());
 
   // Hold(this) ensures this layer is kept alive through the current transaction
   // The ContentClient assumes this layer is kept alive (e.g., in CreateBuffer),
   // so deleting this Hold for whatever reason will break things.
   ClientManager()->Hold(this);
   contentClientRemote->Updated(aState.mRegionToDraw,
                                mVisibleRegion.ToUnknownRegion(),
@@ -208,23 +208,17 @@ ClientPaintedLayer::PaintThebes(nsTArray
  */
 bool
 ClientPaintedLayer::PaintOffMainThread()
 {
   mContentClient->BeginAsyncPaint();
 
   uint32_t flags = GetPaintFlags();
 
-  PaintState state = mContentClient->BeginPaintBuffer(this, flags, false);
-  MOZ_ASSERT(mContentClient->IsRemoteBuffer());
-  if (state.mFinalizeOnPaintThread) {
-    PaintThread::Get()->CopyFrontBufferToBackBuffer(static_cast<ContentClientRemoteBuffer*>(mContentClient.get()),
-                                                    state.mRegionToDraw);
-  }
-
+  PaintState state = mContentClient->BeginPaintBuffer(this, flags);
   if (!UpdatePaintRegion(state)) {
     return false;
   }
 
   bool didUpdate = false;
   RotatedContentBuffer::DrawIterator iter;
 
   // Debug Protip: Change to BorrowDrawTargetForPainting if using sync OMTP.
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -18,17 +18,16 @@
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/gfx/Types.h"
 #include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersMessages.h"  // for ThebesBufferData
 #include "mozilla/layers/LayersTypes.h"
-#include "mozilla/layers/PaintThread.h"
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
 #include "nsISupportsImpl.h"            // for gfxContext::Release, etc
 #include "nsIWidget.h"                  // for nsIWidget
 #include "nsLayoutUtils.h"
 #ifdef XP_WIN
 #include "gfxWindowsPlatform.h"
 #endif
 #ifdef MOZ_WIDGET_GTK
@@ -608,21 +607,16 @@ ContentClientDoubleBuffered::BeginAsyncP
 
 // Sync front/back buffers content
 // After executing, the new back buffer has the same (interesting) pixels as
 // the new front buffer, and mValidRegion et al. are correct wrt the new
 // back buffer (i.e. as they were for the old back buffer)
 void
 ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
 {
-  MOZ_ASSERT(NS_IsMainThread() || PaintThread::IsOnPaintThread());
-  if (!HaveBuffer()) {
-    return;
-  }
-
   if (!mFrontAndBackBufferDiffer) {
     MOZ_ASSERT(!mDidSelfCopy, "If we have to copy the world, then our buffers are different, right?");
     return;
   }
   MOZ_ASSERT(mFrontClient);
   if (!mFrontClient) {
     return;
   }
@@ -644,24 +638,16 @@ ContentClientDoubleBuffered::FinalizeFra
 
   // No point in sync'ing what we are going to draw over anyway. And if there is
   // nothing to sync at all, there is nothing to do and we can go home early.
   updateRegion.Sub(updateRegion, aRegionToDraw);
   if (updateRegion.IsEmpty()) {
     return;
   }
 
-  CopyFrontBufferToBackBuffer(updateRegion);
-}
-
-void
-ContentClientDoubleBuffered::CopyFrontBufferToBackBuffer(nsIntRegion& aUpdateRegion)
-{
-  MOZ_ASSERT(NS_IsMainThread() || PaintThread::IsOnPaintThread());
-
   // We need to ensure that we lock these two buffers in the same
   // order as the compositor to prevent deadlocks.
   TextureClientAutoLock frontLock(mFrontClient, OpenMode::OPEN_READ_ONLY);
   if (!frontLock.Succeeded()) {
     return;
   }
   Maybe<TextureClientAutoLock> frontOnWhiteLock;
   if (mFrontClientOnWhite) {
@@ -678,17 +664,17 @@ ContentClientDoubleBuffered::CopyFrontBu
   gfx::DrawTarget* dtw = mFrontClientOnWhite ? mFrontClientOnWhite->BorrowDrawTarget() : nullptr;
   if (dt && dt->IsValid()) {
     RefPtr<SourceSurface> surf = dt->Snapshot();
     RefPtr<SourceSurface> surfOnWhite = dtw ? dtw->Snapshot() : nullptr;
     SourceRotatedBuffer frontBuffer(surf,
                                     surfOnWhite,
                                     mFrontBufferRect,
                                     mFrontBufferRotation);
-    UpdateDestinationFrom(frontBuffer, aUpdateRegion);
+    UpdateDestinationFrom(frontBuffer, updateRegion);
   } else {
     // We know this can happen, but we want to track it somewhat, in case it leads
     // to other problems.
     gfxCriticalNote << "Invalid draw target(s) " << hexa(dt) << " and " << hexa(dtw);
   }
 }
 
 void
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -12,17 +12,16 @@
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "mozilla/Assertions.h"         // for MOZ_CRASH
 #include "mozilla/Attributes.h"         // for override
 #include "mozilla/RefPtr.h"             // for RefPtr, already_AddRefed
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/CompositorTypes.h"  // for TextureInfo, etc
-#include "mozilla/layers/PaintThread.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/LayersTypes.h"  // for TextureDumpMode
 #include "mozilla/layers/TextureClient.h"  // for TextureClient
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "ReadbackProcessor.h"          // For ReadbackProcessor::Update
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsPoint.h"                    // for nsIntPoint
@@ -89,35 +88,33 @@ public:
   {}
   virtual ~ContentClient()
   {}
 
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
 
   virtual void Clear() = 0;
   virtual RotatedContentBuffer::PaintState BeginPaintBuffer(PaintedLayer* aLayer,
-                                                            uint32_t aFlags,
-                                                            bool aCopyFrontToBack = true) = 0;
+                                                            uint32_t aFlags) = 0;
   virtual gfx::DrawTarget* BorrowDrawTargetForPainting(RotatedContentBuffer::PaintState& aPaintState,
                                                        RotatedContentBuffer::DrawIterator* aIter = nullptr) = 0;
   virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) = 0;
   virtual RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(
     RotatedContentBuffer::PaintState& aPaintState,
     RotatedContentBuffer::DrawIterator* aIter) = 0;
 
   // Called as part of the layers transation reply. Conveys data about our
   // buffer(s) from the compositor. If appropriate we should swap references
   // to our buffers.
   virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) {}
 
   // call before and after painting into this content client
   virtual void BeginPaint() {}
   virtual void BeginAsyncPaint();
   virtual void EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr);
-  virtual bool IsRemoteBuffer() { return false; }
 
 protected:
   bool mInAsyncPaint;
 };
 
 /**
  * A ContentClient for use with OMTC.
  */
@@ -144,20 +141,19 @@ class ContentClientBasic final : public 
 public:
   explicit ContentClientBasic(gfx::BackendType aBackend);
 
   typedef RotatedContentBuffer::PaintState PaintState;
   typedef RotatedContentBuffer::ContentType ContentType;
 
   virtual void Clear() override { RotatedContentBuffer::Clear(); }
   virtual PaintState BeginPaintBuffer(PaintedLayer* aLayer,
-                                      uint32_t aFlags,
-                                      bool aCopyFrontToBack = true) override
+                                      uint32_t aFlags) override
   {
-    return RotatedContentBuffer::BeginPaint(aLayer, aFlags, aCopyFrontToBack);
+    return RotatedContentBuffer::BeginPaint(aLayer, aFlags);
   }
   virtual gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
                                                        RotatedContentBuffer::DrawIterator* aIter = nullptr) override
   {
     return RotatedContentBuffer::BorrowDrawTargetForPainting(aPaintState, aIter);
   }
   virtual RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(PaintState& aPaintState,
                                                                   RotatedContentBuffer::DrawIterator* aIter) override;
@@ -231,20 +227,19 @@ public:
   }
 
   virtual void Dump(std::stringstream& aStream,
                     const char* aPrefix="",
                     bool aDumpHtml=false,
                     TextureDumpMode aCompress=TextureDumpMode::Compress) override;
 
   virtual PaintState BeginPaintBuffer(PaintedLayer* aLayer,
-                                      uint32_t aFlags,
-                                      bool aCopyFrontToBack = true) override
+                                      uint32_t aFlags) override
   {
-    return RotatedContentBuffer::BeginPaint(aLayer, aFlags, aCopyFrontToBack);
+    return RotatedContentBuffer::BeginPaint(aLayer, aFlags);
   }
   virtual gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
                                                        RotatedContentBuffer::DrawIterator* aIter = nullptr) override
   {
     return RotatedContentBuffer::BorrowDrawTargetForPainting(aPaintState, aIter);
   }
   virtual RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(PaintState& aPaintState,
                                                                   RotatedContentBuffer::DrawIterator* aIter) override;
@@ -285,22 +280,16 @@ public:
   virtual void CreateBuffer(ContentType aType, const gfx::IntRect& aRect, uint32_t aFlags,
                             RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) override;
 
   virtual TextureFlags ExtraTextureFlags() const
   {
     return TextureFlags::IMMEDIATE_UPLOAD;
   }
 
-  virtual bool IsRemoteBuffer() override { return true; }
-  virtual void FinalizeFrameOnPaintThread(nsIntRegion aRegionToDraw) {
-    MOZ_ASSERT(PaintThread::IsOnPaintThread());
-    FinalizeFrame(aRegionToDraw);
-  }
-
 protected:
   void DestroyBuffers();
 
   virtual nsIntRegion GetUpdatedRegion(const nsIntRegion& aRegionToDraw,
                                        const nsIntRegion& aVisibleRegion,
                                        bool aDidSelfCopy);
 
   void BuildTextureClients(gfx::SurfaceFormat aFormat,
@@ -391,18 +380,16 @@ public:
                     TextureDumpMode aCompress=TextureDumpMode::Compress) override;
 protected:
   virtual void DestroyFrontBuffer() override;
 
 private:
   void UpdateDestinationFrom(const RotatedBuffer& aSource,
                              const nsIntRegion& aUpdateRegion);
 
-  void CopyFrontBufferToBackBuffer(nsIntRegion& aUpdateRegion);
-
   virtual void AbortTextureClientCreation() override
   {
     mTextureClient = nullptr;
     mTextureClientOnWhite = nullptr;
     mFrontClient = nullptr;
     mFrontClientOnWhite = nullptr;
   }
 
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -625,21 +625,22 @@ void
 BufferTextureHost::PushExternalImage(wr::DisplayListBuilder& aBuilder,
                                      const wr::LayoutRect& aBounds,
                                      const wr::LayoutRect& aClip,
                                      wr::ImageRendering aFilter,
                                      Range<const wr::ImageKey>& aImageKeys)
 {
   if (GetFormat() != gfx::SurfaceFormat::YUV) {
     MOZ_ASSERT(aImageKeys.length() == 1);
-    aBuilder.PushImage(aBounds, aClip, aFilter, aImageKeys[0]);
+    aBuilder.PushImage(aBounds, aClip, true, aFilter, aImageKeys[0]);
   } else {
     MOZ_ASSERT(aImageKeys.length() == 3);
     aBuilder.PushYCbCrPlanarImage(aBounds,
                                   aClip,
+                                  true,
                                   aImageKeys[0],
                                   aImageKeys[1],
                                   aImageKeys[2],
                                   wr::WrYuvColorSpace::Rec601,
                                   aFilter);
   }
 }
 
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -1124,23 +1124,24 @@ DXGITextureHostD3D11::PushExternalImage(
                                         Range<const wr::ImageKey>& aImageKeys)
 {
   switch (GetFormat()) {
     case gfx::SurfaceFormat::R8G8B8X8:
     case gfx::SurfaceFormat::R8G8B8A8:
     case gfx::SurfaceFormat::B8G8R8A8:
     case gfx::SurfaceFormat::B8G8R8X8: {
       MOZ_ASSERT(aImageKeys.length() == 1);
-      aBuilder.PushImage(aBounds, aClip, aFilter, aImageKeys[0]);
+      aBuilder.PushImage(aBounds, aClip, true, aFilter, aImageKeys[0]);
       break;
     }
     case gfx::SurfaceFormat::NV12: {
       MOZ_ASSERT(aImageKeys.length() == 2);
       aBuilder.PushNV12Image(aBounds,
                              aClip,
+                             true,
                              aImageKeys[0],
                              aImageKeys[1],
                              wr::WrYuvColorSpace::Rec601,
                              aFilter);
       break;
     }
     default: {
       MOZ_ASSERT_UNREACHABLE("unexpected to be called");
@@ -1359,17 +1360,17 @@ void
 DXGIYCbCrTextureHostD3D11::PushExternalImage(wr::DisplayListBuilder& aBuilder,
                                              const wr::LayoutRect& aBounds,
                                              const wr::LayoutRect& aClip,
                                              wr::ImageRendering aFilter,
                                              Range<const wr::ImageKey>& aImageKeys)
 {
   // 1 image key
   MOZ_ASSERT(aImageKeys.length() == 1);
-  aBuilder.PushImage(aBounds, aClip, aFilter, aImageKeys[0]);
+  aBuilder.PushImage(aBounds, aClip, true, aFilter, aImageKeys[0]);
 }
 
 bool
 DXGIYCbCrTextureHostD3D11::AcquireTextureSource(CompositableTextureSourceRef& aTexture)
 {
   if (!EnsureTextureSource()) {
     return false;
   }
--- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
+++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
@@ -231,34 +231,36 @@ MacIOSurfaceTextureHostOGL::PushExternal
 {
   switch (GetFormat()) {
     case gfx::SurfaceFormat::R8G8B8X8:
     case gfx::SurfaceFormat::R8G8B8A8:
     case gfx::SurfaceFormat::B8G8R8A8:
     case gfx::SurfaceFormat::B8G8R8X8: {
       MOZ_ASSERT(aImageKeys.length() == 1);
       MOZ_ASSERT(mSurface->GetPlaneCount() == 0);
-      aBuilder.PushImage(aBounds, aClip, aFilter, aImageKeys[0]);
+      aBuilder.PushImage(aBounds, aClip, true, aFilter, aImageKeys[0]);
       break;
     }
     case gfx::SurfaceFormat::YUV422: {
       MOZ_ASSERT(aImageKeys.length() == 1);
       MOZ_ASSERT(mSurface->GetPlaneCount() == 0);
       aBuilder.PushYCbCrInterleavedImage(aBounds,
                                          aClip,
+                                         true,
                                          aImageKeys[0],
                                          wr::WrYuvColorSpace::Rec601,
                                          aFilter);
       break;
     }
     case gfx::SurfaceFormat::NV12: {
       MOZ_ASSERT(aImageKeys.length() == 2);
       MOZ_ASSERT(mSurface->GetPlaneCount() == 2);
       aBuilder.PushNV12Image(aBounds,
                              aClip,
+                             true,
                              aImageKeys[0],
                              aImageKeys[1],
                              wr::WrYuvColorSpace::Rec601,
                              aFilter);
       break;
     }
     default: {
       MOZ_ASSERT_UNREACHABLE("unexpected to be called");
--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp
+++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp
@@ -286,17 +286,18 @@ AsyncImagePipelineManager::ApplyAsyncIma
       float opacity = 1.0f;
       builder.PushStackingContext(wr::ToLayoutRect(pipeline->mScBounds),
                                   0,
                                   &opacity,
                                   pipeline->mScTransform.IsIdentity() ? nullptr : &pipeline->mScTransform,
                                   wr::TransformStyle::Flat,
                                   nullptr,
                                   pipeline->mMixBlendMode,
-                                  nsTArray<wr::WrFilterOp>());
+                                  nsTArray<wr::WrFilterOp>(),
+                                  true);
 
       LayerRect rect(0, 0, pipeline->mCurrentTexture->GetSize().width, pipeline->mCurrentTexture->GetSize().height);
       if (pipeline->mScaleToSize.isSome()) {
         rect = LayerRect(0, 0, pipeline->mScaleToSize.value().width, pipeline->mScaleToSize.value().height);
       }
 
       if (useExternalImage) {
         MOZ_ASSERT(pipeline->mCurrentTexture->AsWebRenderTextureHost());
@@ -306,16 +307,17 @@ AsyncImagePipelineManager::ApplyAsyncIma
                                                      wr::ToLayoutRect(rect),
                                                      pipeline->mFilter,
                                                      range_keys);
         HoldExternalImage(pipelineId, epoch, pipeline->mCurrentTexture->AsWebRenderTextureHost());
       } else {
         MOZ_ASSERT(keys.Length() == 1);
         builder.PushImage(wr::ToLayoutRect(rect),
                           wr::ToLayoutRect(rect),
+                          true,
                           pipeline->mFilter,
                           keys[0]);
       }
       builder.PopStackingContext();
     }
 
     wr::BuiltDisplayList dl;
     wr::LayoutSize builderContentSize;
--- a/gfx/layers/wr/StackingContextHelper.cpp
+++ b/gfx/layers/wr/StackingContextHelper.cpp
@@ -30,17 +30,18 @@ StackingContextHelper::StackingContextHe
   mTransform = aTransform.valueOr(layer->GetTransform());
 
   float opacity = 1.0f;
   mBuilder->PushStackingContext(scBounds, 0, &opacity,
                                 mTransform.IsIdentity() ? nullptr : &mTransform,
                                 wr::TransformStyle::Flat,
                                 nullptr,
                                 wr::ToMixBlendMode(layer->GetMixBlendMode()),
-                                aFilters);
+                                aFilters,
+                                true);
   mOrigin = aLayer->Bounds().TopLeft();
 }
 
 StackingContextHelper::StackingContextHelper(const StackingContextHelper& aParentSC,
                                              wr::DisplayListBuilder& aBuilder,
                                              WebRenderLayer* aLayer,
                                              uint64_t aAnimationsId,
                                              float* aOpacityPtr,
@@ -55,47 +56,50 @@ StackingContextHelper::StackingContextHe
 
   mBuilder->PushStackingContext(scBounds,
                                 aAnimationsId,
                                 aOpacityPtr,
                                 aTransformPtr,
                                 wr::TransformStyle::Flat,
                                 nullptr,
                                 wr::ToMixBlendMode(aLayer->GetLayer()->GetMixBlendMode()),
-                                aFilters);
+                                aFilters,
+                                true);
   mOrigin = aLayer->Bounds().TopLeft();
 }
 
 StackingContextHelper::StackingContextHelper(const StackingContextHelper& aParentSC,
                                              wr::DisplayListBuilder& aBuilder,
                                              nsDisplayListBuilder* aDisplayListBuilder,
                                              nsDisplayItem* aItem,
                                              nsDisplayList* aDisplayList,
                                              gfx::Matrix4x4Typed<LayerPixel, LayerPixel>* aBoundTransform,
                                              uint64_t aAnimationsId,
                                              float* aOpacityPtr,
                                              gfx::Matrix4x4* aTransformPtr,
                                              gfx::Matrix4x4* aPerspectivePtr,
                                              const nsTArray<wr::WrFilterOp>& aFilters,
-                                             const gfx::CompositionOp& aMixBlendMode)
+                                             const gfx::CompositionOp& aMixBlendMode,
+                                             bool aBackfaceVisible)
   : mBuilder(&aBuilder)
 {
   bool is2d = !aTransformPtr || (aTransformPtr->Is2D() && !aPerspectivePtr);
   if (aTransformPtr) {
     mTransform = *aTransformPtr;
   }
 
   mBuilder->PushStackingContext(wr::LayoutRect(),
                                 aAnimationsId,
                                 aOpacityPtr,
                                 aTransformPtr,
                                 is2d ? wr::TransformStyle::Flat : wr::TransformStyle::Preserve3D,
                                 aPerspectivePtr,
                                 wr::ToMixBlendMode(aMixBlendMode),
-                                aFilters);
+                                aFilters,
+                                aBackfaceVisible);
 }
 
 StackingContextHelper::~StackingContextHelper()
 {
   if (mBuilder) {
     mBuilder->PopStackingContext();
   }
 }
--- a/gfx/layers/wr/StackingContextHelper.h
+++ b/gfx/layers/wr/StackingContextHelper.h
@@ -53,17 +53,18 @@ public:
                         nsDisplayItem* aItem,
                         nsDisplayList* aDisplayList,
                         gfx::Matrix4x4Typed<LayerPixel, LayerPixel>* aBoundTransform,
                         uint64_t aAnimationsId,
                         float* aOpacityPtr,
                         gfx::Matrix4x4* aTransformPtr,
                         gfx::Matrix4x4* aPerspectivePtr = nullptr,
                         const nsTArray<wr::WrFilterOp>& aFilters = nsTArray<wr::WrFilterOp>(),
-                        const gfx::CompositionOp& aMixBlendMode = gfx::CompositionOp::OP_OVER);
+                        const gfx::CompositionOp& aMixBlendMode = gfx::CompositionOp::OP_OVER,
+                        bool aBackfaceVisible = true);
   // This version of the constructor should only be used at the root level
   // of the tree, so that we have a StackingContextHelper to pass down into
   // the RenderLayer traversal, but don't actually want it to push a stacking
   // context on the display list builder.
   StackingContextHelper();
 
   // Pops the stacking context, if one was pushed during the constructor.
   ~StackingContextHelper();
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -158,40 +158,47 @@ WebRenderBridgeChild::EndTransaction(wr:
   mParentCommands.Clear();
   mDestroyedActors.Clear();
   mIsInTransaction = false;
 }
 
 void
 WebRenderBridgeChild::ProcessWebRenderParentCommands()
 {
+  MOZ_ASSERT(!mDestroyed);
+
   if (mParentCommands.IsEmpty()) {
     return;
   }
   this->SendParentCommands(mParentCommands);
   mParentCommands.Clear();
 }
 
 void
 WebRenderBridgeChild::AddPipelineIdForAsyncCompositable(const wr::PipelineId& aPipelineId,
                                                         const CompositableHandle& aHandle)
 {
+  MOZ_ASSERT(!mDestroyed);
   SendAddPipelineIdForCompositable(aPipelineId, aHandle, true);
 }
 
 void
 WebRenderBridgeChild::AddPipelineIdForCompositable(const wr::PipelineId& aPipelineId,
                                                    const CompositableHandle& aHandle)
 {
+  MOZ_ASSERT(!mDestroyed);
   SendAddPipelineIdForCompositable(aPipelineId, aHandle, false);
 }
 
 void
 WebRenderBridgeChild::RemovePipelineIdForCompositable(const wr::PipelineId& aPipelineId)
 {
+  if (!IPCOpen()) {
+    return;
+  }
   SendRemovePipelineIdForCompositable(aPipelineId);
 }
 
 wr::ExternalImageId
 WebRenderBridgeChild::GetNextExternalImageId()
 {
   wr::MaybeExternalImageId id = GetCompositorBridgeChild()->GetNextExternalImageId();
   MOZ_RELEASE_ASSERT(id.isSome());
@@ -238,17 +245,17 @@ WriteFontFileData(const uint8_t* aData, 
   memcpy(data->mFontBuffer.mData, aData, aLength);
 
   data->mFontIndex = aIndex;
 }
 
 void
 WebRenderBridgeChild::PushGlyphs(wr::DisplayListBuilder& aBuilder, const nsTArray<gfx::Glyph>& aGlyphs,
                                  gfx::ScaledFont* aFont, const gfx::Color& aColor, const StackingContextHelper& aSc,
-                                 const LayerRect& aBounds, const LayerRect& aClip)
+                                 const LayerRect& aBounds, const LayerRect& aClip, bool aBackfaceVisible)
 {
   MOZ_ASSERT(aFont);
   MOZ_ASSERT(!aGlyphs.IsEmpty());
 
   wr::WrFontInstanceKey key = GetFontKeyForScaledFont(aFont);
   MOZ_ASSERT(key.mNamespace.mHandle && key.mHandle);
 
   nsTArray<wr::GlyphInstance> wr_glyph_instances;
@@ -257,16 +264,17 @@ WebRenderBridgeChild::PushGlyphs(wr::Dis
   for (size_t j = 0; j < aGlyphs.Length(); j++) {
     wr_glyph_instances[j].index = aGlyphs[j].mIndex;
     wr_glyph_instances[j].point = aSc.ToRelativeLayoutPoint(
             LayerPoint::FromUnknownPoint(aGlyphs[j].mPosition));
   }
 
   aBuilder.PushText(aSc.ToRelativeLayoutRect(aBounds),
                     aSc.ToRelativeLayoutRect(aClip),
+                    aBackfaceVisible,
                     aColor,
                     key,
                     Range<const wr::GlyphInstance>(wr_glyph_instances.Elements(), wr_glyph_instances.Length()));
 }
 
 wr::FontInstanceKey
 WebRenderBridgeChild::GetFontKeyForScaledFont(gfx::ScaledFont* aScaledFont)
 {
@@ -357,16 +365,17 @@ WebRenderBridgeChild::GetLayersIPCActor(
 {
   return static_cast<LayersIPCActor*>(GetCompositorBridgeChild());
 }
 
 void
 WebRenderBridgeChild::Connect(CompositableClient* aCompositable,
                               ImageContainer* aImageContainer)
 {
+  MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(aCompositable);
 
   static uint64_t sNextID = 1;
   uint64_t id = sNextID++;
 
   mCompositables.Put(id, aCompositable);
 
   CompositableHandle handle(id);
@@ -523,16 +532,20 @@ void
 WebRenderBridgeChild::BeginClearCachedResources()
 {
   mIsInClearCachedResources = true;
 }
 
 void
 WebRenderBridgeChild::EndClearCachedResources()
 {
+  if (!IPCOpen()) {
+    mIsInClearCachedResources = false;
+    return;
+  }
   ProcessWebRenderParentCommands();
   SendClearCachedResources();
   mIsInClearCachedResources = false;
 }
 
 ipc::IShmemAllocator*
 WebRenderBridgeChild::GetShmemAllocator()
 {
--- a/gfx/layers/wr/WebRenderBridgeChild.h
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -111,17 +111,18 @@ public:
   wr::WrImageKey GetNextImageKey()
   {
     return wr::WrImageKey{ GetNamespace(), GetNextResourceId() };
   }
 
   void PushGlyphs(wr::DisplayListBuilder& aBuilder, const nsTArray<gfx::Glyph>& aGlyphs,
                   gfx::ScaledFont* aFont, const gfx::Color& aColor,
                   const StackingContextHelper& aSc,
-                  const LayerRect& aBounds, const LayerRect& aClip);
+                  const LayerRect& aBounds, const LayerRect& aClip,
+                  bool aBackfaceVisible);
 
   wr::FontInstanceKey GetFontKeyForScaledFont(gfx::ScaledFont* aScaledFont);
 
   void RemoveExpiredFontKeys();
   void ClearReadLocks();
 
   void BeginClearCachedResources();
   void EndClearCachedResources();
--- a/gfx/layers/wr/WebRenderCanvasLayer.cpp
+++ b/gfx/layers/wr/WebRenderCanvasLayer.cpp
@@ -68,17 +68,17 @@ WebRenderCanvasLayer::RenderLayer(wr::Di
   // Eww. Re-creating image keys every time is bad. Probably not worth fixing here
   // since layers-full webrender is going away soon-ish. But don't reproduce what
   // you see here.
   wr::WrImageKey key = GenerateImageKey();
   aResources.AddExternalImage(canvasRenderer->GetExternalImageId().value(), key);
   WrManager()->AddImageKeyForDiscard(key);
 
   wr::LayoutRect r = sc.ToRelativeLayoutRect(rect);
-  aBuilder.PushImage(r, r, filter, key);
+  aBuilder.PushImage(r, r, true, filter, key);
 }
 
 void
 WebRenderCanvasLayer::ClearCachedResources()
 {
   mCanvasRenderer->ClearCachedResources();
 }
 
--- a/gfx/layers/wr/WebRenderColorLayer.cpp
+++ b/gfx/layers/wr/WebRenderColorLayer.cpp
@@ -25,13 +25,13 @@ WebRenderColorLayer::RenderLayer(wr::Dis
 {
   ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
   StackingContextHelper sc(aSc, aBuilder, this);
 
   LayerRect rect = Bounds();
   DumpLayerInfo("ColorLayer", rect);
 
   wr::LayoutRect r = sc.ToRelativeLayoutRect(rect);
-  aBuilder.PushRect(r, r, wr::ToColorF(mColor));
+  aBuilder.PushRect(r, r, true, wr::ToColorF(mColor));
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderContainerLayer.cpp
+++ b/gfx/layers/wr/WebRenderContainerLayer.cpp
@@ -135,13 +135,13 @@ WebRenderRefLayer::RenderLayer(wr::Displ
   // The conversion from ParentLayerPixel to LayerPixel below is a result of
   // changing the reference layer from "this layer" to the "the layer that
   // created aSc".
   LayerRect rect = ViewAs<LayerPixel>(bounds,
       PixelCastJustification::MovingDownToChildren);
   DumpLayerInfo("RefLayer", rect);
 
   wr::LayoutRect r = aSc.ToRelativeLayoutRect(rect);
-  aBuilder.PushIFrame(r, wr::AsPipelineId(mId));
+  aBuilder.PushIFrame(r, true, wr::AsPipelineId(mId));
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderImageLayer.cpp
+++ b/gfx/layers/wr/WebRenderImageLayer.cpp
@@ -203,17 +203,17 @@ WebRenderImageLayer::RenderLayer(wr::Dis
     // where it will be done when we build the display list for the iframe.
     // That happens in AsyncImagePipelineManager.
 
     LayerRect rect = ViewAs<LayerPixel>(bounds,
         PixelCastJustification::MovingDownToChildren);
     DumpLayerInfo("Image Layer async", rect);
 
     wr::LayoutRect r = aSc.ToRelativeLayoutRect(rect);
-    aBuilder.PushIFrame(r, mPipelineId.ref());
+    aBuilder.PushIFrame(r, true, mPipelineId.ref());
 
     gfx::Matrix4x4 scTransform = GetTransform();
     // Translate is applied as part of PushIFrame()
     scTransform.PostTranslate(-rect.x, -rect.y, 0);
     // Adjust transform as to apply origin
     LayerPoint scOrigin = Bounds().TopLeft();
     scTransform.PreTranslate(-scOrigin.x, -scOrigin.y, 0);
 
@@ -268,17 +268,17 @@ WebRenderImageLayer::RenderLayer(wr::Dis
 
   DumpLayerInfo("Image Layer", rect);
   if (gfxPrefs::LayersDump()) {
     printf_stderr("ImageLayer %p texture-filter=%s \n",
                   GetLayer(),
                   Stringify(filter).c_str());
   }
   wr::LayoutRect r = sc.ToRelativeLayoutRect(rect);
-  aBuilder.PushImage(r, r, filter, mKey.value());
+  aBuilder.PushImage(r, r, true, filter, mKey.value());
 }
 
 Maybe<wr::WrImageMask>
 WebRenderImageLayer::RenderMaskLayer(const StackingContextHelper& aSc,
                                      const gfx::Matrix4x4& aTransform,
                                      wr::IpcResourceUpdateQueue& aResources)
 {
   if (!mContainer) {
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -252,21 +252,16 @@ WebRenderLayerManager::CreateWebRenderCo
     nsDisplayList* itemSameCoordinateSystemChildren
       = item->GetSameCoordinateSystemChildren();
     if (item->ShouldFlattenAway(aDisplayListBuilder)) {
       aDisplayList->AppendToBottom(itemSameCoordinateSystemChildren);
       item->Destroy(aDisplayListBuilder);
       continue;
     }
 
-    if (item->BackfaceIsHidden() && aSc.IsBackfaceVisible()) {
-      item->Destroy(aDisplayListBuilder);
-      continue;
-    }
-
     savedItems.AppendToTop(item);
 
     bool forceNewLayerData = false;
     size_t layerCountBeforeRecursing = mLayerScrollData.size();
     if (apzEnabled) {
       // For some types of display items we want to force a new
       // WebRenderLayerScrollData object, to ensure we preserve the APZ-relevant
       // data that is in the display item.
@@ -416,17 +411,18 @@ WebRenderLayerManager::CreateImageKey(ns
     imageData->CreateAsyncImageWebRenderCommands(aBuilder,
                                                  aContainer,
                                                  aSc,
                                                  rect,
                                                  scBounds,
                                                  gfx::Matrix4x4(),
                                                  scaleToSize,
                                                  wr::ImageRendering::Auto,
-                                                 wr::MixBlendMode::Normal);
+                                                 wr::MixBlendMode::Normal,
+                                                 !aItem->BackfaceIsHidden());
     return Nothing();
   }
 
   AutoLockImage autoLock(aContainer);
   if (!autoLock.HasImage()) {
     return Nothing();
   }
   mozilla::layers::Image* image = autoLock.GetImage();
@@ -453,17 +449,17 @@ WebRenderLayerManager::PushImage(nsDispl
     return true;
   }
   if (!key) {
     return false;
   }
 
   auto r = aSc.ToRelativeLayoutRect(aRect);
   SamplingFilter sampleFilter = nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame());
-  aBuilder.PushImage(r, r, wr::ToImageRendering(sampleFilter), key.value());
+  aBuilder.PushImage(r, r, !aItem->BackfaceIsHidden(), wr::ToImageRendering(sampleFilter), key.value());
 
   return true;
 }
 
 static void
 PaintItemByDrawTarget(nsDisplayItem* aItem,
                       DrawTarget* aDT,
                       const LayerRect& aImageRect,
@@ -679,16 +675,17 @@ WebRenderLayerManager::PushItemAsImage(n
   if (!fallbackData) {
     return false;
   }
 
   wr::LayoutRect dest = aSc.ToRelativeLayoutRect(imageRect + offset);
   SamplingFilter sampleFilter = nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame());
   aBuilder.PushImage(dest,
                      dest,
+                     !aItem->BackfaceIsHidden(),
                      wr::ToImageRendering(sampleFilter),
                      fallbackData->GetKey().value());
   return true;
 }
 
 void
 WebRenderLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
                                       void* aCallbackData,
@@ -962,17 +959,18 @@ void
 WebRenderLayerManager::AddCompositorAnimationsIdForDiscard(uint64_t aId)
 {
   mDiscardedCompositorAnimationsIds.AppendElement(aId);
 }
 
 void
 WebRenderLayerManager::DiscardCompositorAnimations()
 {
-  if (WrBridge()->IPCOpen() && !mDiscardedCompositorAnimationsIds.IsEmpty()) {
+  if (WrBridge()->IPCOpen() &&
+      !mDiscardedCompositorAnimationsIds.IsEmpty()) {
     WrBridge()->
       SendDeleteCompositorAnimations(mDiscardedCompositorAnimationsIds);
   }
   mDiscardedCompositorAnimationsIds.Clear();
 }
 
 void
 WebRenderLayerManager::DiscardLocalImages()
--- a/gfx/layers/wr/WebRenderPaintedLayer.cpp
+++ b/gfx/layers/wr/WebRenderPaintedLayer.cpp
@@ -102,17 +102,17 @@ WebRenderPaintedLayer::CreateWebRenderDi
   DumpLayerInfo("PaintedLayer", rect);
 
   wr::WrImageKey key = GenerateImageKey();
   aResources.AddExternalImage(mExternalImageId.value(), key);
   // TODO: reuse image keys!
   WrManager()->AddImageKeyForDiscard(key);
 
   wr::LayoutRect r = sc.ToRelativeLayoutRect(rect);
-  aBuilder.PushImage(r, r, wr::ImageRendering::Auto, key);
+  aBuilder.PushImage(r, r, true, wr::ImageRendering::Auto, key);
 }
 
 void
 WebRenderPaintedLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
                                    wr::IpcResourceUpdateQueue& aResources,
                                    const StackingContextHelper& aSc)
 {
   if (!SetupExternalImages()) {
--- a/gfx/layers/wr/WebRenderPaintedLayerBlob.cpp
+++ b/gfx/layers/wr/WebRenderPaintedLayerBlob.cpp
@@ -88,13 +88,14 @@ WebRenderPaintedLayerBlob::RenderLayer(w
 
   ScrollingLayersHelper scroller(this, aBuilder, aResources, aSc);
   StackingContextHelper sc(aSc, aBuilder, this);
   LayerRect rect = Bounds();
   DumpLayerInfo("PaintedLayer", rect);
 
   aBuilder.PushImage(sc.ToRelativeLayoutRect(LayerRect(mImageBounds)),
                      sc.ToRelativeLayoutRect(rect),
+                     true,
                      wr::ImageRendering::Auto, mImageKey.value());
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderTextLayer.cpp
+++ b/gfx/layers/wr/WebRenderTextLayer.cpp
@@ -38,14 +38,14 @@ WebRenderTextLayer::RenderLayer(wr::Disp
         // we apply it here. The glyphs that we push to WR should already be
         // taking the transform into account.
         GetTransform().TransformBounds(IntRectToRect(mBounds))
     );
     DumpLayerInfo("TextLayer", rect);
 
     for (GlyphArray& glyphs : mGlyphs) {
         WrBridge()->PushGlyphs(aBuilder, glyphs.glyphs(), mFont,
-                               glyphs.color().value(), aSc, rect, rect);
+                               glyphs.color().value(), aSc, rect, rect, true);
     }
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderUserData.cpp
+++ b/gfx/layers/wr/WebRenderUserData.cpp
@@ -130,17 +130,18 @@ void
 WebRenderImageData::CreateAsyncImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                                       ImageContainer* aContainer,
                                                       const StackingContextHelper& aSc,
                                                       const LayerRect& aBounds,
                                                       const LayerRect& aSCBounds,
                                                       const gfx::Matrix4x4& aSCTransform,
                                                       const gfx::MaybeIntSize& aScaleToSize,
                                                       const wr::ImageRendering& aFilter,
-                                                      const wr::MixBlendMode& aMixBlendMode)
+                                                      const wr::MixBlendMode& aMixBlendMode,
+                                                      bool aIsBackfaceVisible)
 {
   MOZ_ASSERT(aContainer->IsAsync());
   if (!mPipelineId) {
     // Alloc async image pipeline id.
     mPipelineId = Some(WrBridge()->GetCompositorBridgeChild()->GetNextPipelineId());
     WrBridge()->AddPipelineIdForAsyncCompositable(mPipelineId.ref(),
                                                   aContainer->GetAsyncContainerHandle());
   }
@@ -151,17 +152,17 @@ WebRenderImageData::CreateAsyncImageWebR
   //
   // We don't push a stacking context for this async image pipeline here.
   // Instead, we do it inside the iframe that hosts the image. As a result,
   // a bunch of the calculations normally done as part of that stacking
   // context need to be done manually and pushed over to the parent side,
   // where it will be done when we build the display list for the iframe.
   // That happens in AsyncImagePipelineManager.
   wr::LayoutRect r = aSc.ToRelativeLayoutRect(aBounds);
-  aBuilder.PushIFrame(r, mPipelineId.ref());
+  aBuilder.PushIFrame(r, aIsBackfaceVisible, mPipelineId.ref());
 
   WrBridge()->AddWebRenderParentCommand(OpUpdateAsyncImagePipeline(mPipelineId.value(),
                                                                    aSCBounds,
                                                                    aSCTransform,
                                                                    aScaleToSize,
                                                                    aFilter,
                                                                    aMixBlendMode));
 }
--- a/gfx/layers/wr/WebRenderUserData.h
+++ b/gfx/layers/wr/WebRenderUserData.h
@@ -90,17 +90,18 @@ public:
   void CreateAsyncImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                          ImageContainer* aContainer,
                                          const StackingContextHelper& aSc,
                                          const LayerRect& aBounds,
                                          const LayerRect& aSCBounds,
                                          const gfx::Matrix4x4& aSCTransform,
                                          const gfx::MaybeIntSize& aScaleToSize,
                                          const wr::ImageRendering& aFilter,
-                                         const wr::MixBlendMode& aMixBlendMode);
+                                         const wr::MixBlendMode& aMixBlendMode,
+                                         bool aIsBackfaceVisible);
 
   void CreateImageClientIfNeeded();
 
 protected:
   void CreateExternalImageIfNeeded();
 
   wr::MaybeExternalImageId mExternalImageId;
   Maybe<wr::ImageKey> mKey;
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -605,17 +605,17 @@ private:
   DECL_GFX_PREF(Live, "layers.offmainthreadcomposition.frame-rate", LayersCompositionFrameRate, int32_t,-1);
   DECL_GFX_PREF(Live, "layers.omtp.force-sync",                LayersOMTPForceSync, bool, false);
   DECL_GFX_PREF(Live, "layers.orientation.sync.timeout",       OrientationSyncMillis, uint32_t, (uint32_t)0);
   DECL_GFX_PREF(Once, "layers.prefer-opengl",                  LayersPreferOpenGL, bool, false);
   DECL_GFX_PREF(Live, "layers.progressive-paint",              ProgressivePaint, bool, false);
   DECL_GFX_PREF(Live, "layers.shared-buffer-provider.enabled", PersistentBufferProviderSharedEnabled, bool, false);
   DECL_GFX_PREF(Live, "layers.single-tile.enabled",            LayersSingleTileEnabled, bool, true);
   DECL_GFX_PREF(Once, "layers.stereo-video.enabled",           StereoVideoEnabled, bool, false);
-  DECL_GFX_PREF(Live, "layers.force-synchronous-resize",       LayersForceSynchronousResize, bool, false);
+  DECL_GFX_PREF(Live, "layers.force-synchronous-resize",       LayersForceSynchronousResize, bool, true);
 
   // We allow for configurable and rectangular tile size to avoid wasting memory on devices whose
   // screen size does not align nicely to the default tile size. Although layers can be any size,
   // they are often the same size as the screen, especially for width.
   DECL_GFX_PREF(Once, "layers.tile-width",                     LayersTileWidth, int32_t, 256);
   DECL_GFX_PREF(Once, "layers.tile-height",                    LayersTileHeight, int32_t, 256);
   DECL_GFX_PREF(Once, "layers.tile-initial-pool-size",         LayersTileInitialPoolSize, uint32_t, (uint32_t)50);
   DECL_GFX_PREF(Once, "layers.tile-pool-unused-size",          LayersTilePoolUnusedSize, uint32_t, (uint32_t)10);
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -658,33 +658,34 @@ DisplayListBuilder::Finalize(wr::LayoutS
 void
 DisplayListBuilder::PushStackingContext(const wr::LayoutRect& aBounds,
                                         const uint64_t& aAnimationId,
                                         const float* aOpacity,
                                         const gfx::Matrix4x4* aTransform,
                                         wr::TransformStyle aTransformStyle,
                                         const gfx::Matrix4x4* aPerspective,
                                         const wr::MixBlendMode& aMixBlendMode,
-                                        const nsTArray<wr::WrFilterOp>& aFilters)
+                                        const nsTArray<wr::WrFilterOp>& aFilters,
+                                        bool aIsBackfaceVisible)
 {
   wr::LayoutTransform matrix;
   if (aTransform) {
     matrix = ToLayoutTransform(*aTransform);
   }
   const wr::LayoutTransform* maybeTransform = aTransform ? &matrix : nullptr;
   wr::LayoutTransform perspective;
   if (aPerspective) {
     perspective = ToLayoutTransform(*aPerspective);
   }
   const wr::LayoutTransform* maybePerspective = aPerspective ? &perspective : nullptr;
   WRDL_LOG("PushStackingContext b=%s t=%s\n", mWrState, Stringify(aBounds).c_str(),
       aTransform ? Stringify(*aTransform).c_str() : "none");
   wr_dp_push_stacking_context(mWrState, aBounds, aAnimationId, aOpacity,
                               maybeTransform, aTransformStyle, maybePerspective,
-                              aMixBlendMode, aFilters.Elements(), aFilters.Length());
+                              aMixBlendMode, aFilters.Elements(), aFilters.Length(), aIsBackfaceVisible);
 }
 
 void
 DisplayListBuilder::PopStackingContext()
 {
   WRDL_LOG("PopStackingContext\n", mWrState);
   wr_dp_pop_stacking_context(mWrState);
 }
@@ -795,228 +796,246 @@ DisplayListBuilder::PopClipAndScrollInfo
   WRDL_LOG("PopClipAndScroll\n", mWrState);
   mScrollIdStack.pop_back();
   wr_dp_pop_clip_and_scroll_info(mWrState);
 }
 
 void
 DisplayListBuilder::PushRect(const wr::LayoutRect& aBounds,
                              const wr::LayoutRect& aClip,
+                             bool aIsBackfaceVisible,
                              const wr::ColorF& aColor)
 {
   WRDL_LOG("PushRect b=%s cl=%s c=%s\n", mWrState,
       Stringify(aBounds).c_str(),
       Stringify(aClip).c_str(),
       Stringify(aColor).c_str());
-  wr_dp_push_rect(mWrState, aBounds, aClip, aColor);
+  wr_dp_push_rect(mWrState, aBounds, aClip, aIsBackfaceVisible, aColor);
 }
 
 void
 DisplayListBuilder::PushLinearGradient(const wr::LayoutRect& aBounds,
                                        const wr::LayoutRect& aClip,
+                                       bool aIsBackfaceVisible,
                                        const wr::LayoutPoint& aStartPoint,
                                        const wr::LayoutPoint& aEndPoint,
                                        const nsTArray<wr::GradientStop>& aStops,
                                        wr::ExtendMode aExtendMode,
                                        const wr::LayoutSize aTileSize,
                                        const wr::LayoutSize aTileSpacing)
 {
   wr_dp_push_linear_gradient(mWrState,
-                             aBounds, aClip,
+                             aBounds, aClip, aIsBackfaceVisible,
                              aStartPoint, aEndPoint,
                              aStops.Elements(), aStops.Length(),
                              aExtendMode,
                              aTileSize, aTileSpacing);
 }
 
 void
 DisplayListBuilder::PushRadialGradient(const wr::LayoutRect& aBounds,
                                        const wr::LayoutRect& aClip,
+                                       bool aIsBackfaceVisible,
                                        const wr::LayoutPoint& aCenter,
                                        const wr::LayoutSize& aRadius,
                                        const nsTArray<wr::GradientStop>& aStops,
                                        wr::ExtendMode aExtendMode,
                                        const wr::LayoutSize aTileSize,
                                        const wr::LayoutSize aTileSpacing)
 {
   wr_dp_push_radial_gradient(mWrState,
-                             aBounds, aClip,
+                             aBounds, aClip, aIsBackfaceVisible,
                              aCenter, aRadius,
                              aStops.Elements(), aStops.Length(),
                              aExtendMode,
                              aTileSize, aTileSpacing);
 }
 
 void
 DisplayListBuilder::PushImage(const wr::LayoutRect& aBounds,
                               const wr::LayoutRect& aClip,
+                              bool aIsBackfaceVisible,
                               wr::ImageRendering aFilter,
                               wr::ImageKey aImage)
 {
   wr::LayoutSize size;
   size.width = aBounds.size.width;
   size.height = aBounds.size.height;
-  PushImage(aBounds, aClip, size, size, aFilter, aImage);
+  PushImage(aBounds, aClip, aIsBackfaceVisible, size, size, aFilter, aImage);
 }
 
 void
 DisplayListBuilder::PushImage(const wr::LayoutRect& aBounds,
                               const wr::LayoutRect& aClip,
+                              bool aIsBackfaceVisible,
                               const wr::LayoutSize& aStretchSize,
                               const wr::LayoutSize& aTileSpacing,
                               wr::ImageRendering aFilter,
                               wr::ImageKey aImage)
 {
   WRDL_LOG("PushImage b=%s cl=%s s=%s t=%s\n", mWrState,
       Stringify(aBounds).c_str(),
       Stringify(aClip).c_str(), Stringify(aStretchSize).c_str(),
       Stringify(aTileSpacing).c_str());
-  wr_dp_push_image(mWrState, aBounds, aClip, aStretchSize, aTileSpacing, aFilter, aImage);
+  wr_dp_push_image(mWrState, aBounds, aClip, aIsBackfaceVisible, aStretchSize, aTileSpacing, aFilter, aImage);
 }
 
 void
 DisplayListBuilder::PushYCbCrPlanarImage(const wr::LayoutRect& aBounds,
                                          const wr::LayoutRect& aClip,
+                                         bool aIsBackfaceVisible,
                                          wr::ImageKey aImageChannel0,
                                          wr::ImageKey aImageChannel1,
                                          wr::ImageKey aImageChannel2,
                                          wr::WrYuvColorSpace aColorSpace,
                                          wr::ImageRendering aRendering)
 {
   wr_dp_push_yuv_planar_image(mWrState,
                               aBounds,
                               aClip,
+                              aIsBackfaceVisible,
                               aImageChannel0,
                               aImageChannel1,
                               aImageChannel2,
                               aColorSpace,
                               aRendering);
 }
 
 void
 DisplayListBuilder::PushNV12Image(const wr::LayoutRect& aBounds,
                                   const wr::LayoutRect& aClip,
+                                  bool aIsBackfaceVisible,
                                   wr::ImageKey aImageChannel0,
                                   wr::ImageKey aImageChannel1,
                                   wr::WrYuvColorSpace aColorSpace,
                                   wr::ImageRendering aRendering)
 {
   wr_dp_push_yuv_NV12_image(mWrState,
                             aBounds,
                             aClip,
+                            aIsBackfaceVisible,
                             aImageChannel0,
                             aImageChannel1,
                             aColorSpace,
                             aRendering);
 }
 
 void
 DisplayListBuilder::PushYCbCrInterleavedImage(const wr::LayoutRect& aBounds,
                                               const wr::LayoutRect& aClip,
+                                              bool aIsBackfaceVisible,
                                               wr::ImageKey aImageChannel0,
                                               wr::WrYuvColorSpace aColorSpace,
                                               wr::ImageRendering aRendering)
 {
   wr_dp_push_yuv_interleaved_image(mWrState,
                                    aBounds,
                                    aClip,
+                                   aIsBackfaceVisible,
                                    aImageChannel0,
                                    aColorSpace,
                                    aRendering);
 }
 
 void
 DisplayListBuilder::PushIFrame(const wr::LayoutRect& aBounds,
+                               bool aIsBackfaceVisible,
                                PipelineId aPipeline)
 {
-  wr_dp_push_iframe(mWrState, aBounds, aPipeline);
+  wr_dp_push_iframe(mWrState, aBounds, aIsBackfaceVisible, aPipeline);
 }
 
 void
 DisplayListBuilder::PushBorder(const wr::LayoutRect& aBounds,
                                const wr::LayoutRect& aClip,
+                               bool aIsBackfaceVisible,
                                const wr::BorderWidths& aWidths,
                                const Range<const wr::BorderSide>& aSides,
                                const wr::BorderRadius& aRadius)
 {
   MOZ_ASSERT(aSides.length() == 4);
   if (aSides.length() != 4) {
     return;
   }
-  wr_dp_push_border(mWrState, aBounds, aClip,
+  wr_dp_push_border(mWrState, aBounds, aClip, aIsBackfaceVisible,
                     aWidths, aSides[0], aSides[1], aSides[2], aSides[3], aRadius);
 }
 
 void
 DisplayListBuilder::PushBorderImage(const wr::LayoutRect& aBounds,
                                     const wr::LayoutRect& aClip,
+                                    bool aIsBackfaceVisible,
                                     const wr::BorderWidths& aWidths,
                                     wr::ImageKey aImage,
                                     const wr::NinePatchDescriptor& aPatch,
                                     const wr::SideOffsets2D_f32& aOutset,
                                     const wr::RepeatMode& aRepeatHorizontal,
                                     const wr::RepeatMode& aRepeatVertical)
 {
-  wr_dp_push_border_image(mWrState, aBounds, aClip,
+  wr_dp_push_border_image(mWrState, aBounds, aClip, aIsBackfaceVisible,
                           aWidths, aImage, aPatch, aOutset,
                           aRepeatHorizontal, aRepeatVertical);
 }
 
 void
 DisplayListBuilder::PushBorderGradient(const wr::LayoutRect& aBounds,
                                        const wr::LayoutRect& aClip,
+                                       bool aIsBackfaceVisible,
                                        const wr::BorderWidths& aWidths,
                                        const wr::LayoutPoint& aStartPoint,
                                        const wr::LayoutPoint& aEndPoint,
                                        const nsTArray<wr::GradientStop>& aStops,
                                        wr::ExtendMode aExtendMode,
                                        const wr::SideOffsets2D_f32& aOutset)
 {
-  wr_dp_push_border_gradient(mWrState, aBounds, aClip,
+  wr_dp_push_border_gradient(mWrState, aBounds, aClip, aIsBackfaceVisible,
                              aWidths, aStartPoint, aEndPoint,
                              aStops.Elements(), aStops.Length(),
                              aExtendMode, aOutset);
 }
 
 void
 DisplayListBuilder::PushBorderRadialGradient(const wr::LayoutRect& aBounds,
                                              const wr::LayoutRect& aClip,
+                                             bool aIsBackfaceVisible,
                                              const wr::BorderWidths& aWidths,
                                              const wr::LayoutPoint& aCenter,
                                              const wr::LayoutSize& aRadius,
                                              const nsTArray<wr::GradientStop>& aStops,
                                              wr::ExtendMode aExtendMode,
                                              const wr::SideOffsets2D_f32& aOutset)
 {
   wr_dp_push_border_radial_gradient(
-    mWrState, aBounds, aClip, aWidths, aCenter,
+    mWrState, aBounds, aClip, aIsBackfaceVisible, aWidths, aCenter,
     aRadius, aStops.Elements(), aStops.Length(),
     aExtendMode, aOutset);
 }
 
 void
 DisplayListBuilder::PushText(const wr::LayoutRect& aBounds,
                              const wr::LayoutRect& aClip,
+                             bool aIsBackfaceVisible,
                              const gfx::Color& aColor,
                              wr::FontInstanceKey aFontKey,
                              Range<const wr::GlyphInstance> aGlyphBuffer,
                              const wr::GlyphOptions* aGlyphOptions)
 {
-  wr_dp_push_text(mWrState, aBounds, aClip,
+  wr_dp_push_text(mWrState, aBounds, aClip, aIsBackfaceVisible,
                   ToColorF(aColor),
                   aFontKey,
                   &aGlyphBuffer[0], aGlyphBuffer.length(),
                   aGlyphOptions);
 }
 
 void
 DisplayListBuilder::PushLine(const wr::LayoutRect& aClip,
+                             bool aIsBackfaceVisible,
                              const wr::Line& aLine)
 {
- wr_dp_push_line(mWrState, aClip, aLine.baseline, aLine.start, aLine.end,
+ wr_dp_push_line(mWrState, aClip, aIsBackfaceVisible, aLine.baseline, aLine.start, aLine.end,
                  aLine.orientation, aLine.width, aLine.color, aLine.style);
 
 /* TODO(Gankro): remove this
   LayoutRect rect;
   if (aLine.orientation == wr::LineOrientation::Horizontal) {
     rect.origin.x = aLine.start;
     rect.origin.y = aLine.baseline;
     rect.size.width = aLine.end - aLine.start;
@@ -1030,39 +1049,41 @@ DisplayListBuilder::PushLine(const wr::L
 
   PushRect(rect, aClip, aLine.color);
 */
 }
 
 void
 DisplayListBuilder::PushTextShadow(const wr::LayoutRect& aRect,
                                    const wr::LayoutRect& aClip,
+                                   bool aIsBackfaceVisible,
                                    const wr::TextShadow& aShadow)
 {
-  wr_dp_push_text_shadow(mWrState, aRect, aClip, aShadow);
+  wr_dp_push_text_shadow(mWrState, aRect, aClip, aIsBackfaceVisible, aShadow);
 }
 
 void
 DisplayListBuilder::PopTextShadow()
 {
   wr_dp_pop_text_shadow(mWrState);
 }
 
 void
 DisplayListBuilder::PushBoxShadow(const wr::LayoutRect& aRect,
                                   const wr::LayoutRect& aClip,
+                                  bool aIsBackfaceVisible,
                                   const wr::LayoutRect& aBoxBounds,
                                   const wr::LayoutVector2D& aOffset,
                                   const wr::ColorF& aColor,
                                   const float& aBlurRadius,
                                   const float& aSpreadRadius,
                                   const float& aBorderRadius,
                                   const wr::BoxShadowClipMode& aClipMode)
 {
-  wr_dp_push_box_shadow(mWrState, aRect, aClip,
+  wr_dp_push_box_shadow(mWrState, aRect, aClip, aIsBackfaceVisible,
                         aBoxBounds, aOffset, aColor,
                         aBlurRadius, aSpreadRadius, aBorderRadius,
                         aClipMode);
 }
 
 Maybe<wr::WrClipId>
 DisplayListBuilder::TopmostClipId()
 {
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -214,17 +214,18 @@ public:
 
   void PushStackingContext(const wr::LayoutRect& aBounds, // TODO: We should work with strongly typed rects
                            const uint64_t& aAnimationId,
                            const float* aOpacity,
                            const gfx::Matrix4x4* aTransform,
                            wr::TransformStyle aTransformStyle,
                            const gfx::Matrix4x4* aPerspective,
                            const wr::MixBlendMode& aMixBlendMode,
-                           const nsTArray<wr::WrFilterOp>& aFilters);
+                           const nsTArray<wr::WrFilterOp>& aFilters,
+                           bool aIsBackfaceVisible);
   void PopStackingContext();
 
   wr::WrClipId DefineClip(const wr::LayoutRect& aClipRect,
                           const nsTArray<wr::WrComplexClipRegion>* aComplex = nullptr,
                           const wr::WrImageMask* aMask = nullptr);
   void PushClip(const wr::WrClipId& aClipId, bool aRecordInStack = true);
   void PopClip(bool aRecordInStack = true);
 
@@ -238,127 +239,144 @@ public:
   void PopScrollLayer();
 
   void PushClipAndScrollInfo(const layers::FrameMetrics::ViewID& aScrollId,
                              const wr::WrClipId* aClipId);
   void PopClipAndScrollInfo();
 
   void PushRect(const wr::LayoutRect& aBounds,
                 const wr::LayoutRect& aClip,
+                bool aIsBackfaceVisible,
                 const wr::ColorF& aColor);
 
   void PushLinearGradient(const wr::LayoutRect& aBounds,
                           const wr::LayoutRect& aClip,
+                          bool aIsBackfaceVisible,
                           const wr::LayoutPoint& aStartPoint,
                           const wr::LayoutPoint& aEndPoint,
                           const nsTArray<wr::GradientStop>& aStops,
                           wr::ExtendMode aExtendMode,
                           const wr::LayoutSize aTileSize,
                           const wr::LayoutSize aTileSpacing);
 
   void PushRadialGradient(const wr::LayoutRect& aBounds,
                           const wr::LayoutRect& aClip,
+                          bool aIsBackfaceVisible,
                           const wr::LayoutPoint& aCenter,
                           const wr::LayoutSize& aRadius,
                           const nsTArray<wr::GradientStop>& aStops,
                           wr::ExtendMode aExtendMode,
                           const wr::LayoutSize aTileSize,
                           const wr::LayoutSize aTileSpacing);
 
   void PushImage(const wr::LayoutRect& aBounds,
                  const wr::LayoutRect& aClip,
+                 bool aIsBackfaceVisible,
                  wr::ImageRendering aFilter,
                  wr::ImageKey aImage);
 
   void PushImage(const wr::LayoutRect& aBounds,
                  const wr::LayoutRect& aClip,
+                 bool aIsBackfaceVisible,
                  const wr::LayoutSize& aStretchSize,
                  const wr::LayoutSize& aTileSpacing,
                  wr::ImageRendering aFilter,
                  wr::ImageKey aImage);
 
   void PushYCbCrPlanarImage(const wr::LayoutRect& aBounds,
                             const wr::LayoutRect& aClip,
+                            bool aIsBackfaceVisible,
                             wr::ImageKey aImageChannel0,
                             wr::ImageKey aImageChannel1,
                             wr::ImageKey aImageChannel2,
                             wr::WrYuvColorSpace aColorSpace,
                             wr::ImageRendering aFilter);
 
   void PushNV12Image(const wr::LayoutRect& aBounds,
                      const wr::LayoutRect& aClip,
+                     bool aIsBackfaceVisible,
                      wr::ImageKey aImageChannel0,
                      wr::ImageKey aImageChannel1,
                      wr::WrYuvColorSpace aColorSpace,
                      wr::ImageRendering aFilter);
 
   void PushYCbCrInterleavedImage(const wr::LayoutRect& aBounds,
                                  const wr::LayoutRect& aClip,
+                                 bool aIsBackfaceVisible,
                                  wr::ImageKey aImageChannel0,
                                  wr::WrYuvColorSpace aColorSpace,
                                  wr::ImageRendering aFilter);
 
   void PushIFrame(const wr::LayoutRect& aBounds,
+                  bool aIsBackfaceVisible,
                   wr::PipelineId aPipeline);
 
   // XXX WrBorderSides are passed with Range.
   // It is just to bypass compiler bug. See Bug 1357734.
   void PushBorder(const wr::LayoutRect& aBounds,
                   const wr::LayoutRect& aClip,
+                  bool aIsBackfaceVisible,
                   const wr::BorderWidths& aWidths,
                   const Range<const wr::BorderSide>& aSides,
                   const wr::BorderRadius& aRadius);
 
   void PushBorderImage(const wr::LayoutRect& aBounds,
                        const wr::LayoutRect& aClip,
+                       bool aIsBackfaceVisible,
                        const wr::BorderWidths& aWidths,
                        wr::ImageKey aImage,
                        const wr::NinePatchDescriptor& aPatch,
                        const wr::SideOffsets2D_f32& aOutset,
                        const wr::RepeatMode& aRepeatHorizontal,
                        const wr::RepeatMode& aRepeatVertical);
 
   void PushBorderGradient(const wr::LayoutRect& aBounds,
                           const wr::LayoutRect& aClip,
+                          bool aIsBackfaceVisible,
                           const wr::BorderWidths& aWidths,
                           const wr::LayoutPoint& aStartPoint,
                           const wr::LayoutPoint& aEndPoint,
                           const nsTArray<wr::GradientStop>& aStops,
                           wr::ExtendMode aExtendMode,
                           const wr::SideOffsets2D_f32& aOutset);
 
   void PushBorderRadialGradient(const wr::LayoutRect& aBounds,
                                 const wr::LayoutRect& aClip,
+                                bool aIsBackfaceVisible,
                                 const wr::BorderWidths& aWidths,
                                 const wr::LayoutPoint& aCenter,
                                 const wr::LayoutSize& aRadius,
                                 const nsTArray<wr::GradientStop>& aStops,
                                 wr::ExtendMode aExtendMode,
                                 const wr::SideOffsets2D_f32& aOutset);
 
   void PushText(const wr::LayoutRect& aBounds,
                 const wr::LayoutRect& aClip,
+                bool aIsBackfaceVisible,
                 const gfx::Color& aColor,
                 wr::FontInstanceKey aFontKey,
                 Range<const wr::GlyphInstance> aGlyphBuffer,
                 const wr::GlyphOptions* aGlyphOptions = nullptr);
 
   void PushLine(const wr::LayoutRect& aClip,
+                bool aIsBackfaceVisible,
                 const wr::Line& aLine);
 
   void PushTextShadow(const wr::LayoutRect& aBounds,
                       const wr::LayoutRect& aClip,
+                      bool aIsBackfaceVisible,
                       const wr::TextShadow& aShadow);
 
   void PopTextShadow();
 
 
 
   void PushBoxShadow(const wr::LayoutRect& aRect,
                      const wr::LayoutRect& aClip,
+                     bool aIsBackfaceVisible,
                      const wr::LayoutRect& aBoxBounds,
                      const wr::LayoutVector2D& aOffset,
                      const wr::ColorF& aColor,
                      const float& aBlurRadius,
                      const float& aSpreadRadius,
                      const float& aBorderRadius,
                      const wr::BoxShadowClipMode& aClipMode);
 
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1075,17 +1075,17 @@ pub extern "C" fn wr_state_delete(state:
         Box::from_raw(state);
     }
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_begin(state: &mut WrState,
                               width: u32,
                               height: u32) {
-    assert!(unsafe { !is_in_render_thread() });
+    debug_assert!(unsafe { !is_in_render_thread() });
     state.frame_builder.dl_builder.data.clear();
 
     let bounds = LayoutRect::new(LayoutPoint::new(0.0, 0.0),
                                  LayoutSize::new(width as f32, height as f32));
     let prim_info = LayoutPrimitiveInfo::new(bounds);
 
     state.frame_builder
          .dl_builder
@@ -1095,32 +1095,33 @@ pub extern "C" fn wr_dp_begin(state: &mu
                                 TransformStyle::Flat,
                                 None,
                                 MixBlendMode::Normal,
                                 Vec::new());
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_end(state: &mut WrState) {
-    assert!(unsafe { !is_in_render_thread() });
+    debug_assert!(unsafe { !is_in_render_thread() });
     state.frame_builder.dl_builder.pop_stacking_context();
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_stacking_context(state: &mut WrState,
                                               bounds: LayoutRect,
                                               animation_id: u64,
                                               opacity: *const f32,
                                               transform: *const LayoutTransform,
                                               transform_style: TransformStyle,
                                               perspective: *const LayoutTransform,
                                               mix_blend_mode: MixBlendMode,
                                               filters: *const WrFilterOp,
-                                              filter_count: usize) {
-    assert!(unsafe { !is_in_render_thread() });
+                                              filter_count: usize,
+                                              is_backface_visible: bool) {
+    debug_assert!(unsafe { !is_in_render_thread() });
 
     let c_filters = make_slice(filters, filter_count);
     let mut filters : Vec<FilterOp> = c_filters.iter().map(|c_filter| {
         match c_filter.filter_type {
             WrFilterOpType::Blur => FilterOp::Blur(c_filter.argument),
             WrFilterOpType::Brightness => FilterOp::Brightness(c_filter.argument),
             WrFilterOpType::Contrast => FilterOp::Contrast(c_filter.argument),
             WrFilterOpType::Grayscale => FilterOp::Grayscale(c_filter.argument),
@@ -1151,42 +1152,44 @@ pub extern "C" fn wr_dp_push_stacking_co
     };
 
     let perspective_ref = unsafe { perspective.as_ref() };
     let perspective = match perspective_ref {
         Some(perspective) => Some(perspective.clone()),
         None => None,
     };
 
-    let prim_info = LayoutPrimitiveInfo::new(bounds);
+    let mut prim_info = LayoutPrimitiveInfo::new(bounds);
+    prim_info.is_backface_visible = is_backface_visible;
+
     state.frame_builder
          .dl_builder
          .push_stacking_context(&prim_info,
                                 webrender_api::ScrollPolicy::Scrollable,
                                 transform_binding,
                                 transform_style,
                                 perspective,
                                 mix_blend_mode,
                                 filters);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_pop_stacking_context(state: &mut WrState) {
-    assert!(unsafe { !is_in_render_thread() });
+    debug_assert!(unsafe { !is_in_render_thread() });
     state.frame_builder.dl_builder.pop_stacking_context();
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_define_clip(state: &mut WrState,
                                     clip_rect: LayoutRect,
                                     complex: *const WrComplexClipRegion,
                                     complex_count: usize,
                                     mask: *const WrImageMask)
                                     -> u64 {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
     let complex_slice = make_slice(complex, complex_count);
     let complex_iter = complex_slice.iter().map(|x| x.into());
     let mask : Option<ImageMask> = unsafe { mask.as_ref() }.map(|x| x.into());
 
     let clip_id = state.frame_builder.dl_builder.define_clip(None, clip_rect, complex_iter, mask);
     // return the u64 id value from inside the ClipId::Clip(..)
     match clip_id {
         ClipId::Clip(id, nesting_index, pipeline_id) => {
@@ -1196,23 +1199,23 @@ pub extern "C" fn wr_dp_define_clip(stat
         },
         _ => panic!("Got unexpected clip id type"),
     }
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_clip(state: &mut WrState,
                                   clip_id: u64) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
     state.frame_builder.dl_builder.push_clip_id(ClipId::Clip(clip_id, 0, state.pipeline_id));
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_pop_clip(state: &mut WrState) {
-    assert!(unsafe { !is_in_render_thread() });
+    debug_assert!(unsafe { !is_in_render_thread() });
     state.frame_builder.dl_builder.pop_clip_id();
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_define_scroll_layer(state: &mut WrState,
                                             scroll_id: u64,
                                             content_rect: LayoutRect,
                                             clip_rect: LayoutRect) {
@@ -1221,24 +1224,24 @@ pub extern "C" fn wr_dp_define_scroll_la
     state.frame_builder.dl_builder.define_scroll_frame(
         Some(clip_id), content_rect, clip_rect, vec![], None,
         ScrollSensitivity::Script);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_scroll_layer(state: &mut WrState,
                                           scroll_id: u64) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
     let clip_id = ClipId::new(scroll_id, state.pipeline_id);
     state.frame_builder.dl_builder.push_clip_id(clip_id);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_pop_scroll_layer(state: &mut WrState) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
     state.frame_builder.dl_builder.pop_clip_id();
 }
 
 #[no_mangle]
 pub extern "C" fn wr_scroll_layer_with_id(dh: &mut DocumentHandle,
                                           pipeline_id: WrPipelineId,
                                           scroll_id: u64,
                                           new_scroll_origin: LayoutPoint) {
@@ -1246,190 +1249,208 @@ pub extern "C" fn wr_scroll_layer_with_i
     let clip_id = ClipId::new(scroll_id, pipeline_id);
     dh.api.scroll_node_with_id(dh.document_id, new_scroll_origin, clip_id, ScrollClamping::NoClamping);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_clip_and_scroll_info(state: &mut WrState,
                                                   scroll_id: u64,
                                                   clip_id: *const u64) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
     let scroll_id = ClipId::new(scroll_id, state.pipeline_id);
     let info = if let Some(&id) = unsafe { clip_id.as_ref() } {
         ClipAndScrollInfo::new(
             scroll_id,
             ClipId::Clip(id, 0, state.pipeline_id))
     } else {
         ClipAndScrollInfo::simple(scroll_id)
     };
     state.frame_builder.dl_builder.push_clip_and_scroll_info(info);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_pop_clip_and_scroll_info(state: &mut WrState) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
     state.frame_builder.dl_builder.pop_clip_id();
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_iframe(state: &mut WrState,
                                     rect: LayoutRect,
+                                    is_backface_visible: bool,
                                     pipeline_id: WrPipelineId) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
 
-    let prim_info = LayoutPrimitiveInfo::new(rect);
+    let mut prim_info = LayoutPrimitiveInfo::new(rect);
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder.dl_builder.push_iframe(&prim_info, pipeline_id);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_rect(state: &mut WrState,
                                   rect: LayoutRect,
                                   clip: LayoutRect,
+                                  is_backface_visible: bool,
                                   color: ColorF) {
-    assert!(unsafe { !is_in_render_thread() });
+    debug_assert!(unsafe { !is_in_render_thread() });
 
-    let prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder.dl_builder.push_rect(&prim_info,
                                              color);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_image(state: &mut WrState,
                                    bounds: LayoutRect,
                                    clip: LayoutRect,
+                                   is_backface_visible: bool,
                                    stretch_size: LayoutSize,
                                    tile_spacing: LayoutSize,
                                    image_rendering: ImageRendering,
                                    key: WrImageKey) {
-    assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
+    debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
 
-    let prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
+    let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder
          .dl_builder
          .push_image(&prim_info,
                      stretch_size,
                      tile_spacing,
                      image_rendering,
                      key);
 }
 
 /// Push a 3 planar yuv image.
 #[no_mangle]
 pub extern "C" fn wr_dp_push_yuv_planar_image(state: &mut WrState,
                                               bounds: LayoutRect,
                                               clip: LayoutRect,
+                                              is_backface_visible: bool,
                                               image_key_0: WrImageKey,
                                               image_key_1: WrImageKey,
                                               image_key_2: WrImageKey,
                                               color_space: WrYuvColorSpace,
                                               image_rendering: ImageRendering) {
-    assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
+    debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
 
-    let prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
+    let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder
          .dl_builder
          .push_yuv_image(&prim_info,
                          YuvData::PlanarYCbCr(image_key_0, image_key_1, image_key_2),
                          color_space,
                          image_rendering);
 }
 
 /// Push a 2 planar NV12 image.
 #[no_mangle]
 pub extern "C" fn wr_dp_push_yuv_NV12_image(state: &mut WrState,
                                             bounds: LayoutRect,
                                             clip: LayoutRect,
+                                            is_backface_visible: bool,
                                             image_key_0: WrImageKey,
                                             image_key_1: WrImageKey,
                                             color_space: WrYuvColorSpace,
                                             image_rendering: ImageRendering) {
-    assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
+    debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
 
-    let prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
+    let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder
          .dl_builder
          .push_yuv_image(&prim_info,
                          YuvData::NV12(image_key_0, image_key_1),
                          color_space,
                          image_rendering);
 }
 
 /// Push a yuv interleaved image.
 #[no_mangle]
 pub extern "C" fn wr_dp_push_yuv_interleaved_image(state: &mut WrState,
                                                    bounds: LayoutRect,
                                                    clip: LayoutRect,
+                                                   is_backface_visible: bool,
                                                    image_key_0: WrImageKey,
                                                    color_space: WrYuvColorSpace,
                                                    image_rendering: ImageRendering) {
-    assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
+    debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
 
-    let prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
+    let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder
          .dl_builder
          .push_yuv_image(&prim_info,
                          YuvData::InterleavedYCbCr(image_key_0),
                          color_space,
                          image_rendering);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_text(state: &mut WrState,
                                   bounds: LayoutRect,
                                   clip: LayoutRect,
+                                  is_backface_visible: bool,
                                   color: ColorF,
                                   font_key: WrFontInstanceKey,
                                   glyphs: *const GlyphInstance,
                                   glyph_count: u32,
                                   glyph_options: *const GlyphOptions) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
 
     let glyph_slice = make_slice(glyphs, glyph_count as usize);
 
-    let prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
+    let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder
          .dl_builder
          .push_text(&prim_info,
                     &glyph_slice,
                     font_key,
                     color,
                     unsafe { glyph_options.as_ref().cloned() });
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_text_shadow(state: &mut WrState,
                                          bounds: LayoutRect,
                                          clip: LayoutRect,
+                                         is_backface_visible: bool,
                                          shadow: TextShadow) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
 
-    let prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
+    let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(bounds, clip.into());
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder.dl_builder.push_text_shadow(&prim_info, shadow.into());
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_pop_text_shadow(state: &mut WrState) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
 
     state.frame_builder.dl_builder.pop_text_shadow();
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_line(state: &mut WrState,
                                   clip: LayoutRect,
+                                  is_backface_visible: bool,
                                   baseline: f32,
                                   start: f32,
                                   end: f32,
                                   orientation: LineOrientation,
                                   width: f32,
                                   color: ColorF,
                                   style: LineStyle) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
 
-    let prim_info = LayoutPrimitiveInfo::with_clip_rect(LayoutRect::zero(), clip.into());
+    let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(LayoutRect::zero(), clip.into());
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder
          .dl_builder
          .push_line(&prim_info,
                     baseline,
                     start,
                     end,
                     orientation,
                     width,
@@ -1437,212 +1458,226 @@ pub extern "C" fn wr_dp_push_line(state:
                     style);
 
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_border(state: &mut WrState,
                                     rect: LayoutRect,
                                     clip: LayoutRect,
+                                    is_backface_visible: bool,
                                     widths: BorderWidths,
                                     top: BorderSide,
                                     right: BorderSide,
                                     bottom: BorderSide,
                                     left: BorderSide,
                                     radius: BorderRadius) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
 
     let border_details = BorderDetails::Normal(NormalBorder {
                                                    left: left.into(),
                                                    right: right.into(),
                                                    top: top.into(),
                                                    bottom: bottom.into(),
                                                    radius: radius.into(),
                                                });
-    let prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder
          .dl_builder
          .push_border(&prim_info,
                       widths,
                       border_details);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_border_image(state: &mut WrState,
                                           rect: LayoutRect,
                                           clip: LayoutRect,
+                                          is_backface_visible: bool,
                                           widths: BorderWidths,
                                           image: WrImageKey,
                                           patch: NinePatchDescriptor,
                                           outset: SideOffsets2D<f32>,
                                           repeat_horizontal: RepeatMode,
                                           repeat_vertical: RepeatMode) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
     let border_details =
         BorderDetails::Image(ImageBorder {
                                  image_key: image,
                                  patch: patch.into(),
                                  fill: false,
                                  outset: outset.into(),
                                  repeat_horizontal: repeat_horizontal.into(),
                                  repeat_vertical: repeat_vertical.into(),
                              });
-    let prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder
          .dl_builder
          .push_border(&prim_info,
                       widths.into(),
                       border_details);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_border_gradient(state: &mut WrState,
                                              rect: LayoutRect,
                                              clip: LayoutRect,
+                                             is_backface_visible: bool,
                                              widths: BorderWidths,
                                              start_point: LayoutPoint,
                                              end_point: LayoutPoint,
                                              stops: *const GradientStop,
                                              stops_count: usize,
                                              extend_mode: ExtendMode,
                                              outset: SideOffsets2D<f32>) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
 
     let stops_slice = make_slice(stops, stops_count);
     let stops_vector = stops_slice.to_owned();
 
     let border_details = BorderDetails::Gradient(GradientBorder {
                                                      gradient:
                                                          state.frame_builder
                                                               .dl_builder
                                                               .create_gradient(start_point.into(),
                                                                                end_point.into(),
                                                                                stops_vector,
                                                                                extend_mode.into()),
                                                      outset: outset.into(),
                                                  });
-    let prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder
          .dl_builder
          .push_border(&prim_info,
                       widths.into(),
                       border_details);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_border_radial_gradient(state: &mut WrState,
                                                     rect: LayoutRect,
                                                     clip: LayoutRect,
+                                                    is_backface_visible: bool,
                                                     widths: BorderWidths,
                                                     center: LayoutPoint,
                                                     radius: LayoutSize,
                                                     stops: *const GradientStop,
                                                     stops_count: usize,
                                                     extend_mode: ExtendMode,
                                                     outset: SideOffsets2D<f32>) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
 
     let stops_slice = make_slice(stops, stops_count);
     let stops_vector = stops_slice.to_owned();
 
     let border_details =
         BorderDetails::RadialGradient(RadialGradientBorder {
                                           gradient:
                                               state.frame_builder
                                                    .dl_builder
                                                    .create_radial_gradient(center.into(),
                                                                            radius.into(),
                                                                            stops_vector,
                                                                            extend_mode.into()),
                                           outset: outset.into(),
                                       });
-    let prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder
          .dl_builder
          .push_border(&prim_info,
                       widths.into(),
                       border_details);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_linear_gradient(state: &mut WrState,
                                              rect: LayoutRect,
                                              clip: LayoutRect,
+                                             is_backface_visible: bool,
                                              start_point: LayoutPoint,
                                              end_point: LayoutPoint,
                                              stops: *const GradientStop,
                                              stops_count: usize,
                                              extend_mode: ExtendMode,
                                              tile_size: LayoutSize,
                                              tile_spacing: LayoutSize) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
 
     let stops_slice = make_slice(stops, stops_count);
     let stops_vector = stops_slice.to_owned();
 
     let gradient = state.frame_builder
                         .dl_builder
                         .create_gradient(start_point.into(),
                                          end_point.into(),
                                          stops_vector,
                                          extend_mode.into());
-    let prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder
          .dl_builder
          .push_gradient(&prim_info,
                         gradient,
                         tile_size.into(),
                         tile_spacing.into());
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_radial_gradient(state: &mut WrState,
                                              rect: LayoutRect,
                                              clip: LayoutRect,
+                                             is_backface_visible: bool,
                                              center: LayoutPoint,
                                              radius: LayoutSize,
                                              stops: *const GradientStop,
                                              stops_count: usize,
                                              extend_mode: ExtendMode,
                                              tile_size: LayoutSize,
                                              tile_spacing: LayoutSize) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
 
     let stops_slice = make_slice(stops, stops_count);
     let stops_vector = stops_slice.to_owned();
 
     let gradient = state.frame_builder
                         .dl_builder
                         .create_radial_gradient(center.into(),
                                                 radius.into(),
                                                 stops_vector,
                                                 extend_mode.into());
-    let prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder
          .dl_builder
          .push_radial_gradient(&prim_info,
                                gradient,
                                tile_size,
                                tile_spacing);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_box_shadow(state: &mut WrState,
                                         rect: LayoutRect,
                                         clip: LayoutRect,
+                                        is_backface_visible: bool,
                                         box_bounds: LayoutRect,
                                         offset: LayoutVector2D,
                                         color: ColorF,
                                         blur_radius: f32,
                                         spread_radius: f32,
                                         border_radius: f32,
                                         clip_mode: BoxShadowClipMode) {
-    assert!(unsafe { is_in_main_thread() });
+    debug_assert!(unsafe { is_in_main_thread() });
 
-    let prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    let mut prim_info = LayoutPrimitiveInfo::with_clip_rect(rect, clip.into());
+    prim_info.is_backface_visible = is_backface_visible;
     state.frame_builder
          .dl_builder
          .push_box_shadow(&prim_info,
                           box_bounds,
                           offset,
                           color,
                           blur_radius,
                           spread_radius,
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -881,66 +881,71 @@ WR_FUNC;
 WR_INLINE
 void wr_dp_pop_text_shadow(WrState *aState)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_border(WrState *aState,
                        LayoutRect aRect,
                        LayoutRect aClip,
+                       bool aIsBackfaceVisible,
                        BorderWidths aWidths,
                        BorderSide aTop,
                        BorderSide aRight,
                        BorderSide aBottom,
                        BorderSide aLeft,
                        BorderRadius aRadius)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_border_gradient(WrState *aState,
                                 LayoutRect aRect,
                                 LayoutRect aClip,
+                                bool aIsBackfaceVisible,
                                 BorderWidths aWidths,
                                 LayoutPoint aStartPoint,
                                 LayoutPoint aEndPoint,
                                 const GradientStop *aStops,
                                 size_t aStopsCount,
                                 ExtendMode aExtendMode,
                                 SideOffsets2D_f32 aOutset)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_border_image(WrState *aState,
                              LayoutRect aRect,
                              LayoutRect aClip,
+                             bool aIsBackfaceVisible,
                              BorderWidths aWidths,
                              WrImageKey aImage,
                              NinePatchDescriptor aPatch,
                              SideOffsets2D_f32 aOutset,
                              RepeatMode aRepeatHorizontal,
                              RepeatMode aRepeatVertical)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_border_radial_gradient(WrState *aState,
                                        LayoutRect aRect,
                                        LayoutRect aClip,
+                                       bool aIsBackfaceVisible,
                                        BorderWidths aWidths,
                                        LayoutPoint aCenter,
                                        LayoutSize aRadius,
                                        const GradientStop *aStops,
                                        size_t aStopsCount,
                                        ExtendMode aExtendMode,
                                        SideOffsets2D_f32 aOutset)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_box_shadow(WrState *aState,
                            LayoutRect aRect,
                            LayoutRect aClip,
+                           bool aIsBackfaceVisible,
                            LayoutRect aBoxBounds,
                            LayoutVector2D aOffset,
                            ColorF aColor,
                            float aBlurRadius,
                            float aSpreadRadius,
                            float aBorderRadius,
                            BoxShadowClipMode aClipMode)
 WR_FUNC;
@@ -960,71 +965,77 @@ WR_INLINE
 void wr_dp_push_clip_and_scroll_info(WrState *aState,
                                      uint64_t aScrollId,
                                      const uint64_t *aClipId)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_iframe(WrState *aState,
                        LayoutRect aRect,
+                       bool aIsBackfaceVisible,
                        WrPipelineId aPipelineId)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_image(WrState *aState,
                       LayoutRect aBounds,
                       LayoutRect aClip,
+                      bool aIsBackfaceVisible,
                       LayoutSize aStretchSize,
                       LayoutSize aTileSpacing,
                       ImageRendering aImageRendering,
                       WrImageKey aKey)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_line(WrState *aState,
                      LayoutRect aClip,
+                     bool aIsBackfaceVisible,
                      float aBaseline,
                      float aStart,
                      float aEnd,
                      LineOrientation aOrientation,
                      float aWidth,
                      ColorF aColor,
                      LineStyle aStyle)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_linear_gradient(WrState *aState,
                                 LayoutRect aRect,
                                 LayoutRect aClip,
+                                bool aIsBackfaceVisible,
                                 LayoutPoint aStartPoint,
                                 LayoutPoint aEndPoint,
                                 const GradientStop *aStops,
                                 size_t aStopsCount,
                                 ExtendMode aExtendMode,
                                 LayoutSize aTileSize,
                                 LayoutSize aTileSpacing)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_radial_gradient(WrState *aState,
                                 LayoutRect aRect,
                                 LayoutRect aClip,
+                                bool aIsBackfaceVisible,
                                 LayoutPoint aCenter,
                                 LayoutSize aRadius,
                                 const GradientStop *aStops,
                                 size_t aStopsCount,
                                 ExtendMode aExtendMode,
                                 LayoutSize aTileSize,
                                 LayoutSize aTileSpacing)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_rect(WrState *aState,
                      LayoutRect aRect,
                      LayoutRect aClip,
+                     bool aIsBackfaceVisible,
                      ColorF aColor)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_scroll_layer(WrState *aState,
                              uint64_t aScrollId)
 WR_FUNC;
 
@@ -1033,63 +1044,69 @@ void wr_dp_push_stacking_context(WrState
                                  LayoutRect aBounds,
                                  uint64_t aAnimationId,
                                  const float *aOpacity,
                                  const LayoutTransform *aTransform,
                                  TransformStyle aTransformStyle,
                                  const LayoutTransform *aPerspective,
                                  MixBlendMode aMixBlendMode,
                                  const WrFilterOp *aFilters,
-                                 size_t aFilterCount)
+                                 size_t aFilterCount,
+                                 bool aIsBackfaceVisible)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_text(WrState *aState,
                      LayoutRect aBounds,
                      LayoutRect aClip,
+                     bool aIsBackfaceVisible,
                      ColorF aColor,
                      WrFontInstanceKey aFontKey,
                      const GlyphInstance *aGlyphs,
                      uint32_t aGlyphCount,
                      const GlyphOptions *aGlyphOptions)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_text_shadow(WrState *aState,
                             LayoutRect aBounds,
                             LayoutRect aClip,
+                            bool aIsBackfaceVisible,
                             TextShadow aShadow)
 WR_FUNC;
 
 // Push a 2 planar NV12 image.
 WR_INLINE
 void wr_dp_push_yuv_NV12_image(WrState *aState,
                                LayoutRect aBounds,
                                LayoutRect aClip,
+                               bool aIsBackfaceVisible,
                                WrImageKey aImageKey0,
                                WrImageKey aImageKey1,
                                WrYuvColorSpace aColorSpace,
                                ImageRendering aImageRendering)
 WR_FUNC;
 
 // Push a yuv interleaved image.
 WR_INLINE
 void wr_dp_push_yuv_interleaved_image(WrState *aState,
                                       LayoutRect aBounds,
                                       LayoutRect aClip,
+                                      bool aIsBackfaceVisible,
                                       WrImageKey aImageKey0,
                                       WrYuvColorSpace aColorSpace,
                                       ImageRendering aImageRendering)
 WR_FUNC;
 
 // Push a 3 planar yuv image.
 WR_INLINE
 void wr_dp_push_yuv_planar_image(WrState *aState,
                                  LayoutRect aBounds,
                                  LayoutRect aClip,
+                                 bool aIsBackfaceVisible,
                                  WrImageKey aImageKey0,
                                  WrImageKey aImageKey1,
                                  WrImageKey aImageKey2,
                                  WrYuvColorSpace aColorSpace,
                                  ImageRendering aImageRendering)
 WR_FUNC;
 
 extern bool wr_moz2d_render_cb(ByteSlice aBlob,
--- a/layout/forms/nsButtonFrameRenderer.cpp
+++ b/layout/forms/nsButtonFrameRenderer.cpp
@@ -246,16 +246,17 @@ nsDisplayButtonBoxShadowOuter::CreateWeb
     mozilla::gfx::Point shadowOffset;
     shadowOffset.x = (shadow->mXOffset / appUnitsPerDevPixel);
     shadowOffset.y = (shadow->mYOffset / appUnitsPerDevPixel);
 
     float spreadRadius = float(shadow->mSpread) / float(appUnitsPerDevPixel);
 
     aBuilder.PushBoxShadow(deviceBoxRect,
                            deviceClipRect,
+                           !BackfaceIsHidden(),
                            deviceBoxRect,
                            wr::ToLayoutVector2D(shadowOffset),
                            wr::ToColorF(shadowColor),
                            blurRadius,
                            spreadRadius,
                            borderRadius,
                            wr::BoxShadowClipMode::Outset);
   }
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -478,16 +478,17 @@ BulletRenderer::CreateWebRenderCommandsF
   }
 
   const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
   LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(mDest, appUnitsPerDevPixel);
   wr::LayoutRect dest = aSc.ToRelativeLayoutRect(destRect);
 
   aBuilder.PushImage(dest,
                      dest,
+                     !aItem->BackfaceIsHidden(),
                      wr::ImageRendering::Auto,
                      key.value());
 }
 
 void
 BulletRenderer::CreateWebRenderCommandsForPath(nsDisplayItem* aItem,
                                                wr::DisplayListBuilder& aBuilder,
                                                wr::IpcResourceUpdateQueue& aResources,
@@ -519,17 +520,17 @@ BulletRenderer::CreateWebRenderCommandsF
   LayerRect destRect = ViewAs<LayerPixel>(
       LayoutDeviceRect::FromAppUnits(
           aItem->GetBounds(aDisplayListBuilder, &dummy), appUnitsPerDevPixel),
       PixelCastJustification::WebRenderHasUnitResolution);
 
   for (layers::GlyphArray& glyphs : mGlyphs) {
     aManager->WrBridge()->PushGlyphs(aBuilder, glyphs.glyphs(), mFont,
                                      glyphs.color().value(),
-                                     aSc, destRect, destRect);
+                                     aSc, destRect, destRect, !aItem->BackfaceIsHidden());
   }
 }
 
 class nsDisplayBullet final : public nsDisplayItem {
 public:
   nsDisplayBullet(nsDisplayListBuilder* aBuilder, nsBulletFrame* aFrame)
     : nsDisplayItem(aBuilder, aFrame)
   {
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -325,16 +325,17 @@ nsDisplayCanvasBackgroundColor::CreateWe
   int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
 
   LayoutDeviceRect rect = LayoutDeviceRect::FromAppUnits(
           bgClipRect, appUnitsPerDevPixel);
 
   wr::LayoutRect transformedRect = aSc.ToRelativeLayoutRect(rect);
   aBuilder.PushRect(transformedRect,
                     transformedRect,
+                    !BackfaceIsHidden(),
                     wr::ToColorF(ToDeviceColor(mColor)));
   return true;
 }
 
 #ifdef MOZ_DUMP_PAINTING
 void
 nsDisplayCanvasBackgroundColor::WriteDebugInfo(std::stringstream& aStream)
 {
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -170,17 +170,17 @@ public:
         // We don't push a stacking context for this async image pipeline here.
         // Instead, we do it inside the iframe that hosts the image. As a result,
         // a bunch of the calculations normally done as part of that stacking
         // context need to be done manually and pushed over to the parent side,
         // where it will be done when we build the display list for the iframe.
         // That happens in WebRenderCompositableHolder.
 
         wr::LayoutRect r = aSc.ToRelativeLayoutRect(bounds);
-        aBuilder.PushIFrame(r, data->GetPipelineId().ref());
+        aBuilder.PushIFrame(r, !BackfaceIsHidden(), data->GetPipelineId().ref());
 
         gfx::Matrix4x4 scTransform;
         if (data->NeedsYFlip()) {
           scTransform = scTransform.PreTranslate(0, data->GetSize().height, 0).PreScale(1, -1, 1);
         }
 
         gfxRect destGFXRect = mFrame->PresContext()->AppUnitsToGfxUnits(dest);
         scTransform.PreScale(destGFXRect.Width() / canvasSizeInPx.width,
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -5197,53 +5197,55 @@ nsDisplayText::CreateWebRenderCommands(m
     layoutClipRect = LayoutDeviceRect::FromAppUnits(
                 GetClip().GetClipRect(), appUnitsPerDevPixel);
   }
 
   LayerRect boundsRect = LayerRect::FromUnknownRect(layoutBoundsRect.ToUnknownRect());
   LayerRect clipRect = LayerRect::FromUnknownRect(layoutClipRect.ToUnknownRect());
   wr::LayoutRect wrClipRect = aSc.ToRelativeLayoutRect(clipRect); // wr::ToLayoutRect(clipRect);
   wr::LayoutRect wrBoundsRect = aSc.ToRelativeLayoutRect(boundsRect); //wr::ToLayoutRect(boundsRect);
+  bool backfaceVisible = !BackfaceIsHidden();
 
   // Drawing order: selections, shadows,
   //                underline, overline, [grouped in one array]
   //                text, emphasisText,  [grouped in one array]
   //                lineThrough
 
   for (auto& part : mTextDrawer->GetParts()) {
     if (part.selection) {
       auto selection = part.selection.value();
-      aBuilder.PushRect(selection.rect, wrClipRect, selection.color);
+      aBuilder.PushRect(selection.rect, wrClipRect, backfaceVisible, selection.color);
     }
   }
 
   for (auto& part : mTextDrawer->GetParts()) {
     // WR takes the shadows in CSS-order (reverse of rendering order),
     // because the drawing of a shadow actually occurs when it's popped.
     for (const wr::TextShadow& shadow : part.shadows) {
-      aBuilder.PushTextShadow(wrBoundsRect, wrClipRect, shadow);
+      aBuilder.PushTextShadow(wrBoundsRect, wrClipRect, backfaceVisible, shadow);
     }
 
     for (const wr::Line& decoration : part.beforeDecorations) {
-      aBuilder.PushLine(wrClipRect, decoration);
+      aBuilder.PushLine(wrClipRect, backfaceVisible, decoration);
     }
 
     for (const mozilla::layout::TextRunFragment& text : part.text) {
       // mOpacity is set after we do our analysis, so we need to apply it here.
       // mOpacity is only non-trivial when we have "pure" text, so we don't
       // ever need to apply it to shadows or decorations.
       auto color = text.color;
       color.a *= mOpacity;
 
       aManager->WrBridge()->PushGlyphs(aBuilder, text.glyphs, text.font,
-                                       color, aSc, boundsRect, clipRect);
+                                       color, aSc, boundsRect, clipRect,
+                                       backfaceVisible);
     }
 
     for (const wr::Line& decoration : part.afterDecorations) {
-      aBuilder.PushLine(wrClipRect, decoration);
+      aBuilder.PushLine(wrClipRect, backfaceVisible, decoration);
     }
 
     for (size_t i = 0; i < part.shadows.Length(); ++i) {
       aBuilder.PopTextShadow();
     }
   }
 
   return true;
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -392,16 +392,17 @@ nsDisplayRemote::CreateWebRenderCommands
 
   mOffset = mozilla::layout::GetContentRectLayerOffset(mFrame, aDisplayListBuilder);
 
   mozilla::LayoutDeviceRect visible = mozilla::LayoutDeviceRect::FromAppUnits(
       GetVisibleRect(), mFrame->PresContext()->AppUnitsPerDevPixel());
   visible += mOffset;
 
   aBuilder.PushIFrame(aSc.ToRelativeLayoutRect(visible),
+      !BackfaceIsHidden(),
       mozilla::wr::AsPipelineId(GetRemoteLayersId()));
 
   return true;
 }
 
 bool
 nsDisplayRemote::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
                                   mozilla::layers::WebRenderLayerScrollData* aLayerData)
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -781,17 +781,18 @@ ConstructBorderRenderer(nsPresContext* a
                              aDrawTarget,
                              dirtyRect,
                              joinedBorderAreaPx,
                              borderStyles,
                              borderWidths,
                              bgRadii,
                              borderColors,
                              aStyleBorder.mBorderColors.get(),
-                             bgColor);
+                             bgColor,
+                             !aForFrame->BackfaceIsHidden());
 }
 
 
 DrawResult
 nsCSSRendering::PaintBorderWithStyleBorder(nsPresContext* aPresContext,
                                            gfxContext& aRenderingContext,
                                            nsIFrame* aForFrame,
                                            const nsRect& aDirtyRect,
@@ -1060,17 +1061,18 @@ nsCSSRendering::CreateBorderRendererForO
                          dt,
                          dirtyRect,
                          oRect,
                          outlineStyles,
                          outlineWidths,
                          outlineRadii,
                          outlineColors,
                          nullptr,
-                         bgColor);
+                         bgColor,
+                         !aForFrame->BackfaceIsHidden());
 
   return Some(br);
 }
 
 void
 nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
                              gfxContext& aRenderingContext,
                              nsIFrame* aForFrame,
@@ -1122,27 +1124,31 @@ nsCSSRendering::PaintFocus(nsPresContext
   nscolor focusColors[4] = { aColor, aColor, aColor, aColor };
 
   // Because this renders a dotted border, the background color
   // should not be used.  Therefore, we provide a value that will
   // be blatantly wrong if it ever does get used.  (If this becomes
   // something that CSS can style, this function will then have access
   // to a style context and can use the same logic that PaintBorder
   // and PaintOutline do.)
+  //
+  // WebRender layers-free mode don't use PaintFocus function. Just assign
+  // the backface-visibility to true for this case.
   nsCSSBorderRenderer br(aPresContext,
                          nullptr,
                          aDrawTarget,
                          focusRect,
                          focusRect,
                          focusStyles,
                          focusWidths,
                          focusRadii,
                          focusColors,
                          nullptr,
-                         NS_RGB(255, 0, 0));
+                         NS_RGB(255, 0, 0),
+                         true);
   br.DrawBorders();
 
   PrintAsStringNewline();
 }
 
 // Thebes Border Rendering Code End
 //----------------------------------------------------------------------
 
--- a/layout/painting/nsCSSRenderingBorders.cpp
+++ b/layout/painting/nsCSSRenderingBorders.cpp
@@ -171,24 +171,26 @@ nsCSSBorderRenderer::nsCSSBorderRenderer
                                          DrawTarget* aDrawTarget,
                                          const Rect& aDirtyRect,
                                          Rect& aOuterRect,
                                          const uint8_t* aBorderStyles,
                                          const Float* aBorderWidths,
                                          RectCornerRadii& aBorderRadii,
                                          const nscolor* aBorderColors,
                                          const nsBorderColors* aCompositeColors,
-                                         nscolor aBackgroundColor)
+                                         nscolor aBackgroundColor,
+                                         bool aBackfaceIsVisible)
   : mPresContext(aPresContext),
     mDocument(aDocument),
     mDrawTarget(aDrawTarget),
     mDirtyRect(aDirtyRect),
     mOuterRect(aOuterRect),
     mBorderRadii(aBorderRadii),
-    mBackgroundColor(aBackgroundColor)
+    mBackgroundColor(aBackgroundColor),
+    mBackfaceIsVisible(aBackfaceIsVisible)
 {
   PodCopy(mBorderStyles, aBorderStyles, 4);
   PodCopy(mBorderWidths, aBorderWidths, 4);
   PodCopy(mBorderColors, aBorderColors, 4);
   NS_FOR_CSS_SIDES(side) {
     if (aCompositeColors && !(*aCompositeColors)[side].IsEmpty()) {
       mCompositeColors[side] = &(*aCompositeColors)[side];
     } else {
@@ -3612,16 +3614,17 @@ nsCSSBorderRenderer::CreateWebRenderComm
 
   wr::BorderRadius borderRadius = wr::ToBorderRadius(LayerSize(mBorderRadii[0].width, mBorderRadii[0].height),
                                                      LayerSize(mBorderRadii[1].width, mBorderRadii[1].height),
                                                      LayerSize(mBorderRadii[3].width, mBorderRadii[3].height),
                                                      LayerSize(mBorderRadii[2].width, mBorderRadii[2].height));
   Range<const wr::BorderSide> wrsides(side, 4);
   aBuilder.PushBorder(transformedRect,
                       transformedRect,
+                      mBackfaceIsVisible,
                       wr::ToBorderWidths(mBorderWidths[0], mBorderWidths[1], mBorderWidths[2], mBorderWidths[3]),
                       wrsides,
                       borderRadius);
 }
 
 /* static */Maybe<nsCSSBorderImageRenderer>
 nsCSSBorderImageRenderer::CreateBorderImageRenderer(nsPresContext* aPresContext,
                                                     nsIFrame* aForFrame,
--- a/layout/painting/nsCSSRenderingBorders.h
+++ b/layout/painting/nsCSSRenderingBorders.h
@@ -96,17 +96,18 @@ public:
                       DrawTarget* aDrawTarget,
                       const Rect& aDirtyRect,
                       Rect& aOuterRect,
                       const uint8_t* aBorderStyles,
                       const Float* aBorderWidths,
                       RectCornerRadii& aBorderRadii,
                       const nscolor* aBorderColors,
                       const nsBorderColors* aCompositeColors,
-                      nscolor aBackgroundColor);
+                      nscolor aBackgroundColor,
+                      bool aBackfaceIsVisible);
 
   // draw the entire border
   void DrawBorders();
 
   bool CanCreateWebRenderCommands();
   void CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                mozilla::wr::IpcResourceUpdateQueue& aResources,
                                const mozilla::layers::StackingContextHelper& aSc);
@@ -159,16 +160,17 @@ private:
   nscolor mBackgroundColor;
 
   // calculated values
   bool mAllBordersSameStyle;
   bool mAllBordersSameWidth;
   bool mOneUnitBorder;
   bool mNoBorderRadius;
   bool mAvoidStroke;
+  bool mBackfaceIsVisible;
 
   // For all the sides in the bitmask, would they be rendered
   // in an identical color and style?
   bool AreBorderSideFinalStylesSame(uint8_t aSides);
 
   // For the given style, is the given corner a solid color?
   bool IsSolidCornerStyle(uint8_t aStyle, mozilla::Corner aCorner);
 
--- a/layout/painting/nsCSSRenderingGradients.cpp
+++ b/layout/painting/nsCSSRenderingGradients.cpp
@@ -1026,16 +1026,17 @@ nsCSSGradientRenderer::BuildWebRenderPar
 void
 nsCSSGradientRenderer::BuildWebRenderDisplayItems(wr::DisplayListBuilder& aBuilder,
                                                   const layers::StackingContextHelper& aSc,
                                                   layers::WebRenderDisplayItemLayer* aLayer,
                                                   const nsRect& aDest,
                                                   const nsRect& aFillArea,
                                                   const nsSize& aRepeatSize,
                                                   const CSSIntRect& aSrc,
+                                                  bool aIsBackfaceVisible,
                                                   float aOpacity)
 {
   if (aDest.IsEmpty() || aFillArea.IsEmpty()) {
     return;
   }
 
   wr::ExtendMode extendMode;
   nsTArray<wr::GradientStop> stops;
@@ -1080,29 +1081,31 @@ nsCSSGradientRenderer::BuildWebRenderDis
 
   if (mGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR) {
     lineEnd.x = (lineEnd.x - srcTransform.x) * srcTransform.width;
     lineEnd.y = (lineEnd.y - srcTransform.y) * srcTransform.height;
 
     aBuilder.PushLinearGradient(
       wrGradientBounds,
       wrClipBounds,
+      aIsBackfaceVisible,
       mozilla::wr::ToLayoutPoint(lineStart),
       mozilla::wr::ToLayoutPoint(lineEnd),
       stops,
       extendMode,
       mozilla::wr::ToLayoutSize(layerFirstTileSize),
       mozilla::wr::ToLayoutSize(tileSpacing));
   } else {
     gradientRadius.width *= srcTransform.width;
     gradientRadius.height *= srcTransform.height;
 
     aBuilder.PushRadialGradient(
       wrGradientBounds,
       wrClipBounds,
+      aIsBackfaceVisible,
       mozilla::wr::ToLayoutPoint(lineStart),
       mozilla::wr::ToLayoutSize(gradientRadius),
       stops,
       extendMode,
       mozilla::wr::ToLayoutSize(layerFirstTileSize),
       mozilla::wr::ToLayoutSize(tileSpacing));
   }
 }
--- a/layout/painting/nsCSSRenderingGradients.h
+++ b/layout/painting/nsCSSRenderingGradients.h
@@ -82,16 +82,17 @@ public:
    */
   void BuildWebRenderDisplayItems(wr::DisplayListBuilder& aBuilder,
                                   const layers::StackingContextHelper& aSc,
                                   layers::WebRenderDisplayItemLayer* aLayer,
                                   const nsRect& aDest,
                                   const nsRect& aFill,
                                   const nsSize& aRepeatSize,
                                   const mozilla::CSSIntRect& aSrc,
+                                  bool aIsBackfaceVisible,
                                   float aOpacity = 1.0);
 
 private:
   nsCSSGradientRenderer() {}
 
   nsPresContext* mPresContext;
   nsStyleGradient* mGradient;
   nsTArray<ColorStop> mStops;
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -2941,16 +2941,17 @@ nsDisplaySolidColor::CreateWebRenderComm
   }
 
   LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
         mVisibleRect, mFrame->PresContext()->AppUnitsPerDevPixel());
   wr::LayoutRect transformedRect = aSc.ToRelativeLayoutRect(bounds);
 
   aBuilder.PushRect(transformedRect,
                     transformedRect,
+                    !BackfaceIsHidden(),
                     wr::ToColorF(ToDeviceColor(mColor)));
 
   return true;
 }
 
 nsRect
 nsDisplaySolidColorRegion::GetBounds(nsDisplayListBuilder* aBuilder,
                                      bool* aSnap) const
@@ -2992,16 +2993,17 @@ nsDisplaySolidColorRegion::CreateWebRend
 {
   for (auto iter = mRegion.RectIter(); !iter.Done(); iter.Next()) {
     nsRect rect = iter.Get();
     LayoutDeviceRect layerRects = LayoutDeviceRect::FromAppUnits(
       rect, mFrame->PresContext()->AppUnitsPerDevPixel());
     wr::LayoutRect transformedRect = aSc.ToRelativeLayoutRect(layerRects);
     aBuilder.PushRect(transformedRect,
                       transformedRect,
+                      !BackfaceIsHidden(),
                       wr::ToColorF(ToDeviceColor(mColor)));
   }
 
   return true;
 }
 
 static void
 RegisterThemeGeometry(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
@@ -4261,16 +4263,17 @@ nsDisplayBackgroundColor::CreateWebRende
   }
 
   LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
         mBackgroundRect, mFrame->PresContext()->AppUnitsPerDevPixel());
   wr::LayoutRect transformedRect = aSc.ToRelativeLayoutRect(bounds);
 
   aBuilder.PushRect(transformedRect,
                     transformedRect,
+                    !BackfaceIsHidden(),
                     wr::ToColorF(ToDeviceColor(mColor)));
 
   return true;
 }
 
 void
 nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder,
                                 gfxContext* aCtx)
@@ -4780,21 +4783,23 @@ nsDisplayCaret::CreateWebRenderCommands(
     hookRect + ToReferenceFrame(), appUnitsPerDevPixel);
 
   wr::LayoutRect caret = aSc.ToRelativeLayoutRect(devCaretRect);
   wr::LayoutRect hook = aSc.ToRelativeLayoutRect(devHookRect);
 
   // Note, WR will pixel snap anything that is layout aligned.
   aBuilder.PushRect(caret,
                     caret,
+                    !BackfaceIsHidden(),
                     wr::ToColorF(color));
 
   if (!devHookRect.IsEmpty()) {
     aBuilder.PushRect(hook,
                       hook,
+                      !BackfaceIsHidden(),
                       wr::ToColorF(color));
   }
   return true;
 }
 
 LayerState
 nsDisplayCaret::GetLayerState(nsDisplayListBuilder* aBuilder,
                               LayerManager* aManager,
@@ -5083,16 +5088,17 @@ nsDisplayBorder::CreateBorderImageWebRen
       gfx::IntSize size;
       Maybe<wr::ImageKey> key = aManager->CreateImageKey(this, container, aBuilder, aResources, aSc, size);
       if (key.isNothing()) {
         return;
       }
 
       aBuilder.PushBorderImage(dest,
                                clip,
+                               !BackfaceIsHidden(),
                                wr::ToBorderWidths(widths[0], widths[1], widths[2], widths[3]),
                                key.value(),
                                wr::ToNinePatchDescriptor(
                                  (float)(mBorderImageRenderer->mImageSize.width) / appUnitsPerDevPixel,
                                  (float)(mBorderImageRenderer->mImageSize.height) / appUnitsPerDevPixel,
                                  wr::ToSideOffsets2D_u32(slice[0], slice[1], slice[2], slice[3])),
                                wr::ToSideOffsets2D_f32(outset[0], outset[1], outset[2], outset[3]),
                                wr::ToRepeatMode(mBorderImageRenderer->mRepeatModeHorizontal),
@@ -5116,25 +5122,27 @@ nsDisplayBorder::CreateBorderImageWebRen
       if (gradientData->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR) {
         LayerPoint startPoint = LayerPoint(dest.origin.x, dest.origin.y);
         startPoint = startPoint + ViewAs<LayerPixel>(lineStart, PixelCastJustification::WebRenderHasUnitResolution);
         LayerPoint endPoint = LayerPoint(dest.origin.x, dest.origin.y);
         endPoint = endPoint + ViewAs<LayerPixel>(lineEnd, PixelCastJustification::WebRenderHasUnitResolution);
 
         aBuilder.PushBorderGradient(dest,
                                     clip,
+                                    !BackfaceIsHidden(),
                                     wr::ToBorderWidths(widths[0], widths[1], widths[2], widths[3]),
                                     wr::ToLayoutPoint(startPoint),
                                     wr::ToLayoutPoint(endPoint),
                                     stops,
                                     extendMode,
                                     wr::ToSideOffsets2D_f32(outset[0], outset[1], outset[2], outset[3]));
       } else {
         aBuilder.PushBorderRadialGradient(dest,
                                           clip,
+                                          !BackfaceIsHidden(),
                                           wr::ToBorderWidths(widths[0], widths[1], widths[2], widths[3]),
                                           wr::ToLayoutPoint(lineStart),
                                           wr::ToLayoutSize(gradientRadius),
                                           stops,
                                           extendMode,
                                           wr::ToSideOffsets2D_f32(outset[0], outset[1], outset[2], outset[3]));
       }
       break;
@@ -5447,16 +5455,17 @@ nsDisplayBoxShadowOuter::CreateWebRender
 
       // TODO: support non-uniform border radius.
       float borderRadius = hasBorderRadius ? borderRadii.TopLeft().width
                                            : 0.0;
       float spreadRadius = float(shadow->mSpread) / float(appUnitsPerDevPixel);
 
       aBuilder.PushBoxShadow(deviceBoxRect,
                              deviceClipRect,
+                             !BackfaceIsHidden(),
                              deviceBoxRect,
                              wr::ToLayoutVector2D(shadowOffset),
                              wr::ToColorF(shadowColor),
                              blurRadius,
                              spreadRadius,
                              borderRadius,
                              wr::BoxShadowClipMode::Outset);
     }
@@ -5619,16 +5628,17 @@ nsDisplayBoxShadowInner::CreateInsetBoxS
       float blurRadius = float(shadowItem->mRadius) / float(appUnitsPerDevPixel);
       // TODO: WR doesn't support non-uniform border radii
       float borderRadius = innerRadii.TopLeft().width;
       // NOTE: Any spread radius > 0 will render nothing. WR Bug.
       float spreadRadius = float(shadowItem->mSpread) / float(appUnitsPerDevPixel);
 
       aBuilder.PushBoxShadow(wr::ToLayoutRect(deviceBoxRect),
                              deviceClipRect,
+                             !aFrame->BackfaceIsHidden(),
                              wr::ToLayoutRect(deviceBoxRect),
                              wr::ToLayoutVector2D(shadowOffset),
                              wr::ToColorF(shadowColor),
                              blurRadius,
                              spreadRadius,
                              borderRadius,
                              wr::BoxShadowClipMode::Inset
                              );
@@ -7938,17 +7948,19 @@ nsDisplayTransform::CreateWebRenderComma
                            aDisplayListBuilder,
                            this,
                            mStoredList.GetChildren(),
                            &boundTransform,
                            animationsId,
                            nullptr,
                            transformForSC,
                            nullptr,
-                           filters);
+                           filters,
+                           gfx::CompositionOp::OP_OVER,
+                           !BackfaceIsHidden());
 
   return mStoredList.CreateWebRenderCommands(aBuilder, aResources, sc,
                                              aManager, aDisplayListBuilder);
 }
 
 bool
 nsDisplayTransform::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
                                      mozilla::layers::WebRenderLayerScrollData* aLayerData)
@@ -8543,17 +8555,19 @@ nsDisplayPerspective::CreateWebRenderCom
                            aDisplayListBuilder,
                            this,
                            mList.GetChildren(),
                            nullptr,
                            0,
                            nullptr,
                            &transformForSC,
                            &perspectiveMatrix,
-                           filters);
+                           filters,
+                           gfx::CompositionOp::OP_OVER,
+                           !BackfaceIsHidden());
 
   return mList.CreateWebRenderCommands(aBuilder, aResources, sc,
                                        aManager, aDisplayListBuilder);
 }
 
 int32_t
 nsDisplayPerspective::ZIndex() const
 {
--- a/layout/painting/nsImageRenderer.cpp
+++ b/layout/painting/nsImageRenderer.cpp
@@ -610,17 +610,18 @@ nsImageRenderer::BuildWebRenderDisplayIt
   }
 
   switch (mType) {
     case eStyleImageType_Gradient:
     {
       nsCSSGradientRenderer renderer =
         nsCSSGradientRenderer::Create(aPresContext, mGradientData, mSize);
 
-      renderer.BuildWebRenderDisplayItems(aBuilder, aSc, aLayer, aDest, aFill, aRepeatSize, aSrc, aOpacity);
+      renderer.BuildWebRenderDisplayItems(aBuilder, aSc, aLayer, aDest, aFill,
+                                          aRepeatSize, aSrc, !aItem->BackfaceIsHidden(), aOpacity);
       break;
     }
     case eStyleImageType_Image:
     {
       // XXX(aosmond): We will support downscale-on-decode in bug 1368776. Until
       // then, don't pass FLAG_HIGH_QUALITY_SCALING.
       uint32_t containerFlags = imgIContainer::FLAG_NONE;
       if (mFlags & nsImageRenderer::FLAG_SYNC_DECODE_IMAGES) {
@@ -654,17 +655,17 @@ nsImageRenderer::BuildWebRenderDisplayIt
       wr::LayoutRect fill = aSc.ToRelativeLayoutRect(fillRect);
       wr::LayoutRect clip = aSc.ToRelativeLayoutRect(
           LayoutDeviceRect::FromAppUnits(aFill, appUnitsPerDevPixel));
 
       LayoutDeviceSize gapSize = LayoutDeviceSize::FromAppUnits(
           aRepeatSize - aDest.Size(), appUnitsPerDevPixel);
 
       SamplingFilter samplingFilter = nsLayoutUtils::GetSamplingFilterForFrame(mForFrame);
-      aBuilder.PushImage(fill, clip,
+      aBuilder.PushImage(fill, clip, !aItem->BackfaceIsHidden(),
                          wr::ToLayoutSize(destRect.Size()), wr::ToLayoutSize(gapSize),
                          wr::ToImageRendering(samplingFilter), key.value());
       break;
     }
     default:
       break;
   }
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-bordercollapse/bug1394226-notref.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Table border collapse</title>
+<style>
+  table {
+    border-collapse: collapse;
+  }
+  tr.odd {
+    background-color: LightCyan;
+  }
+  tr.even {
+    background-color: LightSkyBlue;
+  }
+  td {
+    border: 5px solid DarkBlue;
+  }
+  .inner td {
+    border: 5px solid red;
+  }
+  .inner tr:first-child td {
+    border-top: 5px solid DarkBlue;
+  }
+  .inner tr td:first-child {
+    border-left: 5px solid DarkBlue;
+  }
+  .inner tr:last-child td {
+    border-bottom: 5px solid DarkBlue;
+  }
+  .inner tr td:last-child {
+    border-right: 5px solid DarkBlue;
+  }
+  div {
+    height: 10px;
+  }
+</style>
+</head>
+<body>
+  <div></div>
+  <table>
+    <caption></caption>
+    <tr class="odd">
+      <td>Cell 1-1</td>
+      <td>Cell 1-2</td>
+    </tr>
+    <tr class="even">
+      <td>Cell 2-1</td>
+      <td>Cell 2-2
+        <table class="inner">
+          <tr class="odd">
+            <td>Cell 2-2/1-1</td>
+            <td>Cell 2-2/1-2</td>
+          </tr>
+          <tr class="even">
+            <td>Cell 2-2/2-1</td>
+            <td>Cell 2-2/2-2</td>
+          </tr>
+        </table>
+      </td>
+    </tr>
+  </table>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-bordercollapse/bug1394226-ref.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Table border collapse</title>
+<style>
+  table {
+    border-collapse: collapse;
+  }
+  tr.odd {
+    background-color: LightCyan;
+  }
+  tr.even {
+    background-color: LightSkyBlue;
+  }
+  td {
+    border: 5px solid DarkBlue;
+  }
+  div {
+    height: 10px;
+  }
+</style>
+</head>
+<body>
+  <div></div>
+  <table>
+    <tr class="odd">
+      <td>Cell 1-1</td>
+      <td>Cell 1-2</td>
+    </tr>
+    <tr class="even">
+      <td>Cell 2-1</td>
+      <td>Cell 2-2
+        <table>
+          <tr class="odd">
+            <td>Cell 2-2/1-1</td>
+            <td>Cell 2-2/1-2</td>
+          </tr>
+          <tr class="even">
+            <td>Cell 2-2/2-1</td>
+            <td>Cell 2-2/2-2</td>
+          </tr>
+        </table>
+      </td>
+    </tr>
+  </table>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-bordercollapse/bug1394226.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Table border collapse</title>
+<style>
+  table {
+    border-collapse: collapse;
+  }
+  tr.odd {
+    background-color: LightCyan;
+  }
+  tr.even {
+    background-color: LightSkyBlue;
+  }
+  td {
+    border: 5px solid DarkBlue;
+  }
+  caption {
+    height: 10px
+  }
+</style>
+</head>
+<body>
+  <table>
+    <caption></caption>
+    <tr class="odd">
+      <td>Cell 1-1</td>
+      <td>Cell 1-2</td>
+    </tr>
+    <tr class="even">
+      <td>Cell 2-1</td>
+      <td>Cell 2-2
+        <table>
+          <tr class="odd">
+            <td>Cell 2-2/1-1</td>
+            <td>Cell 2-2/1-2</td>
+          </tr>
+          <tr class="even">
+            <td>Cell 2-2/2-1</td>
+            <td>Cell 2-2/2-2</td>
+          </tr>
+        </table>
+      </td>
+    </tr>
+  </table>
+</body>
+</html>
--- a/layout/reftests/table-bordercollapse/reftest.list
+++ b/layout/reftests/table-bordercollapse/reftest.list
@@ -1,14 +1,16 @@
 == bug1375518.html bug1375518-ref.html
 == bug1375518-2.html bug1375518-ref.html
 == bug1375518-3.html bug1375518-ref.html
 == bug1375518-4.html bug1375518-4-ref.html
 == bug1375518-5.html bug1375518-5-ref.html
 == bug1379306.html bug1379306-ref.html
+== bug1394226.html bug1394226-ref.html
+!= bug1394226.html bug1394226-notref.html
 == bc_dyn_cell1.html bc_dyn_cell1_ref.html
 == bc_dyn_cell2.html bc_dyn_cell2_ref.html
 == bc_dyn_cell3.html bc_dyn_cell3_ref.html
 == bc_dyn_cell4.html bc_dyn_cell4_ref.html
 == bc_dyn_cell5.html bc_dyn_cell5_ref.html
 == bc_dyn_row1.html bc_dyn_rg1_ref.html
 == bc_dyn_row2.html bc_dyn_rg2_ref.html
 == bc_dyn_row3.html bc_dyn_rg3_ref.html
--- a/layout/reftests/transform-3d/reftest.list
+++ b/layout/reftests/transform-3d/reftest.list
@@ -34,19 +34,19 @@ fuzzy-if(winWidget,143,689) fuzzy-if(OSX
 == translatez-1a.html translatez-1-ref.html
 != translatez-1b.html translatez-1-ref.html
 == translate3d-1a.html translate3d-1-ref.html
 fuzzy-if(skiaContent,1,4) == matrix3d-1a.html matrix3d-1-ref.html
 == matrix3d-2a.html matrix3d-2-ref.html
 == rotate3d-1a.html rotatex-1-ref.html
 == rotate3d-2a.html rotatey-1-ref.html
 != backface-visibility-1a.html about:blank
-fails-if(webrender) == backface-visibility-1b.html about:blank
-fails-if(webrender) == backface-visibility-1c.html about:blank
-fuzzy-if(winWidget&&!layersGPUAccelerated,1,251) fails-if(webrender) == backface-visibility-2.html backface-visibility-2-ref.html
+== backface-visibility-1b.html about:blank
+== backface-visibility-1c.html about:blank
+fuzzy-if(winWidget&&!layersGPUAccelerated,1,251) == backface-visibility-2.html backface-visibility-2-ref.html
 == backface-visibility-3.html backface-visibility-3-ref.html
 fails-if(webrender) == perspective-clipping-1.html perspective-clipping-1-ref.html
 == perspective-clipping-2.html perspective-clipping-2-ref.html
 != perspective-origin-1a.html rotatex-perspective-1a.html
 fuzzy-if(webrender,0-1,0-1) == perspective-origin-1b.html perspective-origin-1a.html
 fuzzy(3,99) random-if(Android&&!browserIsRemote) == perspective-origin-2a.html perspective-origin-2-ref.html # subpixel AA, bug 732568
 fuzzy-if(winWidget&&!layersGPUAccelerated,1,61) == perspective-origin-3a.html perspective-origin-3-ref.html
 == perspective-origin-4a.html perspective-origin-4-ref.html
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -1600,16 +1600,18 @@ nsTableFrame::DisplayGenericTablePart(ns
 
     // Paint the inset box-shadows for the table frames
     if (aFrame->StyleEffects()->mBoxShadow) {
       aLists.BorderBackground()->AppendNewToTop(
         new (aBuilder) nsDisplayBoxShadowInner(aBuilder, aFrame));
     }
   }
 
+  aFrame->DisplayOutline(aBuilder, aLists);
+
   aTraversal(aBuilder, aFrame, aLists);
 
   if (isVisible) {
     if (isTable) {
       nsTableFrame* table = static_cast<nsTableFrame*>(aFrame);
       // In the collapsed border model, overlay all collapsed borders.
       if (table->IsBorderCollapse()) {
         if (table->HasBCBorders()) {
@@ -1620,18 +1622,16 @@ nsTableFrame::DisplayGenericTablePart(ns
         const nsStyleBorder* borderStyle = aFrame->StyleBorder();
         if (borderStyle->HasBorder()) {
           aLists.BorderBackground()->AppendNewToTop(
             new (aBuilder) nsDisplayBorder(aBuilder, table));
         }
       }
     }
   }
-
-  aFrame->DisplayOutline(aBuilder, aLists);
 }
 
 // table paint code is concerned primarily with borders and bg color
 // SEC: TODO: adjust the rect for captions
 void
 nsTableFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                const nsDisplayListSet& aLists)
 {
@@ -6494,16 +6494,17 @@ struct BCBorderParameters
   nscolor mBorderColor;
   nscolor mBGColor;
   nsRect mBorderRect;
   int32_t mAppUnitsPerDevPixel;
   mozilla::Side mStartBevelSide;
   nscoord mStartBevelOffset;
   mozilla::Side mEndBevelSide;
   nscoord mEndBevelOffset;
+  bool mBackfaceIsVisible;
 };
 
 struct BCBlockDirSeg
 {
   BCBlockDirSeg();
 
   void Start(BCPaintBorderIterator& aIter,
              BCBorderOwner          aBorderOwner,
@@ -7321,16 +7322,17 @@ BCBlockDirSeg::BuildBorderParameters(BCP
     aIter.IsDamageAreaIEndMost() ? eLogicalSideIEnd : eLogicalSideIStart;
   int32_t relColIndex = aIter.GetRelativeColIndex();
   nsTableColFrame* col           = mCol; if (!col) ABORT1(Nothing());
   nsTableCellFrame* cell         = mFirstCell; // ???
   nsIFrame* owner = nullptr;
   result.mBorderStyle = NS_STYLE_BORDER_STYLE_SOLID;
   result.mBorderColor = 0xFFFFFFFF;
   result.mBGColor = aIter.mTableBgColor;
+  result.mBackfaceIsVisible = true;
 
   // All the tables frames have the same presContext, so we just use any one
   // that exists here:
   nsPresContext* presContext = aIter.mTable->PresContext();
   result.mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
 
   switch (mOwner) {
     case eTableOwner:
@@ -7377,16 +7379,17 @@ BCBlockDirSeg::BuildBorderParameters(BCP
       cell = mAjaCell;
       MOZ_FALLTHROUGH;
     case eCellOwner:
       owner = cell;
       break;
   }
   if (owner) {
     ::GetPaintStyleInfo(owner, aIter.mTableWM, side, &result.mBorderStyle, &result.mBorderColor);
+    result.mBackfaceIsVisible = !owner->BackfaceIsHidden();
   }
   BCPixelSize smallHalf, largeHalf;
   DivideBCBorderSize(mWidth, smallHalf, largeHalf);
   LogicalRect segRect(aIter.mTableWM,
                  mOffsetI - presContext->DevPixelsToAppUnits(largeHalf),
                  mOffsetB,
                  presContext->DevPixelsToAppUnits(mWidth), mLength);
   nscoord bEndBevelOffset = (mIsBEndBevel) ?
@@ -7477,16 +7480,17 @@ BCBlockDirSeg::CreateWebRenderCommands(B
   // each side to width of rect is fine.
   wr::BorderWidths borderWidths = wr::ToBorderWidths(transformedRect.size.width,
                                                      transformedRect.size.width,
                                                      transformedRect.size.width,
                                                      transformedRect.size.width);
   Range<const wr::BorderSide> wrsides(wrSide, 4);
   aBuilder.PushBorder(transformedRect,
                       transformedRect,
+                      param->mBackfaceIsVisible,
                       borderWidths,
                       wrsides,
                       borderRadii);
 }
 
 /**
  * Advance the start point of a segment
  */
@@ -7589,16 +7593,17 @@ BCInlineDirSeg::BuildBorderParameters(BC
   // get the border style, color and paint the segment
   LogicalSide side =
     aIter.IsDamageAreaBEndMost() ? eLogicalSideBEnd : eLogicalSideBStart;
   nsIFrame* rg   = aIter.mRg;  if (!rg) ABORT1(Nothing());
   nsIFrame* row  = aIter.mRow; if (!row) ABORT1(Nothing());
   nsIFrame* cell = mFirstCell;
   nsIFrame* col;
   nsIFrame* owner = nullptr;
+  result.mBackfaceIsVisible = true;
 
   // All the tables frames have the same presContext, so we just use any one
   // that exists here:
   nsPresContext* presContext = aIter.mTable->PresContext();
   result.mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
 
   result.mBorderStyle = NS_STYLE_BORDER_STYLE_SOLID;
   result.mBorderColor = 0xFFFFFFFF;
@@ -7647,16 +7652,17 @@ BCInlineDirSeg::BuildBorderParameters(BC
       cell = mAjaCell;
       MOZ_FALLTHROUGH;
     case eCellOwner:
       owner = cell;
       break;
   }
   if (owner) {
     ::GetPaintStyleInfo(owner, aIter.mTableWM, side, &result.mBorderStyle, &result.mBorderColor);
+    result.mBackfaceIsVisible = !owner->BackfaceIsHidden();
   }
   BCPixelSize smallHalf, largeHalf;
   DivideBCBorderSize(mWidth, smallHalf, largeHalf);
   LogicalRect segRect(aIter.mTableWM, mOffsetI,
                       mOffsetB - presContext->DevPixelsToAppUnits(largeHalf),
                       mLength,
                       presContext->DevPixelsToAppUnits(mWidth));
 
@@ -7735,16 +7741,17 @@ BCInlineDirSeg::CreateWebRenderCommands(
   // each side to height of rect is fine.
   wr::BorderWidths borderWidths = wr::ToBorderWidths(transformedRect.size.height,
                                                      transformedRect.size.height,
                                                      transformedRect.size.height,
                                                      transformedRect.size.height);
   Range<const wr::BorderSide> wrsides(wrSide, 4);
   aBuilder.PushBorder(transformedRect,
                       transformedRect,
+                      param->mBackfaceIsVisible,
                       borderWidths,
                       wrsides,
                       borderRadii);
 }
 
 /**
  * Advance the start point of a segment
  */
--- a/layout/tables/nsTableWrapperFrame.cpp
+++ b/layout/tables/nsTableWrapperFrame.cpp
@@ -182,18 +182,21 @@ nsTableWrapperFrame::BuildDisplayList(ns
 
   nsDisplayListCollection set;
   BuildDisplayListForInnerTable(aBuilder, set);
 
   nsDisplayListSet captionSet(set, set.BlockBorderBackgrounds());
   BuildDisplayListForChild(aBuilder, mCaptionFrames.FirstChild(), captionSet);
 
   // Now we have to sort everything by content order, since the caption
-  // may be somewhere inside the table
-  set.BlockBorderBackgrounds()->SortByContentOrder(GetContent());
+  // may be somewhere inside the table.
+  // We don't sort BlockBorderBackgrounds and BorderBackgrounds because the
+  // display items in those lists should stay out of content order in order to
+  // follow the rules in https://www.w3.org/TR/CSS21/zindex.html#painting-order
+  // and paint the caption background after all of the rest.
   set.Floats()->SortByContentOrder(GetContent());
   set.Content()->SortByContentOrder(GetContent());
   set.PositionedDescendants()->SortByContentOrder(GetContent());
   set.Outlines()->SortByContentOrder(GetContent());
   set.MoveTo(aLists);
 }
 
 void
--- a/layout/xul/nsImageBoxFrame.cpp
+++ b/layout/xul/nsImageBoxFrame.cpp
@@ -455,17 +455,17 @@ nsImageBoxFrame::CreateWebRenderCommands
   }
   const int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
   LayoutDeviceRect fillRect = LayoutDeviceRect::FromAppUnits(dest,
                                                              appUnitsPerDevPixel);
   wr::LayoutRect fill = aSc.ToRelativeLayoutRect(fillRect);
 
   LayoutDeviceSize gapSize(0, 0);
   SamplingFilter sampleFilter = nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame());
-  aBuilder.PushImage(fill, fill,
+  aBuilder.PushImage(fill, fill, !BackfaceIsHidden(),
                      wr::ToLayoutSize(fillRect.Size()), wr::ToLayoutSize(gapSize),
                      wr::ToImageRendering(sampleFilter), key.value());
 
   return DrawResult::SUCCESS;
 }
 
 nsRect
 nsImageBoxFrame::GetDestRect(const nsPoint& aOffset, Maybe<nsPoint>& aAnchorPoint)
--- a/media/mtransport/third_party/nICEr/nicer.gyp
+++ b/media/mtransport/third_party/nICEr/nicer.gyp
@@ -231,13 +231,18 @@
 
 		 'sources': [
 		 ],
              }],
              ['have_ethtool_cmd_speed_hi==0', {
                'defines': [
                   "DONT_HAVE_ETHTOOL_SPEED_HI",
                ]
-             }]
+             }],
+        ['libfuzzer == 1', {
+          'cflags_mozilla': [
+            '-fsanitize-coverage=trace-pc-guard',
+         ],
+        }],
           ],
       }]
 }
 
--- a/mozglue/build/WindowsDllBlocklist.cpp
+++ b/mozglue/build/WindowsDllBlocklist.cpp
@@ -298,20 +298,18 @@ printf_stderr(const char *fmt, ...)
   va_start(args, fmt);
   vfprintf(fp, fmt, args);
   va_end(args);
 
   fclose(fp);
 }
 
 
-#ifdef _M_IX86
 typedef MOZ_NORETURN_PTR void (__fastcall* BaseThreadInitThunk_func)(BOOL aIsInitialThread, void* aStartAddress, void* aThreadParam);
 static BaseThreadInitThunk_func stub_BaseThreadInitThunk = nullptr;
-#endif
 
 typedef NTSTATUS (NTAPI *LdrLoadDll_func) (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle);
 static LdrLoadDll_func stub_LdrLoadDll;
 
 #ifdef _M_AMD64
 typedef decltype(RtlInstallFunctionTableCallback)* RtlInstallFunctionTableCallback_func;
 static RtlInstallFunctionTableCallback_func stub_RtlInstallFunctionTableCallback;
 
@@ -783,17 +781,16 @@ continue_loading:
   // Prevent the stack walker from suspending this thread when LdrLoadDll
   // holds the RtlLookupFunctionEntry lock.
   AutoSuppressStackWalking suppress;
 #endif
 
   return stub_LdrLoadDll(filePath, flags, moduleFileName, handle);
 }
 
-#ifdef _M_IX86
 static bool
 ShouldBlockThread(void* aStartAddress)
 {
   // Allows crashfirefox.exe to continue to work. Also if your threadproc is null, this crash is intentional.
   if (aStartAddress == 0)
     return false;
 
   bool shouldBlock = false;
@@ -819,18 +816,16 @@ patched_BaseThreadInitThunk(BOOL aIsInit
 {
   if (ShouldBlockThread(aStartAddress)) {
     aStartAddress = (void*)NopThreadProc;
   }
 
   stub_BaseThreadInitThunk(aIsInitialThread, aStartAddress, aThreadParam);
 }
 
-#endif // _M_IX86
-
 
 static WindowsDllInterceptor NtDllIntercept;
 static WindowsDllInterceptor Kernel32Intercept;
 
 MFBT_API void
 DllBlocklist_Initialize(uint32_t aInitFlags)
 {
   if (sBlocklistInitAttempted) {
@@ -870,30 +865,27 @@ DllBlocklist_Initialize(uint32_t aInitFl
   if (!IsWin8OrLater()) {
     // The crash that this hook works around is only seen on Win7.
     Kernel32Intercept.AddHook("RtlInstallFunctionTableCallback",
                               reinterpret_cast<intptr_t>(patched_RtlInstallFunctionTableCallback),
                               (void**)&stub_RtlInstallFunctionTableCallback);
   }
 #endif
 
-#ifdef _M_IX86 // Minimize impact. Crashes in BaseThreadInitThunk are more frequent on x86
-
   // Bug 1361410: WRusr.dll will overwrite our hook and cause a crash.
   // Workaround: If we detect WRusr.dll, don't hook.
   if (!GetModuleHandleW(L"WRusr.dll")) {
     if(!Kernel32Intercept.AddDetour("BaseThreadInitThunk",
                                     reinterpret_cast<intptr_t>(patched_BaseThreadInitThunk),
                                     (void**) &stub_BaseThreadInitThunk)) {
 #ifdef DEBUG
       printf_stderr("BaseThreadInitThunk hook failed\n");
 #endif
     }
   }
-#endif // _M_IX86
 }
 
 MFBT_API void
 DllBlocklist_WriteNotes(HANDLE file)
 {
   DWORD nBytes;
 
   WriteFile(file, kBlockedDllsParameter, kBlockedDllsParameterLen, &nBytes, nullptr);
--- a/toolkit/components/backgroundhangmonitor/BHRTelemetryService.js
+++ b/toolkit/components/backgroundhangmonitor/BHRTelemetryService.js
@@ -86,18 +86,17 @@ BHRTelemetryService.prototype = Object.f
     if (!Services.telemetry.canRecordExtended) {
       return;
     }
 
     // NOTE: We check a separate bhrPing.enabled pref here. This pref is unset
     // when running tests so that we run as much of BHR as possible (to catch
     // errors) while avoiding timeouts caused by invoking `pingsender` during
     // testing.
-    if (Services.prefs.getBoolPref("toolkit.telemetry.bhrPing.enabled", false) &&
-        this.payload.hangs.length > 0) {
+    if (Services.prefs.getBoolPref("toolkit.telemetry.bhrPing.enabled", false)) {
       this.payload.timeSinceLastPing = new Date() - this.startTime;
       TelemetryController.submitExternalPing("bhr", this.payload, {
         addEnvironment: true,
       });
     }
     this.resetPayload();
   },
 
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -2476,34 +2476,34 @@
     "kind": "enumerated",
     "n_values": 8,
     "description": "TCP Fast Open was: 0=enabled during the session, 1=not available or disabled in the os, 2=disabled by the pref, 3=disabled based on the too many connection failures.",
     "alert_emails": ["necko@mozilla.com", "ddamjanovic@mozilla.com"],
     "bug_numbers": [1390881]
   },
   "TLS_EARLY_DATA_NEGOTIATED": {
     "record_in_processes": ["main", "content"],
-    "expires_in_version": "58",
+    "expires_in_version": "62",
     "kind": "enumerated",
     "n_values": 3,
     "description": "Sending TLS early data was possible: 0 - not possible, 1 - possible but not used, 2 - possible and used.",
     "alert_emails": ["necko@mozilla.com"],
     "bug_numbers": [1296288]
   },
   "TLS_EARLY_DATA_ACCEPTED": {
     "record_in_processes": ["main", "content"],
-    "expires_in_version": "58",
+    "expires_in_version": "62",
     "kind": "boolean",
     "description": "TLS early data was used and it was accepted (true) or rejected (false) by the remote host.",
     "alert_emails": ["necko@mozilla.com"],
     "bug_numbers": [1296288]
   },
   "TLS_EARLY_DATA_BYTES_WRITTEN": {
     "record_in_processes": ["main", "content"],
-    "expires_in_version": "58",
+    "expires_in_version": "62",
     "kind": "exponential",
     "high": 60000,
     "n_buckets": 100,
     "description": "Amount of bytes sent using TLS early data at the start of a TLS connection for a given channel.",
     "alert_emails": ["necko@mozilla.com"],
     "bug_numbers": [1296288]
   },
   "SSL_HANDSHAKE_VERSION": {
--- a/toolkit/content/mozilla.xhtml
+++ b/toolkit/content/mozilla.xhtml
@@ -8,17 +8,17 @@
 
 <!-- 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/. -->
 
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
     <meta charset='utf-8' />
-    <title>&mozilla.title.15.1;</title>
+    <title>&mozilla.title.11.14;</title>
 
 <style>
 html {
   background: maroon radial-gradient( circle, #a01010 0%, #800000 80%) center center / cover no-repeat;
   color: white;
   font-style: italic;
   text-rendering: optimizeLegibility;
   min-height: 100%;
@@ -49,18 +49,18 @@ a {
 }
 </style>
 </head>
 
 <body dir="&locale.dir;">
 
 <section>
   <p id="moztext">
-  &mozilla.quote.15.1;
+  &mozilla.quote.11.14;
   </p>
 
   <p id="from">
-  &mozilla.from.15.1;
+  &mozilla.from.11.14;
   </p>
 </section>
 
 </body>
 </html>
--- a/toolkit/locales/en-US/chrome/global/mozilla.dtd
+++ b/toolkit/locales/en-US/chrome/global/mozilla.dtd
@@ -1,14 +1,15 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
-<!ENTITY mozilla.title.15.1
-'The Book of Mozilla, 15:1'>
+<!ENTITY mozilla.title.11.14
+'The Book of Mozilla, 11:14'>
 
-<!ENTITY mozilla.quote.15.1
-'The <em>twins</em> of Mammon quarrelled. Their warring plunged the world into a <em>new darkness</em>, and the beast 
-abhorred the darkness. So it began to move <em>swiftly</em>, and grew more powerful, and went forth and multiplied. 
-And the beasts brought <em>fire</em> and light to the darkness.'>
+<!ENTITY mozilla.quote.11.14
+'The Beast adopted <em>new raiment</em> and studied the ways of <em>Time</em> and <em>Space</em> 
+and <em>Light</em> and the <em>Flow</em> of energy through the Universe. From its studies, 
+the Beast fashioned new structures from <em>oxidised metal</em> and proclaimed their glories. 
+And the Beast’s followers rejoiced, finding renewed purpose in these <em>teachings</em>.'>
 
-<!ENTITY mozilla.from.15.1
-'from <strong>The Book of Mozilla,</strong> 15:1'>
+<!ENTITY mozilla.from.11.14
+'from <strong>The Book of Mozilla,</strong> 11:14'>
--- a/toolkit/xre/test/win/TestDllInterceptor.cpp
+++ b/toolkit/xre/test/win/TestDllInterceptor.cpp
@@ -543,18 +543,16 @@ int main()
 #endif
       MaybeTestHook(ShouldTestTipTsf(), TestProcessCaretEvents, "tiptsf.dll", "ProcessCaretEvents") &&
 #ifdef _M_IX86
       TestHook(TestSendMessageTimeoutW, "user32.dll", "SendMessageTimeoutW") &&
 #endif
       TestHook(TestSetCursorPos, "user32.dll", "SetCursorPos") &&
       TestHook(TestTlsAlloc, "kernel32.dll", "TlsAlloc") &&
       TestHook(TestTlsFree, "kernel32.dll", "TlsFree") &&
-#ifdef _M_IX86
       TestDetour("kernel32.dll", "BaseThreadInitThunk") &&
-#endif
       TestDetour("ntdll.dll", "LdrLoadDll")) {
     printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n");
     return 0;
   }
 
   return 1;
 }
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -2117,17 +2117,17 @@ nsChildView::AddWindowOverlayWebRenderCo
 
     if (needUpdate) {
       wr::ImageDescriptor descriptor(size, stride, format);
       aResources.UpdateImageBuffer(*mTitlebarImageKey, descriptor, buffer);
     }
 
     wr::LayoutRect rect = wr::ToLayoutRect(mTitlebarRect);
     aBuilder.PushImage(wr::LayoutRect{ rect.origin, { float(size.width), float(size.height) } },
-                       rect, wr::ImageRendering::Auto, *mTitlebarImageKey);
+                       rect, true, wr::ImageRendering::Auto, *mTitlebarImageKey);
   }
 }
 
 void
 nsChildView::CleanupWebRenderWindowOverlay(layers::WebRenderBridgeChild* aWrBridge,
                                            wr::IpcResourceUpdateQueue& aResources)
 {
   if (mTitlebarImageKey) {
--- a/xpcom/threads/nsThreadManager.cpp
+++ b/xpcom/threads/nsThreadManager.cpp
@@ -100,16 +100,23 @@ nsThreadManager::Release()
 NS_IMPL_CLASSINFO(nsThreadManager, nullptr,
                   nsIClassInfo::THREADSAFE | nsIClassInfo::SINGLETON,
                   NS_THREADMANAGER_CID)
 NS_IMPL_QUERY_INTERFACE_CI(nsThreadManager, nsIThreadManager)
 NS_IMPL_CI_INTERFACE_GETTER(nsThreadManager, nsIThreadManager)
 
 //-----------------------------------------------------------------------------
 
+/*static*/ nsThreadManager&
+nsThreadManager::get()
+{
+  static nsThreadManager sInstance;
+  return sInstance;
+}
+
 nsresult
 nsThreadManager::Init()
 {
   // Child processes need to initialize the thread manager before they
   // initialize XPCOM in order to set up the crash reporter. This leads to
   // situations where we get initialized twice.
   if (mInitialized) {
     return NS_OK;
--- a/xpcom/threads/nsThreadManager.h
+++ b/xpcom/threads/nsThreadManager.h
@@ -15,21 +15,17 @@
 class nsIRunnable;
 
 class nsThreadManager : public nsIThreadManager
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSITHREADMANAGER
 
-  static nsThreadManager& get()
-  {
-    static nsThreadManager sInstance;
-    return sInstance;
-  }
+  static nsThreadManager& get();
 
   nsresult Init();
 
   // Shutdown all threads.  This function should only be called on the main
   // thread of the application process.
   void Shutdown();
 
   // Called by nsThread to inform the ThreadManager it exists.  This method