Merge mozilla-central to b2g-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 03 Aug 2015 16:20:10 +0200
changeset 287495 2069f49438af702519aebff3364e3bef7c30aa6e
parent 287494 3579abb90b81d87f35b2e38526a70ba7cff042f6 (current diff)
parent 287484 1d4f44ee51668865945db95c5fbd898e71955a33 (diff)
child 287496 71cc4122aa236250ecf71b5c8213c0b271d2d09a
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to b2g-inbound
browser/themes/linux/devtools/canvasdebugger.css
browser/themes/linux/devtools/debugger.css
browser/themes/linux/devtools/performance.css
browser/themes/linux/devtools/scratchpad.css
browser/themes/linux/devtools/shadereditor.css
browser/themes/linux/devtools/webaudioeditor.css
browser/themes/osx/devtools/canvasdebugger.css
browser/themes/osx/devtools/debugger.css
browser/themes/osx/devtools/performance.css
browser/themes/osx/devtools/scratchpad.css
browser/themes/osx/devtools/shadereditor.css
browser/themes/osx/devtools/webaudioeditor.css
browser/themes/shared/devtools/canvasdebugger.inc.css
browser/themes/shared/devtools/debugger.inc.css
browser/themes/shared/devtools/performance.inc.css
browser/themes/shared/devtools/scratchpad.inc.css
browser/themes/shared/devtools/shadereditor.inc.css
browser/themes/shared/devtools/webaudioeditor.inc.css
browser/themes/windows/devtools/canvasdebugger.css
browser/themes/windows/devtools/debugger.css
browser/themes/windows/devtools/performance.css
browser/themes/windows/devtools/scratchpad.css
browser/themes/windows/devtools/shadereditor.css
browser/themes/windows/devtools/webaudioeditor.css
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1186748 needed a CLOBBER again
+Bug 1190180 - need clobber for backouts
--- a/accessible/windows/ia2/moz.build
+++ b/accessible/windows/ia2/moz.build
@@ -42,16 +42,11 @@ LOCAL_INCLUDES += [
     '/accessible/windows',
     '/accessible/windows/msaa',
     '/accessible/xpcom',
     '/accessible/xul',
 ]
 
 FINAL_LIBRARY = 'xul'
 
-# The midl generated code include Windows headers which defines min and max
-# macros which conflicts with std::min/max.  Suppress the macros:
-if CONFIG['OS_ARCH'] == 'WINNT':
-    DEFINES['NOMINMAX'] = True
-
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
--- a/accessible/windows/sdn/moz.build
+++ b/accessible/windows/sdn/moz.build
@@ -14,15 +14,11 @@ LOCAL_INCLUDES += [
     '/accessible/base',
     '/accessible/generic',
     '/accessible/html',
     '/accessible/windows/msaa',
     '/accessible/xpcom',
     '/accessible/xul',
 ]
 
-# The midl generated code include Windows headers which defines min and max
-# macros which conflicts with std::min/max.  Suppress the macros:
-DEFINES['NOMINMAX'] = True
-
 FINAL_LIBRARY = 'xul'
 
 FAIL_ON_WARNINGS = True
--- a/accessible/windows/uia/moz.build
+++ b/accessible/windows/uia/moz.build
@@ -14,14 +14,9 @@ LOCAL_INCLUDES += [
     '/accessible/html',
     '/accessible/windows/msaa',
     '/accessible/xpcom',
     '/accessible/xul',
 ]
 
 FINAL_LIBRARY = 'xul'
 
-# The midl generated code include Windows headers which defines min and max
-# macros which conflicts with std::min/max.  Suppress the macros:
-if CONFIG['OS_ARCH'] == 'WINNT':
-    DEFINES['NOMINMAX'] = True
-
 FAIL_ON_WARNINGS = True
--- a/b2g/config/tooltool-manifests/linux32/releng.manifest
+++ b/b2g/config/tooltool-manifests/linux32/releng.manifest
@@ -2,24 +2,16 @@
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 11179576,
-"digest": "91567ce8e2bb8ab0ebc60c31e90731d88a1ea889fb71bcf55c735746a60fa7610b7e040ea3d8f727b6f692ae3ee703d6f3b30cdbd76fdf5617f77d9c38aa20ed",
-"algorithm": "sha512",
-"filename": "gtk3.tar.xz",
-"setup": "setup.sh",
-"unpack": true
-},
-{
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
 "filename": "sccache.tar.bz2",
 "unpack": true
 },
 {
 "size": 31078810,
--- a/b2g/config/tooltool-manifests/linux64/releng.manifest
+++ b/b2g/config/tooltool-manifests/linux64/releng.manifest
@@ -2,24 +2,16 @@
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
-"algorithm": "sha512",
-"filename": "gtk3.tar.xz",
-"setup": "setup.sh",
-"unpack": true
-},
-{
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
 "filename": "sccache.tar.bz2",
 "unpack": true
 },
 {
 "size": 31078810,
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -66,18 +66,18 @@ pref("extensions.hotfix.id", "firefox-ho
 pref("extensions.hotfix.cert.checkAttributes", true);
 pref("extensions.hotfix.certs.1.sha1Fingerprint", "91:53:98:0C:C1:86:DF:47:8F:35:22:9E:11:C9:A7:31:04:49:A1:AA");
 pref("extensions.hotfix.certs.2.sha1Fingerprint", "39:E7:2B:7A:5B:CF:37:78:F9:5D:4A:E0:53:2D:2F:3D:68:53:C5:60");
 
 // Disable add-ons that are not installed by the user in all scopes by default.
 // See the SCOPE constants in AddonManager.jsm for values to use here.
 pref("extensions.autoDisableScopes", 15);
 
-// Don't require signed add-ons by default
-pref("xpinstall.signatures.required", false);
+// Require signed add-ons by default
+pref("xpinstall.signatures.required", true);
 pref("xpinstall.signatures.devInfoURL", "https://wiki.mozilla.org/Addons/Extension_Signing");
 
 // Dictionary download preference
 pref("browser.dictionaries.download.url", "https://addons.mozilla.org/%LOCALE%/firefox/dictionaries/");
 
 // At startup, should we check to see if the installation
 // date is older than some threshold
 pref("app.update.checkInstallTime", true);
--- a/browser/base/content/aboutaccounts/aboutaccounts.xhtml
+++ b/browser/base/content/aboutaccounts/aboutaccounts.xhtml
@@ -2,23 +2,25 @@
 <!-- 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/. -->
 <!DOCTYPE html [
   <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
   %htmlDTD;
   <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
   %brandDTD;
+  <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
+  %globalDTD;
   <!ENTITY % aboutAccountsDTD SYSTEM "chrome://browser/locale/aboutAccounts.dtd">
   %aboutAccountsDTD;
   <!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd">
   %syncBrandDTD;
 ]>
 
-<html xmlns="http://www.w3.org/1999/xhtml">
+<html xmlns="http://www.w3.org/1999/xhtml" dir="&locale.dir;">
   <head>
    <title>&syncBrand.fullName.label;</title>
    <meta name="viewport" content="width=device-width"/>
 
 
    <link rel="icon" type="image/png" id="favicon"
          href="chrome://branding/content/icon32.png"/>
    <link rel="stylesheet"
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -5880,30 +5880,34 @@
         ]]>
         </body>
       </method>
     </implementation>
 
     <handlers>
       <handler event="mouseover"><![CDATA[
         let anonid = event.originalTarget.getAttribute("anonid");
+        let iconVisible = this.hasAttribute("soundplaying") ||
+                          this.hasAttribute("muted");
         if (anonid == "close-button")
           this.mOverCloseButton = true;
         else if ((anonid == "soundplaying-icon") ||
-                 ((anonid == "overlay-icon") && this.hasAttribute("soundplaying")))
+                 ((anonid == "overlay-icon") && iconVisible))
           this._overPlayingIcon = true;
 
         this._mouseenter();
       ]]></handler>
       <handler event="mouseout"><![CDATA[
         let anonid = event.originalTarget.getAttribute("anonid");
+        let iconVisible = this.hasAttribute("soundplaying") ||
+                          this.hasAttribute("muted");
         if (anonid == "close-button")
           this.mOverCloseButton = false;
         else if ((anonid == "soundplaying-icon") ||
-                 ((anonid == "overlay-icon") && this.hasAttribute("soundplaying")))
+                 ((anonid == "overlay-icon") && iconVisible))
           this._overPlayingIcon = false;
 
         this._mouseleave();
       ]]></handler>
       <handler event="dragstart" phase="capturing">
         this.style.MozUserFocus = '';
       </handler>
       <handler event="mousedown" phase="capturing">
@@ -5923,18 +5927,20 @@
       </handler>
       <handler event="click">
       <![CDATA[
         if (event.button != 0) {
           return;
         }
 
         let anonid = event.originalTarget.getAttribute("anonid");
+        let iconVisible = this.hasAttribute("soundplaying") ||
+                          this.hasAttribute("muted");
         if ((anonid == "soundplaying-icon") ||
-            ((anonid == "overlay-icon") && this.hasAttribute("soundplaying"))) {
+            ((anonid == "overlay-icon") && iconVisible)) {
           this._toggleMuteAudio();
         }
       ]]>
       </handler>
     </handlers>
   </binding>
 
   <binding id="tabbrowser-alltabs-popup"
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -468,17 +468,16 @@ skip-if = true # Bug 1005420 - fails int
 skip-if = (os == "win" && !debug)
 [browser_web_channel.js]
 [browser_windowopen_reflows.js]
 skip-if = buildapp == 'mulet'
 [browser_wyciwyg_urlbarCopying.js]
 [browser_zbug569342.js]
 skip-if = e10s # Bug 1094240 - has findbar-related failures
 [browser_registerProtocolHandler_notification.js]
-skip-if = e10s # Bug 940206 - nsIWebContentHandlerRegistrar::registerProtocolHandler doesn't work in e10s
 [browser_no_mcb_on_http_site.js]
 [browser_bug1104165-switchtab-decodeuri.js]
 [browser_bug1003461-switchtab-override.js]
 [browser_bug1024133-switchtab-override-keynav.js]
 [browser_bug1025195_switchToTabHavingURI_aOpenParams.js]
 [browser_addCertException.js]
 skip-if = e10s # Bug 1100687 - test directly manipulates content (content.document.getElementById)
 [browser_bug1045809.js]
--- a/browser/base/content/test/general/browser_audioTabIcon.js
+++ b/browser/base/content/test/general/browser_audioTabIcon.js
@@ -82,21 +82,33 @@ function* test_playing_icon_on_tab(tab, 
   yield test_mute_tab(tab, icon, true);
 
   yield test_tooltip(icon, "This tab has been muted");
 
   yield test_mute_tab(tab, icon, false);
 
   yield test_tooltip(icon, "This tab is playing audio");
 
+  yield test_mute_tab(tab, icon, true);
+
   yield ContentTask.spawn(browser, {}, function* () {
     let audio = content.document.querySelector("audio");
     audio.pause();
   });
   yield wait_for_tab_playing_event(tab, false);
+
+  ok(tab.hasAttribute("muted") &&
+     !tab.hasAttribute("soundplaying"), "Tab should still be muted but not playing");
+
+  yield test_tooltip(icon, "This tab has been muted");
+
+  yield test_mute_tab(tab, icon, false);
+
+  ok(!tab.hasAttribute("muted") &&
+     !tab.hasAttribute("soundplaying"), "Tab should not be be muted or playing");
 }
 
 function* test_on_browser(browser) {
   let tab = gBrowser.getTabForBrowser(browser);
 
   // Test the icon in a normal tab.
   yield test_playing_icon_on_tab(tab, browser, false);
 
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -962,18 +962,18 @@ file, You can obtain one at http://mozil
 
         // Drag only if the entire value is selected and it's a valid URI.
         var isFullSelection = this.selectionStart == 0 &&
                               this.selectionEnd == this.textLength;
         if (!isFullSelection ||
             this.getAttribute("pageproxystate") != "valid")
           return;
 
-        var urlString = content.location.href;
-        var title = content.document.title || urlString;
+        var urlString = gBrowser.selectedBrowser.currentURI.spec;
+        var title = gBrowser.selectedBrowser.contentTitle || urlString;
         var htmlString = "<a href=\"" + urlString + "\">" + urlString + "</a>";
 
         var dt = event.dataTransfer;
         dt.setData("text/x-moz-url", urlString + "\n" + title);
         dt.setData("text/unicode", urlString);
         dt.setData("text/html", htmlString);
 
         dt.effectAllowed = "copyLink";
--- a/browser/components/feeds/WebContentConverter.js
+++ b/browser/components/feeds/WebContentConverter.js
@@ -1,13 +1,14 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 function LOG(str) {
@@ -127,26 +128,101 @@ ServiceInfo.prototype = {
   QueryInterface: function SI_QueryInterface(iid) {
     if (iid.equals(Ci.nsIWebContentHandlerInfo) ||
         iid.equals(Ci.nsISupports))
       return this;
     throw Cr.NS_ERROR_NO_INTERFACE;
   }
 };
 
+const Utils = {
+  makeURI(aURL, aOriginCharset, aBaseURI) {
+    return Services.io.newURI(aURL, aOriginCharset, aBaseURI);
+  },
+
+  checkAndGetURI(aURIString, aContentWindow) {
+    try {
+      let baseURI = aContentWindow.document.baseURIObject;
+      var uri = this.makeURI(aURIString, null, baseURI);
+    } catch (ex) {
+      throw NS_ERROR_DOM_SYNTAX_ERR;
+    }
+
+    // For security reasons we reject non-http(s) urls (see bug 354316),
+    // we may need to revise this once we support more content types
+    // XXX this should be a "security exception" according to spec, but that
+    // isn't defined yet.
+    if (uri.scheme != "http" && uri.scheme != "https")
+      throw("Permission denied to add " + uri.spec + " as a content or protocol handler");
+
+    // We also reject handlers registered from a different host (see bug 402287)
+    // The pref allows us to test the feature
+    var pb = Services.prefs;
+    if ((!pb.prefHasUserValue(PREF_ALLOW_DIFFERENT_HOST) ||
+         !pb.getBoolPref(PREF_ALLOW_DIFFERENT_HOST)) &&
+        aContentWindow.location.hostname != uri.host)
+      throw("Permission denied to add " + uri.spec + " as a content or protocol handler");
+
+    // If the uri doesn't contain '%s', it won't be a good handler
+    if (uri.spec.indexOf("%s") < 0)
+      throw NS_ERROR_DOM_SYNTAX_ERR;
+
+    return uri;
+  },
+
+  // NB: Throws if aProtocol is not allowed.
+  checkProtocolHandlerAllowed(aProtocol, aURIString) {
+    // First, check to make sure this isn't already handled internally (we don't
+    // want to let them take over, say "chrome").
+    var handler = Services.io.getProtocolHandler(aProtocol);
+    if (!(handler instanceof Ci.nsIExternalProtocolHandler)) {
+      // This is handled internally, so we don't want them to register
+      // XXX this should be a "security exception" according to spec, but that
+      // isn't defined yet.
+      throw(`Permission denied to add ${aURIString} as a protocol handler`);
+    }
+
+    // check if it is in the black list
+    var pb = Services.prefs;
+    var allowed;
+    try {
+      allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "." + aProtocol);
+    }
+    catch (e) {
+      allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "-default");
+    }
+    if (!allowed) {
+      // XXX this should be a "security exception" according to spec
+      throw(`Not allowed to register a protocol handler for ${aProtocol}`);
+    }
+  },
+
+  /**
+   * Mappings from known feed types to our internal content type.
+   */
+  _mappings: {
+    "application/rss+xml": TYPE_MAYBE_FEED,
+    "application/atom+xml": TYPE_MAYBE_FEED,
+  },
+
+  resolveContentType(aContentType) {
+    if (aContentType in this._mappings)
+      return this._mappings[aContentType];
+    return aContentType;
+  }
+};
+
 function WebContentConverterRegistrar() {
   this._contentTypes = { };
   this._autoHandleContentTypes = { };
 }
 
 WebContentConverterRegistrar.prototype = {
   get stringBundle() {
-    var sb = Cc["@mozilla.org/intl/stringbundle;1"].
-              getService(Ci.nsIStringBundleService).
-              createBundle(STRING_BUNDLE_URI);
+    var sb = Services.strings.createBundle(STRING_BUNDLE_URI);
     delete WebContentConverterRegistrar.prototype.stringBundle;
     return WebContentConverterRegistrar.prototype.stringBundle = sb;
   },
 
   _getFormattedString: function WCCR__getFormattedString(key, params) {
     return this.stringBundle.formatStringFromName(key, params, params.length);
   },
   
@@ -154,42 +230,40 @@ WebContentConverterRegistrar.prototype =
     return this.stringBundle.GetStringFromName(key);
   },
 
   /**
    * See nsIWebContentConverterService
    */
   getAutoHandler: 
   function WCCR_getAutoHandler(contentType) {
-    contentType = this._resolveContentType(contentType);
+    contentType = Utils.resolveContentType(contentType);
     if (contentType in this._autoHandleContentTypes)
       return this._autoHandleContentTypes[contentType];
     return null;
   },
   
   /**
    * See nsIWebContentConverterService
    */
   setAutoHandler:
   function WCCR_setAutoHandler(contentType, handler) {
     if (handler && !this._typeIsRegistered(contentType, handler.uri))
       throw Cr.NS_ERROR_NOT_AVAILABLE;
-      
-    contentType = this._resolveContentType(contentType);
+
+    contentType = Utils.resolveContentType(contentType);
     this._setAutoHandler(contentType, handler);
-    
-    var ps = 
-        Cc["@mozilla.org/preferences-service;1"].
-        getService(Ci.nsIPrefService);
+
+    var ps = Services.prefs;
     var autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
     if (handler)
       autoBranch.setCharPref(contentType, handler.uri);
     else if (autoBranch.prefHasUserValue(contentType))
       autoBranch.clearUserPref(contentType);
-     
+
     ps.savePrefFile(null);
   },
   
   /**
    * Update the internal data structure (not persistent)
    */
   _setAutoHandler:
   function WCCR__setAutoHandler(contentType, handler) {
@@ -213,17 +287,17 @@ WebContentConverterRegistrar.prototype =
   },
   
   /**
    * See nsIWebContentConverterService
    */
   loadPreferredHandler: 
   function WCCR_loadPreferredHandler(request) {
     var channel = request.QueryInterface(Ci.nsIChannel);
-    var contentType = this._resolveContentType(channel.contentType);
+    var contentType = Utils.resolveContentType(channel.contentType);
     var handler = this.getAutoHandler(contentType);
     if (handler) {
       request.cancel(Cr.NS_ERROR_FAILURE);
       
       var webNavigation = 
           channel.notificationCallbacks.getInterface(Ci.nsIWebNavigation);
       webNavigation.loadURI(handler.getHandlerURI(channel.URI.spec), 
                             Ci.nsIWebNavigation.LOAD_FLAGS_NONE, 
@@ -263,84 +337,25 @@ WebContentConverterRegistrar.prototype =
       return serviceInfo.uri != uri;
     }
   
     if (contentType in this._contentTypes) {
       this._contentTypes[contentType] = 
         this._contentTypes[contentType].filter(notURI);
     }
   },
-  
-  /**
-   *
-   */
-  _mappings: { 
-    "application/rss+xml": TYPE_MAYBE_FEED,
-    "application/atom+xml": TYPE_MAYBE_FEED,
-  },
-  
+
   /**
    * These are types for which there is a separate content converter aside 
    * from our built in generic one. We should not automatically register
    * a factory for creating a converter for these types.
    */
   _blockedTypes: {
     "application/vnd.mozilla.maybe.feed": true,
   },
-  
-  /**
-   * Determines the "internal" content type based on the _mappings.
-   * @param   contentType
-   * @returns The resolved contentType value. 
-   */
-  _resolveContentType: 
-  function WCCR__resolveContentType(contentType) {
-    if (contentType in this._mappings)
-      return this._mappings[contentType];
-    return contentType;
-  },
-
-  _makeURI: function(aURL, aOriginCharset, aBaseURI) {
-    var ioService = Components.classes["@mozilla.org/network/io-service;1"]
-                              .getService(Components.interfaces.nsIIOService);
-    return ioService.newURI(aURL, aOriginCharset, aBaseURI);
-  },
-
-  _checkAndGetURI:
-  function WCCR_checkAndGetURI(aURIString, aContentWindow)
-  {
-    try {
-      let baseURI = aContentWindow.document.baseURIObject;
-      var uri = this._makeURI(aURIString, null, baseURI);
-    } catch (ex) {
-      // not supposed to throw according to spec
-      return; 
-    }
-
-    // For security reasons we reject non-http(s) urls (see bug 354316),
-    // we may need to revise this once we support more content types
-    // XXX this should be a "security exception" according to spec, but that
-    // isn't defined yet.
-    if (uri.scheme != "http" && uri.scheme != "https")
-      throw("Permission denied to add " + uri.spec + " as a content or protocol handler");
-
-    // We also reject handlers registered from a different host (see bug 402287)
-    // The pref allows us to test the feature
-    var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
-    if ((!pb.prefHasUserValue(PREF_ALLOW_DIFFERENT_HOST) ||
-         !pb.getBoolPref(PREF_ALLOW_DIFFERENT_HOST)) &&
-        aContentWindow.location.hostname != uri.host)
-      throw("Permission denied to add " + uri.spec + " as a content or protocol handler");
-
-    // If the uri doesn't contain '%s', it won't be a good handler
-    if (uri.spec.indexOf("%s") < 0)
-      throw NS_ERROR_DOM_SYNTAX_ERR; 
-
-    return uri;
-  },
 
   /**
    * Determines if a web handler is already registered.
    *
    * @param aProtocol
    *        The scheme of the web handler we are checking for.
    * @param aURITemplate
    *        The URI template that the handler uses to handle the protocol.
@@ -361,62 +376,51 @@ WebContentConverterRegistrar.prototype =
     }
     return false;
   },
 
   /**
    * See nsIWebContentHandlerRegistrar
    */
   registerProtocolHandler: 
-  function WCCR_registerProtocolHandler(aProtocol, aURIString, aTitle, aContentWindow) {
+  function WCCR_registerProtocolHandler(aProtocol, aURIString, aTitle, aBrowserOrWindow) {
     LOG("registerProtocolHandler(" + aProtocol + "," + aURIString + "," + aTitle + ")");
-
-    var uri = this._checkAndGetURI(aURIString, aContentWindow);
+    var haveWindow = (aBrowserOrWindow instanceof Ci.nsIDOMWindow);
+    var uri;
+    if (haveWindow) {
+      uri = Utils.checkAndGetURI(aURIString, aBrowserOrWindow);
+    } else {
+      // aURIString must not be a relative URI.
+      uri = Utils.makeURI(aURIString, null);
+    }
 
     // If the protocol handler is already registered, just return early.
     if (this._protocolHandlerRegistered(aProtocol, uri.spec)) {
       return;
     }
 
-    var browserWindow = this._getBrowserWindowForContentWindow(aContentWindow);    
-    if (PrivateBrowsingUtils.isWindowPrivate(browserWindow)) {
+    var browser;
+    if (haveWindow) {
+      let browserWindow =
+        this._getBrowserWindowForContentWindow(aBrowserOrWindow);
+      browser = this._getBrowserForContentWindow(browserWindow,
+                                                 aBrowserOrWindow);
+    } else {
+      browser = aBrowserOrWindow;
+    }
+    if (PrivateBrowsingUtils.isBrowserPrivate(browser)) {
       // Inside the private browsing mode, we don't want to alert the user to save
       // a protocol handler.  We log it to the error console so that web developers
       // would have some way to tell what's going wrong.
-      Cc["@mozilla.org/consoleservice;1"].
-      getService(Ci.nsIConsoleService).
+      Services.console.
       logStringMessage("Web page denied access to register a protocol handler inside private browsing mode");
       return;
     }
-    
-    // First, check to make sure this isn't already handled internally (we don't
-    // want to let them take over, say "chrome").
-    var ios = Cc["@mozilla.org/network/io-service;1"].
-              getService(Ci.nsIIOService);
-    var handler = ios.getProtocolHandler(aProtocol);
-    if (!(handler instanceof Ci.nsIExternalProtocolHandler)) {
-      // This is handled internally, so we don't want them to register
-      // XXX this should be a "security exception" according to spec, but that
-      // isn't defined yet.
-      throw("Permission denied to add " + aURIString + "as a protocol handler");
-    }
 
-    // check if it is in the black list
-    var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
-    var allowed;
-    try {
-      allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "." + aProtocol);
-    }
-    catch (e) {
-      allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "-default");
-    }
-    if (!allowed) {
-      // XXX this should be a "security exception" according to spec
-      throw("Not allowed to register a protocol handler for " + aProtocol);
-    }
+    Utils.checkProtocolHandlerAllowed(aProtocol, aURIString);
 
     // Now Ask the user and provide the proper callback
     var message = this._getFormattedString("addProtocolHandler",
                                            [aTitle, uri.host, aProtocol]);
 
     var notificationIcon = uri.prePath + "/favicon.ico";
     var notificationValue = "Protocol Registration: " + aProtocol;
     var addButton = {
@@ -446,47 +450,57 @@ WebContentConverterRegistrar.prototype =
           // use.
           handlerInfo.alwaysAskBeforeHandling = true;
 
           var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
                    getService(Ci.nsIHandlerService);
           hs.store(handlerInfo);
         }
     };
-    var browserElement = this._getBrowserForContentWindow(browserWindow, aContentWindow);
-    var notificationBox = browserWindow.gBrowser.getNotificationBox(browserElement);
+    var notificationBox = browser.getTabBrowser().getNotificationBox(browser);
     notificationBox.appendNotification(message,
                                        notificationValue,
                                        notificationIcon,
                                        notificationBox.PRIORITY_INFO_LOW,
                                        [addButton]);
   },
 
   /**
    * See nsIWebContentHandlerRegistrar
    * If a DOM window is provided, then the request came from content, so we
    * prompt the user to confirm the registration.
    */
-  registerContentHandler: 
-  function WCCR_registerContentHandler(aContentType, aURIString, aTitle, aContentWindow) {
+  registerContentHandler:
+  function WCCR_registerContentHandler(aContentType, aURIString, aTitle, aWindowOrBrowser) {
     LOG("registerContentHandler(" + aContentType + "," + aURIString + "," + aTitle + ")");
 
     // We only support feed types at present.
     // XXX this should be a "security exception" according to spec, but that
     // isn't defined yet.
-    var contentType = this._resolveContentType(aContentType);
+    var contentType = Utils.resolveContentType(aContentType);
     if (contentType != TYPE_MAYBE_FEED)
       return;
 
-    if (aContentWindow) {
-      var uri = this._checkAndGetURI(aURIString, aContentWindow);
-  
-      var browserWindow = this._getBrowserWindowForContentWindow(aContentWindow);
-      var browserElement = this._getBrowserForContentWindow(browserWindow, aContentWindow);
-      var notificationBox = browserWindow.gBrowser.getNotificationBox(browserElement);
+    if (aWindowOrBrowser) {
+      var haveWindow = (aWindowOrBrowser instanceof Ci.nsIDOMWindow);
+      var uri;
+      var notificationBox;
+      if (haveWindow) {
+        uri = Utils.checkAndGetURI(aURIString, aWindowOrBrowser);
+
+        var browserWindow = this._getBrowserWindowForContentWindow(aWindowOrBrowser);
+        var browserElement = this._getBrowserForContentWindow(browserWindow, aWindowOrBrowser);
+        notificationBox = browserElement.getTabBrowser().getNotificationBox(browserElement);
+      } else {
+        // uri was vetted in the content process.
+        uri = Utils.makeURI(aURIString, null);
+        notificationBox = aWindowOrBrowser.getTabBrowser()
+                                          .getNotificationBox(aWindowOrBrowser);
+      }
+
       this._appendFeedReaderNotification(uri, aTitle, notificationBox);
     }
     else
       this._registerContentHandler(contentType, aURIString, aTitle);
   },
 
   /**
    * Returns the browser chrome window in which the content window is in
@@ -607,19 +621,17 @@ WebContentConverterRegistrar.prototype =
    * This data is stored under:
    * 
    *    browser.contentHandlers.type0 = content/type
    *    browser.contentHandlers.uri0 = http://www.foo.com/q=%s
    *    browser.contentHandlers.title0 = Foo 2.0alphr
    */
   _saveContentHandlerToPrefs: 
   function WCCR__saveContentHandlerToPrefs(contentType, uri, title) {
-    var ps = 
-        Cc["@mozilla.org/preferences-service;1"].
-        getService(Ci.nsIPrefService);
+    var ps = Services.prefs;
     var i = 0;
     var typeBranch = null;
     while (true) {
       typeBranch = 
         ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + i + ".");
       try {
         typeBranch.getCharPref("type");
         ++i;
@@ -689,18 +701,17 @@ WebContentConverterRegistrar.prototype =
   _registerContentHandler:
   function WCCR__registerContentHandler(contentType, uri, title) {
     this._updateContentTypeHandlerMap(contentType, uri, title);
     this._saveContentHandlerToPrefs(contentType, uri, title);
 
     if (contentType == TYPE_MAYBE_FEED) {
       // Make the new handler the last-selected reader in the preview page
       // and make sure the preview page is shown the next time a feed is visited
-      var pb = Cc["@mozilla.org/preferences-service;1"].
-               getService(Ci.nsIPrefService).getBranch(null);
+      var pb = Services.prefs.getBranch(null);
       pb.setCharPref(PREF_SELECTED_READER, "web");
   
       var supportsString = 
         Cc["@mozilla.org/supports-string;1"].
         createInstance(Ci.nsISupportsString);
         supportsString.data = uri;
       pb.setComplexValue(PREF_SELECTED_WEB, Ci.nsISupportsString,
                          supportsString);
@@ -795,19 +806,17 @@ WebContentConverterRegistrar.prototype =
     }
   },
 
   /**
    * Load the auto handler, content handler and protocol tables from 
    * preferences.
    */
   _init: function WCCR__init() {
-    var ps = 
-        Cc["@mozilla.org/preferences-service;1"].
-        getService(Ci.nsIPrefService);
+    var ps = Services.prefs;
 
     var kids = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH)
                  .getChildList("");
 
     // first get the numbers of the providers by getting all ###.uri prefs
     var nums = [];
     for (var i = 0; i < kids.length; i++) {
       var match = /^(\d+)\.uri$/.exec(kids[i]);
@@ -845,19 +854,17 @@ WebContentConverterRegistrar.prototype =
       //LOG("WCCR.init: There is no auto branch, benign");
     }
   },
 
   /**
    * See nsIObserver
    */
   observe: function WCCR_observe(subject, topic, data) {
-    var os = 
-        Cc["@mozilla.org/observer-service;1"].
-        getService(Ci.nsIObserverService);
+    var os = Services.obs;
     switch (topic) {
     case "app-startup":
       os.addObserver(this, "browser-ui-startup-complete", false);
       break;
     case "browser-ui-startup-complete":
       os.removeObserver(this, "browser-ui-startup-complete");
       this._init();
       break;
@@ -885,9 +892,76 @@ WebContentConverterRegistrar.prototype =
       Ci.nsIFactory]),
 
   _xpcom_categories: [{
     category: "app-startup",
     service: true
   }]
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WebContentConverterRegistrar]);
+function WebContentConverterRegistrarContent() {
+}
+
+WebContentConverterRegistrarContent.prototype = {
+  /**
+   * See nsIWebContentHandlerRegistrar
+   */
+  registerContentHandler(aContentType, aURIString, aTitle, aBrowserOrWindow) {
+    // aBrowserOrWindow must be a window.
+    let messageManager = aBrowserOrWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                                         .getInterface(Ci.nsIWebNavigation)
+                                         .QueryInterface(Ci.nsIDocShell)
+                                         .QueryInterface(Ci.nsIInterfaceRequestor)
+                                         .getInterface(Ci.nsITabChild)
+                                         .messageManager;
+
+    let uri = Utils.checkAndGetURI(aURIString, aBrowserOrWindow);
+    if (Utils.resolveContentType(aContentType) != TYPE_MAYBE_FEED) {
+      return;
+    }
+
+    messageManager.sendAsyncMessage("WCCR:registerContentHandler",
+                                    { contentType: aContentType,
+                                      uri: uri.spec,
+                                      title: aTitle });
+  },
+
+  registerProtocolHandler(aProtocol, aURIString, aTitle, aBrowserOrWindow) {
+    // aBrowserOrWindow must be a window.
+    let messageManager = aBrowserOrWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                                         .getInterface(Ci.nsIWebNavigation)
+                                         .QueryInterface(Ci.nsIDocShell)
+                                         .QueryInterface(Ci.nsIInterfaceRequestor)
+                                         .getInterface(Ci.nsITabChild)
+                                         .messageManager;
+
+    let uri = Utils.checkAndGetURI(aURIString, aBrowserOrWindow);
+    Utils.checkProtocolHandlerAllowed(aProtocol, aURIString);
+
+    messageManager.sendAsyncMessage("WCCR:registerProtocolHandler",
+                                    { protocol: aProtocol,
+                                      uri: uri.spec,
+                                      title: aTitle });
+  },
+
+  /**
+   * See nsIFactory
+   */
+  createInstance: function WCCR_createInstance(outer, iid) {
+    if (outer != null)
+      throw Cr.NS_ERROR_NO_AGGREGATION;
+    return this.QueryInterface(iid);
+  },
+
+  classID: WCCR_CLASSID,
+
+  /**
+   * See nsISupports
+   */
+  QueryInterface: XPCOMUtils.generateQI(
+                     [Ci.nsIWebContentHandlerRegistrar,
+                      Ci.nsIFactory])
+};
+
+this.NSGetFactory =
+  (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) ?
+    XPCOMUtils.generateNSGetFactory([WebContentConverterRegistrarContent]) :
+    XPCOMUtils.generateNSGetFactory([WebContentConverterRegistrar]);
--- a/browser/components/feeds/test/mochitest.ini
+++ b/browser/components/feeds/test/mochitest.ini
@@ -1,15 +1,18 @@
 [DEFAULT]
-skip-if = buildapp == 'mulet' || buildapp == 'b2g' || e10s
+skip-if = buildapp == 'mulet' || buildapp == 'b2g'
 support-files =
   bug368464-data.xml
   bug408328-data.xml
   bug436801-data.xml
   bug494328-data.xml
   bug589543-data.xml
   valid-feed.xml
   valid-unsniffable-feed.xml
 
 [test_bug436801.html]
+skip-if = e10s
 [test_bug494328.html]
+skip-if = e10s
 [test_bug589543.html]
+skip-if = e10s
 [test_registerHandler.html]
--- a/browser/components/feeds/test/test_registerHandler.html
+++ b/browser/components/feeds/test/test_registerHandler.html
@@ -34,52 +34,52 @@ https://bugzilla.mozilla.org/show_bug.cg
 
     return true;
   }
 
   ok(navigator.registerProtocolHandler, "navigator.registerProtocolHandler should be defined");
   ok(navigator.registerContentHandler, "navigator.registerContentHandler should be defined");
 
   // testing a generic case
-  is(true, testRegisterHandler(true, "foo", "http://mochi.test:8888/%s", "Foo handler"), "registering a foo protocol handler should work");
-  is(true, testRegisterHandler(false, "application/rss+xml", "http://mochi.test:8888/%s", "Foo handler"), "registering a foo content handler should work");
+  is(testRegisterHandler(true, "foo", "http://mochi.test:8888/%s", "Foo handler"), true, "registering a foo protocol handler should work");
+  is(testRegisterHandler(false, "application/rss+xml", "http://mochi.test:8888/%s", "Foo handler"), true, "registering a foo content handler should work");
 
   // testing with wrong uris
-  is(false, testRegisterHandler(true, "foo", "http://mochi.test:8888/", "Foo handler"), "a protocol handler uri should contain %s");
-  is(false, testRegisterHandler(false, "application/rss+xml", "http://mochi.test:8888/", "Foo handler"), "a content handler uri should contain %s");
+  is(testRegisterHandler(true, "foo", "http://mochi.test:8888/", "Foo handler"), false, "a protocol handler uri should contain %s");
+  is(testRegisterHandler(false, "application/rss+xml", "http://mochi.test:8888/", "Foo handler"), false, "a content handler uri should contain %s");
 
   // the spec explicitly allows relative urls to be passed
-  is(true, testRegisterHandler(true, "foo", "foo/%s", "Foo handler"), "a protocol handler uri should be valid");
-  is(true, testRegisterHandler(false, "application/rss+xml", "foo/%s", "Foo handler"), "a content handler uri should be valid");
+  is(testRegisterHandler(true, "foo", "foo/%s", "Foo handler"), true, "a protocol handler uri should be valid");
+  is(testRegisterHandler(false, "application/rss+xml", "foo/%s", "Foo handler"), true, "a content handler uri should be valid");
 
   // we should only accept to register when the handler has the same host as the current page (bug 402287)
-  is(false, testRegisterHandler(true, "foo", "http://remotehost:8888/%s", "Foo handler"), "registering a foo protocol handler with a different host should not work");
-  is(false, testRegisterHandler(false, "application/rss+xml", "http://remotehost:8888/%s", "Foo handler"), "registering a foo content handler with a different host should not work");
+  is(testRegisterHandler(true, "foo", "http://remotehost:8888/%s", "Foo handler"), false, "registering a foo protocol handler with a different host should not work");
+  is(testRegisterHandler(false, "application/rss+xml", "http://remotehost:8888/%s", "Foo handler"), false, "registering a foo content handler with a different host should not work");
 
   // restriction to http(s) for the uri of the handler (bug 401343)
   // https should work (http already tested in the generic case)
-  is(true, testRegisterHandler(true, "foo", "https://mochi.test:8888/%s", "Foo handler"), "registering a foo protocol handler with https scheme should work");
-  is(true, testRegisterHandler(false, "application/rss+xml", "https://mochi.test:8888/%s", "Foo handler"), "registering a foo content handler with https scheme should work");
+  is(testRegisterHandler(true, "foo", "https://mochi.test:8888/%s", "Foo handler"), true, "registering a foo protocol handler with https scheme should work");
+  is(testRegisterHandler(false, "application/rss+xml", "https://mochi.test:8888/%s", "Foo handler"), true, "registering a foo content handler with https scheme should work");
   // ftp should not work
-  is(false, testRegisterHandler(true, "foo", "ftp://mochi.test:8888/%s", "Foo handler"), "registering a foo protocol handler with ftp scheme should not work");
-  is(false, testRegisterHandler(false, "application/rss+xml", "ftp://mochi.test:8888/%s", "Foo handler"), "registering a foo content handler with ftp scheme should not work");
+  is(testRegisterHandler(true, "foo", "ftp://mochi.test:8888/%s", "Foo handler"), false, "registering a foo protocol handler with ftp scheme should not work");
+  is(testRegisterHandler(false, "application/rss+xml", "ftp://mochi.test:8888/%s", "Foo handler"), false, "registering a foo content handler with ftp scheme should not work");
   // chrome should not work 
-  is(false, testRegisterHandler(true, "foo", "chrome://mochi.test:8888/%s", "Foo handler"), "registering a foo protocol handler with chrome scheme should not work");
-  is(false, testRegisterHandler(false, "application/rss+xml", "chrome://mochi.test:8888/%s", "Foo handler"), "registering a foo content handler with chrome scheme should not work");
+  is(testRegisterHandler(true, "foo", "chrome://mochi.test:8888/%s", "Foo handler"), false, "registering a foo protocol handler with chrome scheme should not work");
+  is(testRegisterHandler(false, "application/rss+xml", "chrome://mochi.test:8888/%s", "Foo handler"), false, "registering a foo content handler with chrome scheme should not work");
   // foo should not work 
-  is(false, testRegisterHandler(true, "foo", "foo://mochi.test:8888/%s", "Foo handler"), "registering a foo protocol handler with foo scheme should not work");
-  is(false, testRegisterHandler(false, "application/rss+xml", "foo://mochi.test:8888/%s", "Foo handler"), "registering a foo content handler with foo scheme should not work");
+  is(testRegisterHandler(true, "foo", "foo://mochi.test:8888/%s", "Foo handler"), false, "registering a foo protocol handler with foo scheme should not work");
+  is(testRegisterHandler(false, "application/rss+xml", "foo://mochi.test:8888/%s", "Foo handler"), false, "registering a foo content handler with foo scheme should not work");
 
   // for security reasons, protocol handlers should never be registered for some schemes (chrome, vbscript, ...) (bug 402788)
-  is(false, testRegisterHandler(true, "chrome", "http://mochi.test:8888/%s", "chrome handler"), "registering a chrome protocol handler should not work");
-  is(false, testRegisterHandler(true, "vbscript", "http://mochi.test:8888/%s", "vbscript handler"), "registering a vbscript protocol handler should not work");
-  is(false, testRegisterHandler(true, "javascript", "http://mochi.test:8888/%s", "javascript handler"), "registering a javascript protocol handler should not work");
-  is(false, testRegisterHandler(true, "moz-icon", "http://mochi.test:8888/%s", "moz-icon handler"), "registering a moz-icon protocol handler should not work");
+  is(testRegisterHandler(true, "chrome", "http://mochi.test:8888/%s", "chrome handler"), false, "registering a chrome protocol handler should not work");
+  is(testRegisterHandler(true, "vbscript", "http://mochi.test:8888/%s", "vbscript handler"), false, "registering a vbscript protocol handler should not work");
+  is(testRegisterHandler(true, "javascript", "http://mochi.test:8888/%s", "javascript handler"), false, "registering a javascript protocol handler should not work");
+  is(testRegisterHandler(true, "moz-icon", "http://mochi.test:8888/%s", "moz-icon handler"), false, "registering a moz-icon protocol handler should not work");
 
   // for security reasons, content handlers should never be registered for some types (html, ...)
-  is(true, testRegisterHandler(false, "application/rss+xml", "http://mochi.test:8888/%s", "Foo handler"), "registering rss content handlers should work");
-  is(true, testRegisterHandler(false, "application/atom+xml", "http://mochi.test:8888/%s", "Foo handler"), "registering atom content handlers should work");
-  todo(false, testRegisterHandler(false, "text/html", "http://mochi.test:8888/%s", "Foo handler"), "registering html content handlers should not work"); // bug 403798
+  is(testRegisterHandler(false, "application/rss+xml", "http://mochi.test:8888/%s", "Foo handler"), true, "registering rss content handlers should work");
+  is(testRegisterHandler(false, "application/atom+xml", "http://mochi.test:8888/%s", "Foo handler"), true, "registering atom content handlers should work");
+  todo_is(testRegisterHandler(false, "text/html", "http://mochi.test:8888/%s", "Foo handler"), false, "registering html content handlers should not work"); // bug 403798
 
 </script>
 </pre>
 </body>
 </html>
--- a/browser/components/loop/test/desktop-local/conversationViews_test.js
+++ b/browser/components/loop/test/desktop-local/conversationViews_test.js
@@ -97,18 +97,23 @@ describe("loop.conversationViews", funct
     loop.shared.mixins.setRootObject(fakeWindow);
 
     conversationStore = new loop.store.ConversationStore(dispatcher, {
       client: {},
       mozLoop: fakeMozLoop,
       sdkDriver: {}
     });
 
+    var textChatStore = new loop.store.TextChatStore(dispatcher, {
+      sdkDriver: {}
+    });
+
     loop.store.StoreMixin.register({
-      conversationStore: conversationStore
+      conversationStore: conversationStore,
+      textChatStore: textChatStore
     });
   });
 
   afterEach(function() {
     loop.shared.mixins.setRootObject(window);
     view = undefined;
     delete navigator.mozLoop;
     sandbox.restore();
--- a/browser/components/loop/test/shared/mixins_test.js
+++ b/browser/components/loop/test/shared/mixins_test.js
@@ -222,19 +222,19 @@ describe("loop.shared.mixins", function(
       };
 
       sharedMixins.setRootObject(rootObject);
 
       view = TestUtils.renderIntoDocument(React.createElement(TestComp));
 
       sandbox.stub(view, "getDOMNode").returns({
         querySelector: function(classSelector) {
-          if (classSelector.includes("local")) {
+          if (classSelector.indexOf("local") > -1) {
             return localElement;
-          } else if (classSelector.includes("screen")) {
+          } else if (classSelector.indexOf("screen") > -1) {
             return screenShareElement;
           }
           return remoteElement;
         }
       });
     });
 
     afterEach(function() {
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -89,16 +89,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/osfile.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "RemotePrompt",
                                   "resource:///modules/RemotePrompt.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ContentPrefServiceParent",
                                   "resource://gre/modules/ContentPrefServiceParent.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "Feeds",
+                                  "resource:///modules/Feeds.jsm");
+
 XPCOMUtils.defineLazyModuleGetter(this, "SelfSupportBackend",
                                   "resource:///modules/SelfSupportBackend.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
                                   "resource:///modules/sessionstore/SessionStore.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
                                   "resource:///modules/BrowserUITelemetry.jsm");
@@ -757,16 +760,17 @@ BrowserGlue.prototype = {
     AboutNewTab.init();
     SessionStore.init();
     BrowserUITelemetry.init();
     ContentSearch.init();
     FormValidationHandler.init();
 
     ContentClick.init();
     RemotePrompt.init();
+    Feeds.init();
     ContentPrefServiceParent.init();
 
     LoginManagerParent.init();
     ReaderParent.init();
 
     SelfSupportBackend.init();
 
 #ifdef NIGHTLY_BUILD
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -84,43 +84,43 @@
 </hbox>
 
 <!-- Tracking -->
 <groupbox id="trackingGroup" data-category="panePrivacy" hidden="true" align="start">
   <caption><label>&tracking.label;</label></caption>
   <vbox>
     <hbox align="center">
       <checkbox id="privacyDoNotTrackCheckbox"
-                label="&dntTrackingNotOkay3.label;"
-                accesskey="&dntTrackingNotOkay3.accesskey;"
+                label="&dntTrackingNotOkay4.label;"
+                accesskey="&dntTrackingNotOkay4.accesskey;"
                 preference="privacy.donottrackheader.enabled"/>
       <label id="doNotTrackInfo"
              class="text-link"
              href="https://www.mozilla.org/dnt">
         &doNotTrackInfo.label;
       </label>
     </hbox>
   </vbox>
   <vbox id="trackingprotectionbox" hidden="true">
     <hbox align="center">
       <checkbox id="trackingProtection"
                 preference="privacy.trackingprotection.enabled"
-                accesskey="&trackingProtection3.accesskey;"
-                label="&trackingProtection3.label;" />
+                accesskey="&trackingProtection4.accesskey;"
+                label="&trackingProtection4.label;" />
       <label id="trackingProtectionLearnMore"
              class="text-link"
              value="&trackingProtectionLearnMore.label;"/>
     </hbox>
   </vbox>
   <vbox id="trackingprotectionpbmbox">
     <hbox align="center">
       <checkbox id="trackingProtectionPBM"
                 preference="privacy.trackingprotection.pbmode.enabled"
-                accesskey="&trackingProtectionPBM3.accesskey;"
-                label="&trackingProtectionPBM3.label;" />
+                accesskey="&trackingProtectionPBM4.accesskey;"
+                label="&trackingProtectionPBM4.label;" />
       <label id="trackingProtectionPBMLearnMore"
              class="text-link"
              value="&trackingProtectionPBMLearnMore.label;"/>
     </hbox>
   </vbox>
 </groupbox>
 
 <!-- History -->
--- a/browser/components/preferences/privacy.xul
+++ b/browser/components/preferences/privacy.xul
@@ -91,33 +91,33 @@
 
     <!-- Tracking -->
     <groupbox id="trackingGroup" align="start">
       <caption label="&tracking.label;"/>
       <vbox id="trackingprotectionbox" hidden="true">
         <hbox align="center">
           <checkbox id="trackingProtection"
                     preference="privacy.trackingprotection.enabled"
-                    accesskey="&trackingProtection3.accesskey;"
-                    label="&trackingProtection3.label;" />
+                    accesskey="&trackingProtection4.accesskey;"
+                    label="&trackingProtection4.label;" />
           <image id="trackingProtectionImage"
                  src="chrome://browser/skin/bad-content-blocked-16.png"/>
         </hbox>
         <hbox align="center"
               class="indent">
           <label id="trackingProtectionLearnMore"
                  class="text-link"
                  value="&trackingProtectionLearnMore.label;"/>
         </hbox>
       </vbox>
       <vbox>
         <hbox align="center">
           <checkbox id="privacyDoNotTrackCheckbox"
-                    label="&dntTrackingNotOkay3.label;"
-                    accesskey="&dntTrackingNotOkay3.accesskey;"
+                    label="&dntTrackingNotOkay4.label;"
+                    accesskey="&dntTrackingNotOkay4.accesskey;"
                     preference="privacy.donottrackheader.enabled"/>
         </hbox>
         <hbox align="center"
               class="indent">
           <label id="doNotTrackInfo"
                  class="text-link"
                  href="https://www.mozilla.org/dnt">
             &doNotTrackInfo.label;
--- a/browser/components/privatebrowsing/test/browser/browser.ini
+++ b/browser/components/privatebrowsing/test/browser/browser.ini
@@ -33,17 +33,16 @@ support-files =
 [browser_privatebrowsing_localStorage_before_after.js]
 [browser_privatebrowsing_noSessionRestoreMenuOption.js]
 [browser_privatebrowsing_nonbrowser.js]
 [browser_privatebrowsing_opendir.js]
 [browser_privatebrowsing_placesTitleNoUpdate.js]
 [browser_privatebrowsing_placestitle.js]
 [browser_privatebrowsing_popupblocker.js]
 [browser_privatebrowsing_protocolhandler.js]
-skip-if = e10s # Bug 940206 -  nsIWebContentHandlerRegistrar::registerProtocolHandler doesn't work in e10s
 [browser_privatebrowsing_sidebar.js]
 [browser_privatebrowsing_theming.js]
 [browser_privatebrowsing_ui.js]
 [browser_privatebrowsing_urlbarfocus.js]
 [browser_privatebrowsing_windowtitle.js]
 skip-if = e10s
 [browser_privatebrowsing_zoom.js]
 skip-if = e10s
--- a/browser/config/mozconfigs/linux64/hazards
+++ b/browser/config/mozconfigs/linux64/hazards
@@ -21,13 +21,12 @@ mk_add_options MOZ_OBJDIR=obj-analyzed
 ac_add_options --enable-debug
 ac_add_options --enable-tests
 ac_add_options --enable-optimize
 
 CFLAGS="$CFLAGS -Wno-attributes"
 CPPFLAGS="$CPPFLAGS -Wno-attributes"
 CXXFLAGS="$CXXFLAGS -Wno-attributes"
 
-TOOLTOOL_DIR="$(dirname $topsrcdir)"
 export PKG_CONFIG_LIBDIR=/usr/lib64/pkgconfig:/usr/share/pkgconfig
 . $topsrcdir/build/unix/mozconfig.gtk
 
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/tooltool-manifests/linux32/releng.manifest
+++ b/browser/config/tooltool-manifests/linux32/releng.manifest
@@ -2,21 +2,20 @@
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512", 
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 11179576,
-"digest": "91567ce8e2bb8ab0ebc60c31e90731d88a1ea889fb71bcf55c735746a60fa7610b7e040ea3d8f727b6f692ae3ee703d6f3b30cdbd76fdf5617f77d9c38aa20ed",
+"size": 4079256,
+"digest": "bb5238558bcf6db2ca395513c8dccaa15dd61b3c375598eb6a685356b0c1a2d9840e3bf81bc00242b872fd798541f53d723777c754412abf0e772b7cc284937c",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
-"setup": "setup.sh",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
 "filename": "sccache.tar.bz2",
 "unpack": true
new file mode 100644
--- /dev/null
+++ b/browser/config/tooltool-manifests/linux32/valgrind.manifest
@@ -0,0 +1,16 @@
+[
+{
+"size": 80458572,
+"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"algorithm": "sha512", 
+"filename": "gcc.tar.xz",
+"unpack": true
+},
+{
+"size": 167175,
+"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
+"algorithm": "sha512",
+"filename": "sccache.tar.bz2",
+"unpack": true
+}
+]
--- a/browser/config/tooltool-manifests/linux64/clang.manifest
+++ b/browser/config/tooltool-manifests/linux64/clang.manifest
@@ -3,18 +3,10 @@
 "clang_version": "r241406"
 }, 
 {
 "size": 100307285, 
 "digest": "4d147d0072a928945fc1e938f39a5d0a9d3c676399c09e092c8750b2f973cdbbebda8d94d4d05805fae74a5c49c54263dc22b8b443c23c9a0ae830a261d3cf30", 
 "algorithm": "sha512", 
 "filename": "clang.tar.bz2",
 "unpack": true
-},
-{
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
-"algorithm": "sha512",
-"filename": "gtk3.tar.xz",
-"setup": "setup.sh",
-"unpack": true
 }
 ]
--- a/browser/config/tooltool-manifests/linux64/releng.manifest
+++ b/browser/config/tooltool-manifests/linux64/releng.manifest
@@ -2,21 +2,20 @@
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512", 
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 4431740,
+"digest": "68fc56b0fb0cdba629b95683d6649ff76b00dccf97af90960c3d7716f6108b2162ffd5ffcd5c3a60a21b28674df688fe4dabc67345e2da35ec5abeae3d48c8e3",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
-"setup": "setup.sh",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
 "filename": "sccache.tar.bz2",
 "unpack": true
--- a/browser/config/tooltool-manifests/linux64/tsan.manifest
+++ b/browser/config/tooltool-manifests/linux64/tsan.manifest
@@ -5,16 +5,15 @@
 {
 "size": 89690541, 
 "digest": "470d258d9785a120fcba65eee90daa632a42affa0f97f57d70fc8285bd76bcc27d4d0d70b6c37577ab271a04c843b6269425391a8d6df1967718dba26dd3a73d", 
 "algorithm": "sha512", 
 "filename": "clang.tar.bz2",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 4431740,
+"digest": "68fc56b0fb0cdba629b95683d6649ff76b00dccf97af90960c3d7716f6108b2162ffd5ffcd5c3a60a21b28674df688fe4dabc67345e2da35ec5abeae3d48c8e3",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
-"setup": "setup.sh",
 "unpack": true
 }
 ]
new file mode 100644
--- /dev/null
+++ b/browser/config/tooltool-manifests/linux64/valgrind.manifest
@@ -0,0 +1,16 @@
+[
+{
+"size": 80458572,
+"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
+"algorithm": "sha512", 
+"filename": "gcc.tar.xz",
+"unpack": true
+},
+{
+"size": 167175,
+"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
+"algorithm": "sha512",
+"filename": "sccache.tar.bz2",
+"unpack": true
+}
+]
--- a/browser/devtools/performance/modules/widgets/marker-details.js
+++ b/browser/devtools/performance/modules/widgets/marker-details.js
@@ -97,17 +97,17 @@ MarkerDetails.prototype = {
   },
 
   /**
    * Handles click in the marker details view. Based on the target,
    * can handle different actions -- only supporting view source links
    * for the moment.
    */
   _onClick: function (e) {
-    let data = findActionFromEvent(e.target);
+    let data = findActionFromEvent(e.target, this._parent);
     if (!data) {
       return;
     }
 
     if (data.action === "view-source") {
       this.emit("view-source", data.url, data.line);
     }
   },
@@ -116,17 +116,17 @@ MarkerDetails.prototype = {
    * Handles the "mouseup" event on the marker details view splitter.
    */
   _onSplitterMouseUp: function() {
     this.emit("resize");
   }
 };
 
 /**
- * Take an element from an event `target`, and asend through
+ * Take an element from an event `target`, and ascend through
  * the DOM, looking for an element with a `data-action` attribute. Return
  * the parsed `data-action` value found, or null if none found before
  * reaching the parent `container`.
  *
  * @param {Element} target
  * @param {Element} container
  * @return {?object}
  */
--- a/browser/locales/en-US/chrome/browser/preferences/privacy.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/privacy.dtd
@@ -1,22 +1,22 @@
 <!-- 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 tracking.label                 "Tracking">
 
-<!ENTITY dntTrackingNotOkay3.label     "Request that sites not track you.">
-<!ENTITY dntTrackingNotOkay3.accesskey "n">
+<!ENTITY dntTrackingNotOkay4.label     "Request that sites not track you">
+<!ENTITY dntTrackingNotOkay4.accesskey "n">
 <!ENTITY doNotTrackInfo.label          "Learn More">
-<!ENTITY trackingProtection3.label     "Stop sites from tracking you.">
-<!ENTITY trackingProtection3.accesskey "m">
+<!ENTITY trackingProtection4.label     "Stop sites from tracking you">
+<!ENTITY trackingProtection4.accesskey "m">
 <!ENTITY trackingProtectionLearnMore.label "Learn more">
-<!ENTITY trackingProtectionPBM3.label         "Stop sites from tracking you in Private Windows.">
-<!ENTITY trackingProtectionPBM3.accesskey     "y">
+<!ENTITY trackingProtectionPBM4.label         "Stop sites from tracking you in Private Windows">
+<!ENTITY trackingProtectionPBM4.accesskey     "y">
 <!ENTITY trackingProtectionPBMLearnMore.label "Learn more">
 
 <!ENTITY  history.label                 "History">
 
 <!ENTITY  locationBar.label             "Location Bar">
 
 <!ENTITY  locbar.suggest.label          "When using the location bar, suggest:">
 <!ENTITY  locbar.history.label          "History">
--- a/browser/modules/Feeds.jsm
+++ b/browser/modules/Feeds.jsm
@@ -7,19 +7,45 @@
 this.EXPORTED_SYMBOLS = [ "Feeds" ];
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
                                   "resource://gre/modules/BrowserUtils.jsm");
 
-const Ci = Components.interfaces;
+const { interfaces: Ci, classes: Cc } = Components;
 
 this.Feeds = {
+  init() {
+    let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
+    mm.addMessageListener("WCCR:registerProtocolHandler", this);
+  },
+
+  receiveMessage(aMessage) {
+    switch (aMessage.name) {
+      case "WCCR:registerProtocolHandler": {
+        let data = aMessage.data;
+        let registrar = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
+                          getService(Ci.nsIWebContentHandlerRegistrar);
+        registrar.registerProtocolHandler(data.protocol, data.uri, data.title,
+                                          aMessage.target);
+        break;
+      }
+
+      case "WCCR:registerContentHandler": {
+        let data = aMessage.data;
+        let registrar = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
+                          getService(Ci.nsIWebContentHandlerRegistrar);
+        registrar.registerContentHandler(data.contentType, data.uri, data.title,
+                                         aMessage.target);
+        break;
+      }
+    }
+  },
 
   /**
    * isValidFeed: checks whether the given data represents a valid feed.
    *
    * @param  aLink
    *         An object representing a feed with title, href and type.
    * @param  aPrincipal
    *         The principal of the document, used for security check.
deleted file mode 100644
--- a/browser/themes/linux/devtools/canvasdebugger.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../../shared/devtools/canvasdebugger.inc.css
deleted file mode 100644
--- a/browser/themes/linux/devtools/debugger.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../../shared/devtools/debugger.inc.css
deleted file mode 100644
--- a/browser/themes/linux/devtools/performance.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../../shared/devtools/performance.inc.css
deleted file mode 100644
--- a/browser/themes/linux/devtools/scratchpad.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../../shared/devtools/scratchpad.inc.css
\ No newline at end of file
deleted file mode 100644
--- a/browser/themes/linux/devtools/shadereditor.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../../shared/devtools/shadereditor.inc.css
deleted file mode 100644
--- a/browser/themes/linux/devtools/webaudioeditor.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../../shared/devtools/webaudioeditor.inc.css
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -330,29 +330,29 @@ browser.jar:
   skin/classic/browser/devtools/editor-error.png       (../shared/devtools/images/editor-error.png)
   skin/classic/browser/devtools/editor-breakpoint.png  (../shared/devtools/images/editor-breakpoint.png)
   skin/classic/browser/devtools/editor-debug-location.png (../shared/devtools/images/editor-debug-location.png)
   skin/classic/browser/devtools/editor-debug-location@2x.png (../shared/devtools/images/editor-debug-location@2x.png)
   skin/classic/browser/devtools/breadcrumbs-divider@2x.png      (../shared/devtools/images/breadcrumbs-divider@2x.png)
   skin/classic/browser/devtools/breadcrumbs-scrollbutton.png    (../shared/devtools/images/breadcrumbs-scrollbutton.png)
   skin/classic/browser/devtools/breadcrumbs-scrollbutton@2x.png (../shared/devtools/images/breadcrumbs-scrollbutton@2x.png)
   skin/classic/browser/devtools/animationinspector.css          (../shared/devtools/animationinspector.css)
-* skin/classic/browser/devtools/canvasdebugger.css    (devtools/canvasdebugger.css)
-* skin/classic/browser/devtools/debugger.css          (devtools/debugger.css)
+* skin/classic/browser/devtools/canvasdebugger.css    (../shared/devtools/canvasdebugger.css)
+  skin/classic/browser/devtools/debugger.css          (../shared/devtools/debugger.css)
   skin/classic/browser/devtools/eyedropper.css        (../shared/devtools/eyedropper.css)
 * skin/classic/browser/devtools/netmonitor.css        (devtools/netmonitor.css)
-* skin/classic/browser/devtools/performance.css       (devtools/performance.css)
+  skin/classic/browser/devtools/performance.css       (../shared/devtools/performance.css)
   skin/classic/browser/devtools/promisedebugger.css   (../shared/devtools/promisedebugger.css)
   skin/classic/browser/devtools/timeline-filter.svg   (../shared/devtools/images/timeline-filter.svg)
-* skin/classic/browser/devtools/scratchpad.css        (devtools/scratchpad.css)
-* skin/classic/browser/devtools/shadereditor.css      (devtools/shadereditor.css)
+* skin/classic/browser/devtools/scratchpad.css        (../shared/devtools/scratchpad.css)
+  skin/classic/browser/devtools/shadereditor.css      (../shared/devtools/shadereditor.css)
 * skin/classic/browser/devtools/splitview.css         (../shared/devtools/splitview.css)
   skin/classic/browser/devtools/styleeditor.css       (../shared/devtools/styleeditor.css)
   skin/classic/browser/devtools/storage.css           (../shared/devtools/storage.css)
-* skin/classic/browser/devtools/webaudioeditor.css    (devtools/webaudioeditor.css)
+  skin/classic/browser/devtools/webaudioeditor.css    (../shared/devtools/webaudioeditor.css)
   skin/classic/browser/devtools/magnifying-glass.png        (../shared/devtools/images/magnifying-glass.png)
   skin/classic/browser/devtools/magnifying-glass@2x.png     (../shared/devtools/images/magnifying-glass@2x.png)
   skin/classic/browser/devtools/magnifying-glass-light.png  (../shared/devtools/images/magnifying-glass-light.png)
   skin/classic/browser/devtools/magnifying-glass-light@2x.png (../shared/devtools/images/magnifying-glass-light@2x.png)
   skin/classic/browser/devtools/itemToggle.png         (../shared/devtools/images/itemToggle.png)
   skin/classic/browser/devtools/itemToggle@2x.png      (../shared/devtools/images/itemToggle@2x.png)
   skin/classic/browser/devtools/itemArrow-dark-rtl.svg (../shared/devtools/images/itemArrow-dark-rtl.svg)
   skin/classic/browser/devtools/itemArrow-dark-ltr.svg (../shared/devtools/images/itemArrow-dark-ltr.svg)
deleted file mode 100644
--- a/browser/themes/osx/devtools/canvasdebugger.css
+++ /dev/null
@@ -1,6 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../shared.inc
-%include ../../shared/devtools/canvasdebugger.inc.css
deleted file mode 100644
--- a/browser/themes/osx/devtools/debugger.css
+++ /dev/null
@@ -1,6 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../shared.inc
-%include ../../shared/devtools/debugger.inc.css
deleted file mode 100644
--- a/browser/themes/osx/devtools/performance.css
+++ /dev/null
@@ -1,6 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../shared.inc
-%include ../../shared/devtools/performance.inc.css
deleted file mode 100644
--- a/browser/themes/osx/devtools/scratchpad.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../../shared/devtools/scratchpad.inc.css
\ No newline at end of file
deleted file mode 100644
--- a/browser/themes/osx/devtools/shadereditor.css
+++ /dev/null
@@ -1,6 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../shared.inc
-%include ../../shared/devtools/shadereditor.inc.css
deleted file mode 100644
--- a/browser/themes/osx/devtools/webaudioeditor.css
+++ /dev/null
@@ -1,6 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../shared.inc
-%include ../../shared/devtools/webaudioeditor.inc.css
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -432,29 +432,29 @@ browser.jar:
   skin/classic/browser/devtools/editor-debug-location@2x.png    (../shared/devtools/images/editor-debug-location@2x.png)
 * skin/classic/browser/devtools/webconsole.css                  (devtools/webconsole.css)
   skin/classic/browser/devtools/webconsole_networkpanel.css     (devtools/webconsole_networkpanel.css)
   skin/classic/browser/devtools/webconsole.svg                  (../shared/devtools/images/webconsole.svg)
   skin/classic/browser/devtools/breadcrumbs-divider@2x.png      (../shared/devtools/images/breadcrumbs-divider@2x.png)
   skin/classic/browser/devtools/breadcrumbs-scrollbutton.png    (../shared/devtools/images/breadcrumbs-scrollbutton.png)
   skin/classic/browser/devtools/breadcrumbs-scrollbutton@2x.png (../shared/devtools/images/breadcrumbs-scrollbutton@2x.png)
   skin/classic/browser/devtools/animationinspector.css          (../shared/devtools/animationinspector.css)
-* skin/classic/browser/devtools/canvasdebugger.css          (devtools/canvasdebugger.css)
-* skin/classic/browser/devtools/debugger.css                (devtools/debugger.css)
+* skin/classic/browser/devtools/canvasdebugger.css          (../shared/devtools/canvasdebugger.css)
+  skin/classic/browser/devtools/debugger.css                (../shared/devtools/debugger.css)
   skin/classic/browser/devtools/eyedropper.css              (../shared/devtools/eyedropper.css)
 * skin/classic/browser/devtools/netmonitor.css              (devtools/netmonitor.css)
-* skin/classic/browser/devtools/performance.css             (devtools/performance.css)
+  skin/classic/browser/devtools/performance.css             (../shared/devtools/performance.css)
   skin/classic/browser/devtools/promisedebugger.css         (../shared/devtools/promisedebugger.css)
   skin/classic/browser/devtools/timeline-filter.svg         (../shared/devtools/images/timeline-filter.svg)
-* skin/classic/browser/devtools/scratchpad.css              (devtools/scratchpad.css)
-* skin/classic/browser/devtools/shadereditor.css            (devtools/shadereditor.css)
+* skin/classic/browser/devtools/scratchpad.css              (../shared/devtools/scratchpad.css)
+  skin/classic/browser/devtools/shadereditor.css            (../shared/devtools/shadereditor.css)
 * skin/classic/browser/devtools/splitview.css               (../shared/devtools/splitview.css)
   skin/classic/browser/devtools/styleeditor.css             (../shared/devtools/styleeditor.css)
   skin/classic/browser/devtools/storage.css                 (../shared/devtools/storage.css)
-* skin/classic/browser/devtools/webaudioeditor.css          (devtools/webaudioeditor.css)
+  skin/classic/browser/devtools/webaudioeditor.css          (../shared/devtools/webaudioeditor.css)
   skin/classic/browser/devtools/magnifying-glass.png        (../shared/devtools/images/magnifying-glass.png)
   skin/classic/browser/devtools/magnifying-glass@2x.png     (../shared/devtools/images/magnifying-glass@2x.png)
   skin/classic/browser/devtools/magnifying-glass-light.png  (../shared/devtools/images/magnifying-glass-light.png)
   skin/classic/browser/devtools/magnifying-glass-light@2x.png (../shared/devtools/images/magnifying-glass-light@2x.png)
   skin/classic/browser/devtools/itemToggle.png              (../shared/devtools/images/itemToggle.png)
   skin/classic/browser/devtools/itemToggle@2x.png           (../shared/devtools/images/itemToggle@2x.png)
   skin/classic/browser/devtools/itemArrow-dark-rtl.svg      (../shared/devtools/images/itemArrow-dark-rtl.svg)
   skin/classic/browser/devtools/itemArrow-dark-ltr.svg      (../shared/devtools/images/itemArrow-dark-ltr.svg)
--- a/browser/themes/shared/devedition.inc.css
+++ b/browser/themes/shared/devedition.inc.css
@@ -48,20 +48,22 @@
   --toolbarbutton-combined-boxshadow: none;
   --toolbarbutton-combined-backgroundimage: linear-gradient(#5F6670 0, #5F6670 18px);
 
   /* Url and search bars */
   --url-and-searchbar-background-color: #171B1F;
   --url-and-searchbar-color: #fff;
   --urlbar-dropmarker-url: url("chrome://browser/skin/devedition/urlbar-history-dropmarker.svg");
   --urlbar-dropmarker-region: rect(0px, 11px, 14px, 0px);
-  --urlbar-dropmarker-active-region: rect(0px, 22px, 14px, 11px);
+  --urlbar-dropmarker-hover-region: rect(0, 22px, 14px, 11px);
+  --urlbar-dropmarker-active-region: rect(0px, 33px, 14px, 22px);
   --urlbar-dropmarker-2x-url: url("chrome://browser/skin/devedition/urlbar-history-dropmarker.svg");
   --urlbar-dropmarker-2x-region: rect(0px, 11px, 14px, 0px);
-  --urlbar-dropmarker-active-2x-region: rect(0px, 22px, 14px, 11px);
+  --urlbar-dropmarker-hover-2x-region: rect(0, 22px, 14px, 11px);
+  --urlbar-dropmarker-active-2x-region: rect(0px, 33px, 14px, 22px);
   --search-button-image: url("chrome://browser/skin/devedition/search.svg#search-icon-inverted");
 }
 
 :root[devtoolstheme="dark"] #identity-box {
   --identity-box-border-color: #5F6670;
   --identity-box-chrome-color: #46afe3;
   --identity-box-verified-background-color: transparent;
   --identity-box-selected-background-color: rgba(231,230,230,.2);
rename from browser/themes/shared/devtools/canvasdebugger.inc.css
rename to browser/themes/shared/devtools/canvasdebugger.css
rename from browser/themes/shared/devtools/debugger.inc.css
rename to browser/themes/shared/devtools/debugger.css
rename from browser/themes/shared/devtools/performance.inc.css
rename to browser/themes/shared/devtools/performance.css
rename from browser/themes/shared/devtools/scratchpad.inc.css
rename to browser/themes/shared/devtools/scratchpad.css
rename from browser/themes/shared/devtools/shadereditor.inc.css
rename to browser/themes/shared/devtools/shadereditor.css
rename from browser/themes/shared/devtools/webaudioeditor.inc.css
rename to browser/themes/shared/devtools/webaudioeditor.css
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -195,16 +195,17 @@ treecol {
   -moz-margin-end: 8px !important;
 }
 
 /* Privacy pane */
 
 #doNotTrackInfo,
 #trackingProtectionPBMLearnMore,
 #trackingProtectionLearnMore {
+  -moz-margin-start: 1.5em !important;
   margin-top: 0;
 }
 
 /* Collapse the non-active vboxes in decks to use only the height the
    active vbox needs */
 #historyPane:not([selectedIndex="1"]) > #historyDontRememberPane,
 #historyPane:not([selectedIndex="2"]) > #historyCustomPane,
 #weavePrefsDeck:not([selectedIndex="1"]) > #hasAccount,
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -96,30 +96,37 @@
   display: none;
 }
 
 .tab-icon-overlay[crashed] {
   display: -moz-box;
   list-style-image: url("chrome://browser/skin/tabbrowser/crashed.svg");
 }
 
-.tab-icon-overlay[soundplaying][pinned] {
+.tab-icon-overlay[soundplaying][pinned],
+.tab-icon-overlay[muted][pinned] {
   display: -moz-box;
+  border-radius: 8px;
+}
+
+.tab-icon-overlay[soundplaying][pinned]:hover,
+.tab-icon-overlay[muted][pinned]:hover {
+  background-color: white;
+}
+
+.tab-icon-overlay[soundplaying][pinned] {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio");
-  border-radius: 8px;
 }
 
 .tab-icon-overlay[soundplaying][pinned]:hover {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-hover");
-  background-color: white;
 }
 
 .tab-icon-overlay[soundplaying][pinned]:hover:active {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-pressed");
-  background-color: white;
 }
 
 .tab-icon-overlay[muted][pinned] {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-muted");
 }
 
 .tab-icon-overlay[muted][pinned]:hover {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-muted-hover");
@@ -174,17 +181,17 @@
 
 .tab-icon-sound {
   -moz-margin-start: 4px;
   width: 16px;
   height: 16px;
   padding: 0;
 }
 
-.tab-icon-sound:not([soundplaying]),
+.tab-icon-sound:not([soundplaying]):not([muted]),
 .tab-icon-sound[pinned] {
   display: none;
 }
 
 .tab-icon-sound[soundplaying] {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio");
 }
 
@@ -409,16 +416,17 @@
 /* Tab pointer-events */
 .tabbrowser-tab {
   pointer-events: none;
 }
 
 .tab-background-middle,
 .tabs-newtab-button,
 .tab-icon-overlay[soundplaying],
+.tab-icon-overlay[muted],
 .tab-icon-sound,
 .tab-close-button {
   pointer-events: auto;
 }
 
 /* Pinned tabs */
 
 /* Pinned tab separators need position: absolute when positioned (during overflow). */
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -767,19 +767,19 @@ toolbarbutton[constrain-size="true"][cui
 }
 
 #nav-bar toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
   /* XXXgijs box models strike again: this is 16px + 2 * 7px padding + 2 * 1px border (from the rules above) */
   width: 32px;
 }
 
 #nav-bar .toolbarbutton-1[type=panel] > .toolbarbutton-icon,
-#nav-bar .toolbarbutton-1[type=panel] > .toolbarbutton-badge-container,
-#nav-bar .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#PanelUI-menu-button) > .toolbarbutton-icon,
-#nav-bar .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#PanelUI-menu-button) > .toolbarbutton-badge-container,
+#nav-bar .toolbarbutton-1[type=panel] > .toolbarbutton-badge-stack,
+#nav-bar .toolbarbutton-1[type=menu]:not(#PanelUI-menu-button):not(#back-button):not(#forward-button) > .toolbarbutton-icon,
+#nav-bar .toolbarbutton-1[type=menu]:not(#PanelUI-menu-button) > .toolbarbutton-badge-stack,
 #nav-bar .toolbarbutton-1[type=menu] > .toolbarbutton-text /* hack for add-ons that forcefully display the label */ {
   -moz-padding-end: 17px;
 }
 
 #nav-bar .toolbarbutton-1 > .toolbarbutton-menu-dropmarker {
   -moz-margin-start: -15px;
 }
 
deleted file mode 100644
--- a/browser/themes/windows/devtools/canvasdebugger.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../../shared/devtools/canvasdebugger.inc.css
deleted file mode 100644
--- a/browser/themes/windows/devtools/debugger.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../../shared/devtools/debugger.inc.css
deleted file mode 100644
--- a/browser/themes/windows/devtools/performance.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../../shared/devtools/performance.inc.css
deleted file mode 100644
--- a/browser/themes/windows/devtools/scratchpad.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../../shared/devtools/scratchpad.inc.css
\ No newline at end of file
deleted file mode 100644
--- a/browser/themes/windows/devtools/shadereditor.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../../shared/devtools/shadereditor.inc.css
deleted file mode 100644
--- a/browser/themes/windows/devtools/webaudioeditor.css
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-%include ../../shared/devtools/webaudioeditor.inc.css
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -446,28 +446,28 @@ browser.jar:
 *       skin/classic/browser/devtools/webconsole.css                (devtools/webconsole.css)
         skin/classic/browser/devtools/webconsole_networkpanel.css   (devtools/webconsole_networkpanel.css)
         skin/classic/browser/devtools/webconsole.svg                (../shared/devtools/images/webconsole.svg)
         skin/classic/browser/devtools/breadcrumbs-divider@2x.png    (../shared/devtools/images/breadcrumbs-divider@2x.png)
         skin/classic/browser/devtools/breadcrumbs-scrollbutton.png  (../shared/devtools/images/breadcrumbs-scrollbutton.png)
         skin/classic/browser/devtools/breadcrumbs-scrollbutton@2x.png (../shared/devtools/images/breadcrumbs-scrollbutton@2x.png)
         skin/classic/browser/devtools/animationinspector.css        (../shared/devtools/animationinspector.css)
         skin/classic/browser/devtools/eyedropper.css                (../shared/devtools/eyedropper.css)
-*       skin/classic/browser/devtools/canvasdebugger.css            (devtools/canvasdebugger.css)
-*       skin/classic/browser/devtools/debugger.css                  (devtools/debugger.css)
+*       skin/classic/browser/devtools/canvasdebugger.css            (../shared/devtools/canvasdebugger.css)
+        skin/classic/browser/devtools/debugger.css                  (../shared/devtools/debugger.css)
 *       skin/classic/browser/devtools/netmonitor.css                (devtools/netmonitor.css)
-*       skin/classic/browser/devtools/performance.css               (devtools/performance.css)
+        skin/classic/browser/devtools/performance.css               (../shared/devtools/performance.css)
         skin/classic/browser/devtools/promisedebugger.css           (../shared/devtools/promisedebugger.css)
         skin/classic/browser/devtools/timeline-filter.svg           (../shared/devtools/images/timeline-filter.svg)
-*       skin/classic/browser/devtools/scratchpad.css                (devtools/scratchpad.css)
-*       skin/classic/browser/devtools/shadereditor.css              (devtools/shadereditor.css)
+*       skin/classic/browser/devtools/scratchpad.css                (../shared/devtools/scratchpad.css)
+        skin/classic/browser/devtools/shadereditor.css              (../shared/devtools/shadereditor.css)
         skin/classic/browser/devtools/storage.css                   (../shared/devtools/storage.css)
 *       skin/classic/browser/devtools/splitview.css                 (../shared/devtools/splitview.css)
         skin/classic/browser/devtools/styleeditor.css               (../shared/devtools/styleeditor.css)
-*       skin/classic/browser/devtools/webaudioeditor.css            (devtools/webaudioeditor.css)
+        skin/classic/browser/devtools/webaudioeditor.css            (../shared/devtools/webaudioeditor.css)
         skin/classic/browser/devtools/magnifying-glass.png          (../shared/devtools/images/magnifying-glass.png)
         skin/classic/browser/devtools/magnifying-glass@2x.png       (../shared/devtools/images/magnifying-glass@2x.png)
         skin/classic/browser/devtools/magnifying-glass-light.png    (../shared/devtools/images/magnifying-glass-light.png)
         skin/classic/browser/devtools/magnifying-glass-light@2x.png  (../shared/devtools/images/magnifying-glass-light@2x.png)
         skin/classic/browser/devtools/itemToggle.png                (../shared/devtools/images/itemToggle.png)
         skin/classic/browser/devtools/itemToggle@2x.png             (../shared/devtools/images/itemToggle@2x.png)
         skin/classic/browser/devtools/itemArrow-dark-rtl.svg        (../shared/devtools/images/itemArrow-dark-rtl.svg)
         skin/classic/browser/devtools/itemArrow-dark-ltr.svg        (../shared/devtools/images/itemArrow-dark-ltr.svg)
--- a/build/unix/build-gtk3/build-gtk3.sh
+++ b/build/unix/build-gtk3/build-gtk3.sh
@@ -52,17 +52,17 @@ build() {
 	version=$(eval echo \$${pkg}_version)
 	url=$(eval echo \$${pkg}_url)
 	wget -c -P $TMPDIR $url
 	tar -axf $TMPDIR/$name-$version.tar.*
 	mkdir -p build/$name
 	cd build/$name
 	eval ../../$name-$version/configure --disable-static $* $configure_args
 	make $make_flags
-	make install DESTDIR=$root_dir/gtk3
+	make install-strip DESTDIR=$root_dir/gtk3
 	find $root_dir/gtk3 -name \*.la -delete
 	cd ../..
 }
 
 case "$1" in
 32)
 	configure_args='--host=i686-pc-linux --build=i686-pc-linux CC="gcc -m32" CXX="g++ -m32"'
         lib=lib
@@ -98,49 +98,10 @@ build cairo --enable-tee
 build pango
 build atk
 make_flags="$make_flags GLIB_COMPILE_SCHEMAS=glib-compile-schemas"
 build gtk+
 
 rm -rf $root_dir/gtk3/usr/local/share/gtk-doc
 rm -rf $root_dir/gtk3/usr/local/share/locale
 
-# mock build environment doesn't have fonts in /usr/share/fonts, but
-# has some in /usr/share/X11/fonts. Add this directory to the
-# fontconfig configuration without changing the gtk3 tooltool package.
-cat << EOF > $root_dir/gtk3/usr/local/etc/fonts/local.conf
-<?xml version="1.0"?>
-<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
-<fontconfig>
-  <dir>/usr/share/X11/fonts</dir>
-</fontconfig>
-EOF
-
-cat <<EOF > $root_dir/gtk3/setup.sh
-#!/bin/sh
-
-cd \$(dirname \$0)
-
-# pango expects absolute paths in pango.modules, and TOOLTOOL_DIR may vary...
-LD_LIBRARY_PATH=./usr/local/lib \
-PANGO_SYSCONFDIR=./usr/local/etc \
-PANGO_LIBDIR=./usr/local/lib \
-./usr/local/bin/pango-querymodules > ./usr/local/etc/pango/pango.modules
-
-# same with gdb-pixbuf and loaders.cache
-LD_LIBRARY_PATH=./usr/local/lib \
-GDK_PIXBUF_MODULE_FILE=./usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache \
-GDK_PIXBUF_MODULEDIR=./usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders \
-./usr/local/bin/gdk-pixbuf-query-loaders > ./usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache
-
-# The fontconfig version in the tooltool package has known uses of
-# uninitialized memory when creating its cache, and while most users
-# will already have an existing cache, running Firefox on automation
-# will create it. Combined with valgrind, this generates irrelevant
-# errors.
-# So create the fontconfig cache beforehand.
-./usr/local/bin/fc-cache
-EOF
-
-chmod +x $root_dir/gtk3/setup.sh
-
 cd $cwd
 tar -C $root_dir -Jcf gtk3.tar.xz gtk3
--- a/build/unix/mozconfig.gtk
+++ b/build/unix/mozconfig.gtk
@@ -1,28 +1,48 @@
-TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
-
-# $TOOLTOOL_DIR/gtk3 comes from tooltool, when the tooltool manifest contains it.
-if [ -d "$TOOLTOOL_DIR/gtk3" ]; then
+# $topsrcdir/gtk3 comes from tooltool, when the tooltool manifest contains it.
+if [ -d "$topsrcdir/gtk3" ]; then
   if [ -z "$PKG_CONFIG_LIBDIR" ]; then
     echo PKG_CONFIG_LIBDIR must be set >&2
     exit 1
   fi
-  export PKG_CONFIG_SYSROOT_DIR="$TOOLTOOL_DIR/gtk3"
-  export PKG_CONFIG_PATH="$TOOLTOOL_DIR/gtk3/usr/local/lib/pkgconfig"
-  export PATH="$TOOLTOOL_DIR/gtk3/usr/local/bin:${PATH}"
+  export PKG_CONFIG_SYSROOT_DIR="$topsrcdir/gtk3"
+  export PKG_CONFIG_PATH="$topsrcdir/gtk3/usr/local/lib/pkgconfig"
+  export PATH="$topsrcdir/gtk3/usr/local/bin:${PATH}"
   # Ensure cairo, gdk-pixbuf, etc. are not taken from the system installed packages.
-  LDFLAGS="-L$TOOLTOOL_DIR/gtk3/usr/local/lib ${LDFLAGS}"
+  LDFLAGS="-L$topsrcdir/gtk3/usr/local/lib ${LDFLAGS}"
+  mk_add_options "export LD_LIBRARY_PATH=$topsrcdir/gtk3/usr/local/lib"
   ac_add_options --enable-default-toolkit=cairo-gtk3
 
   # Set things up to use Gtk+3 from the tooltool package
-  mk_add_options "export FONTCONFIG_PATH=$TOOLTOOL_DIR/gtk3/usr/local/etc/fonts"
-  mk_add_options "export PANGO_SYSCONFDIR=$TOOLTOOL_DIR/gtk3/usr/local/etc"
-  mk_add_options "export PANGO_LIBDIR=$TOOLTOOL_DIR/gtk3/usr/local/lib"
-  mk_add_options "export GDK_PIXBUF_MODULE_FILE=$TOOLTOOL_DIR/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"
-  mk_add_options "export GDK_PIXBUF_MODULEDIR=$TOOLTOOL_DIR/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders"
-  mk_add_options "export LD_LIBRARY_PATH=$TOOLTOOL_DIR/gtk3/usr/local/lib"
+  mk_add_options "export FONTCONFIG_PATH=$topsrcdir/gtk3/usr/local/etc/fonts"
+  mk_add_options "export PANGO_SYSCONFDIR=$topsrcdir/gtk3/usr/local/etc"
+  mk_add_options "export PANGO_LIBDIR=$topsrcdir/gtk3/usr/local/lib"
+  mk_add_options "export GDK_PIXBUF_MODULE_FILE=$topsrcdir/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"
+  mk_add_options "export GDK_PIXBUF_MODULEDIR=$topsrcdir/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders"
+  mk_add_options "export LD_LIBRARY_PATH=$topsrcdir/gtk3/usr/local/lib"
+
+  # pango expects absolute paths in pango.modules, and topsrcdir may vary...
+  LD_LIBRARY_PATH=$topsrcdir/gtk3/usr/local/lib \
+  PANGO_SYSCONFDIR=$topsrcdir/gtk3/usr/local/etc \
+  PANGO_LIBDIR=$topsrcdir/gtk3/usr/local/lib \
+  $topsrcdir/gtk3/usr/local/bin/pango-querymodules > $topsrcdir/gtk3/usr/local/etc/pango/pango.modules
 
-  # Until a tooltool with bug 1188571 landed is available everywhere
-  $TOOLTOOL_DIR/gtk3/setup.sh
+  # same with gdb-pixbuf and loaders.cache
+  LD_LIBRARY_PATH=$topsrcdir/gtk3/usr/local/lib \
+  GDK_PIXBUF_MODULE_FILE=$topsrcdir/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache \
+  GDK_PIXBUF_MODULEDIR=$topsrcdir/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders \
+  $topsrcdir/gtk3/usr/local/bin/gdk-pixbuf-query-loaders > $topsrcdir/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache
+
+  # mock build environment doesn't have fonts in /usr/share/fonts, but
+  # has some in /usr/share/X11/fonts. Add this directory to the
+  # fontconfig configuration without changing the gtk3 tooltool package.
+  cat << EOF > $topsrcdir/gtk3/usr/local/etc/fonts/local.conf
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<fontconfig>
+  <dir>/usr/share/X11/fonts</dir>
+</fontconfig>
+EOF
+
 else
   ac_add_options --enable-default-toolkit=cairo-gtk2
 fi
--- a/build/valgrind/mach_commands.py
+++ b/build/valgrind/mach_commands.py
@@ -106,23 +106,16 @@ class MachCommands(MachCommandBase):
                 '--smc-check=all-non-file',
                 '--vex-iropt-register-updates=allregs-at-mem-access',
                 '--gen-suppressions=all',
                 '--num-callers=36',
                 '--leak-check=full',
                 '--show-possibly-lost=no',
                 '--track-origins=yes',
                 '--trace-children=yes',
-                # The gstreamer plugin scanner can run as part of executing
-                # firefox, but is an external program. In some weird cases,
-                # valgrind finds errors while executing __libc_freeres when
-                # it runs, but those are not relevant, as it's related to
-                # executing third party code. So don't trace
-                # gst-plugin-scanner.
-                '--trace-children-skip=*/gst-plugin-scanner',
                 '-v',  # Enable verbosity to get the list of used suppressions
             ]
 
             for s in suppressions:
                 valgrind_args.append('--suppressions=' + s)
 
             supps_dir = os.path.join(build_dir, 'valgrind')
             supps_file1 = os.path.join(supps_dir, 'cross-architecture.sup')
--- a/build/valgrind/valgrind.sh
+++ b/build/valgrind/valgrind.sh
@@ -20,17 +20,17 @@ fi
 cd $objdir
 
 if [ "`uname -m`" = "x86_64" ]; then
     _arch=64
 else
     _arch=32
 fi
 
-TOOLTOOL_MANIFEST=browser/config/tooltool-manifests/linux${_arch}/releng.manifest
+TOOLTOOL_MANIFEST=browser/config/tooltool-manifests/linux${_arch}/valgrind.manifest
 TOOLTOOL_SERVER=https://api.pub.build.mozilla.org/tooltool/
 (cd $srcdir; python /builds/tooltool.py --url $TOOLTOOL_SERVER --overwrite -m $TOOLTOOL_MANIFEST fetch ${TOOLTOOL_CACHE:+ -c ${TOOLTOOL_CACHE}}) || exit 2
 
 # Note: an exit code of 2 turns the job red on TBPL.
 MOZCONFIG=$srcdir/browser/config/mozconfigs/linux${_arch}/valgrind make -f $srcdir/client.mk configure || exit 2
 make -j4 || exit 2
 make package || exit 2
 
--- a/config/gcc-stl-wrapper.template.h
+++ b/config/gcc-stl-wrapper.template.h
@@ -12,21 +12,16 @@
 // compiling ObjC.
 #if defined(__EXCEPTIONS) && __EXCEPTIONS && !(__OBJC__ && __GNUC__ && XP_IOS)
 #  error "STL code can only be used with -fno-exceptions"
 #endif
 
 // Silence "warning: #include_next is a GCC extension"
 #pragma GCC system_header
 
-#ifdef _WIN32
-// Suppress windef.h min and max macros - they make std::min/max not compile.
-#define NOMINMAX 1
-#endif
-
 // mozalloc.h wants <new>; break the cycle by always explicitly
 // including <new> here.  NB: this is a tad sneaky.  Sez the gcc docs:
 //
 //    `#include_next' does not distinguish between <file> and "file"
 //    inclusion, nor does it check that the file you specify has the
 //    same name as the current file. It simply looks for the file
 //    named, starting with the directory in the search path after the
 //    one where the current file was found.
--- a/config/msvc-stl-wrapper.template.h
+++ b/config/msvc-stl-wrapper.template.h
@@ -7,19 +7,16 @@
 
 #ifndef mozilla_${HEADER}_h
 #define mozilla_${HEADER}_h
 
 #if _HAS_EXCEPTIONS
 #  error "STL code can only be used with -fno-exceptions"
 #endif
 
-// Suppress windef.h min and max macros - they make std::min/max not compile.
-#define NOMINMAX 1
-
 // Code built with !_HAS_EXCEPTIONS calls std::_Throw(), but the win2k
 // CRT doesn't export std::_Throw().  So we define it.
 #ifndef mozilla_Throw_h
 #  include "mozilla/throw_msvc.h"
 #endif
 
 // Code might include <new> before other wrapped headers, but <new>
 // includes <exception> and so we want to wrap it.  But mozalloc.h
--- a/configure.in
+++ b/configure.in
@@ -2327,16 +2327,18 @@ ia64*-hpux*)
     AC_DEFINE(HAVE_SNPRINTF)
     AC_DEFINE(_WINDOWS)
     AC_DEFINE(WIN32)
     AC_DEFINE(XP_WIN)
     AC_DEFINE(XP_WIN32)
     AC_DEFINE(HW_THREADS)
     AC_DEFINE(STDC_HEADERS)
     AC_DEFINE(WIN32_LEAN_AND_MEAN)
+    dnl See http://support.microsoft.com/kb/143208 to use STL
+    AC_DEFINE(NOMINMAX)
     TARGET_MD_ARCH=win32
     _PLATFORM_DEFAULT_TOOLKIT='cairo-windows'
     BIN_SUFFIX='.exe'
     MOZ_USER_DIR="Mozilla"
 
     dnl Hardcode to win95 for now - cls
     TARGET_NSPR_MDCPUCFG='\"md/_win95.cfg\"'
 
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1129,22 +1129,24 @@ nsFocusManager::ActivateOrDeactivate(nsP
     return;
   }
 
   // Inform the DOM window that it has activated or deactivated, so that
   // the active attribute is updated on the window.
   aWindow->ActivateOrDeactivate(aActive);
 
   // Send the activate event.
-  nsContentUtils::DispatchEventOnlyToChrome(aWindow->GetExtantDoc(),
-                                            aWindow,
-                                            aActive ?
-                                              NS_LITERAL_STRING("activate") :
-                                              NS_LITERAL_STRING("deactivate"),
-                                            true, true, nullptr);
+  if (aWindow->GetExtantDoc()) {
+    nsContentUtils::DispatchEventOnlyToChrome(aWindow->GetExtantDoc(),
+                                              aWindow,
+                                              aActive ?
+                                                NS_LITERAL_STRING("activate") :
+                                                NS_LITERAL_STRING("deactivate"),
+                                              true, true, nullptr);
+  }
 
   // Look for any remote child frames, iterate over them and send the activation notification.
   nsContentUtils::CallOnAllRemoteChildren(aWindow, ActivateOrDeactivateChild,
                                           (void *)aActive);
 }
 
 void
 nsFocusManager::SetFocusInner(nsIContent* aNewContent, int32_t aFlags,
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2689,167 +2689,167 @@ protected:
 
   // Our readyState
   ReadyState mReadyState;
 
   // Our visibility state
   mozilla::dom::VisibilityState mVisibilityState;
 
   // True if BIDI is enabled.
-  bool mBidiEnabled;
+  bool mBidiEnabled : 1;
   // True if a MathML element has ever been owned by this document.
-  bool mMathMLEnabled;
+  bool mMathMLEnabled : 1;
 
   // True if this document is the initial document for a window.  This should
   // basically be true only for documents that exist in newly-opened windows or
   // documents created to satisfy a GetDocument() on a window when there's no
   // document in it.
-  bool mIsInitialDocumentInWindow;
+  bool mIsInitialDocumentInWindow : 1;
 
   // True if we're loaded as data and therefor has any dangerous stuff, such
   // as scripts and plugins, disabled.
-  bool mLoadedAsData;
+  bool mLoadedAsData : 1;
 
   // This flag is only set in XMLDocument, for e.g. documents used in XBL. We
   // don't want animations to play in such documents, so we need to store the
   // flag here so that we can check it in nsDocument::GetAnimationController.
-  bool mLoadedAsInteractiveData;
+  bool mLoadedAsInteractiveData : 1;
 
   // If true, whoever is creating the document has gotten it to the
   // point where it's safe to start layout on it.
-  bool mMayStartLayout;
+  bool mMayStartLayout : 1;
 
   // True iff we've ever fired a DOMTitleChanged event for this document
-  bool mHaveFiredTitleChange;
+  bool mHaveFiredTitleChange : 1;
 
   // True iff IsShowing() should be returning true
-  bool mIsShowing;
+  bool mIsShowing : 1;
 
   // True iff the document "page" is not hidden (i.e. currently in the
   // bfcache)
-  bool mVisible;
+  bool mVisible : 1;
 
   // True if our content viewer has been removed from the docshell
   // (it may still be displayed, but in zombie state). Form control data
   // has been saved.
-  bool mRemovedFromDocShell;
+  bool mRemovedFromDocShell : 1;
 
   // True iff DNS prefetch is allowed for this document.  Note that if the
   // document has no window, DNS prefetch won't be performed no matter what.
-  bool mAllowDNSPrefetch;
+  bool mAllowDNSPrefetch : 1;
 
   // True when this document is a static clone of a normal document
-  bool mIsStaticDocument;
+  bool mIsStaticDocument : 1;
 
   // True while this document is being cloned to a static document.
-  bool mCreatingStaticClone;
+  bool mCreatingStaticClone : 1;
 
   // True iff the document is being unlinked or deleted.
-  bool mInUnlinkOrDeletion;
+  bool mInUnlinkOrDeletion : 1;
 
   // True if document has ever had script handling object.
-  bool mHasHadScriptHandlingObject;
+  bool mHasHadScriptHandlingObject : 1;
 
   // True if we're an SVG document being used as an image.
-  bool mIsBeingUsedAsImage;
+  bool mIsBeingUsedAsImage : 1;
 
   // True is this document is synthetic : stand alone image, video, audio
   // file, etc.
-  bool mIsSyntheticDocument;
+  bool mIsSyntheticDocument : 1;
 
   // True if this document has links whose state needs updating
-  bool mHasLinksToUpdate;
+  bool mHasLinksToUpdate : 1;
 
   // True if a layout flush might not be a no-op
-  bool mNeedLayoutFlush;
+  bool mNeedLayoutFlush : 1;
 
   // True if a style flush might not be a no-op
-  bool mNeedStyleFlush;
+  bool mNeedStyleFlush : 1;
 
   // True if a DOMMutationObserver is perhaps attached to a node in the document.
-  bool mMayHaveDOMMutationObservers;
+  bool mMayHaveDOMMutationObservers : 1;
 
   // True if an nsIAnimationObserver is perhaps attached to a node in the document.
-  bool mMayHaveAnimationObservers;
+  bool mMayHaveAnimationObservers : 1;
 
   // True if a document has loaded Mixed Active Script (see nsMixedContentBlocker.cpp)
-  bool mHasMixedActiveContentLoaded;
+  bool mHasMixedActiveContentLoaded : 1;
 
   // True if a document has blocked Mixed Active Script (see nsMixedContentBlocker.cpp)
-  bool mHasMixedActiveContentBlocked;
+  bool mHasMixedActiveContentBlocked : 1;
 
   // True if a document has loaded Mixed Display/Passive Content (see nsMixedContentBlocker.cpp)
-  bool mHasMixedDisplayContentLoaded;
+  bool mHasMixedDisplayContentLoaded : 1;
 
   // True if a document has blocked Mixed Display/Passive Content (see nsMixedContentBlocker.cpp)
-  bool mHasMixedDisplayContentBlocked;
+  bool mHasMixedDisplayContentBlocked : 1;
 
   // True if a document has blocked Tracking Content
-  bool mHasTrackingContentBlocked;
+  bool mHasTrackingContentBlocked : 1;
 
   // True if a document has loaded Tracking Content
-  bool mHasTrackingContentLoaded;
+  bool mHasTrackingContentLoaded : 1;
 
   // True if DisallowBFCaching has been called on this document.
-  bool mBFCacheDisallowed;
+  bool mBFCacheDisallowed : 1;
 
   // If true, we have an input encoding.  If this is false, then the
   // document was created entirely in memory
-  bool mHaveInputEncoding;
-
-  bool mHasHadDefaultView;
+  bool mHaveInputEncoding : 1;
+
+  bool mHasHadDefaultView : 1;
 
   // Whether style sheet change events will be dispatched for this document
-  bool mStyleSheetChangeEventsEnabled;
+  bool mStyleSheetChangeEventsEnabled : 1;
 
   // Whether the document was created by a srcdoc iframe.
-  bool mIsSrcdocDocument;
+  bool mIsSrcdocDocument : 1;
 
   // Records whether we've done a document.open. If this is true, it's possible
   // for nodes from this document to have outdated wrappers in their wrapper
   // caches.
-  bool mDidDocumentOpen;
-
-#ifdef DEBUG
-  /**
-   * This is true while FlushPendingLinkUpdates executes.  Calls to
-   * [Un]RegisterPendingLinkUpdate will assert when this is true.
-   */
-  bool mIsLinkUpdateRegistrationsForbidden;
-#endif
+  bool mDidDocumentOpen : 1;
 
   // Is the current mFontFaceSet valid?
-  bool mFontFaceSetDirty;
+  bool mFontFaceSetDirty : 1;
 
   // Has GetUserFontSet() been called?
-  bool mGetUserFontSetCalled;
+  bool mGetUserFontSetCalled : 1;
 
   // Do we currently have an event posted to call FlushUserFontSet?
-  bool mPostedFlushUserFontSet;
+  bool mPostedFlushUserFontSet : 1;
 
   enum Type {
     eUnknown, // should never be used
     eHTML,
     eXHTML,
     eGenericXML,
     eSVG,
     eXUL
   };
 
-  uint8_t mType;
+  Type mType;
 
   uint8_t mDefaultElementType;
 
-  enum {
+  enum Tri {
     eTriUnset = 0,
     eTriFalse,
     eTriTrue
   };
 
-  uint8_t mAllowXULXBL;
+  Tri mAllowXULXBL;
+
+#ifdef DEBUG
+  /**
+   * This is true while FlushPendingLinkUpdates executes.  Calls to
+   * [Un]RegisterPendingLinkUpdate will assert when this is true.
+   */
+  bool mIsLinkUpdateRegistrationsForbidden;
+#endif
 
   // The document's script global object, the object from which the
   // document can get its script context and scope. This is the
   // *inner* window object.
   nsCOMPtr<nsIScriptGlobalObject> mScriptGlobalObject;
 
   // If mIsStaticDocument is true, mOriginalDocument points to the original
   // document.
--- a/dom/base/nsStructuredCloneContainer.cpp
+++ b/dom/base/nsStructuredCloneContainer.cpp
@@ -90,35 +90,47 @@ nsStructuredCloneContainer::InitFromBase
   NS_ENSURE_STATE(mData);
   memcpy(mData, binaryData.get(), binaryData.Length());
 
   mSize = binaryData.Length();
   mVersion = aFormatVersion;
   return NS_OK;
 }
 
+nsresult
+nsStructuredCloneContainer::DeserializeToJsval(JSContext* aCx,
+                                               JS::MutableHandle<JS::Value> aValue)
+{
+  aValue.setNull();
+  JS::Rooted<JS::Value> jsStateObj(aCx);
+  bool hasTransferable = false;
+  bool success = JS_ReadStructuredClone(aCx, mData, mSize, mVersion,
+                                        &jsStateObj, nullptr, nullptr) &&
+                 JS_StructuredCloneHasTransferables(mData, mSize,
+                                                    &hasTransferable);
+  // We want to be sure that mData doesn't contain transferable objects
+  MOZ_ASSERT(!hasTransferable);
+  NS_ENSURE_STATE(success && !hasTransferable);
+
+  aValue.set(jsStateObj);
+  return NS_OK;
+}
 
 nsresult
 nsStructuredCloneContainer::DeserializeToVariant(JSContext *aCx,
                                                  nsIVariant **aData)
 {
   NS_ENSURE_STATE(mData);
   NS_ENSURE_ARG_POINTER(aData);
   *aData = nullptr;
 
   // Deserialize to a JS::Value.
   JS::Rooted<JS::Value> jsStateObj(aCx);
-  bool hasTransferable = false;
-  bool success = JS_ReadStructuredClone(aCx, mData, mSize, mVersion,
-                                        &jsStateObj, nullptr, nullptr) &&
-                 JS_StructuredCloneHasTransferables(mData, mSize,
-                                                    &hasTransferable);
-  // We want to be sure that mData doesn't contain transferable objects
-  MOZ_ASSERT(!hasTransferable);
-  NS_ENSURE_STATE(success && !hasTransferable);
+  nsresult rv = DeserializeToJsval(aCx, &jsStateObj);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   // Now wrap the JS::Value as an nsIVariant.
   nsCOMPtr<nsIVariant> varStateObj;
   nsCOMPtr<nsIXPConnect> xpconnect = do_GetService(nsIXPConnect::GetCID());
   NS_ENSURE_STATE(xpconnect);
   xpconnect->JSValToVariant(aCx, jsStateObj, getter_AddRefs(varStateObj));
   NS_ENSURE_STATE(varStateObj);
 
--- a/dom/cache/PCacheStorage.ipdl
+++ b/dom/cache/PCacheStorage.ipdl
@@ -1,16 +1,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/. */
 
 include protocol PBackground;
 include protocol PBlob; // FIXME: bug 792908
 include protocol PCache;
 include protocol PCacheOp;
+include protocol PCachePushStream;
 include protocol PCacheStreamControl;
 include protocol PFileDescriptorSet;
 
 include CacheTypes;
 
 namespace mozilla {
 namespace dom {
 namespace cache {
--- a/dom/canvas/compiledtest/moz.build
+++ b/dom/canvas/compiledtest/moz.build
@@ -1,17 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-# http://support.microsoft.com/kb/143208
-DEFINES['NOMINMAX'] = True
-
 GeckoCppUnitTests([
     'TestWebGLElementArrayCache',
 ])
 
 FAIL_ON_WARNINGS = True
 
 LOCAL_INCLUDES += [
     '../',
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -31,19 +31,16 @@ EXPORTS.mozilla.dom += [
     'CanvasUtils.h',
     'ImageBitmap.h',
     'ImageBitmapSource.h',
     'ImageData.h',
     'TextMetrics.h',
     'WebGLVertexArrayObject.h',
 ]
 
-# http://support.microsoft.com/kb/143208
-DEFINES['NOMINMAX'] = True
-
 # Canvas 2D and common sources
 UNIFIED_SOURCES += [
     'CanvasImageCache.cpp',
     'CanvasRenderingContext2D.cpp',
     'CanvasUtils.cpp',
     'DocumentRendererChild.cpp',
     'DocumentRendererParent.cpp',
     'ImageBitmap.cpp',
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -494,39 +494,39 @@ interface nsIDOMWindowUtils : nsISupport
    *                           dispatch NS_MOUSE_SCROLL event for horizontal
    *                           scroll.
    * @param aLineOrPageDeltaY  If you set this value non-zero for
    *                           DOM_DELTA_PIXEL event, EventStateManager will
    *                           dispatch NS_MOUSE_SCROLL event for vertical
    *                           scroll.
    * @param aOptions           Set following flags.
    */
-   const unsigned long WHEEL_EVENT_CAUSED_BY_NO_LINE_OR_PAGE_DELTA_DEVICE = 0x0001;
-   // @deprecated Use WHEEL_EVENT_CAUSED_BY_NO_LINE_OR_PAGE_DELTA_DEVICE.
-   const unsigned long WHEEL_EVENT_CAUSED_BY_PIXEL_ONLY_DEVICE            = 0x0001;
-   const unsigned long WHEEL_EVENT_CAUSED_BY_MOMENTUM          	          = 0x0002;
-   const unsigned long WHEEL_EVENT_CUSTOMIZED_BY_USER_PREFS               = 0x0004;
-   // If any of the following flags is specified this method will throw an
-   // exception in case the relevant overflowDelta has an unexpected value.
-   const unsigned long WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_ZERO      = 0x0010;
-   const unsigned long WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_POSITIVE  = 0x0020;
-   const unsigned long WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_NEGATIVE  = 0x0040;
-   const unsigned long WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_ZERO      = 0x0100;
-   const unsigned long WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_POSITIVE  = 0x0200;
-   const unsigned long WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_NEGATIVE  = 0x0400;
-   void sendWheelEvent(in float aX,
-                       in float aY,
-                       in double aDeltaX,
-                       in double aDeltaY,
-                       in double aDeltaZ,
-                       in unsigned long aDeltaMode,
-                       in long aModifiers,
-                       in long aLineOrPageDeltaX,
-                       in long aLineOrPageDeltaY,
-                       in unsigned long aOptions);
+  const unsigned long WHEEL_EVENT_CAUSED_BY_NO_LINE_OR_PAGE_DELTA_DEVICE = 0x0001;
+  // @deprecated Use WHEEL_EVENT_CAUSED_BY_NO_LINE_OR_PAGE_DELTA_DEVICE.
+  const unsigned long WHEEL_EVENT_CAUSED_BY_PIXEL_ONLY_DEVICE            = 0x0001;
+  const unsigned long WHEEL_EVENT_CAUSED_BY_MOMENTUM                     = 0x0002;
+  const unsigned long WHEEL_EVENT_CUSTOMIZED_BY_USER_PREFS               = 0x0004;
+  // If any of the following flags is specified this method will throw an
+  // exception in case the relevant overflowDelta has an unexpected value.
+  const unsigned long WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_ZERO      = 0x0010;
+  const unsigned long WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_POSITIVE  = 0x0020;
+  const unsigned long WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_NEGATIVE  = 0x0040;
+  const unsigned long WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_ZERO      = 0x0100;
+  const unsigned long WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_POSITIVE  = 0x0200;
+  const unsigned long WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_NEGATIVE  = 0x0400;
+  void sendWheelEvent(in float aX,
+                      in float aY,
+                      in double aDeltaX,
+                      in double aDeltaY,
+                      in double aDeltaZ,
+                      in unsigned long aDeltaMode,
+                      in long aModifiers,
+                      in long aLineOrPageDeltaX,
+                      in long aLineOrPageDeltaY,
+                      in unsigned long aOptions);
 
   /**
    * Synthesize a key event to the window. The event types supported are:
    *   keydown, keyup, keypress
    *
    * Key events generally end up being sent to the focused node.
    *
    * Cannot be accessed from unprivileged context (not content-accessible)
@@ -1354,26 +1354,26 @@ interface nsIDOMWindowUtils : nsISupport
    *     Can be changed (up to 1 hour) via pref: toolkit.framesRecording.bufferSize.
    * - Note: the first frame-interval may be longer than expected because last frame
    *     might have been presented some time before calling StartFrameTimeRecording.
    */
 
   /**
    * Returns a handle which represents current recording start position.
    */
-   void startFrameTimeRecording([retval] out unsigned long startIndex);
+  void startFrameTimeRecording([retval] out unsigned long startIndex);
 
   /**
    * Returns number of recorded frames since startIndex was issued,
    *   and allocates+populates 2 arraye with the recorded data.
    * - Allocation is infallible. Should be released even if size is 0.
    */
-   void stopFrameTimeRecording(in unsigned long startIndex,
-                              [optional] out unsigned long frameCount,
-                              [retval, array, size_is(frameCount)] out float frameIntervals);
+  void stopFrameTimeRecording(in unsigned long startIndex,
+                             [optional] out unsigned long frameCount,
+                             [retval, array, size_is(frameCount)] out float frameIntervals);
 
   /**
    * Signals that we're begining to tab switch. This is used by painting code to
    * determine total tab switch time.
    */
   void beginTabSwitch();
 
   /**
@@ -1692,132 +1692,132 @@ interface nsIDOMWindowUtils : nsISupport
    * This calls EventStateManager::IsHandlingUserInput().
    */
   readonly attribute boolean isHandlingUserInput;
 
   /**
    * After calling the method, the window for which this DOMWindowUtils
    * was created can be closed using scripts.
    */
-   void allowScriptsToClose();
+  void allowScriptsToClose();
 
   /**
    * Is the parent window's main widget visible?  If it isn't, we probably
    * don't want to display any dialogs etc it may request.  This corresponds
    * to the visibility check in nsWindowWatcher::OpenWindowInternal().
    *
    * Will throw a DOM security error if called without chrome privileges or
    * NS_ERROR_NOT_AVAILABLE in the unlikely event that the parent window's
    * main widget can't be reached.
    */
   readonly attribute boolean isParentWindowMainWidgetVisible;
 
-   /**
-    * In certain cases the event handling of nodes, form controls in practice,
-    * may be disabled. Such cases are for example the existence of disabled
-    * attribute or -moz-user-input: none/disabled.
-    */
-   boolean isNodeDisabledForEvents(in nsIDOMNode aNode);
+  /**
+   * In certain cases the event handling of nodes, form controls in practice,
+   * may be disabled. Such cases are for example the existence of disabled
+   * attribute or -moz-user-input: none/disabled.
+   */
+  boolean isNodeDisabledForEvents(in nsIDOMNode aNode);
 
-   /**
-    * Setting paintFlashing to true will flash newly painted area.
-    */
-   attribute boolean paintFlashing;
+  /**
+   * Setting paintFlashing to true will flash newly painted area.
+   */
+  attribute boolean paintFlashing;
 
-   /**
-    * Add a "synchronous section", in the form of an nsIRunnable run once the
-    * event loop has reached a "stable state". |runnable| must not cause any
-    * queued events to be processed (i.e. must not spin the event loop).
-    * We've reached a stable state when the currently executing task/event has
-    * finished, see:
-    * http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#synchronous-section
-    * In practice this runs aRunnable once the currently executing event
-    * finishes. If called multiple times per task/event, all the runnables will
-    * be executed, in the order in which runInStableState() was called.
-    *
-    * XXX - This can wreak havoc if you're not using this for very simple
-    * purposes, eg testing or setting a flag.
-    */
-   void runInStableState(in nsIRunnable runnable);
+  /**
+   * Add a "synchronous section", in the form of an nsIRunnable run once the
+   * event loop has reached a "stable state". |runnable| must not cause any
+   * queued events to be processed (i.e. must not spin the event loop).
+   * We've reached a stable state when the currently executing task/event has
+   * finished, see:
+   * http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#synchronous-section
+   * In practice this runs aRunnable once the currently executing event
+   * finishes. If called multiple times per task/event, all the runnables will
+   * be executed, in the order in which runInStableState() was called.
+   *
+   * XXX - This can wreak havoc if you're not using this for very simple
+   * purposes, eg testing or setting a flag.
+   */
+  void runInStableState(in nsIRunnable runnable);
 
-   /**
-    * Run the given runnable before the next iteration of the event loop (this
-    * includes native events too). If a nested loop is spawned within the current
-    * event then the runnable will not be run until that loop has terminated.
-    *
-    * XXX - This can wreak havoc if you're not using this for very simple
-    * purposes, eg testing or setting a flag.
-    */
-   void runBeforeNextEvent(in nsIRunnable runnable);
+  /**
+   * Run the given runnable before the next iteration of the event loop (this
+   * includes native events too). If a nested loop is spawned within the current
+   * event then the runnable will not be run until that loop has terminated.
+   *
+   * XXX - This can wreak havoc if you're not using this for very simple
+   * purposes, eg testing or setting a flag.
+   */
+  void runBeforeNextEvent(in nsIRunnable runnable);
 
-   /*
-    * Returns the value of a given property animated on the compositor thread.
-    * If the property is NOT currently being animated on the compositor thread,
-    * returns an empty string.
-    */
-   AString getOMTAStyle(in nsIDOMElement aElement, in AString aProperty,
-                        [optional] in AString aPseudoElement);
+  /*
+   * Returns the value of a given property animated on the compositor thread.
+   * If the property is NOT currently being animated on the compositor thread,
+   * returns an empty string.
+   */
+  AString getOMTAStyle(in nsIDOMElement aElement, in AString aProperty,
+                       [optional] in AString aPseudoElement);
 
-   /**
-    * Special function that gets a property syncronously from the last composite
-    * that occured.
-    *
-    * Supported properties:
-    *   "overdraw": Report a percentage between 0 and 999 indicate how many times
-    *               each pixels on the destination window have been touched.
-    *   "missed_hwc": Report a bool if hardware composer is supported but was
-    *                 not used for the last frame.
-    */
-   float requestCompositorProperty(in AString aProperty);
+  /**
+   * Special function that gets a property syncronously from the last composite
+   * that occured.
+   *
+   * Supported properties:
+   *   "overdraw": Report a percentage between 0 and 999 indicate how many times
+   *               each pixels on the destination window have been touched.
+   *   "missed_hwc": Report a bool if hardware composer is supported but was
+   *                 not used for the last frame.
+   */
+  float requestCompositorProperty(in AString aProperty);
 
-   /**
-    * If aHandlingInput is true, this informs the event state manager that
-    * we're handling user input. Otherwise, this is a no-op (as by default
-    * we're not handling user input).
-    * Remember to call destruct() on the return value!
-    * See also nsIDOMWindowUtils::isHandlingUserInput.
-    */
-   nsIJSRAIIHelper setHandlingUserInput(in boolean aHandlingInput);
+  /**
+   * If aHandlingInput is true, this informs the event state manager that
+   * we're handling user input. Otherwise, this is a no-op (as by default
+   * we're not handling user input).
+   * Remember to call destruct() on the return value!
+   * See also nsIDOMWindowUtils::isHandlingUserInput.
+   */
+  nsIJSRAIIHelper setHandlingUserInput(in boolean aHandlingInput);
 
-   /**
-    * Get the content- and compositor-side APZ test data instances.
-    * The return values are of type APZTestData (see APZTestData.webidl).
-    */
-   [implicit_jscontext] jsval getContentAPZTestData();
-   [implicit_jscontext] jsval getCompositorAPZTestData();
+  /**
+   * Get the content- and compositor-side APZ test data instances.
+   * The return values are of type APZTestData (see APZTestData.webidl).
+   */
+  [implicit_jscontext] jsval getContentAPZTestData();
+  [implicit_jscontext] jsval getCompositorAPZTestData();
 
-   /**
-    * Posts an eRestyle_Self restyle event for the given element.
-    */
-   void postRestyleSelfEvent(in nsIDOMElement aElement);
+  /**
+   * Posts an eRestyle_Self restyle event for the given element.
+   */
+  void postRestyleSelfEvent(in nsIDOMElement aElement);
 
-   /**
-    * With this it's possible to mute all the MediaElements in this window.
-    * We have audioMuted and audioVolume to preserve the volume across
-    * mute/umute.
-    */
-   attribute boolean audioMuted;
+  /**
+   * With this it's possible to mute all the MediaElements in this window.
+   * We have audioMuted and audioVolume to preserve the volume across
+   * mute/umute.
+   */
+  attribute boolean audioMuted;
 
-    /**
-     * range: greater or equal to 0. The real volume level is affected by the
-     * volume of all ancestor windows.
-     */
-    attribute float audioVolume;
+  /**
+   * range: greater or equal to 0. The real volume level is affected by the
+   * volume of all ancestor windows.
+   */
+  attribute float audioVolume;
 
-    /**
-     * This method doesn't do anything useful.  It was solely added for the
-     * purpose of the test for bug 503926.
-     */
-    void xpconnectArgument(in nsIDOMWindowUtils aThis);
+  /**
+   * This method doesn't do anything useful.  It was solely added for the
+   * purpose of the test for bug 503926.
+   */
+  void xpconnectArgument(in nsIDOMWindowUtils aThis);
 
-    /**
-     * Helper for JS components that need to send permission requests with
-     * e10s support properly.
-     */
-     void askPermission(in nsIContentPermissionRequest aRequest);
+  /**
+   * Helper for JS components that need to send permission requests with
+   * e10s support properly.
+   */
+  void askPermission(in nsIContentPermissionRequest aRequest);
 
   /**
    * Number of frames constructed (excluding breaking) for the curent
    * document.
    *
    * May throw NS_ERROR_NOT_AVAILABLE.
    */
   readonly attribute unsigned long long framesConstructed;
--- a/dom/interfaces/base/nsIStructuredCloneContainer.idl
+++ b/dom/interfaces/base/nsIStructuredCloneContainer.idl
@@ -22,17 +22,17 @@ interface nsIDocument;
  * initFromJSVal or initFromBase64.  It's an error to initialize an
  * nsIStructuredCloneContainer more than once.
  *
  * Once you've initialized the container, you can get a copy of the object it
  * stores by calling deserializeToVariant.  You can also get a base-64-encoded
  * string containing a copy of the container's serialized data, using
  * getDataAsBase64.
  */
-[scriptable, uuid(63eeafec-63f5-42c3-aea9-5c04678784e7)]
+[scriptable, uuid(c664aae7-0d67-4155-a2dd-a3861778626f)]
 interface nsIStructuredCloneContainer : nsISupports
 {
   /**
    * Initialize this structured clone container so it contains a clone of the
    * given jsval.
    */
   [noscript, implicit_jscontext]
   void initFromJSVal(in jsval aData);
@@ -41,18 +41,26 @@ interface nsIStructuredCloneContainer : 
    * Initialize this structured clone container from a base-64-encoded byte
    * stream, stored in aData.  aFormatVersion should be the version of the
    * structured clone algorithm which was used to generate aData.
    */
   [implicit_jscontext]
   void initFromBase64(in AString aData,in unsigned long aFormatVersion);
 
   /**
+   * Deserializes this structured clone container returning it as a jsval.
+   * Can be called on main and worker threads.
+   */
+  [implicit_jscontext]
+  jsval deserializeToJsval();
+
+  /**
    * Deserialize the object this container holds, returning it wrapped as
    * an nsIVariant.
+   * Main thread only!
    */
   [implicit_jscontext]
   nsIVariant deserializeToVariant();
 
   /**
    * Get this structured clone container's data as a base-64-encoded string.
    */
   AString getDataAsBase64();
--- a/dom/interfaces/push/nsIPushNotificationService.idl
+++ b/dom/interfaces/push/nsIPushNotificationService.idl
@@ -6,17 +6,17 @@
 #include "nsISupports.idl"
 
 /**
  * A service for components to subscribe and receive push messages from web
  * services. This functionality is exposed to content via the Push API, which
  * uses service workers to notify applications. This interface exists to allow
  * privileged code to receive messages without migrating to service workers.
  */
-[scriptable, uuid(abde228b-7d14-4cab-b1f9-9f87750ede0f)]
+[scriptable, uuid(74586476-d73f-4867-bece-87c1dea35750)]
 interface nsIPushNotificationService : nsISupports
 {
   /**
    * Creates a push subscription for the given |scope| URL and |pageURL|.
    * Returns a promise for the new subscription record, or the existing
    * record if this |scope| already has a subscription.
    *
    * The |pushEndpoint| property of the subscription record is a URL string
@@ -43,12 +43,17 @@ interface nsIPushNotificationService : n
 
   /**
    * Returns a promise for the subscription record associated with the
    * given |scope|, or `null` if the |scope| does not have a subscription.
    */
   jsval registration(in string scope, in jsval originAttributes);
 
   /**
-   * Clear all subscriptions
+   * Clear all subscriptions.
    */
-   jsval clearAll();
+  jsval clearAll();
+
+  /**
+   * Clear subscriptions for a domain.
+   */
+  jsval clearForDomain(in string domain);
 };
--- a/dom/interfaces/sidebar/nsIWebContentHandlerRegistrar.idl
+++ b/dom/interfaces/sidebar/nsIWebContentHandlerRegistrar.idl
@@ -1,43 +1,41 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
-interface nsIDOMWindow;
-
 /**
  * nsIWebContentHandlerRegistrar
  * 
  * Applications wishing to use web content handlers need to implement this
  * interface. Typically they will prompt the user to confirm adding an entry
  * to the local list. 
  *
  * The component must have the contract id defined below so that nsNavigator
  * can invoke it. 
  */
 
-[scriptable, uuid(e6a75410-c93e-42bf-84ca-a5c3ec34a2f1)]
+[scriptable, uuid(65a3fafd-0e4a-4b06-8b4e-6a611da63d98)]
 interface nsIWebContentHandlerRegistrar : nsISupports
 {
   /**
    * See documentation in Navigator.webidl
    * The additional contentWindow param for both methods represents the dom
    * content window from which the method has been called.
    */
    void registerContentHandler(in DOMString mimeType,
                                in DOMString uri,
                                in DOMString title,
-                               in nsIDOMWindow contentWindow);
+                               in nsISupports windowOrBrowser);
    void registerProtocolHandler(in DOMString protocol,
                                 in DOMString uri,
                                 in DOMString title,
-                                in nsIDOMWindow contentWindow);
+                                in nsISupports windowOrBrowser);
 };
 
 %{ C++
 
 #define NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID "@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"
 %}
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -188,16 +188,17 @@
 #include "mozilla/dom/telephony/PTelephonyChild.h"
 #include "mozilla/dom/time/DateCacheCleaner.h"
 #include "mozilla/dom/voicemail/VoicemailIPCService.h"
 #include "mozilla/net/NeckoMessageUtils.h"
 #include "mozilla/widget/PuppetBidiKeyboard.h"
 #include "mozilla/RemoteSpellCheckEngineChild.h"
 #include "GMPServiceChild.h"
 #include "gfxPlatform.h"
+#include "nscore.h" // for NS_FREE_PERMANENT_DATA
 
 using namespace mozilla;
 using namespace mozilla::docshell;
 using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::cellbroadcast;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::icc;
 using namespace mozilla::dom::ipc;
@@ -758,16 +759,24 @@ ContentChild::AppendProcessId(nsACString
     if (!aName.IsEmpty()) {
         aName.Append(' ');
     }
     unsigned pid = getpid();
     aName.Append(nsPrintfCString("(pid %u)", pid));
 }
 
 void
+ContentChild::InitGraphicsDeviceData()
+{
+    // Initialize the graphics platform. This may contact the parent process
+    // to read device preferences.
+    gfxPlatform::GetPlatform();
+}
+
+void
 ContentChild::InitXPCOM()
 {
     // Do this as early as possible to get the parent process to initialize the
     // background thread since we'll likely need database information very soon.
     BackgroundChild::Startup();
 
     nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
         new BackgroundChildPrimer();
@@ -1892,17 +1901,17 @@ ContentChild::RecvSetConnectivity(const 
 void
 ContentChild::ActorDestroy(ActorDestroyReason why)
 {
     if (AbnormalShutdown == why) {
         NS_WARNING("shutting down early because of crash!");
         QuickExit();
     }
 
-#if !defined(DEBUG) && !defined(MOZ_ASAN)
+#ifndef NS_FREE_PERMANENT_DATA
     // In release builds, there's no point in the content process
     // going through the full XPCOM shutdown path, because it doesn't
     // keep persistent state.
     QuickExit();
 #endif
 
     if (sFirstIdleTask) {
         sFirstIdleTask->Cancel();
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -71,16 +71,17 @@ public:
         nsCString vendor;
     };
 
     bool Init(MessageLoop* aIOLoop,
               base::ProcessId aParentPid,
               IPC::Channel* aChannel);
     void InitProcessAttributes();
     void InitXPCOM();
+    void InitGraphicsDeviceData();
 
     static ContentChild* GetSingleton() {
         return sSingleton;
     }
 
     const AppInfo& GetAppInfo() {
         return mAppInfo;
     }
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -5143,16 +5143,23 @@ ContentParent::RecvProfile(const nsCStri
     }
     mProfile = aProfile;
     mGatherer->GatheredOOPProfile();
     mGatherer = nullptr;
 #endif
     return true;
 }
 
+bool
+ContentParent::RecvGetGraphicsDeviceInitData(DeviceInitData* aOut)
+{
+  gfxPlatform::GetPlatform()->GetDeviceInitData(aOut);
+  return true;
+}
+
 } // namespace dom
 } // namespace mozilla
 
 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
 
 NS_IMETHODIMP
 ParentIdleListener::Observe(nsISupports*, const char* aTopic, const char16_t* aData) {
     mozilla::unused << mParent->SendNotifyIdleObserver(mObserver,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -857,16 +857,17 @@ private:
     virtual bool RecvUpdateDropEffect(const uint32_t& aDragAction,
                                       const uint32_t& aDropEffect) override;
 
     virtual bool RecvGetBrowserConfiguration(const nsCString& aURI, BrowserConfiguration* aConfig) override;
 
     virtual bool RecvGamepadListenerAdded() override;
     virtual bool RecvGamepadListenerRemoved() override;
     virtual bool RecvProfile(const nsCString& aProfile) override;
+    virtual bool RecvGetGraphicsDeviceInitData(DeviceInitData* aOut) override;
 
     // If you add strong pointers to cycle collected objects here, be sure to
     // release these objects in ShutDownProcess.  See the comment there for more
     // details.
 
     GeckoChildProcessHost* mSubprocess;
     ContentParent* mOpener;
 
--- a/dom/ipc/ContentProcess.cpp
+++ b/dom/ipc/ContentProcess.cpp
@@ -71,20 +71,21 @@ ContentProcess::SetAppDir(const nsACStri
 {
   mXREEmbed.SetAppDir(aPath);
 }
 
 bool
 ContentProcess::Init()
 {
     mContent.Init(IOThreadChild::message_loop(),
-                         ParentPid(),
-                         IOThreadChild::channel());
+                  ParentPid(),
+                  IOThreadChild::channel());
     mXREEmbed.Start();
     mContent.InitXPCOM();
+    mContent.InitGraphicsDeviceData();
 
 #if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
     SetUpSandboxEnvironment();
 #endif
     
     return true;
 }
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -55,16 +55,17 @@ include DOMTypes;
 include JavaScriptTypes;
 include InputStreamParams;
 include PTabContext;
 include URIParams;
 include PluginTypes;
 include ProtocolTypes;
 include PContentPermission;
 include BrowserConfiguration;
+include GraphicsMessages;
 
 // Workaround to prevent error if PContentChild.cpp & PContentBridgeParent.cpp
 // are put into different UnifiedProtocolsXX.cpp files.
 // XXX Remove this once bug 1069073 is fixed
 include "mozilla/dom/PContentBridgeParent.h";
 
 include "mozilla/dom/indexedDB/SerializationHelpers.h";
 
@@ -1048,15 +1049,21 @@ parent:
 
     /**
      * Tells the parent to stop the gamepad listening service if it hasn't already.
      */
     GamepadListenerRemoved();
 
     async Profile(nsCString aProfile);
 
+    /**
+     * Request graphics initialization information from the parent.
+     */
+    sync GetGraphicsDeviceInitData()
+        returns (DeviceInitData aData);
+
 both:
      AsyncMessage(nsString aMessage, ClonedMessageData aData,
                   CpowEntry[] aCpows, Principal aPrincipal);
 };
 
 }
 }
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -3232,19 +3232,25 @@ bool
 TabParent::RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
                                  const uint32_t& aAction,
                                  const nsCString& aVisualDnDData,
                                  const uint32_t& aWidth, const uint32_t& aHeight,
                                  const uint32_t& aStride, const uint8_t& aFormat,
                                  const int32_t& aDragAreaX, const int32_t& aDragAreaY)
 {
   mInitialDataTransferItems.Clear();
-  nsPresContext* pc = mFrameElement->OwnerDoc()->GetShell()->GetPresContext();
-  EventStateManager* esm = pc->EventStateManager();
-
+  nsIPresShell* shell = mFrameElement->OwnerDoc()->GetShell();
+  if (!shell) {
+    if (Manager()->IsContentParent()) {
+      unused << Manager()->AsContentParent()->SendEndDragSession(true, true);
+    }
+    return true;
+  }
+
+  EventStateManager* esm = shell->GetPresContext()->EventStateManager();
   for (uint32_t i = 0; i < aTransfers.Length(); ++i) {
     auto& items = aTransfers[i].items();
     nsTArray<DataTransferItem>* itemArray = mInitialDataTransferItems.AppendElement();
     for (uint32_t j = 0; j < items.Length(); ++j) {
       const IPCDataTransferItem& item = items[j];
       DataTransferItem* localItem = itemArray->AppendElement();
       localItem->mFlavor = item.flavor();
       if (item.data().type() == IPCDataTransferData::TnsString) {
--- a/dom/locales/en-US/chrome/security/security.properties
+++ b/dom/locales/en-US/chrome/security/security.properties
@@ -1,17 +1,16 @@
 # Mixed Content Blocker
 # LOCALIZATION NOTE: "%1$S" is the URI of the blocked mixed content resource
 BlockMixedDisplayContent = Blocked loading mixed display content "%1$S"
 BlockMixedActiveContent = Blocked loading mixed active content "%1$S"
 
 # CORS
 # LOCALIZATION NOTE: Do not translate "Access-Control-Allow-Origin", Access-Control-Allow-Credentials, Access-Control-Allow-Methods, Access-Control-Allow-Headers
 CORSDisabled=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS disabled).
-CORSRequestFailed=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS request failed).
 CORSRequestNotHttp=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS request not http).
 CORSMissingAllowOrigin=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
 CORSAllowOriginNotMatchingOrigin=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS header 'Access-Control-Allow-Origin' does not match '%2$S').
 CORSMethodNotFound=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: Did not find method in CORS header 'Access-Control-Allow-Methods').
 CORSMissingAllowCredentials=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: expected 'true' in CORS header 'Access-Control-Allow-Credentials').
 CORSPreflightDidNotSucceed=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS preflight channel did not succeed).
 CORSInvalidAllowMethod=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: invalid token '%2$S' in CORS header 'Access-Control-Allow-Methods').
 CORSInvalidAllowHeader=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: invalid token '%2$S' in CORS header 'Access-Control-Allow-Headers').
--- a/dom/media/directshow/moz.build
+++ b/dom/media/directshow/moz.build
@@ -36,11 +36,8 @@ if not CONFIG['MOZ_WEBRTC']:
     ]
 
 FAIL_ON_WARNINGS = True
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '/media/webrtc/trunk/webrtc/modules/video_capture/windows',
 ]
-
-if CONFIG['OS_ARCH'] == 'WINNT':
-    DEFINES['NOMINMAX'] = True
--- a/dom/media/fmp4/moz.build
+++ b/dom/media/fmp4/moz.build
@@ -18,13 +18,10 @@ UNIFIED_SOURCES += [
 SOURCES += [
     'MP4Demuxer.cpp',
 ]
 
 FINAL_LIBRARY = 'xul'
 
 FAIL_ON_WARNINGS = True
 
-if CONFIG['OS_ARCH'] == 'WINNT':
-    DEFINES['NOMINMAX'] = True
-
 if CONFIG['MOZ_GONK_MEDIACODEC']:
     DEFINES['MOZ_GONK_MEDIACODEC'] = True
--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -172,16 +172,26 @@ public:
       return true;
     }
     // 0x1c53bb6b // Cues
     if (aData->Length() >= 4 &&
         (*aData)[0] == 0x1c && (*aData)[1] == 0x53 && (*aData)[2] == 0xbb &&
         (*aData)[3] == 0x6b) {
       return true;
     }
+    // 0xa3 // SimpleBlock
+    if (aData->Length() >= 1 &&
+        (*aData)[0] == 0xa3) {
+      return true;
+    }
+    // 0xa1 // Block
+    if (aData->Length() >= 1 &&
+        (*aData)[0] == 0xa1) {
+      return true;
+    }
     return false;
   }
 
   bool ParseStartAndEndTimestamps(MediaByteBuffer* aData,
                                   int64_t& aStart, int64_t& aEnd) override
   {
     bool initSegment = IsInitSegmentPresent(aData);
     if (initSegment) {
--- a/dom/media/mediasource/MediaSource.cpp
+++ b/dom/media/mediasource/MediaSource.cpp
@@ -94,18 +94,17 @@ IsTypeSupported(const nsAString& aType)
         }
         if (hasCodecs &&
             DecoderTraits::CanHandleCodecsType(mimeTypeUTF8.get(),
                                                codecs) == CANPLAY_NO) {
           return NS_ERROR_DOM_INVALID_STATE_ERR;
         }
         return NS_OK;
       } else if (DecoderTraits::IsWebMType(mimeTypeUTF8)) {
-        if (!Preferences::GetBool("media.mediasource.webm.enabled", false) ||
-            Preferences::GetBool("media.mediasource.format-reader", false)) {
+        if (!Preferences::GetBool("media.mediasource.webm.enabled", false)) {
           return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
         }
         if (hasCodecs &&
             DecoderTraits::CanHandleCodecsType(mimeTypeUTF8.get(),
                                                codecs) == CANPLAY_NO) {
           return NS_ERROR_DOM_INVALID_STATE_ERR;
         }
         return NS_OK;
--- a/dom/media/platforms/agnostic/eme/moz.build
+++ b/dom/media/platforms/agnostic/eme/moz.build
@@ -18,11 +18,8 @@ UNIFIED_SOURCES += [
     'SamplesWaitingForKey.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 FAIL_ON_WARNINGS = True
-
-if CONFIG['OS_ARCH'] == 'WINNT':
-    DEFINES['NOMINMAX'] = True
--- a/dom/media/platforms/moz.build
+++ b/dom/media/platforms/moz.build
@@ -77,11 +77,8 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'andr
     ]
     UNIFIED_SOURCES += [
         'android/AndroidDecoderModule.cpp',
     ]
 
 FINAL_LIBRARY = 'xul'
 
 FAIL_ON_WARNINGS = True
-
-if CONFIG['OS_ARCH'] == 'WINNT':
-    DEFINES['NOMINMAX'] = True
--- a/dom/media/platforms/wmf/moz.build
+++ b/dom/media/platforms/wmf/moz.build
@@ -26,14 +26,11 @@ UNIFIED_SOURCES += [
 SOURCES += [
     'WMFUtils.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
-if CONFIG['OS_ARCH'] == 'WINNT':
-    DEFINES['NOMINMAX'] = True
-
 FAIL_ON_WARNINGS = True
 
 CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
--- a/dom/media/webaudio/FFTBlock.h
+++ b/dom/media/webaudio/FFTBlock.h
@@ -128,57 +128,16 @@ public:
       AudioBufferInPlaceScale(aDataOut, mFFTSize, mFFTSize);
     } else
 #endif
     {
       kiss_fftri(mKissIFFT, &(mOutputBuffer.Elements()->c), aDataOut);
     }
 #endif
   }
-  // Inverse-transform the FFTSize()/2+1 points of data in each
-  // of aRealDataIn and aImagDataIn and store the resulting
-  // FFTSize() points in aRealDataOut.
-  void PerformInverseFFT(float* aRealDataIn,
-                         float *aImagDataIn,
-                         float *aRealDataOut)
-  {
-    EnsureIFFT();
-    const uint32_t inputSize = mFFTSize / 2 + 1;
-#if defined(MOZ_LIBAV_FFT)
-    AlignedTArray<FFTSample> inputBuffer(inputSize * 2);
-    for (uint32_t i = 0; i < inputSize; ++i) {
-      inputBuffer[2*i] = aRealDataIn[i];
-      inputBuffer[(2*i)+1] = aImagDataIn[i];
-    }
-    av_rdft_calc(mAvIRDFT, inputBuffer.Elements());
-    PodCopy(aRealDataOut, inputBuffer.Elements(), FFTSize());
-    // TODO: Once bug 877662 lands, change this to use SSE.
-    for (uint32_t i = 0; i < mFFTSize; ++i) {
-      aRealDataOut[i] /= mFFTSize;
-    }
-#else
-    AlignedTArray<ComplexU> inputBuffer(inputSize);
-    for (uint32_t i = 0; i < inputSize; ++i) {
-      inputBuffer[i].r = aRealDataIn[i];
-      inputBuffer[i].i = aImagDataIn[i];
-    }
-#if defined(BUILD_ARM_NEON)
-    if (mozilla::supports_neon()) {
-      omxSP_FFTInv_CCSToR_F32_Sfs(inputBuffer.Elements()->f,
-                                  aRealDataOut, mOmxIFFT);
-    } else
-#endif
-    {
-      kiss_fftri(mKissIFFT, &(inputBuffer.Elements()->c), aRealDataOut);
-      for (uint32_t i = 0; i < mFFTSize; ++i) {
-        aRealDataOut[i] /= mFFTSize;
-      }
-    }
-#endif
-  }
 
   void Multiply(const FFTBlock& aFrame)
   {
     BufferComplexMultiply(mOutputBuffer.Elements()->f,
                           aFrame.mOutputBuffer.Elements()->f,
                           mOutputBuffer.Elements()->f,
                           mFFTSize / 2 + 1);
   }
@@ -212,20 +171,28 @@ public:
   uint32_t FFTSize() const
   {
     return mFFTSize;
   }
   float RealData(uint32_t aIndex) const
   {
     return mOutputBuffer[aIndex].r;
   }
+  float& RealData(uint32_t aIndex)
+  {
+    return mOutputBuffer[aIndex].r;
+  }
   float ImagData(uint32_t aIndex) const
   {
     return mOutputBuffer[aIndex].i;
   }
+  float& ImagData(uint32_t aIndex)
+  {
+    return mOutputBuffer[aIndex].i;
+  }
 
   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   {
     size_t amount = 0;
 #if defined(MOZ_LIBAV_FFT)
     amount += aMallocSizeOf(mAvRDFT);
     amount += aMallocSizeOf(mAvIRDFT);
 #else
--- a/dom/media/webaudio/blink/PeriodicWave.cpp
+++ b/dom/media/webaudio/blink/PeriodicWave.cpp
@@ -173,74 +173,57 @@ unsigned PeriodicWave::numberOfPartialsF
 // One table is created for each range for non-aliasing playback
 // at different playback rates. Thus, higher ranges have more
 // high-frequency partials culled out.
 void PeriodicWave::createBandLimitedTables(const float* realData, const float* imagData, unsigned numberOfComponents)
 {
     float normalizationScale = 1;
 
     unsigned fftSize = m_periodicWaveSize;
-    unsigned halfSize = fftSize / 2 + 1;
+    unsigned halfSize = fftSize / 2;
     unsigned i;
 
+    // Limit the number of components used to those for frequencies below the
+    // Nyquist of the fixed length inverse FFT.
     numberOfComponents = std::min(numberOfComponents, halfSize);
 
     m_bandLimitedTables.SetCapacity(m_numberOfRanges);
 
     for (unsigned rangeIndex = 0; rangeIndex < m_numberOfRanges; ++rangeIndex) {
         // This FFTBlock is used to cull partials (represented by frequency bins).
         FFTBlock frame(fftSize);
-        nsAutoArrayPtr<float> realP(new float[halfSize]);
-        nsAutoArrayPtr<float> imagP(new float[halfSize]);
+
+        // Find the starting bin where we should start culling the aliasing
+        // partials for this pitch range.  We need to clear out the highest
+        // frequencies to band-limit the waveform.
+        unsigned numberOfPartials = numberOfPartialsForRange(rangeIndex);
+        // Also limit to the number of components that are provided.
+        numberOfPartials = std::min(numberOfPartials, numberOfComponents - 1);
 
-        // Copy from loaded frequency data and scale.
-        float scale = fftSize;
-        AudioBufferCopyWithScale(realData, scale, realP, numberOfComponents);
-        AudioBufferCopyWithScale(imagData, scale, imagP, numberOfComponents);
-
-        // If fewer components were provided than 1/2 FFT size,
-        // then clear the remaining bins.
-        for (i = numberOfComponents; i < halfSize; ++i) {
-            realP[i] = 0;
-            imagP[i] = 0;
+        // Copy from loaded frequency data and generate complex conjugate
+        // because of the way the inverse FFT is defined.
+        // The coefficients of higher partials remain zero, as initialized in
+        // the FFTBlock constructor.
+        for (i = 0; i < numberOfPartials + 1; ++i) {
+            frame.RealData(i) = realData[i];
+            frame.ImagData(i) = -imagData[i];
         }
 
-        // Generate complex conjugate because of the way the
-        // inverse FFT is defined.
-        float minusOne = -1;
-        AudioBufferInPlaceScale(imagP, minusOne, halfSize);
-
-        // Find the starting bin where we should start culling.
-        // We need to clear out the highest frequencies to band-limit
-        // the waveform.
-        unsigned numberOfPartials = numberOfPartialsForRange(rangeIndex);
-
-        // Cull the aliasing partials for this pitch range.
-        for (i = numberOfPartials + 1; i < halfSize; ++i) {
-            realP[i] = 0;
-            imagP[i] = 0;
-        }
-        // Clear nyquist if necessary.
-        if (numberOfPartials < halfSize)
-            realP[halfSize-1] = 0;
-
         // Clear any DC-offset.
-        realP[0] = 0;
-
-        // Clear values which have no effect.
-        imagP[0] = 0;
-        imagP[halfSize-1] = 0;
+        frame.RealData(0) = 0;
+        // Clear value which has no effect.
+        frame.ImagData(0) = 0;
 
         // Create the band-limited table.
         AlignedAudioFloatArray* table = new AlignedAudioFloatArray(m_periodicWaveSize);
         m_bandLimitedTables.AppendElement(table);
 
         // Apply an inverse FFT to generate the time-domain table data.
         float* data = m_bandLimitedTables[rangeIndex]->Elements();
-        frame.PerformInverseFFT(realP, imagP, data);
+        frame.GetInverseWithoutScaling(data);
 
         // For the first range (which has the highest power), calculate
         // its peak value then compute normalization scale.
         if (!rangeIndex) {
             float maxValue;
             maxValue = AudioBufferPeakValue(data, m_periodicWaveSize);
 
             if (maxValue)
@@ -251,28 +234,26 @@ void PeriodicWave::createBandLimitedTabl
         AudioBufferInPlaceScale(data, normalizationScale, m_periodicWaveSize);
     }
 }
 
 void PeriodicWave::generateBasicWaveform(OscillatorType shape)
 {
     const float piFloat = M_PI;
     unsigned fftSize = periodicWaveSize();
-    unsigned halfSize = fftSize / 2 + 1;
+    unsigned halfSize = fftSize / 2;
 
     AudioFloatArray real(halfSize);
     AudioFloatArray imag(halfSize);
     float* realP = real.Elements();
     float* imagP = imag.Elements();
 
-    // Clear DC and Nyquist.
+    // Clear DC and imag value which is ignored.
     realP[0] = 0;
     imagP[0] = 0;
-    realP[halfSize-1] = 0;
-    imagP[halfSize-1] = 0;
 
     for (unsigned n = 1; n < halfSize; ++n) {
         float omega = 2 * piFloat * n;
         float invOmega = 1 / omega;
 
         // Fourier coefficients according to standard definition.
         float a; // Coefficient for cos().
         float b; // Coefficient for sin().
--- a/dom/media/webrtc/moz.build
+++ b/dom/media/webrtc/moz.build
@@ -78,18 +78,15 @@ include('/ipc/chromium/chromium-config.m
 #    defined, which complains about important MOZ_EXPORT attributes for
 #    android API types
 if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
   CXXFLAGS += [
     '-Wno-error=attributes'
   ]
 
 FINAL_LIBRARY = 'xul'
-if CONFIG['OS_ARCH'] == 'WINNT':
-    DEFINES['NOMINMAX'] = True
-
 
 if CONFIG['_MSC_VER']:
   CXXFLAGS += [
     '-wd4275', # non dll-interface class used as base for dll-interface class
   ]
 
 FAIL_ON_WARNINGS = True
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -691,18 +691,18 @@ Notification::IsGetEnabled(JSContext* aC
 Notification::Notification(nsIGlobalObject* aGlobal, const nsAString& aID,
                            const nsAString& aTitle, const nsAString& aBody,
                            NotificationDirection aDir, const nsAString& aLang,
                            const nsAString& aTag, const nsAString& aIconUrl,
                            const NotificationBehavior& aBehavior)
   : DOMEventTargetHelper(),
     mWorkerPrivate(nullptr), mObserver(nullptr),
     mID(aID), mTitle(aTitle), mBody(aBody), mDir(aDir), mLang(aLang),
-    mTag(aTag), mIconUrl(aIconUrl), mBehavior(aBehavior), mIsClosed(false),
-    mIsStored(false), mTaskCount(0)
+    mTag(aTag), mIconUrl(aIconUrl), mBehavior(aBehavior), mData(JS::NullValue()),
+    mIsClosed(false), mIsStored(false), mTaskCount(0)
 {
   if (NS_IsMainThread()) {
     // We can only call this on the main thread because
     // Event::SetEventType() called down the call chain when dispatching events
     // using DOMEventTargetHelper::DispatchTrustedEvent() will assume the event
     // is a main thread event if it has a valid owner. It will then attempt to
     // fetch the atom for the event name which asserts main thread only.
     BindToOwner(aGlobal);
@@ -822,38 +822,31 @@ Notification::PersistNotification()
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   nsString id;
   GetID(id);
 
   nsString alertName;
   GetAlertName(alertName);
 
-  nsString dataString;
-  nsCOMPtr<nsIStructuredCloneContainer> scContainer;
-  scContainer = GetDataCloneContainer();
-  if (scContainer) {
-    scContainer->GetDataAsBase64(dataString);
-  }
-
   nsAutoString behavior;
   if (!mBehavior.ToJSON(behavior)) {
     return NS_ERROR_FAILURE;
   }
 
   rv = notificationStorage->Put(origin,
                                 id,
                                 mTitle,
                                 DirectionToString(mDir),
                                 mLang,
                                 mBody,
                                 mTag,
                                 mIconUrl,
                                 alertName,
-                                dataString,
+                                mDataAsBase64,
                                 behavior,
                                 mScope);
 
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   SetStoredState(true);
@@ -908,32 +901,35 @@ Notification::CreateInternal(nsIGlobalOb
                                                          aOptions.mTag,
                                                          aOptions.mIcon,
                                                          aOptions.mMozbehavior);
   return notification.forget();
 }
 
 Notification::~Notification()
 {
+  mData.setUndefined();
+  mozilla::DropJSObjects(this);
   AssertIsOnTargetThread();
   MOZ_ASSERT(!mFeature);
   MOZ_ASSERT(!mTempRef);
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(Notification)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Notification, DOMEventTargetHelper)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mData)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDataObjectContainer)
+  tmp->mData.setUndefined();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Notification, DOMEventTargetHelper)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDataObjectContainer)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Notification, DOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mData);
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
 NS_IMPL_ADDREF_INHERITED(Notification, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(Notification, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Notification)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 nsIPrincipal*
 Notification::GetPrincipal()
@@ -1389,23 +1385,16 @@ Notification::ShowInternal()
     // This observer does not care about the Notification. It will be released
     // at the end of this function.
     //
     // The observer is wholly owned by the alerts service.
     observer = new ServiceWorkerNotificationObserver(mScope, GetPrincipal(), mID);
   }
   MOZ_ASSERT(observer);
 
-  // mDataObjectContainer might be uninitialized here because the notification
-  // was constructed with an undefined data property.
-  nsString dataStr;
-  if (mDataObjectContainer) {
-    mDataObjectContainer->GetDataAsBase64(dataStr);
-  }
-
 #ifdef MOZ_B2G
   nsCOMPtr<nsIAppNotificationService> appNotifier =
     do_GetService("@mozilla.org/system-alerts-service;1");
   if (appNotifier) {
     uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
     if (mWorkerPrivate) {
       appId = mWorkerPrivate->GetPrincipal()->GetAppId();
     } else {
@@ -1423,17 +1412,17 @@ Notification::ShowInternal()
         AppNotificationServiceOptions ops;
         ops.mTextClickable = true;
         ops.mManifestURL = manifestUrl;
         GetAlertName(ops.mId);
         ops.mDbId = mID;
         ops.mDir = DirectionToString(mDir);
         ops.mLang = mLang;
         ops.mTag = mTag;
-        ops.mData = dataStr;
+        ops.mData = mDataAsBase64;
         ops.mMozbehavior = mBehavior;
         ops.mMozbehavior.mSoundFile = soundUrl;
 
         if (!ToJSValue(cx, ops, &val)) {
           NS_WARNING("Converting dict to object failed!");
           return;
         }
 
@@ -1466,17 +1455,17 @@ Notification::ShowInternal()
     inPrivateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
   }
 
   nsAutoString alertName;
   GetAlertName(alertName);
   alertService->ShowAlertNotification(iconUrl, mTitle, mBody, true,
                                       uniqueCookie, observer, alertName,
                                       DirectionToString(mDir), mLang,
-                                      dataStr, GetPrincipal(),
+                                      mDataAsBase64, GetPrincipal(),
                                       inPrivateBrowsing);
 }
 
 /* static */ bool
 Notification::RequestPermissionEnabledForScope(JSContext* aCx, JSObject* /* unused */)
 {
   // requestPermission() is not allowed on workers. The calling page should ask
   // for permission on the worker's behalf. This is to prevent 'which window
@@ -1972,62 +1961,86 @@ Notification::GetOrigin(nsIPrincipal* aP
       do_GetService("@mozilla.org/AppsService;1", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
     appsService->GetManifestURLByLocalId(appId, aOrigin);
   }
 
   return NS_OK;
 }
 
-nsIStructuredCloneContainer* Notification::GetDataCloneContainer()
-{
-  return mDataObjectContainer;
-}
-
 void
 Notification::GetData(JSContext* aCx,
                       JS::MutableHandle<JS::Value> aRetval)
 {
-  if (!mData && mDataObjectContainer) {
+  if (mData.isNull() && !mDataAsBase64.IsEmpty()) {
     nsresult rv;
-    rv = mDataObjectContainer->DeserializeToVariant(aCx, getter_AddRefs(mData));
+    nsRefPtr<nsStructuredCloneContainer> container =
+      new nsStructuredCloneContainer();
+    rv = container->InitFromBase64(mDataAsBase64, JS_STRUCTURED_CLONE_VERSION,
+                                   aCx);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       aRetval.setNull();
       return;
     }
+
+    JS::Rooted<JS::Value> data(aCx);
+    rv = container->DeserializeToJsval(aCx, &data);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      aRetval.setNull();
+      return;
+    }
+
+    if (data.isGCThing()) {
+      mozilla::HoldJSObjects(this);
+    }
+    mData = data;
   }
-  if (!mData) {
+  if (mData.isNull()) {
     aRetval.setNull();
     return;
   }
-  VariantToJsval(aCx, mData, aRetval);
+
+  JS::ExposeValueToActiveJS(mData);
+  aRetval.set(mData);
 }
 
 void
 Notification::InitFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aData,
                             ErrorResult& aRv)
 {
-  if (mDataObjectContainer || aData.isNull()) {
+  if (!mDataAsBase64.IsEmpty() || aData.isNull()) {
     return;
   }
-  mDataObjectContainer = new nsStructuredCloneContainer();
-  aRv = mDataObjectContainer->InitFromJSVal(aData, aCx);
+  nsRefPtr<nsStructuredCloneContainer> dataObjectContainer =
+    new nsStructuredCloneContainer();
+  aRv = dataObjectContainer->InitFromJSVal(aData, aCx);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+
+  dataObjectContainer->GetDataAsBase64(mDataAsBase64);
 }
 
 void Notification::InitFromBase64(JSContext* aCx, const nsAString& aData,
                                   ErrorResult& aRv)
 {
-  if (mDataObjectContainer || aData.IsEmpty()) {
+  if (!mDataAsBase64.IsEmpty() || aData.IsEmpty()) {
     return;
   }
 
-  auto container = new nsStructuredCloneContainer();
+  // To and fro to ensure it is valid base64.
+  nsRefPtr<nsStructuredCloneContainer> container =
+    new nsStructuredCloneContainer();
   aRv = container->InitFromBase64(aData, JS_STRUCTURED_CLONE_VERSION,
                                   aCx);
-  mDataObjectContainer = container;
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+
+  container->GetDataAsBase64(mDataAsBase64);
 }
 
 bool
 Notification::AddRefObject()
 {
   AssertIsOnTargetThread();
   MOZ_ASSERT_IF(mWorkerPrivate && !mFeature, mTaskCount == 0);
   MOZ_ASSERT_IF(mWorkerPrivate && mFeature, mTaskCount > 0);
--- a/dom/notification/Notification.h
+++ b/dom/notification/Notification.h
@@ -12,17 +12,16 @@
 #include "mozilla/dom/NotificationBinding.h"
 #include "mozilla/dom/workers/bindings/WorkerFeature.h"
 
 #include "nsIObserver.h"
 
 #include "nsCycleCollectionParticipant.h"
 
 class nsIPrincipal;
-class nsIStructuredCloneContainer;
 class nsIVariant;
 
 namespace mozilla {
 namespace dom {
 
 class NotificationRef;
 class WorkerNotificationObserver;
 class Promise;
@@ -121,17 +120,17 @@ class Notification : public DOMEventTarg
 
 public:
   IMPL_EVENT_HANDLER(click)
   IMPL_EVENT_HANDLER(show)
   IMPL_EVENT_HANDLER(error)
   IMPL_EVENT_HANDLER(close)
 
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Notification, DOMEventTargetHelper)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(Notification, DOMEventTargetHelper)
 
   static bool PrefEnabled(JSContext* aCx, JSObject* aObj);
   // Returns if Notification.get() is allowed for the current global.
   static bool IsGetEnabled(JSContext* aCx, JSObject* aObj);
 
   static already_AddRefed<Notification> Constructor(const GlobalObject& aGlobal,
                                                     const nsAString& aTitle,
                                                     const NotificationOptions& aOption,
@@ -200,18 +199,16 @@ public:
     mIsStored = val;
   }
 
   bool IsStored()
   {
     return mIsStored;
   }
 
-  nsIStructuredCloneContainer* GetDataCloneContainer();
-
   static bool RequestPermissionEnabledForScope(JSContext* aCx, JSObject* /* unused */);
 
   static void RequestPermission(const GlobalObject& aGlobal,
                                 const Optional<OwningNonNull<NotificationPermissionCallback> >& aCallback,
                                 ErrorResult& aRv);
 
   static NotificationPermission GetPermission(const GlobalObject& aGlobal,
                                               ErrorResult& aRv);
@@ -354,21 +351,21 @@ protected:
 
   const nsString mID;
   const nsString mTitle;
   const nsString mBody;
   const NotificationDirection mDir;
   const nsString mLang;
   const nsString mTag;
   const nsString mIconUrl;
-  nsCOMPtr<nsIStructuredCloneContainer> mDataObjectContainer;
+  nsString mDataAsBase64;
   const NotificationBehavior mBehavior;
 
   // It's null until GetData is first called
-  nsCOMPtr<nsIVariant> mData;
+  JS::Heap<JS::Value> mData;
 
   nsString mAlertName;
   nsString mScope;
 
   // Main thread only.
   bool mIsClosed;
 
   // We need to make a distinction between the notification being closed i.e.
--- a/dom/push/PushDB.jsm
+++ b/dom/push/PushDB.jsm
@@ -149,16 +149,46 @@ this.PushDB.prototype = {
           aStore.clear();
         },
         resolve,
         reject
       )
     );
   },
 
+  // testFn(record) is called with a database record and should return true if
+  // that record should be deleted.
+  clearIf: function(testFn) {
+    debug("clearIf()");
+    return new Promise((resolve, reject) =>
+      this.newTxn(
+        "readwrite",
+        this._dbStoreName,
+        (aTxn, aStore) => {
+          aTxn.result = undefined;
+
+          aStore.openCursor().onsuccess = event => {
+            let cursor = event.target.result;
+            if (cursor) {
+              if (testFn(this.toPushRecord(cursor.value))) {
+                let deleteRequest = cursor.delete();
+                deleteRequest.onerror = e => {
+                  debug("Failed to delete entry even when test succeeded!");
+                }
+              }
+              cursor.continue();
+            }
+          }
+        },
+        resolve,
+        reject
+      )
+    );
+  },
+
   getByPushEndpoint: function(aPushEndpoint) {
     debug("getByPushEndpoint()");
 
     return new Promise((resolve, reject) =>
       this.newTxn(
         "readonly",
         this._dbStoreName,
         (aTxn, aStore) => {
--- a/dom/push/PushNotificationService.js
+++ b/dom/push/PushNotificationService.js
@@ -53,16 +53,20 @@ PushNotificationService.prototype = {
   registration: function registration(scope, originAttributes) {
     return PushService._registration({scope, originAttributes});
   },
 
   clearAll: function clearAll() {
     return PushService._clearAll();
   },
 
+  clearForDomain: function(domain) {
+    return PushService._clearForDomain(domain);
+  },
+
   observe: function observe(subject, topic, data) {
     switch (topic) {
       case "app-startup":
         Services.obs.addObserver(this, "sessionstore-windows-restored", true);
         break;
       case "sessionstore-windows-restored":
         Services.obs.removeObserver(this, "sessionstore-windows-restored");
         if (isParent) {
--- a/dom/push/PushService.jsm
+++ b/dom/push/PushService.jsm
@@ -1022,17 +1022,57 @@ this.PushService = {
           })
         }
       );
   },
 
   _clearAll: function _clearAll() {
     return this._checkActivated()
       .then(_ => this._db.clearAll())
-      .catch(_ => {
+      .catch(_ => Promise.resolve());
+  },
+
+  _clearForDomain: function(domain) {
+    /**
+     * Copied from ForgetAboutSite.jsm.
+     *
+     * Returns true if the string passed in is part of the root domain of the
+     * current string.  For example, if this is "www.mozilla.org", and we pass in
+     * "mozilla.org", this will return true.  It would return false the other way
+     * around.
+     */
+    function hasRootDomain(str, aDomain)
+    {
+      let index = str.indexOf(aDomain);
+      // If aDomain is not found, we know we do not have it as a root domain.
+      if (index == -1)
+        return false;
+
+      // If the strings are the same, we obviously have a match.
+      if (str == aDomain)
+        return true;
+
+      // Otherwise, we have aDomain as our root domain iff the index of aDomain is
+      // aDomain.length subtracted from our length and (since we do not have an
+      // exact match) the character before the index is a dot or slash.
+      let prevChar = str[index - 1];
+      return (index == (str.length - aDomain.length)) &&
+             (prevChar == "." || prevChar == "/");
+    }
+
+    let clear = (db, domain) => {
+      db.clearIf(record => {
+        return hasRootDomain(record.origin, domain);
+      });
+    }
+
+    return this._checkActivated()
+      .then(_ => clear(this._db, domain))
+      .catch(e => {
+        debug("Error forgetting about domain! " + e);
         return Promise.resolve();
       });
   },
 
   /**
    * Called on message from the child process
    */
   _registration: function(aPageRecord) {
--- a/dom/push/test/xpcshell/head.js
+++ b/dom/push/test/xpcshell/head.js
@@ -1,14 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 'use strict';
 
-const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+let {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://gre/modules/Timer.jsm');
 Cu.import('resource://gre/modules/Promise.jsm');
 Cu.import('resource://gre/modules/Preferences.jsm');
 Cu.import('resource://gre/modules/PlacesUtils.jsm');
 
--- a/dom/security/nsCORSListenerProxy.cpp
+++ b/dom/security/nsCORSListenerProxy.cpp
@@ -533,24 +533,18 @@ nsCORSListenerProxy::CheckRequestApprove
   if (gDisableCORS) {
     LogBlockedRequest(aRequest, "CORSDisabled", nullptr);
     return NS_ERROR_DOM_BAD_URI;
   }
 
   // Check if the request failed
   nsresult status;
   nsresult rv = aRequest->GetStatus(&status);
-  if (NS_FAILED(rv)) {
-    LogBlockedRequest(aRequest, "CORSRequestFailed", nullptr);
-    return rv;
-  }
-  if (NS_FAILED(status)) {
-    LogBlockedRequest(aRequest, "CORSRequestFailed", nullptr);
-    return status;
-  }
+  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_SUCCESS(status, status);
 
   // Test that things worked on a HTTP level
   nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
   if (!http) {
     LogBlockedRequest(aRequest, "CORSRequestNotHttp", nullptr);
     return NS_ERROR_DOM_BAD_URI;
   }
 
--- a/dom/workers/test/notification_worker.js
+++ b/dom/workers/test/notification_worker.js
@@ -15,32 +15,36 @@ if (self.Notification) {
     },
 
     function (done) {
       var options = {
         dir: "auto",
         lang: "",
         body: "This is a notification body",
         tag: "sometag",
-        icon: "icon.png"
+        icon: "icon.png",
+        data: ["a complex object that should be", { "structured": "cloned" }],
+        mozbehavior: { vibrationPattern: [30, 200, 30] },
       };
       var notification = new Notification("This is a title", options);
 
       ok(notification !== undefined, "Notification exists");
       is(notification.onclick, null, "onclick() should be null");
       is(notification.onshow, null, "onshow() should be null");
       is(notification.onerror, null, "onerror() should be null");
       is(notification.onclose, null, "onclose() should be null");
       is(typeof notification.close, "function", "close() should exist");
 
       is(notification.dir, options.dir, "auto should get set");
       is(notification.lang, options.lang, "lang should get set");
       is(notification.body, options.body, "body should get set");
       is(notification.tag, options.tag, "tag should get set");
       is(notification.icon, options.icon, "icon should get set");
+      is(notification.data[0],  "a complex object that should be", "data item 0 should be a matching string");
+      is(notification.data[1]["structured"], "cloned", "data item 1 should be a matching object literal");
 
       // store notification in test context
       this.notification = notification;
 
       notification.onshow = function () {
         ok(true, "onshow handler should be called");
         done();
       };
--- a/dom/workers/test/serviceworkers/notificationclick.html
+++ b/dom/workers/test/serviceworkers/notificationclick.html
@@ -8,20 +8,20 @@
   <title>Bug 1114554 - controlled page</title>
 <script class="testbody" type="text/javascript">
   var testWindow = parent;
   if (opener) {
     testWindow = opener;
   }
 
   navigator.serviceWorker.ready.then(function(swr) {
-    swr.showNotification("Hi there. The ServiceWorker should receive a click event for this.");
+    swr.showNotification("Hi there. The ServiceWorker should receive a click event for this.", { data: { complex: ["jsval", 5] }});
   });
 
   navigator.serviceWorker.onmessage = function(msg) {
-    testWindow.callback();
+    testWindow.callback(msg.data.result);
   };
 </script>
 
 </head>
 <body>
 </body>
 </html>
--- a/dom/workers/test/serviceworkers/notificationclick.js
+++ b/dom/workers/test/serviceworkers/notificationclick.js
@@ -4,12 +4,16 @@
 onnotificationclick = function(e) {
   self.clients.matchAll().then(function(clients) {
     if (clients.length === 0) {
       dump("********************* CLIENTS LIST EMPTY! Test will timeout! ***********************\n");
       return;
     }
 
     clients.forEach(function(client) {
-      client.postMessage("done");
+      client.postMessage({ result: e.notification.data &&
+                                   e.notification.data['complex'] &&
+                                   e.notification.data['complex'][0] == "jsval" &&
+                                   e.notification.data['complex'][1] == 5 });
+
     });
   });
 }
--- a/dom/workers/test/serviceworkers/test_notificationclick.html
+++ b/dom/workers/test/serviceworkers/test_notificationclick.html
@@ -18,21 +18,21 @@ https://bugzilla.mozilla.org/show_bug.cg
 <pre id="test">
 </pre>
 <script type="text/javascript">
   SimpleTest.requestFlakyTimeout("Mock alert service dispatches show and click events.");
 
   function testFrame(src) {
     var iframe = document.createElement("iframe");
     iframe.src = src;
-    window.callback = function() {
+    window.callback = function(result) {
       window.callback = null;
       document.body.removeChild(iframe);
       iframe = null;
-      ok(true, "Got notificationclick event.");
+      ok(result, "Got notificationclick event with correct data.");
       MockServices.unregister();
       SimpleTest.finish();
     };
     document.body.appendChild(iframe);
   }
 
   function runTest() {
     MockServices.register();
--- a/embedding/components/printingui/win/nsPrintDialogUtil.cpp
+++ b/embedding/components/printingui/win/nsPrintDialogUtil.cpp
@@ -15,18 +15,16 @@ To Build This:
 
 WIN_LIBS=                                       \
         winspool.lib                           \
         comctl32.lib                           \
         comdlg32.lib
 
 ---------------------------------------------------------------------- */
 
-#define NOMINMAX 1
-
 #include "plstr.h"
 #include <windows.h>
 #include <tchar.h>
 
 #include <unknwn.h>
 #include <commdlg.h>
 
 #include "nsIWebBrowserPrint.h"
--- a/gfx/angle/moz.build
+++ b/gfx/angle/moz.build
@@ -93,17 +93,16 @@ if CONFIG['GNU_CXX']:
         '-Wno-unknown-pragmas',
     ]
     if CONFIG['CLANG_CXX']:
         CXXFLAGS += ['-Wno-unused-private-field']
 
 if CONFIG['MOZ_DIRECTX_SDK_PATH'] and not CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
     CXXFLAGS += ['-I\'%s/include/\'' % CONFIG['MOZ_DIRECTX_SDK_PATH']]
 
-DEFINES['NOMINMAX'] = True
 DEFINES['_CRT_SECURE_NO_DEPRECATE'] = True
 DEFINES['_HAS_EXCEPTIONS'] = 0
 
 if not CONFIG['MOZ_DEBUG']:
     DEFINES['_SECURE_SCL'] = 0
 
 DEFINES['ANGLE_ENABLE_D3D9'] = True
 if CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
--- a/gfx/angle/src/libEGL/moz.build
+++ b/gfx/angle/src/libEGL/moz.build
@@ -25,17 +25,16 @@ if CONFIG['GNU_CXX']:
         '-Wno-unknown-pragmas',
     ]
     if CONFIG['CLANG_CXX']:
         CXXFLAGS += ['-Wno-unused-private-field']
 
 if CONFIG['MOZ_DIRECTX_SDK_PATH'] and not CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
     CXXFLAGS += ['-I\'%s/include/\'' % CONFIG['MOZ_DIRECTX_SDK_PATH']]
 
-DEFINES['NOMINMAX'] = True
 DEFINES['_CRT_SECURE_NO_DEPRECATE'] = True
 DEFINES['_HAS_EXCEPTIONS'] = 0
 
 if not CONFIG['MOZ_DEBUG']:
     DEFINES['_SECURE_SCL'] = 0
 
 DEFINES['ANGLE_ENABLE_D3D9'] = True
 if CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
--- a/gfx/angle/src/libGLESv2/moz.build
+++ b/gfx/angle/src/libGLESv2/moz.build
@@ -188,17 +188,16 @@ if CONFIG['GNU_CXX']:
         '-Wno-unknown-pragmas',
     ]
     if CONFIG['CLANG_CXX']:
         CXXFLAGS += ['-Wno-unused-private-field']
 
 if CONFIG['MOZ_DIRECTX_SDK_PATH'] and not CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
     CXXFLAGS += ['-I\'%s/include/\'' % CONFIG['MOZ_DIRECTX_SDK_PATH']]
 
-DEFINES['NOMINMAX'] = True
 DEFINES['_CRT_SECURE_NO_DEPRECATE'] = True
 DEFINES['_HAS_EXCEPTIONS'] = 0
 
 if not CONFIG['MOZ_DEBUG']:
     DEFINES['_SECURE_SCL'] = 0
 
 DEFINES['ANGLE_ENABLE_D3D9'] = True
 if CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
new file mode 100644
--- /dev/null
+++ b/gfx/ipc/GraphicsMessages.ipdlh
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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/. */
+
+namespace mozilla {
+namespace gfx {
+
+struct DeviceInitData
+{
+  bool useAcceleration;
+
+  // Windows only.
+  bool useD3D11;
+  bool useD3D11WARP;
+  bool useD3D11ImageBridge;
+  bool d3d11TextureSharingWorks;
+  bool useD2D;
+  bool useD2D1;
+};
+
+} // namespace gfx
+} // namespace mozilla
--- a/gfx/ipc/moz.build
+++ b/gfx/ipc/moz.build
@@ -21,14 +21,18 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'wind
         'SharedDIBSurface.cpp',
         'SharedDIBWin.cpp',
     ]
 
 SOURCES += [
     'SharedDIB.cpp',
 ]
 
+IPDL_SOURCES = [
+    'GraphicsMessages.ipdlh',
+]
+
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
 CXXFLAGS += CONFIG['TK_CFLAGS']
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -491,27 +491,30 @@ public:
     mScreenRotation = aRotation;
   }
 
   TimeStamp GetCompositionTime() const {
     return mCompositionTime;
   }
   void SetCompositionTime(TimeStamp aTimeStamp) {
     mCompositionTime = aTimeStamp;
-    mCompositeAgainTime = TimeStamp();
+    if (!mCompositionTime.IsNull() && !mCompositeUntilTime.IsNull() &&
+        mCompositionTime >= mCompositeUntilTime) {
+      mCompositeUntilTime = TimeStamp();
+    }
   }
 
-  void CompositeAgainAt(TimeStamp aTimeStamp) {
-    if (mCompositeAgainTime.IsNull() ||
-        mCompositeAgainTime > aTimeStamp) {
-      mCompositeAgainTime = aTimeStamp;
+  void CompositeUntil(TimeStamp aTimeStamp) {
+    if (mCompositeUntilTime.IsNull() ||
+        mCompositeUntilTime < aTimeStamp) {
+      mCompositeUntilTime = aTimeStamp;
     }
   }
-  TimeStamp GetCompositeAgainTime() const {
-    return mCompositeAgainTime;
+  TimeStamp GetCompositeUntilTime() const {
+    return mCompositeUntilTime;
   }
 
 protected:
   void DrawDiagnosticsInternal(DiagnosticFlags aFlags,
                                const gfx::Rect& aVisibleRect,
                                const gfx::Rect& aClipRect,
                                const gfx::Matrix4x4& transform,
                                uint32_t aFlashCounter);
@@ -524,19 +527,20 @@ protected:
   static void SetBackend(LayersBackend backend);
 
   /**
    * Render time for the current composition.
    */
   TimeStamp mCompositionTime;
   /**
    * When nonnull, during rendering, some compositable indicated that it will
-   * change its rendering at this time (and this is the earliest such time).
+   * change its rendering at this time. In order not to miss it, we composite
+   * on every vsync until this time occurs (this is the latest such time).
    */
-  TimeStamp mCompositeAgainTime;
+  TimeStamp mCompositeUntilTime;
 
   uint32_t mCompositorID;
   DiagnosticTypes mDiagnosticTypes;
   PCompositorParent* mParent;
 
   /**
    * We keep track of the total number of pixels filled as we composite the
    * current frame. This value is an approximation and is not accurate,
--- a/gfx/layers/client/ClientPaintedLayer.cpp
+++ b/gfx/layers/client/ClientPaintedLayer.cpp
@@ -147,21 +147,17 @@ ClientLayerManager::CreatePaintedLayer()
 {
   return CreatePaintedLayerWithHint(NONE);
 }
 
 already_AddRefed<PaintedLayer>
 ClientLayerManager::CreatePaintedLayerWithHint(PaintedLayerCreationHint aHint)
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
-  if (
-#ifdef MOZ_B2G
-      aHint == SCROLLABLE &&
-#endif
-      gfxPrefs::LayersTilesEnabled()
+  if (gfxPrefs::LayersTilesEnabled()
 #ifndef MOZ_X11
       && (AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_OPENGL ||
           AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_D3D9 ||
           AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_D3D11)
 #endif
   ) {
     nsRefPtr<ClientTiledPaintedLayer> layer = new ClientTiledPaintedLayer(this, aHint);
     CREATE_SHADOW(Painted);
--- a/gfx/layers/client/ClientPaintedLayer.h
+++ b/gfx/layers/client/ClientPaintedLayer.h
@@ -64,25 +64,16 @@ public:
     mInvalidRegion.SimplifyOutward(20);
     mValidRegion.Sub(mValidRegion, mInvalidRegion);
   }
 
   virtual void RenderLayer() override { RenderLayerWithReadback(nullptr); }
 
   virtual void RenderLayerWithReadback(ReadbackProcessor *aReadback) override;
 
-  virtual bool IsOptimizedFor(LayerManager::PaintedLayerCreationHint aCreationHint) override
-  {
-#ifdef MOZ_B2G
-    return aCreationHint == GetCreationHint();
-#else
-    return true;
-#endif
-  }
-
   virtual void ClearCachedResources() override
   {
     if (mContentClient) {
       mContentClient->Clear();
     }
     mValidRegion.SetEmpty();
     DestroyBackBuffer();
   }
--- a/gfx/layers/client/SingleTiledContentClient.cpp
+++ b/gfx/layers/client/SingleTiledContentClient.cpp
@@ -181,17 +181,17 @@ ClientSingleTiledLayerBuffer::PaintThebe
     nsRefPtr<gfxContext> ctx = new gfxContext(dt);
     ctx->SetMatrix(ctx->CurrentMatrix().Translate(-mTilingOrigin.x, -mTilingOrigin.y));
 
     aCallback(mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
   }
 
   // Mark the area we just drew into the back buffer as invalid in the front buffer as they're
   // now out of sync.
-  mTile.mInvalidFront.OrWith(paintRegion);
+  mTile.mInvalidFront.OrWith(tileDirtyRegion);
 
   // The new buffer is now validated, remove the dirty region from it.
   mTile.mInvalidBack.SubOut(tileDirtyRegion);
 
   dt = nullptr;
 
   mTile.Flip();
   UnlockTile(mTile);
--- a/gfx/layers/composite/ImageHost.cpp
+++ b/gfx/layers/composite/ImageHost.cpp
@@ -14,16 +14,18 @@
 #include "mozilla/layers/LayerManagerComposite.h"     // for TexturedEffect, Effect, etc
 #include "nsAString.h"
 #include "nsDebug.h"                    // for NS_WARNING, NS_ASSERTION
 #include "nsPrintfCString.h"            // for nsPrintfCString
 #include "nsString.h"                   // for nsAutoCString
 
 class nsIntRegion;
 
+#define BIAS_TIME_MS 1.0
+
 namespace mozilla {
 namespace gfx {
 class Matrix4x4;
 } // namespace gfx
 
 using namespace gfx;
 
 namespace layers {
@@ -97,16 +99,32 @@ ImageHost::UseTextureHost(const nsTArray
     }
     // SetCropRect() affects only on a specific platform.
     // If it is not implemented, it does nothing.
     img.mFrontBuffer->SetCropRect(img.mPictureRect);
     img.mFrontBuffer->Updated();
     img.mFrontBuffer->PrepareTextureSource(img.mTextureSource);
   }
   mImages.SwapElements(newImages);
+
+  // Video producers generally send replacement images with the same frameID but
+  // slightly different timestamps in order to sync with the audio clock. This
+  // means that any CompositeUntil() call we made in Composite() may no longer
+  // guarantee that we'll composite until the next frame is ready. Fix that here.
+  if (GetCompositor() && mLastFrameID >= 0) {
+    for (size_t i = 0; i < mImages.Length(); ++i) {
+      bool frameComesAfter = mImages[i].mFrameID > mLastFrameID ||
+                             mImages[i].mProducerID != mLastProducerID;
+      if (frameComesAfter && !mImages[i].mTimeStamp.IsNull()) {
+        GetCompositor()->CompositeUntil(mImages[i].mTimeStamp +
+                                        TimeDuration::FromMilliseconds(BIAS_TIME_MS));
+        break;
+      }
+    }
+  }
 }
 
 void
 ImageHost::RemoveTextureHost(TextureHost* aTexture)
 {
   MOZ_ASSERT(!mLocked);
 
   CompositableHost::RemoveTextureHost(aTexture);
@@ -119,19 +137,19 @@ ImageHost::RemoveTextureHost(TextureHost
   }
 }
 
 static TimeStamp
 GetBiasedTime(const TimeStamp& aInput, ImageHost::Bias aBias)
 {
   switch (aBias) {
   case ImageHost::BIAS_NEGATIVE:
-    return aInput - TimeDuration::FromMilliseconds(1.0);
+    return aInput - TimeDuration::FromMilliseconds(BIAS_TIME_MS);
   case ImageHost::BIAS_POSITIVE:
-    return aInput + TimeDuration::FromMilliseconds(1.0);
+    return aInput + TimeDuration::FromMilliseconds(BIAS_TIME_MS);
   default:
     return aInput;
   }
 }
 
 static ImageHost::Bias
 UpdateBias(const TimeStamp& aCompositionTime,
            const TimeStamp& aCompositedImageTime,
@@ -252,17 +270,17 @@ ImageHost::Composite(LayerComposite* aLa
     return;
   }
   int imageIndex = ChooseImageIndex();
   if (imageIndex < 0) {
     return;
   }
 
   if (uint32_t(imageIndex) + 1 < mImages.Length()) {
-    GetCompositor()->CompositeAgainAt(mImages[imageIndex + 1].mTimeStamp);
+    GetCompositor()->CompositeUntil(mImages[imageIndex + 1].mTimeStamp + TimeDuration::FromMilliseconds(BIAS_TIME_MS));
   }
 
   TimedImage* img = &mImages[imageIndex];
   // Make sure the front buffer has a compositor
   img->mFrontBuffer->SetCompositor(GetCompositor());
 
   {
     AutoLockCompositableHost autoLock(this);
--- a/gfx/layers/composite/TiledContentHost.h
+++ b/gfx/layers/composite/TiledContentHost.h
@@ -190,24 +190,27 @@ public:
   virtual LayerRenderState GetRenderState() override
   {
     // If we have exactly one high precision tile, then we can support hwc.
     if (mTiledBuffer.GetTileCount() == 1 &&
         mLowPrecisionTiledBuffer.GetTileCount() == 0) {
       TextureHost* host = mTiledBuffer.GetTile(0).mTextureHost;
       if (host) {
         MOZ_ASSERT(!mTiledBuffer.GetTile(0).mTextureHostOnWhite, "Component alpha not supported!");
-        LayerRenderState state = host->GetRenderState();
 
-        // Offset by the distance between the start of the valid (visible) region and the top-left
-        // of the tile.
         gfx::IntPoint offset = mTiledBuffer.GetTileOffset(mTiledBuffer.GetPlacement().TilePosition(0));
 
-        state.SetOffset(offset - GetValidRegion().GetBounds().TopLeft());
-        return host->GetRenderState();
+        // Don't try to use HWC if the content doesn't start at the top-left of the tile.
+        if (offset != GetValidRegion().GetBounds().TopLeft()) {
+          return LayerRenderState();
+        }
+
+        LayerRenderState state = host->GetRenderState();
+        state.SetOffset(offset);
+        return state;
       }
     }
     return LayerRenderState();
   }
 
 
   virtual bool UpdateThebes(const ThebesBufferData& aData,
                             const nsIntRegion& aUpdated,
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -1175,18 +1175,19 @@ CompositorParent::CompositeToTarget(Draw
 
   if (!aTarget) {
     DidComposite();
   }
 
   // We're not really taking advantage of the stored composite-again-time here.
   // We might be able to skip the next few composites altogether. However,
   // that's a bit complex to implement and we'll get most of the advantage
-  // by skipping compositing when we detect there's nothing invalid.
-  if (!mCompositor->GetCompositeAgainTime().IsNull() ||
+  // by skipping compositing when we detect there's nothing invalid. This is why
+  // we do "composite until" rather than "composite again at".
+  if (!mCompositor->GetCompositeUntilTime().IsNull() ||
       mLayerManager->DebugOverlayWantsNextFrame()) {
     ScheduleComposition();
   }
 
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   TimeDuration executionTime = TimeStamp::Now() - mCompositorScheduler->GetLastComposeTime();
   TimeDuration frameBudget = TimeDuration::FromMilliseconds(15);
   int32_t frameRate = CalculateCompositionFrameRate();
--- a/gfx/ots/src/moz.build
+++ b/gfx/ots/src/moz.build
@@ -49,17 +49,16 @@ UNIFIED_SOURCES += [
 
 if CONFIG['GKMEDIAS_SHARED_LIBRARY']:
     NO_VISIBILITY_FLAGS = True
 
 FINAL_LIBRARY = 'gkmedias'
 
 DEFINES['PACKAGE_VERSION'] = '"moz"'
 DEFINES['PACKAGE_BUGREPORT'] = '"http://bugzilla.mozilla.org/"'
-DEFINES['NOMINMAX'] = True
 
 if CONFIG['GKMEDIAS_SHARED_LIBRARY']:
     DEFINES['OTS_DLL'] = True
     DEFINES['OTS_DLL_EXPORTS'] = True
 
 USE_LIBS += [
     'brotli',
 ]
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -106,16 +106,18 @@ class mozilla::gl::SkiaGLGlue : public G
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Mutex.h"
 
 #include "nsIGfxInfo.h"
 #include "nsIXULRuntime.h"
 #include "VsyncSource.h"
 #include "SoftwareVsyncSource.h"
+#include "nscore.h" // for NS_FREE_PERMANENT_DATA
+#include "mozilla/dom/ContentChild.h"
 
 namespace mozilla {
 namespace layers {
 #ifdef MOZ_WIDGET_GONK
 void InitGralloc();
 #endif
 void ShutdownTileCache();
 } // namespace layers
@@ -254,17 +256,17 @@ void CrashStatsLogForwarder::UpdateCrash
 #else
   nsresult annotated = NS_ERROR_NOT_IMPLEMENTED;
 #endif
   if (annotated != NS_OK) {
     printf("Crash Annotation %s: %s",
            mCrashCriticalKey.get(), message.str().c_str());
   }
 }
-  
+
 void CrashStatsLogForwarder::Log(const std::string& aString)
 {
   MutexAutoLock lock(mMutex);
 
   if (UpdateStringsVector(aString)) {
     UpdateCrashReport();
   }
 }
@@ -640,17 +642,17 @@ gfxPlatform::Shutdown()
     // context providers available, so we have to shut all of them down.
     // We should only support the default GL provider on Windows; then, this
     // could go away. Unfortunately, we currently support WGL (the default) for
     // WebGL on Optimus.
     GLContextProviderEGL::Shutdown();
 #endif
 
     // This is a bit iffy - we're assuming that we were the ones that set the
-    // log forwarder in the Factory, so that it's our responsibility to 
+    // log forwarder in the Factory, so that it's our responsibility to
     // delete it.
     delete mozilla::gfx::Factory::GetLogForwarder();
     mozilla::gfx::Factory::SetLogForwarder(nullptr);
 
     delete gGfxPlatformPrefsLock;
 
     gfxPrefs::DestroySingleton();
     gfxFont::DestroySingletons();
@@ -709,17 +711,17 @@ gfxPlatform::~gfxPlatform()
     VRHMDManager::ManagerDestroy();
 
     // The cairo folks think we should only clean up in debug builds,
     // but we're generally in the habit of trying to shut down as
     // cleanly as possible even in production code, so call this
     // cairo_debug_* function unconditionally.
     //
     // because cairo can assert and thus crash on shutdown, don't do this in release builds
-#if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) || defined(MOZ_VALGRIND)
+#ifdef NS_FREE_PERMANENT_DATA
 #ifdef USE_SKIA
     // must do Skia cleanup before Cairo cleanup, because Skia may be referencing
     // Cairo objects e.g. through SkCairoFTTypeface
     SkGraphics::Term();
 #endif
 
 #if MOZ_TREE_CAIRO
     cairo_debug_reset_static_data();
@@ -1196,17 +1198,17 @@ gfxPlatform::CreateOffscreenContentDrawT
 }
 
 already_AddRefed<DrawTarget>
 gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat)
 {
   NS_ASSERTION(mContentBackend != BackendType::NONE, "No backend.");
 
   BackendType backendType = mContentBackend;
-  
+
   if (!Factory::DoesBackendSupportDataDrawtarget(mContentBackend)) {
     backendType = BackendType::CAIRO;
   }
 
   RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(backendType,
                                                            aData, aSize,
                                                            aStride, aFormat);
 
@@ -2482,8 +2484,29 @@ gfxPlatform::NotifyCompositorCreated(Lay
   // Set the backend before we notify so it's available immediately.
   mCompositorBackend = aBackend;
 
   // Notify that we created a compositor, so telemetry can update.
   if (nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService()) {
     obsvc->NotifyObservers(nullptr, "compositor:created", nullptr);
   }
 }
+
+void
+gfxPlatform::GetDeviceInitData(mozilla::gfx::DeviceInitData* aOut)
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+  aOut->useAcceleration() = ShouldUseLayersAcceleration();
+}
+
+void
+gfxPlatform::UpdateDeviceInitData()
+{
+  if (XRE_IsParentProcess()) {
+    // The parent process figures out device initialization on its own.
+    return;
+  }
+
+  mozilla::gfx::DeviceInitData data;
+  mozilla::dom::ContentChild::GetSingleton()->SendGetGraphicsDeviceInitData(&data);
+
+  SetDeviceInitData(data);
+}
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -44,16 +44,17 @@ class SkiaGLGlue;
 } // namespace gl
 namespace gfx {
 class DrawTarget;
 class SourceSurface;
 class DataSourceSurface;
 class ScaledFont;
 class DrawEventRecorder;
 class VsyncSource;
+class DeviceInitData;
 
 inline uint32_t
 BackendTypeBit(BackendType b)
 {
   return 1 << uint8_t(b);
 }
 
 } // namespace gfx
@@ -480,17 +481,18 @@ public:
 
     static bool OffMainThreadCompositingEnabled();
 
     static bool CanUseDirect3D9();
     static bool CanUseDirect3D11();
     virtual bool CanUseHardwareVideoDecoding();
     static bool CanUseDirect3D11ANGLE();
 
-    // Returns whether or not layers acceleration should be used.
+    // Returns whether or not layers acceleration should be used. This should
+    // only be called on the parent process.
     bool ShouldUseLayersAcceleration();
 
     // Returns a prioritized list of all available compositor backends.
     void GetCompositorBackends(bool useAcceleration, nsTArray<mozilla::layers::LayersBackend>& aBackends);
 
     /**
      * Is it possible to use buffer rotation.  Note that these
      * check the preference, but also allow for the override to
@@ -641,16 +643,20 @@ public:
     mozilla::layers::LayersBackend GetCompositorBackend() const {
       return mCompositorBackend;
     }
 
     // Trigger a test-driven graphics device reset.
     virtual void TestDeviceReset(DeviceResetReason aReason)
     {}
 
+    // Return information on how child processes should initialize graphics
+    // devices. Currently this is only used on Windows.
+    virtual void GetDeviceInitData(mozilla::gfx::DeviceInitData* aOut);
+
 protected:
     gfxPlatform();
     virtual ~gfxPlatform();
 
     void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen,
                             eFontPrefLang aCharLang, eFontPrefLang aPageLang);
 
     /**
@@ -674,16 +680,27 @@ protected:
      * aBackendBitmask specifies the backends which are acceptable to the caller.
      * The backend used is determined by aBackendBitmask and the order specified
      * by the gfx.canvas.azure.backends pref.
      */
     void InitBackendPrefs(uint32_t aCanvasBitmask, mozilla::gfx::BackendType aCanvasDefault,
                           uint32_t aContentBitmask, mozilla::gfx::BackendType aContentDefault);
 
     /**
+     * If in a child process, triggers a refresh of device preferences.
+     */
+    void UpdateDeviceInitData();
+
+    /**
+     * Called when new device preferences are available.
+     */
+    virtual void SetDeviceInitData(mozilla::gfx::DeviceInitData& aData)
+    {}
+
+    /**
      * returns the first backend named in the pref gfx.canvas.azure.backends
      * which is a component of aBackendBitmask, a bitmask of backend types
      */
     static mozilla::gfx::BackendType GetCanvasBackendPref(uint32_t aBackendBitmask);
 
     /**
      * returns the first backend named in the pref gfx.content.azure.backend
      * which is a component of aBackendBitmask, a bitmask of backend types
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -368,16 +368,26 @@ public:
     return MOZ_COLLECT_REPORT("d3d9-shared-texture", KIND_OTHER, UNITS_BYTES,
                               gfxWindowsPlatform::sD3D9SharedTextureUsed,
                               "Memory used for D3D9 shared textures");
   }
 };
 
 NS_IMPL_ISUPPORTS(D3D9SharedTextureReporter, nsIMemoryReporter)
 
+// Device init data should only be used on child processes, so we protect it
+// behind a getter here.
+static DeviceInitData sDeviceInitDataDoNotUseDirectly;
+static inline DeviceInitData&
+GetParentDevicePrefs()
+{
+  MOZ_ASSERT(XRE_IsContentProcess());
+  return sDeviceInitDataDoNotUseDirectly;
+}
+
 gfxWindowsPlatform::gfxWindowsPlatform()
   : mRenderMode(RENDER_GDI)
   , mIsWARP(false)
   , mHasDeviceReset(false)
   , mHasFakeDeviceReset(false)
   , mDoesD3D11TextureSharingWork(false)
   , mAcceleration(FeatureStatus::Unused)
   , mD3D11Status(FeatureStatus::Unused)
@@ -398,16 +408,17 @@ gfxWindowsPlatform::gfxWindowsPlatform()
     if (IsWin8OrLater()) {
       mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1);
     }
     mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0);
     mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1);
     mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0);
     mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3);
 
+    UpdateDeviceInitData();
     InitializeDevices();
     UpdateRenderMode();
 
     RegisterStrongMemoryReporter(new GPUAdapterReporter());
     RegisterStrongMemoryReporter(new D3D11TextureReporter());
     RegisterStrongMemoryReporter(new D3D9TextureReporter());
     RegisterStrongMemoryReporter(new D3D9SurfaceImageReporter());
     RegisterStrongMemoryReporter(new D3D9SharedTextureReporter());
@@ -513,16 +524,19 @@ gfxWindowsPlatform::HandleDeviceReset()
   mHasFakeDeviceReset = false;
   mDoesD3D11TextureSharingWork = false;
   mDeviceResetReason = DeviceResetReason::OK;
 
   imgLoader::Singleton()->ClearCache(true);
   imgLoader::Singleton()->ClearCache(false);
   gfxAlphaBoxBlur::ShutdownBlurCache();
 
+  // Since we got a device reset, we must ask the parent process for an updated
+  // list of which devices to create.
+  UpdateDeviceInitData();
   InitializeDevices();
   return true;
 }
 
 void
 gfxWindowsPlatform::UpdateBackendPrefs()
 {
   uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
@@ -1895,16 +1909,22 @@ bool DoesD3D11AlphaTextureSharingWork(ID
 
 static inline bool
 CanUseWARP()
 {
   if (gfxPrefs::LayersD3D11ForceWARP()) {
     return true;
   }
 
+  // The child process can only use WARP if the parent process is also using
+  // WARP.
+  if (XRE_IsContentProcess()) {
+    return GetParentDevicePrefs().useD3D11WARP();
+  }
+
   // It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703.
   if (!IsWin8OrLater() ||
       gfxPrefs::LayersD3D11DisableWARP() ||
       GetModuleHandleA("nvdxgiwrap.dll"))
   {
     return false;
   }
   return true;
@@ -1913,16 +1933,24 @@ CanUseWARP()
 FeatureStatus
 gfxWindowsPlatform::CheckD3D11Support(bool* aCanUseHardware)
 {
   // Don't revive D3D11 support after a failure.
   if (IsFeatureStatusFailure(mD3D11Status)) {
     return mD3D11Status;
   }
 
+  if (XRE_IsContentProcess()) {
+    if (!GetParentDevicePrefs().useD3D11()) {
+      return FeatureStatus::Blocked;
+    }
+    *aCanUseHardware = !GetParentDevicePrefs().useD3D11WARP();
+    return FeatureStatus::Available;
+  }
+
   if (gfxPrefs::LayersD3D11ForceWARP()) {
     *aCanUseHardware = false;
     return FeatureStatus::Available;
   }
 
   if (nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo()) {
     int32_t status;
     if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
@@ -1977,16 +2005,22 @@ gfxWindowsPlatform::AttemptD3D11DeviceCr
     return;
   }
 
   CheckIfRenderTargetViewNeedsRecreating(mD3D11Device);
 
   // Only test this when not using WARP since it can fail and cause
   // GetDeviceRemovedReason to return weird values.
   mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device);
+
+  // Assert that the child and parent process both computed texture sharing
+  // properly.
+  MOZ_ASSERT_IF(XRE_IsContentProcess(),
+                mDoesD3D11TextureSharingWork == GetParentDevicePrefs().d3d11TextureSharingWorks());
+
   mD3D11Device->SetExceptionMode(0);
   mIsWARP = false;
 }
 
 void
 gfxWindowsPlatform::AttemptWARPDeviceCreation()
 {
   ScopedGfxFeatureReporter reporterWARP("D3D11-WARP", gfxPrefs::LayersD3D11ForceWARP());
@@ -2074,54 +2108,86 @@ gfxWindowsPlatform::AttemptD3D11ImageBri
   mD3D11ImageBridgeDevice->SetExceptionMode(0);
   if (!DoesD3D11AlphaTextureSharingWork(mD3D11ImageBridgeDevice)) {
     mD3D11ImageBridgeDevice = nullptr;
     return;
   }
 }
 
 void
+gfxWindowsPlatform::SetDeviceInitData(mozilla::gfx::DeviceInitData& aData)
+{
+  MOZ_ASSERT(XRE_IsContentProcess());
+  sDeviceInitDataDoNotUseDirectly = aData;
+}
+
+void
 gfxWindowsPlatform::InitializeDevices()
 {
-  // Don't retry acceleration if it failed earlier.
+  // If acceleration is disabled, we refuse to initialize anything.
+  mAcceleration = CheckAccelerationSupport();
   if (IsFeatureStatusFailure(mAcceleration)) {
     return;
   }
 
-  // If we previously crashed initializing devices, or if we're in safe mode,
-  // bail out now.
+  // If we previously crashed initializing devices, bail out now. This is
+  // effectively a parent-process only check, since the content process
+  // cannot create a lock file.
   DriverInitCrashDetection detectCrashes;
-  if (detectCrashes.DisableAcceleration() || InSafeMode()) {
+  if (detectCrashes.DisableAcceleration()) {
     mAcceleration = FeatureStatus::Blocked;
     return;
   }
 
-  // If acceleration is disabled, we refuse to initialize anything.
-  if (!ShouldUseLayersAcceleration()) {
-    mAcceleration = FeatureStatus::Disabled;
-    return;
-  }
-
-  // At this point, as far as we know, we can probably accelerate.
-  mAcceleration = FeatureStatus::Available;
-
   // If we're going to prefer D3D9, stop here. The rest of this function
   // attempts to use D3D11 features.
   if (gfxPrefs::LayersPreferD3D9()) {
     mD3D11Status = FeatureStatus::Disabled;
     return;
   }
 
   // First, initialize D3D11. If this succeeds we attempt to use Direct2D.
   InitializeD3D11();
   if (mD3D11Status == FeatureStatus::Available) {
     InitializeD2D();
   }
 }
 
+FeatureStatus
+gfxWindowsPlatform::CheckAccelerationSupport()
+{
+  // Don't retry acceleration if it failed earlier.
+  if (IsFeatureStatusFailure(mAcceleration)) {
+    return mAcceleration;
+  }
+  if (XRE_IsContentProcess()) {
+    return GetParentDevicePrefs().useAcceleration()
+           ? FeatureStatus::Available
+           : FeatureStatus::Blocked;
+  }
+  if (InSafeMode()) {
+    return FeatureStatus::Blocked;
+  }
+  if (!ShouldUseLayersAcceleration()) {
+    return FeatureStatus::Disabled;
+  }
+  return FeatureStatus::Available;
+}
+
+bool
+gfxWindowsPlatform::CanUseD3D11ImageBridge()
+{
+  if (XRE_IsContentProcess()) {
+    if (!GetParentDevicePrefs().useD3D11ImageBridge()) {
+      return false;
+    }
+  }
+  return !mIsWARP;
+}
+
 void
 gfxWindowsPlatform::InitializeD3D11()
 {
   // This function attempts to initialize our D3D11 devices, if the hardware
   // is not blacklisted for D3D11 layers. This first attempt will try to create
   // a hardware accelerated device. If this creation fails or the hardware is
   // blacklisted, then this function will abort if WARP is disabled, causing us
   // to fallback to D3D9 or Basic layers. If WARP is not disabled it will use
@@ -2165,17 +2231,17 @@ gfxWindowsPlatform::InitializeD3D11()
     mD3D11Status = FeatureStatus::Failed;
     return;
   }
 
   // If we got here, we successfully got a D3D11 device.
   mD3D11Status = FeatureStatus::Available;
   MOZ_ASSERT(mD3D11Device);
 
-  if (!mIsWARP) {
+  if (CanUseD3D11ImageBridge()) {
     AttemptD3D11ImageBridgeDeviceCreation();
   }
 
   // We leak these everywhere and we need them our entire runtime anyway, let's
   // leak it here as well. We keep the pointer to sD3D11CreateDeviceFn around
   // as well for D2D1 and device resets.
   d3d11Module.disown();
 }
@@ -2201,16 +2267,22 @@ IsD2DBlacklisted()
 FeatureStatus
 gfxWindowsPlatform::CheckD2DSupport()
 {
   // Don't revive D2D support after a failure.
   if (IsFeatureStatusFailure(mD2DStatus)) {
     return mD2DStatus;
   }
 
+  if (XRE_IsContentProcess()) {
+    return GetParentDevicePrefs().useD2D()
+           ? FeatureStatus::Available
+           : FeatureStatus::Blocked;
+  }
+
   if (!gfxPrefs::Direct2DForceEnabled() && IsD2DBlacklisted()) {
     return FeatureStatus::Blacklisted;
   }
 
   // Do not ever try to use D2D if it's explicitly disabled.
   if (gfxPrefs::Direct2DDisabled()) {
     return FeatureStatus::Disabled;
   }
@@ -2261,16 +2333,21 @@ gfxWindowsPlatform::CheckD2D1Support()
 {
   // Don't revive D2D1 support after a failure.
   if (IsFeatureStatusFailure(mD2D1Status)) {
     return mD2D1Status;
   }
   if (!Factory::SupportsD2D1()) {
     return FeatureStatus::Unavailable;
   }
+  if (XRE_IsContentProcess()) {
+    return GetParentDevicePrefs().useD2D1()
+           ? FeatureStatus::Available
+           : FeatureStatus::Blocked;
+  }
   if (!gfxPrefs::Direct2DUse1_1()) {
     return FeatureStatus::Disabled;
   }
   // Normally we don't use D2D content drawing when using WARP. However if
   // WARP is force-enabled, we will let Direct2D use WARP as well.
   if (mIsWARP && !gfxPrefs::LayersD3D11ForceWARP()) {
     return FeatureStatus::Blocked;
   }
@@ -2604,8 +2681,29 @@ unsigned
 gfxWindowsPlatform::GetD3D11Version()
 {
   ID3D11Device* device = GetD3D11Device();
   if (!device) {
     return 0;
   }
   return device->GetFeatureLevel();
 }
+
+void
+gfxWindowsPlatform::GetDeviceInitData(DeviceInitData* aOut)
+{
+  // Check for device resets before giving back new graphics information.
+  UpdateRenderMode();
+
+  gfxPlatform::GetDeviceInitData(aOut);
+
+  // IPDL initializes each field to false for us so we can early return.
+  if (GetD3D11Status() != FeatureStatus::Available) {
+    return;
+  }
+
+  aOut->useD3D11() = true;
+  aOut->useD3D11ImageBridge() = !!mD3D11ImageBridgeDevice;
+  aOut->d3d11TextureSharingWorks() = mDoesD3D11TextureSharingWork;
+  aOut->useD3D11WARP() = mIsWARP;
+  aOut->useD2D() = (GetD2DStatus() == FeatureStatus::Available);
+  aOut->useD2D1() = (GetD2D1Status() == FeatureStatus::Available);
+}
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -278,22 +278,25 @@ public:
     void TestDeviceReset(DeviceResetReason aReason) override;
 
     virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() override;
     static mozilla::Atomic<size_t> sD3D11MemoryUsed;
     static mozilla::Atomic<size_t> sD3D9MemoryUsed;
     static mozilla::Atomic<size_t> sD3D9SurfaceImageUsed;
     static mozilla::Atomic<size_t> sD3D9SharedTextureUsed;
 
+    void GetDeviceInitData(mozilla::gfx::DeviceInitData* aOut) override;
+
 protected:
     bool AccelerateLayersByDefault() override {
       return true;
     }
     void GetAcceleratedCompositorBackends(nsTArray<mozilla::layers::LayersBackend>& aBackends);
     virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
+    void SetDeviceInitData(mozilla::gfx::DeviceInitData& aData) override;
 
 protected:
     RenderMode mRenderMode;
 
     int8_t mUseClearTypeForDownloadableFonts;
     int8_t mUseClearTypeAlways;
 
 private:
@@ -302,23 +305,25 @@ private:
     void InitializeDevices();
     void InitializeD3D11();
     void InitializeD2D();
     void InitializeD2D1();
     bool InitDWriteSupport();
 
     void DisableD2D();
 
+    mozilla::gfx::FeatureStatus CheckAccelerationSupport();
     mozilla::gfx::FeatureStatus CheckD3D11Support(bool* aCanUseHardware);
     mozilla::gfx::FeatureStatus CheckD2DSupport();
     mozilla::gfx::FeatureStatus CheckD2D1Support();
     void AttemptD3D11DeviceCreation();
     void AttemptWARPDeviceCreation();
     void AttemptD3D11ImageBridgeDeviceCreation();
     bool AttemptD3D11ContentDeviceCreation();
+    bool CanUseD3D11ImageBridge();
 
     IDXGIAdapter1 *GetDXGIAdapter();
     bool IsDeviceReset(HRESULT hr, DeviceResetReason* aReason);
 
 #ifdef CAIRO_HAS_DWRITE_FONT
     nsRefPtr<IDWriteFactory> mDWriteFactory;
     nsRefPtr<IDWriteRenderingParams> mRenderingParams[TEXT_RENDERING_COUNT];
     DWRITE_MEASURING_MODE mMeasuringMode;
--- a/image/DecodePool.cpp
+++ b/image/DecodePool.cpp
@@ -91,17 +91,16 @@ public:
 
     nsCOMPtr<nsIRunnable> worker = new NotifyDecodeCompleteWorker(aDecoder);
     NS_DispatchToMainThread(worker);
   }
 
   NS_IMETHOD Run() override
   {
     MOZ_ASSERT(NS_IsMainThread());
-    mDecoder->Finish();
     mDecoder->GetImage()->FinalizeDecoder(mDecoder);
     return NS_OK;
   }
 
 private:
   explicit NotifyDecodeCompleteWorker(Decoder* aDecoder)
     : mDecoder(aDecoder)
   { }
@@ -487,14 +486,13 @@ DecodePool::NotifyDecodeComplete(Decoder
   MOZ_ASSERT(aDecoder);
 
   if (!NS_IsMainThread() ||
       (aDecoder->GetFlags() & imgIContainer::FLAG_ASYNC_NOTIFY)) {
     NotifyDecodeCompleteWorker::Dispatch(aDecoder);
     return;
   }
 
-  aDecoder->Finish();
   aDecoder->GetImage()->FinalizeDecoder(aDecoder);
 }
 
 } // namespace image
 } // namespace mozilla
--- a/image/Decoder.cpp
+++ b/image/Decoder.cpp
@@ -5,62 +5,63 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Decoder.h"
 
 #include "mozilla/gfx/2D.h"
 #include "DecodePool.h"
 #include "GeckoProfiler.h"
 #include "imgIContainer.h"
-#include "nsIConsoleService.h"
-#include "nsIScriptError.h"
 #include "nsProxyRelease.h"
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "mozilla/Telemetry.h"
 
 using mozilla::gfx::IntSize;
 using mozilla::gfx::SurfaceFormat;
 
 namespace mozilla {
 namespace image {
 
 Decoder::Decoder(RasterImage* aImage)
-  : mImage(aImage)
+  : mImageData(nullptr)
+  , mImageDataLength(0)
+  , mColormap(nullptr)
+  , mColormapSize(0)
+  , mImage(aImage)
   , mProgress(NoProgress)
-  , mImageData(nullptr)
-  , mColormap(nullptr)
+  , mFrameCount(0)
+  , mFailCode(NS_OK)
   , mChunkCount(0)
   , mFlags(0)
   , mBytesDecoded(0)
+  , mInitialized(false)
+  , mMetadataDecode(false)
   , mSendPartialInvalidations(false)
+  , mImageIsTransient(false)
+  , mImageIsLocked(false)
+  , mFirstFrameDecode(false)
+  , mInFrame(false)
+  , mIsAnimated(false)
   , mDataDone(false)
   , mDecodeDone(false)
   , mDataError(false)
   , mDecodeAborted(false)
   , mShouldReportError(false)
-  , mImageIsTransient(false)
-  , mImageIsLocked(false)
-  , mFrameCount(0)
-  , mFailCode(NS_OK)
-  , mInitialized(false)
-  , mMetadataDecode(false)
-  , mInFrame(false)
-  , mIsAnimated(false)
 { }
 
 Decoder::~Decoder()
 {
-  MOZ_ASSERT(mProgress == NoProgress,
+  MOZ_ASSERT(mProgress == NoProgress || !mImage,
              "Destroying Decoder without taking all its progress changes");
-  MOZ_ASSERT(mInvalidRect.IsEmpty(),
+  MOZ_ASSERT(mInvalidRect.IsEmpty() || !mImage,
              "Destroying Decoder without taking all its invalidations");
   mInitialized = false;
 
-  if (!NS_IsMainThread()) {
+  if (mImage && !NS_IsMainThread()) {
     // Dispatch mImage to main thread to prevent it from being destructed by the
     // decode thread.
     nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
     NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread!");
     if (mainThread) {
       // Handle ambiguous nsISupports inheritance.
       RasterImage* rawImg = nullptr;
       mImage.swap(rawImg);
@@ -76,16 +77,21 @@ Decoder::~Decoder()
  */
 
 void
 Decoder::Init()
 {
   // No re-initializing
   MOZ_ASSERT(!mInitialized, "Can't re-initialize a decoder!");
 
+  // It doesn't make sense to decode anything but the first frame if we can't
+  // store anything in the SurfaceCache, since only the last frame we decode
+  // will be retrievable.
+  MOZ_ASSERT(ShouldUseSurfaceCache() || IsFirstFrameDecode());
+
   // Implementation-specific initialization
   InitInternal();
 
   mInitialized = true;
 }
 
 nsresult
 Decoder::Decode()
@@ -219,72 +225,26 @@ Decoder::CompleteDecode()
     } else {
       // We're not usable. Record some final progress indicating the error.
       if (!IsMetadataDecode()) {
         mProgress |= FLAG_DECODE_COMPLETE;
       }
       mProgress |= FLAG_HAS_ERROR;
     }
   }
-}
-
-void
-Decoder::Finish()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  MOZ_ASSERT(HasError() || !mInFrame, "Finishing while we're still in a frame");
-
-  // If we detected an error in CompleteDecode(), log it to the error console.
-  if (mShouldReportError && !WasAborted()) {
-    nsCOMPtr<nsIConsoleService> consoleService =
-      do_GetService(NS_CONSOLESERVICE_CONTRACTID);
-    nsCOMPtr<nsIScriptError> errorObject =
-      do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
-
-    if (consoleService && errorObject && !HasDecoderError()) {
-      nsAutoString msg(NS_LITERAL_STRING("Image corrupt or truncated."));
-      nsAutoString src;
-      if (mImage->GetURI()) {
-        nsCString uri;
-        if (mImage->GetURI()->GetSpecTruncatedTo1k(uri) == ImageURL::TruncatedTo1k) {
-          msg += NS_LITERAL_STRING(" URI in this note truncated due to length.");
-        }
-        src = NS_ConvertUTF8toUTF16(uri);
-      }
-      if (NS_SUCCEEDED(errorObject->InitWithWindowID(
-                         msg,
-                         src,
-                         EmptyString(), 0, 0, nsIScriptError::errorFlag,
-                         "Image", mImage->InnerWindowID()
-                       ))) {
-        consoleService->LogMessage(errorObject);
-      }
-    }
-  }
-
-  // Set image metadata before calling DecodingComplete, because
-  // DecodingComplete calls Optimize().
-  mImageMetadata.SetOnImage(mImage);
-
-  if (HasSize()) {
-    SetSizeOnImage();
-  }
 
   if (mDecodeDone && !IsMetadataDecode()) {
     MOZ_ASSERT(HasError() || mCurrentFrame, "Should have an error or a frame");
 
     // If this image wasn't animated and isn't a transient image, mark its frame
     // as optimizable. We don't support optimizing animated images and
     // optimizing transient images isn't worth it.
     if (!mIsAnimated && !mImageIsTransient && mCurrentFrame) {
       mCurrentFrame->SetOptimizable();
     }
-
-    mImage->OnDecodingComplete(mIsAnimated);
   }
 }
 
 nsresult
 Decoder::AllocateFrame(uint32_t aFrameNum,
                        const nsIntSize& aTargetSize,
                        const nsIntRect& aFrameRect,
                        gfx::SurfaceFormat aFormat,
@@ -329,17 +289,18 @@ Decoder::AllocateFrameInternal(uint32_t 
 
   if (aTargetSize.width <= 0 || aTargetSize.height <= 0 ||
       aFrameRect.width <= 0 || aFrameRect.height <= 0) {
     NS_WARNING("Trying to add frame with zero or negative size");
     return RawAccessFrameRef();
   }
 
   const uint32_t bytesPerPixel = aPaletteDepth == 0 ? 4 : 1;
-  if (!SurfaceCache::CanHold(aFrameRect.Size(), bytesPerPixel)) {
+  if (ShouldUseSurfaceCache() &&
+      !SurfaceCache::CanHold(aFrameRect.Size(), bytesPerPixel)) {
     NS_WARNING("Trying to add frame that's too large for the SurfaceCache");
     return RawAccessFrameRef();
   }
 
   nsRefPtr<imgFrame> frame = new imgFrame();
   bool nonPremult =
     aDecodeFlags & imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
   if (NS_FAILED(frame->InitForDecoder(aTargetSize, aFrameRect, aFormat,
@@ -349,34 +310,36 @@ Decoder::AllocateFrameInternal(uint32_t 
   }
 
   RawAccessFrameRef ref = frame->RawAccessRef();
   if (!ref) {
     frame->Abort();
     return RawAccessFrameRef();
   }
 
-  InsertOutcome outcome =
-    SurfaceCache::Insert(frame, ImageKey(mImage.get()),
-                         RasterSurfaceKey(aTargetSize,
-                                          aDecodeFlags,
-                                          aFrameNum),
-                         Lifetime::Persistent);
-  if (outcome == InsertOutcome::FAILURE) {
-    // We couldn't insert the surface, almost certainly due to low memory. We
-    // treat this as a permanent error to help the system recover; otherwise, we
-    // might just end up attempting to decode this image again immediately.
-    ref->Abort();
-    return RawAccessFrameRef();
-  } else if (outcome == InsertOutcome::FAILURE_ALREADY_PRESENT) {
-    // Another decoder beat us to decoding this frame. We abort this decoder
-    // rather than treat this as a real error.
-    mDecodeAborted = true;
-    ref->Abort();
-    return RawAccessFrameRef();
+  if (ShouldUseSurfaceCache()) {
+    InsertOutcome outcome =
+      SurfaceCache::Insert(frame, ImageKey(mImage.get()),
+                           RasterSurfaceKey(aTargetSize,
+                                            aDecodeFlags,
+                                            aFrameNum),
+                           Lifetime::Persistent);
+    if (outcome == InsertOutcome::FAILURE) {
+      // We couldn't insert the surface, almost certainly due to low memory. We
+      // treat this as a permanent error to help the system recover; otherwise,
+      // we might just end up attempting to decode this image again immediately.
+      ref->Abort();
+      return RawAccessFrameRef();
+    } else if (outcome == InsertOutcome::FAILURE_ALREADY_PRESENT) {
+      // Another decoder beat us to decoding this frame. We abort this decoder
+      // rather than treat this as a real error.
+      mDecodeAborted = true;
+      ref->Abort();
+      return RawAccessFrameRef();
+    }
   }
 
   nsIntRect refreshArea;
 
   if (aFrameNum == 1) {
     MOZ_ASSERT(aPreviousFrame, "Must provide a previous frame when animated");
     aPreviousFrame->SetRawAccessOnly();
 
@@ -395,35 +358,24 @@ Decoder::AllocateFrameInternal(uint32_t 
     ref->SetRawAccessOnly();
 
     // Some GIFs are huge but only have a small area that they animate. We only
     // need to refresh that small area when frame 0 comes around again.
     refreshArea.UnionRect(refreshArea, frame->GetRect());
   }
 
   mFrameCount++;
-  mImage->OnAddedFrame(mFrameCount, refreshArea);
+
+  if (mImage) {
+    mImage->OnAddedFrame(mFrameCount, refreshArea);
+  }
 
   return ref;
 }
 
-void
-Decoder::SetSizeOnImage()
-{
-  MOZ_ASSERT(mImageMetadata.HasSize(), "Should have size");
-  MOZ_ASSERT(mImageMetadata.HasOrientation(), "Should have orientation");
-
-  nsresult rv = mImage->SetSize(mImageMetadata.GetWidth(),
-                                mImageMetadata.GetHeight(),
-                                mImageMetadata.GetOrientation());
-  if (NS_FAILED(rv)) {
-    PostResizeError();
-  }
-}
-
 /*
  * Hook stubs. Override these as necessary in decoder implementations.
  */
 
 void Decoder::InitInternal() { }
 void Decoder::FinishInternal() { }
 void Decoder::FinishWithErrorInternal() { }
 
--- a/image/Decoder.h
+++ b/image/Decoder.h
@@ -38,22 +38,16 @@ public:
    * data is needed, Decode() automatically ensures that it will be called again
    * on a DecodePool thread when the data becomes available.
    *
    * Any errors are reported by setting the appropriate state on the decoder.
    */
   nsresult Decode();
 
   /**
-   * Cleans up the decoder's state and notifies our image about success or
-   * failure. May only be called on the main thread.
-   */
-  void Finish();
-
-  /**
    * Given a maximum number of bytes we're willing to decode, @aByteLimit,
    * returns true if we should attempt to run this decoder synchronously.
    */
   bool ShouldSyncDecode(size_t aByteLimit);
 
   /**
    * Gets the invalidation region accumulated by the decoder so far, and clears
    * the decoder's invalidation region. This means that each call to
@@ -102,17 +96,17 @@ public:
    * is enough to determine the image's intrinsic size. A metadata decode is
    * enabled by calling SetMetadataDecode() *before* calling Init().
    */
   void SetMetadataDecode(bool aMetadataDecode)
   {
     MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
     mMetadataDecode = aMetadataDecode;
   }
-  bool IsMetadataDecode() { return mMetadataDecode; }
+  bool IsMetadataDecode() const { return mMetadataDecode; }
 
   /**
    * If this decoder supports downscale-during-decode, sets the target size that
    * this image should be decoded to.
    *
    * If this decoder *doesn't* support downscale-during-decode, returns
    * NS_ERROR_NOT_AVAILABLE. If the provided size is unacceptable, returns
    * another error.
@@ -123,16 +117,32 @@ public:
    * This must be called before Init() is called.
    */
   virtual nsresult SetTargetSize(const nsIntSize& aSize)
   {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   /**
+   * Set the requested sample size for this decoder. Used to implement the
+   * -moz-sample-size media fragment.
+   *
+   *  XXX(seth): Support for -moz-sample-size will be removed in bug 1120056.
+   */
+  virtual void SetSampleSize(int aSampleSize) { }
+
+  /**
+   * Set the requested resolution for this decoder. Used to implement the
+   * -moz-resolution media fragment.
+   *
+   *  XXX(seth): Support for -moz-resolution will be removed in bug 1118926.
+   */
+  virtual void SetResolution(const gfx::IntSize& aResolution) { }
+
+  /**
    * Set whether should send partial invalidations.
    *
    * If @aSend is true, we'll send partial invalidations when decoding the first
    * frame of the image, so image notifications observers will be able to
    * gradually draw in the image as it downloads.
    *
    * If @aSend is false (the default), we'll only send an invalidation when we
    * complete the first frame.
@@ -179,16 +189,28 @@ public:
   void SetImageIsLocked()
   {
     MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
     mImageIsLocked = true;
   }
 
   bool ImageIsLocked() const { return mImageIsLocked; }
 
+
+  /**
+   * Set whether we should stop decoding after the first frame.
+   */
+  void SetIsFirstFrameDecode()
+  {
+    MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
+    mFirstFrameDecode = true;
+  }
+
+  bool IsFirstFrameDecode() const { return mFirstFrameDecode; }
+
   size_t BytesDecoded() const { return mBytesDecoded; }
 
   // The amount of time we've spent inside Write() so far for this decoder.
   TimeDuration DecodeTime() const { return mDecodeTime; }
 
   // The number of times Write() has been called so far for this decoder.
   uint32_t ChunkCount() const { return mChunkCount; }
 
@@ -197,29 +219,44 @@ public:
   uint32_t GetFrameCount() { return mFrameCount; }
 
   // The number of complete frames we have (ie, not including anything
   // in-progress).
   uint32_t GetCompleteFrameCount() {
     return mInFrame ? mFrameCount - 1 : mFrameCount;
   }
 
+  // Did we discover that the image we're decoding is animated?
+  bool HasAnimation() const { return mIsAnimated; }
+
   // Error tracking
   bool HasError() const { return HasDataError() || HasDecoderError(); }
   bool HasDataError() const { return mDataError; }
   bool HasDecoderError() const { return NS_FAILED(mFailCode); }
+  bool ShouldReportError() const { return mShouldReportError; }
   nsresult GetDecoderError() const { return mFailCode; }
   void PostResizeError() { PostDataError(); }
 
+  /// Did we finish decoding enough that calling Decode() again would be useless?
   bool GetDecodeDone() const
   {
     return mDecodeDone || (mMetadataDecode && HasSize()) ||
            HasError() || mDataDone;
   }
 
+  /// Did we finish decoding enough to set |RasterImage::mHasBeenDecoded|?
+  // XXX(seth): This will be removed in bug 1187401.
+  bool GetDecodeTotallyDone() const { return mDecodeDone && !IsMetadataDecode(); }
+
+  /// Are we in the middle of a frame right now? Used for assertions only.
+  bool InFrame() const { return mInFrame; }
+
+  /// Should we store surfaces created by this decoder in the SurfaceCache?
+  bool ShouldUseSurfaceCache() const { return bool(mImage); }
+
   /**
    * Returns true if this decoder was aborted.
    *
    * This may happen due to a low-memory condition, or because another decoder
    * was racing with this one to decode the same frames with the same flags and
    * this decoder lost the race. Either way, this is not a permanent situation
    * and does not constitute an error, so we don't report any errors when this
    * happens.
@@ -232,36 +269,32 @@ public:
       SEQUENTIAL   // decode to final image immediately
   };
 
   void SetFlags(uint32_t aFlags) { mFlags = aFlags; }
   uint32_t GetFlags() const { return mFlags; }
   uint32_t GetDecodeFlags() const { return DecodeFlags(mFlags); }
 
   bool HasSize() const { return mImageMetadata.HasSize(); }
-  void SetSizeOnImage();
 
   nsIntSize GetSize() const
   {
     MOZ_ASSERT(HasSize());
     return mImageMetadata.GetSize();
   }
 
   virtual Telemetry::ID SpeedHistogram();
 
   ImageMetadata& GetImageMetadata() { return mImageMetadata; }
 
   /**
    * Returns a weak pointer to the image associated with this decoder.
    */
   RasterImage* GetImage() const { MOZ_ASSERT(mImage); return mImage.get(); }
 
-  // XXX(seth): This should be removed once we can optimize imgFrame objects
-  // off-main-thread. It only exists to support the code in Finish() for
-  // nsICODecoder.
   RawAccessFrameRef GetCurrentFrameRef()
   {
     return mCurrentFrame ? mCurrentFrame->RawAccessRef()
                          : RawAccessFrameRef();
   }
 
   /**
    * Writes data to the decoder. Only public for the benefit of nsICODecoder;
@@ -384,54 +417,52 @@ protected:
   RawAccessFrameRef AllocateFrameInternal(uint32_t aFrameNum,
                                           const nsIntSize& aTargetSize,
                                           const nsIntRect& aFrameRect,
                                           uint32_t aDecodeFlags,
                                           gfx::SurfaceFormat aFormat,
                                           uint8_t aPaletteDepth,
                                           imgFrame* aPreviousFrame);
 
-  /*
-   * Member variables.
-   *
-   */
+protected:
+  uint8_t* mImageData;  // Pointer to image data in either Cairo or 8bit format
+  uint32_t mImageDataLength;
+  uint32_t* mColormap;  // Current colormap to be used in Cairo format
+  uint32_t mColormapSize;
+
+private:
   nsRefPtr<RasterImage> mImage;
   Maybe<SourceBufferIterator> mIterator;
   RawAccessFrameRef mCurrentFrame;
   ImageMetadata mImageMetadata;
   nsIntRect mInvalidRect; // Tracks an invalidation region in the current frame.
   Progress mProgress;
 
-  uint8_t* mImageData;  // Pointer to image data in either Cairo or 8bit format
-  uint32_t mImageDataLength;
-  uint32_t* mColormap;  // Current colormap to be used in Cairo format
-  uint32_t mColormapSize;
+  uint32_t mFrameCount; // Number of frames, including anything in-progress
+
+  nsresult mFailCode;
 
   // Telemetry data for this decoder.
   TimeDuration mDecodeTime;
   uint32_t mChunkCount;
 
   uint32_t mFlags;
   size_t mBytesDecoded;
-  bool mSendPartialInvalidations;
-  bool mDataDone;
-  bool mDecodeDone;
-  bool mDataError;
-  bool mDecodeAborted;
-  bool mShouldReportError;
-  bool mImageIsTransient;
-  bool mImageIsLocked;
 
-private:
-  uint32_t mFrameCount; // Number of frames, including anything in-progress
-
-  nsresult mFailCode;
-
-  bool mInitialized;
-  bool mMetadataDecode;
-  bool mInFrame;
-  bool mIsAnimated;
+  bool mInitialized : 1;
+  bool mMetadataDecode : 1;
+  bool mSendPartialInvalidations : 1;
+  bool mImageIsTransient : 1;
+  bool mImageIsLocked : 1;
+  bool mFirstFrameDecode : 1;
+  bool mInFrame : 1;
+  bool mIsAnimated : 1;
+  bool mDataDone : 1;
+  bool mDecodeDone : 1;
+  bool mDataError : 1;
+  bool mDecodeAborted : 1;
+  bool mShouldReportError : 1;
 };
 
 } // namespace image
 } // namespace mozilla
 
 #endif // mozilla_image_Decoder_h
--- a/image/DecoderFactory.cpp
+++ b/image/DecoderFactory.cpp
@@ -105,31 +105,35 @@ DecoderFactory::GetDecoder(DecoderType a
 }
 
 /* static */ already_AddRefed<Decoder>
 DecoderFactory::CreateDecoder(DecoderType aType,
                               RasterImage* aImage,
                               SourceBuffer* aSourceBuffer,
                               const Maybe<IntSize>& aTargetSize,
                               uint32_t aFlags,
+                              int aSampleSize,
+                              const IntSize& aResolution,
                               bool aIsRedecode,
                               bool aImageIsTransient,
                               bool aImageIsLocked)
 {
   if (aType == DecoderType::UNKNOWN) {
     return nullptr;
   }
 
   nsRefPtr<Decoder> decoder = GetDecoder(aType, aImage, aIsRedecode);
   MOZ_ASSERT(decoder, "Should have a decoder now");
 
   // Initialize the decoder.
   decoder->SetMetadataDecode(false);
   decoder->SetIterator(aSourceBuffer->Iterator());
   decoder->SetFlags(aFlags);
+  decoder->SetSampleSize(aSampleSize);
+  decoder->SetResolution(aResolution);
   decoder->SetSendPartialInvalidations(!aIsRedecode);
   decoder->SetImageIsTransient(aImageIsTransient);
 
   if (aImageIsLocked) {
     decoder->SetImageIsLocked();
   }
 
   // Set a target size for downscale-during-decode if applicable.
@@ -146,29 +150,67 @@ DecoderFactory::CreateDecoder(DecoderTyp
   }
 
   return decoder.forget();
 }
 
 /* static */ already_AddRefed<Decoder>
 DecoderFactory::CreateMetadataDecoder(DecoderType aType,
                                       RasterImage* aImage,
-                                      SourceBuffer* aSourceBuffer)
+                                      SourceBuffer* aSourceBuffer,
+                                      int aSampleSize,
+                                      const IntSize& aResolution)
 {
   if (aType == DecoderType::UNKNOWN) {
     return nullptr;
   }
 
   nsRefPtr<Decoder> decoder =
     GetDecoder(aType, aImage, /* aIsRedecode = */ false);
   MOZ_ASSERT(decoder, "Should have a decoder now");
 
   // Initialize the decoder.
   decoder->SetMetadataDecode(true);
   decoder->SetIterator(aSourceBuffer->Iterator());
+  decoder->SetSampleSize(aSampleSize);
+  decoder->SetResolution(aResolution);
+
+  decoder->Init();
+  if (NS_FAILED(decoder->GetDecoderError())) {
+    return nullptr;
+  }
+
+  return decoder.forget();
+}
+
+/* static */ already_AddRefed<Decoder>
+DecoderFactory::CreateAnonymousDecoder(DecoderType aType,
+                                       SourceBuffer* aSourceBuffer,
+                                       uint32_t aFlags)
+{
+  if (aType == DecoderType::UNKNOWN) {
+    return nullptr;
+  }
+
+  nsRefPtr<Decoder> decoder =
+    GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
+  MOZ_ASSERT(decoder, "Should have a decoder now");
+
+  // Initialize the decoder.
+  decoder->SetMetadataDecode(false);
+  decoder->SetIterator(aSourceBuffer->Iterator());
+  decoder->SetFlags(aFlags);
+  decoder->SetImageIsTransient(true);
+
+  // Without an image, the decoder can't store anything in the SurfaceCache, so
+  // callers will only be able to retrieve the most recent frame via
+  // Decoder::GetCurrentFrame(). That means that anonymous decoders should
+  // always be first-frame-only decoders, because nobody ever wants the *last*
+  // frame.
+  decoder->SetIsFirstFrameDecode();
 
   decoder->Init();
   if (NS_FAILED(decoder->GetDecoderError())) {
     return nullptr;
   }
 
   return decoder.forget();
 }
--- a/image/DecoderFactory.h
+++ b/image/DecoderFactory.h
@@ -51,48 +51,65 @@ public:
    * @param aSourceBuffer The SourceBuffer which the decoder will read its data
    *                      from.
    * @param aTargetSize If not Nothing(), the target size which the image should
    *                    be scaled to during decoding. It's an error to specify
    *                    a target size for a decoder type which doesn't support
    *                    downscale-during-decode.
    * @param aFlags Flags specifying what type of output the decoder should
    *               produce; see GetDecodeFlags() in RasterImage.h.
+   * @param aSampleSize The sample size requested using #-moz-samplesize (or 0
+   *                    if none).
+   * @param aResolution The resolution requested using #-moz-resolution (or an
+   *                    empty rect if none).
    * @param aIsRedecode Specify 'true' if this image has been decoded before.
    * @param aImageIsTransient Specify 'true' if this image is transient.
    * @param aImageIsLocked Specify 'true' if this image is locked for the
    *                       lifetime of this decoder, and should be unlocked
    *                       when the decoder finishes.
    */
   static already_AddRefed<Decoder>
   CreateDecoder(DecoderType aType,
                 RasterImage* aImage,
                 SourceBuffer* aSourceBuffer,
                 const Maybe<gfx::IntSize>& aTargetSize,
                 uint32_t aFlags,
+                int aSampleSize,
+                const gfx::IntSize& aResolution,
                 bool aIsRedecode,
                 bool aImageIsTransient,
                 bool aImageIsLocked);
 
   /**
    * Creates and initializes a metadata decoder of type @aType. This decoder
    * will only decode the image's header, extracting metadata like the size of
    * the image. No actual image data will be decoded and no surfaces will be
    * allocated. The decoder will send notifications to @aImage.
    *
    * @param aType Which type of decoder to create - JPEG, PNG, etc.
    * @param aImage The image will own the decoder and which should receive
    *               notifications as decoding progresses.
    * @param aSourceBuffer The SourceBuffer which the decoder will read its data
    *                      from.
+   * @param aSampleSize The sample size requested using #-moz-samplesize (or 0
+   *                    if none).
+   * @param aResolution The resolution requested using #-moz-resolution (or an
+   *                    empty rect if none).
    */
   static already_AddRefed<Decoder>
   CreateMetadataDecoder(DecoderType aType,
                         RasterImage* aImage,
-                        SourceBuffer* aSourceBuffer);
+                        SourceBuffer* aSourceBuffer,
+                        int aSampleSize,
+                        const gfx::IntSize& aResolution);
+
+  static already_AddRefed<Decoder>
+  CreateAnonymousDecoder(DecoderType aType,
+                         SourceBuffer* aSourceBuffer,
+                         uint32_t aFlags);
 
 private:
   virtual ~DecoderFactory() = 0;
 
   /**
    * An internal method which allocates a new decoder of the requested @aType.
    */
   static already_AddRefed<Decoder> GetDecoder(DecoderType aType,
--- a/image/ImageFactory.cpp
+++ b/image/ImageFactory.cpp
@@ -216,16 +216,39 @@ ImageFactory::CreateRasterImage(nsIReque
   MOZ_ASSERT(aProgressTracker);
 
   nsresult rv;
 
   nsRefPtr<RasterImage> newImage = new RasterImage(aURI);
   aProgressTracker->SetImage(newImage);
   newImage->SetProgressTracker(aProgressTracker);
 
+  nsAutoCString ref;
+  aURI->GetRef(ref);
+  net::nsMediaFragmentURIParser parser(ref);
+  if (parser.HasResolution()) {
+    newImage->SetRequestedResolution(parser.GetResolution());
+  }
+
+  if (parser.HasSampleSize()) {
+      /* Get our principal */
+      nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
+      nsCOMPtr<nsIPrincipal> principal;
+      if (chan) {
+        nsContentUtils::GetSecurityManager()
+          ->GetChannelResultPrincipal(chan, getter_AddRefs(principal));
+      }
+
+      if ((principal &&
+           principal->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED) ||
+          gfxPrefs::ImageMozSampleSizeEnabled()) {
+        newImage->SetRequestedSampleSize(parser.GetSampleSize());
+      }
+  }
+
   rv = newImage->Init(aMimeType.get(), aImageFlags);
   NS_ENSURE_SUCCESS(rv, BadImage(newImage));
 
   newImage->SetInnerWindowID(aInnerWindowId);
 
   uint32_t len = GetContentSize(aRequest);
 
   // Pass anything usable on so that the RasterImage can preallocate
@@ -240,39 +263,16 @@ ImageFactory::CreateRasterImage(nsIReque
       nsresult rv2 = newImage->SetSourceSizeHint(sizeHint);
       // If we've still failed at this point, things are going downhill.
       if (NS_FAILED(rv) || NS_FAILED(rv2)) {
         NS_WARNING("About to hit OOM in imagelib!");
       }
     }
   }
 
-  nsAutoCString ref;
-  aURI->GetRef(ref);
-  net::nsMediaFragmentURIParser parser(ref);
-  if (parser.HasResolution()) {
-    newImage->SetRequestedResolution(parser.GetResolution());
-  }
-
-  if (parser.HasSampleSize()) {
-      /* Get our principal */
-      nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
-      nsCOMPtr<nsIPrincipal> principal;
-      if (chan) {
-        nsContentUtils::GetSecurityManager()
-          ->GetChannelResultPrincipal(chan, getter_AddRefs(principal));
-      }
-
-      if ((principal &&
-           principal->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED) ||
-          gfxPrefs::ImageMozSampleSizeEnabled()) {
-        newImage->SetRequestedSampleSize(parser.GetSampleSize());
-      }
-  }
-
   return newImage.forget();
 }
 
 /* static */ already_AddRefed<Image>
 ImageFactory::CreateVectorImage(nsIRequest* aRequest,
                                 ProgressTracker* aProgressTracker,
                                 const nsCString& aMimeType,
                                 ImageURL* aURI,
--- a/image/ImageMetadata.cpp
+++ b/image/ImageMetadata.cpp
@@ -9,27 +9,36 @@
 #include "RasterImage.h"
 #include "nsComponentManagerUtils.h"
 #include "nsISupportsPrimitives.h"
 #include "nsXPCOMCID.h"
 
 namespace mozilla {
 namespace image {
 
-void
-ImageMetadata::SetOnImage(RasterImage* image)
+nsresult
+ImageMetadata::SetOnImage(RasterImage* aImage)
 {
+  nsresult rv = NS_OK;
+
   if (mHotspotX != -1 && mHotspotY != -1) {
     nsCOMPtr<nsISupportsPRUint32> intwrapx =
       do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID);
     nsCOMPtr<nsISupportsPRUint32> intwrapy =
       do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID);
     intwrapx->SetData(mHotspotX);
     intwrapy->SetData(mHotspotY);
-    image->Set("hotspotX", intwrapx);
-    image->Set("hotspotY", intwrapy);
+    aImage->Set("hotspotX", intwrapx);
+    aImage->Set("hotspotY", intwrapy);
   }
 
-  image->SetLoopCount(mLoopCount);
+  aImage->SetLoopCount(mLoopCount);
+
+  if (HasSize()) {
+    MOZ_ASSERT(HasOrientation(), "Should have orientation");
+    rv = aImage->SetSize(GetWidth(), GetHeight(), GetOrientation());
+  }
+
+  return rv;
 }
 
 } // namespace image
 } // namespace mozilla
--- a/image/ImageMetadata.h
+++ b/image/ImageMetadata.h
@@ -23,17 +23,17 @@ class ImageMetadata
 public:
   ImageMetadata()
     : mHotspotX(-1)
     , mHotspotY(-1)
     , mLoopCount(-1)
   { }
 
   // Set the metadata this object represents on an image.
-  void SetOnImage(RasterImage* image);
+  nsresult SetOnImage(RasterImage* aImage);
 
   void SetHotspot(uint16_t hotspotx, uint16_t hotspoty)
   {
     mHotspotX = hotspotx;
     mHotspotY = hotspoty;
   }
   void SetLoopCount(int32_t loopcount)
   {
--- a/image/ImageOps.cpp
+++ b/image/ImageOps.cpp
@@ -1,22 +1,30 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "imgIContainer.h"
+#include "ImageOps.h"
+
 #include "ClippedImage.h"
+#include "DecodePool.h"
+#include "Decoder.h"
+#include "DecoderFactory.h"
 #include "DynamicImage.h"
 #include "FrozenImage.h"
+#include "Image.h"
+#include "imgIContainer.h"
+#include "mozilla/gfx/2D.h"
+#include "nsStreamUtils.h"
 #include "OrientedImage.h"
-#include "Image.h"
+#include "SourceBuffer.h"
 
-#include "ImageOps.h"
+using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace image {
 
 /* static */ already_AddRefed<Image>
 ImageOps::Freeze(Image* aImage)
 {
   nsRefPtr<Image> frozenImage = new FrozenImage(aImage);
@@ -63,10 +71,75 @@ ImageOps::Orient(imgIContainer* aImage, 
 
 /* static */ already_AddRefed<imgIContainer>
 ImageOps::CreateFromDrawable(gfxDrawable* aDrawable)
 {
   nsCOMPtr<imgIContainer> drawableImage = new DynamicImage(aDrawable);
   return drawableImage.forget();
 }
 
+/* static */ already_AddRefed<gfx::SourceSurface>
+ImageOps::DecodeToSurface(nsIInputStream* aInputStream,
+                          const nsACString& aMimeType,
+                          uint32_t aFlags)
+{
+  MOZ_ASSERT(aInputStream);
+
+  nsresult rv;
+
+  // Prepare the input stream.
+  nsCOMPtr<nsIInputStream> inputStream = aInputStream;
+  if (!NS_InputStreamIsBuffered(aInputStream)) {
+    nsCOMPtr<nsIInputStream> bufStream;
+    rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream),
+                                   aInputStream, 1024);
+    if (NS_SUCCEEDED(rv)) {
+      inputStream = bufStream;
+    }
+  }
+
+  // Figure out how much data we've been passed.
+  uint64_t length;
+  rv = inputStream->Available(&length);
+  if (NS_FAILED(rv) || length > UINT32_MAX) {
+    return nullptr;
+  }
+
+  // Write the data into a SourceBuffer.
+  nsRefPtr<SourceBuffer> sourceBuffer = new SourceBuffer();
+  sourceBuffer->ExpectLength(length);
+  rv = sourceBuffer->AppendFromInputStream(inputStream, length);
+  if (NS_FAILED(rv)) {
+    return nullptr;
+  }
+  sourceBuffer->Complete(NS_OK);
+
+  // Create a decoder.
+  DecoderType decoderType =
+    DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get());
+  nsRefPtr<Decoder> decoder =
+    DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, aFlags);
+  if (!decoder) {
+    return nullptr;
+  }
+
+  // Run the decoder synchronously.
+  decoder->Decode();
+  if (!decoder->GetDecodeDone() || decoder->HasError()) {
+    return nullptr;
+  }
+
+  // Pull out the surface.
+  RawAccessFrameRef frame = decoder->GetCurrentFrameRef();
+  if (!frame) {
+    return nullptr;
+  }
+
+  RefPtr<SourceSurface> surface = frame->GetSurface();
+  if (!surface) {
+    return nullptr;
+  }
+
+  return surface.forget();
+}
+
 } // namespace image
 } // namespace mozilla
--- a/image/ImageOps.h
+++ b/image/ImageOps.h
@@ -7,18 +7,24 @@
 #ifndef mozilla_image_ImageOps_h
 #define mozilla_image_ImageOps_h
 
 #include "nsCOMPtr.h"
 #include "nsRect.h"
 
 class gfxDrawable;
 class imgIContainer;
+class nsIInputStream;
 
 namespace mozilla {
+
+namespace gfx {
+class SourceSurface;
+}
+
 namespace image {
 
 class Image;
 struct Orientation;
 
 class ImageOps
 {
 public:
@@ -56,16 +62,33 @@ public:
   /**
    * Creates an image from a gfxDrawable.
    *
    * @param aDrawable      The gfxDrawable.
    */
   static already_AddRefed<imgIContainer>
   CreateFromDrawable(gfxDrawable* aDrawable);
 
+  /**
+   * Decodes an image from an nsIInputStream directly into a SourceSurface,
+   * without ever creating an Image or imgIContainer (which are mostly
+   * main-thread-only). That means that this function may be called
+   * off-main-thread.
+   *
+   * @param aInputStream An input stream containing an encoded image.
+   * @param aMimeType The MIME type of the image.
+   * @param aFlags Flags of the imgIContainer::FLAG_DECODE_* variety.
+   * @return A SourceSurface containing the first frame of the image at its
+   *         intrinsic size, or nullptr if the image cannot be decoded.
+   */
+  static already_AddRefed<gfx::SourceSurface>
+  DecodeToSurface(nsIInputStream* aInputStream,
+                  const nsACString& aMimeType,
+                  uint32_t aFlags);
+
 private:
   // This is a static utility class, so disallow instantiation.
   virtual ~ImageOps() = 0;
 };
 
 } // namespace image
 } // namespace mozilla
 
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -16,17 +16,19 @@
 #include "Decoder.h"
 #include "nsAutoPtr.h"
 #include "prenv.h"
 #include "prsystem.h"
 #include "ImageContainer.h"
 #include "ImageRegion.h"
 #include "Layers.h"
 #include "LookupResult.h"
+#include "nsIConsoleService.h"
 #include "nsIInputStream.h"
+#include "nsIScriptError.h"
 #include "nsPresContext.h"
 #include "SourceBuffer.h"
 #include "SurfaceCache.h"
 #include "FrameAnimator.h"
 
 #include "gfxContext.h"
 
 #include "mozilla/gfx/2D.h"
@@ -974,52 +976,16 @@ RasterImage::SetSize(int32_t aWidth, int
   // Set the size and flag that we have it
   mSize.SizeTo(aWidth, aHeight);
   mOrientation = aOrientation;
   mHasSize = true;
 
   return NS_OK;
 }
 
-void
-RasterImage::OnDecodingComplete(bool aIsAnimated)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (mError) {
-    return;
-  }
-
-  // Flag that we've been decoded before.
-  mHasBeenDecoded = true;
-
-  if (aIsAnimated) {
-    if (mAnim) {
-      mAnim->SetDoneDecoding(true);
-    } else {
-      // The OnAddedFrame event that will create mAnim is still in the event
-      // queue. Wait for it.
-      nsCOMPtr<nsIRunnable> runnable =
-        NS_NewRunnableMethod(this, &RasterImage::MarkAnimationDecoded);
-      NS_DispatchToMainThread(runnable);
-    }
-  }
-}
-
-void
-RasterImage::MarkAnimationDecoded()
-{
-  MOZ_ASSERT(mAnim, "Should have an animation now");
-  if (!mAnim) {
-    return;
-  }
-
-  mAnim->SetDoneDecoding(true);
-}
-
 NS_IMETHODIMP
 RasterImage::SetAnimationMode(uint16_t aAnimationMode)
 {
   if (mAnim) {
     mAnim->SetAnimationMode(aAnimationMode);
   }
   return SetAnimationModeInternal(aAnimationMode);
 }
@@ -1217,30 +1183,26 @@ RasterImage::NotifyForLoadEvent(Progress
 
   // Notify our listeners, which will fire this image's load event.
   NotifyProgress(aProgress);
 }
 
 nsresult
 RasterImage::OnImageDataAvailable(nsIRequest*,
                                   nsISupports*,
-                                  nsIInputStream* aInStr,
-                                  uint64_t aOffset,
+                                  nsIInputStream* aInputStream,
+                                  uint64_t,
                                   uint32_t aCount)
 {
-  nsresult rv;
+  nsresult rv = mSourceBuffer->AppendFromInputStream(aInputStream, aCount);
+  MOZ_ASSERT(rv == NS_OK || rv == NS_ERROR_OUT_OF_MEMORY);
 
-  // WriteToSourceBuffer always consumes everything it gets if it doesn't run
-  // out of memory.
-  uint32_t bytesRead;
-  rv = aInStr->ReadSegments(WriteToSourceBuffer, this, aCount, &bytesRead);
-
-  MOZ_ASSERT(bytesRead == aCount || HasError() || NS_FAILED(rv),
-    "WriteToSourceBuffer should consume everything if ReadSegments succeeds or "
-    "the image must be in error!");
+  if (MOZ_UNLIKELY(rv == NS_ERROR_OUT_OF_MEMORY)) {
+    DoError();
+  }
 
   return rv;
 }
 
 nsresult
 RasterImage::SetSourceSizeHint(uint32_t aSizeHint)
 {
   return mSourceBuffer->ExpectLength(aSizeHint);
@@ -1440,18 +1402,18 @@ RasterImage::Decode(const IntSize& aSize
     // The corresponding unlock happens in FinalizeDecoder.
     LockImage();
     imageIsLocked = true;
   }
 
   // Create a decoder.
   nsRefPtr<Decoder> decoder =
     DecoderFactory::CreateDecoder(mDecoderType, this, mSourceBuffer, targetSize,
-                                  aFlags, mHasBeenDecoded, mTransient,
-                                  imageIsLocked);
+                                  aFlags, mRequestedSampleSize, mRequestedResolution,
+                                  mHasBeenDecoded, mTransient, imageIsLocked);
 
   // Make sure DecoderFactory was able to create a decoder successfully.
   if (!decoder) {
     return NS_ERROR_FAILURE;
   }
 
   // Add a placeholder for the first frame to the SurfaceCache so we won't
   // trigger any more decoders with the same parameters.
@@ -1494,17 +1456,19 @@ RasterImage::DecodeMetadata(uint32_t aFl
   if (mError) {
     return NS_ERROR_FAILURE;
   }
 
   MOZ_ASSERT(!mHasSize, "Should not do unnecessary metadata decodes");
 
   // Create a decoder.
   nsRefPtr<Decoder> decoder =
-    DecoderFactory::CreateMetadataDecoder(mDecoderType, this, mSourceBuffer);
+    DecoderFactory::CreateMetadataDecoder(mDecoderType, this, mSourceBuffer,
+                                          mRequestedSampleSize,
+                                          mRequestedResolution);
 
   // Make sure DecoderFactory was able to create a decoder successfully.
   if (!decoder) {
     return NS_ERROR_FAILURE;
   }
 
   // We're ready to decode; start the decoder.
   LaunchDecoder(decoder, this, aFlags, mHasSourceData);
@@ -1929,46 +1893,16 @@ RasterImage::HandleErrorWorker::HandleEr
 NS_IMETHODIMP
 RasterImage::HandleErrorWorker::Run()
 {
   mImage->DoError();
 
   return NS_OK;
 }
 
-// nsIInputStream callback to copy the incoming image data directly to the
-// RasterImage without processing. The RasterImage is passed as the closure.
-// Always reads everything it gets, even if the data is erroneous.
-NS_METHOD
-RasterImage::WriteToSourceBuffer(nsIInputStream* /* unused */,
-                                 void*          aClosure,
-                                 const char*    aFromRawSegment,
-                                 uint32_t       /* unused */,
-                                 uint32_t       aCount,
-                                 uint32_t*      aWriteCount)
-{
-  // Retrieve the RasterImage
-  RasterImage* image = static_cast<RasterImage*>(aClosure);
-
-  // Copy the source data. Unless we hit OOM, we squelch the return value
-  // here, because returning an error means that ReadSegments stops
-  // reading data, violating our invariant that we read everything we get.
-  // If we hit OOM then we fail and the load is aborted.
-  nsresult rv = image->mSourceBuffer->Append(aFromRawSegment, aCount);
-  if (rv == NS_ERROR_OUT_OF_MEMORY) {
-    image->DoError();
-    return rv;
-  }
-
-  // We wrote everything we got
-  *aWriteCount = aCount;
-
-  return NS_OK;
-}
-
 bool
 RasterImage::ShouldAnimate()
 {
   return ImageResource::ShouldAnimate() && GetNumFrames() >= 2 &&
          !mAnimationFinished;
 }
 
 /* readonly attribute uint32_t framesNotified; */
@@ -2005,19 +1939,50 @@ RasterImage::NotifyProgress(Progress aPr
   image->mProgressTracker->SyncNotifyProgress(aProgress, aInvalidRect);
 }
 
 void
 RasterImage::FinalizeDecoder(Decoder* aDecoder)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aDecoder);
+  MOZ_ASSERT(aDecoder->HasError() || !aDecoder->InFrame(),
+             "Finalizing a decoder in the middle of a frame");
+
+  // If the decoder detected an error, log it to the error console.
+  if (aDecoder->ShouldReportError() && !aDecoder->WasAborted()) {
+    ReportDecoderError(aDecoder);
+  }
+
+  // Record all the metadata the decoder gathered about this image.
+  nsresult rv = aDecoder->GetImageMetadata().SetOnImage(this);
+  if (NS_FAILED(rv)) {
+    aDecoder->PostResizeError();
+  }
+
   MOZ_ASSERT(mError || mHasSize || !aDecoder->HasSize(),
              "Should have handed off size by now");
 
+  if (aDecoder->GetDecodeTotallyDone() && !mError) {
+    // Flag that we've been decoded before.
+    mHasBeenDecoded = true;
+
+    if (aDecoder->HasAnimation()) {
+      if (mAnim) {
+        mAnim->SetDoneDecoding(true);
+      } else {
+        // The OnAddedFrame event that will create mAnim is still in the event
+        // queue. Wait for it.
+        nsCOMPtr<nsIRunnable> runnable =
+          NS_NewRunnableMethod(this, &RasterImage::MarkAnimationDecoded);
+        NS_DispatchToMainThread(runnable);
+      }
+    }
+  }
+
   // Send out any final notifications.
   NotifyProgress(aDecoder->TakeProgress(),
                  aDecoder->TakeInvalidRect(),
                  aDecoder->GetDecodeFlags());
 
   bool wasMetadata = aDecoder->IsMetadataDecode();
   bool done = aDecoder->GetDecodeDone();
 
@@ -2064,16 +2029,56 @@ RasterImage::FinalizeDecoder(Decoder* aD
 
   // If we were a metadata decode and a full decode was requested, do it.
   if (done && wasMetadata && mWantFullDecode) {
     mWantFullDecode = false;
     RequestDecode();
   }
 }
 
+void
+RasterImage::MarkAnimationDecoded()
+{
+  MOZ_ASSERT(mAnim, "Should have an animation now");
+  if (!mAnim) {
+    return;
+  }
+
+  mAnim->SetDoneDecoding(true);
+}
+
+void
+RasterImage::ReportDecoderError(Decoder* aDecoder)
+{
+  nsCOMPtr<nsIConsoleService> consoleService =
+    do_GetService(NS_CONSOLESERVICE_CONTRACTID);
+  nsCOMPtr<nsIScriptError> errorObject =
+    do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
+
+  if (consoleService && errorObject && !aDecoder->HasDecoderError()) {
+    nsAutoString msg(NS_LITERAL_STRING("Image corrupt or truncated."));
+    nsAutoString src;
+    if (GetURI()) {
+      nsCString uri;
+      if (GetURI()->GetSpecTruncatedTo1k(uri) == ImageURL::TruncatedTo1k) {
+        msg += NS_LITERAL_STRING(" URI in this note truncated due to length.");
+      }
+      src = NS_ConvertUTF8toUTF16(uri);
+    }
+    if (NS_SUCCEEDED(errorObject->InitWithWindowID(
+                       msg,
+                       src,
+                       EmptyString(), 0, 0, nsIScriptError::errorFlag,
+                       "Image", InnerWindowID()
+                     ))) {
+      consoleService->LogMessage(errorObject);
+    }
+  }
+}
+
 already_AddRefed<imgIContainer>
 RasterImage::Unwrap()
 {
   nsCOMPtr<imgIContainer> self(this);
   return self.forget();
 }
 
 IntSize
--- a/image/RasterImage.h
+++ b/image/RasterImage.h
@@ -165,22 +165,16 @@ public:
 #endif
 
   virtual nsresult StartAnimation() override;
   virtual nsresult StopAnimation() override;
 
   // Methods inherited from Image
   virtual void OnSurfaceDiscarded() override;
 
-  // Raster-specific methods
-  static NS_METHOD WriteToSourceBuffer(nsIInputStream* aIn, void* aClosure,
-                                       const char* aFromRawSegment,
-                                       uint32_t aToOffset, uint32_t aCount,
-                                       uint32_t* aWriteCount);
-
   /* The total number of frames in this image. */
   uint32_t GetNumFrames() const { return mFrameCount; }
 
   virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf)
     const override;
   virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
                                      MallocSizeOf aMallocSizeOf) const override;
 
@@ -201,22 +195,16 @@ public:
   nsresult SetSize(int32_t aWidth, int32_t aHeight, Orientation aOrientation);
 
   /**
    * Number of times to loop the image.
    * @note -1 means forever.
    */
   void     SetLoopCount(int32_t aLoopCount);
 
-  /// Notification that the entire image has been decoded.
-  void OnDecodingComplete(bool aIsAnimated);
-
-  /// Helper method for OnDecodingComplete.
-  void MarkAnimationDecoded();
-
   /**
    * Sends the provided progress notifications to ProgressTracker.
    *
    * Main-thread only.
    *
    * @param aProgress    The progress notifications to send.
    * @param aInvalidRect An invalidation rect to send.
    * @param aFlags       The decode flags used by the decoder that generated
@@ -229,16 +217,20 @@ public:
 
   /**
    * Records telemetry and does final teardown of the provided decoder.
    *
    * Main-thread only.
    */
   void FinalizeDecoder(Decoder* aDecoder);
 
+  // Helper methods for FinalizeDecoder.
+  void MarkAnimationDecoded();
+  void ReportDecoderError(Decoder* aDecoder);
+
 
   //////////////////////////////////////////////////////////////////////////////
   // Network callbacks.
   //////////////////////////////////////////////////////////////////////////////
 
   virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
                                         nsISupports* aContext,
                                         nsIInputStream* aInStr,
@@ -264,28 +256,21 @@ public:
    */
   nsresult SetSourceSizeHint(uint32_t aSizeHint);
 
   /* Provide a hint for the requested resolution of the resulting image. */
   void SetRequestedResolution(const nsIntSize requestedResolution) {
     mRequestedResolution = requestedResolution;
   }
 
-  nsIntSize GetRequestedResolution() {
-    return mRequestedResolution;
-  }
   /* Provide a hint for the requested dimension of the resulting image. */
   void SetRequestedSampleSize(int requestedSampleSize) {
     mRequestedSampleSize = requestedSampleSize;
   }
 
-  int GetRequestedSampleSize() {
-    return mRequestedSampleSize;
-  }
-
  nsCString GetURIString() {
     nsCString spec;
     if (GetURI()) {
       GetURI()->GetSpec(spec);
     }
     return spec;
   }
 
--- a/image/SourceBuffer.cpp
+++ b/image/SourceBuffer.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SourceBuffer.h"
 
 #include <algorithm>
 #include <cmath>
 #include <cstring>
 #include "mozilla/Likely.h"
+#include "nsIInputStream.h"
 #include "MainThreadUtils.h"
 #include "SurfaceCache.h"
 
 using std::max;
 using std::min;
 
 namespace mozilla {
 namespace image {
@@ -349,16 +350,56 @@ SourceBuffer::Append(const char* aData, 
 
     // Resume any waiting readers now that there's new data.
     ResumeWaitingConsumers();
   }
 
   return NS_OK;
 }
 
+static NS_METHOD
+AppendToSourceBuffer(nsIInputStream*,
+                     void* aClosure,
+                     const char* aFromRawSegment,
+                     uint32_t,
+                     uint32_t aCount,
+                     uint32_t* aWriteCount)
+{
+  SourceBuffer* sourceBuffer = static_cast<SourceBuffer*>(aClosure);
+
+  // Copy the source data. Unless we hit OOM, we squelch the return value here,
+  // because returning an error means that ReadSegments stops reading data, and
+  // we want to ensure that we read everything we get. If we hit OOM then we
+  // return a failed status to the caller.
+  nsresult rv = sourceBuffer->Append(aFromRawSegment, aCount);
+  if (rv == NS_ERROR_OUT_OF_MEMORY) {
+    return rv;
+  }
+
+  // Report that we wrote everything we got.
+  *aWriteCount = aCount;
+
+  return NS_OK;
+}
+
+nsresult
+SourceBuffer::AppendFromInputStream(nsIInputStream* aInputStream,
+                                    uint32_t aCount)
+{
+  uint32_t bytesRead;
+  nsresult rv = aInputStream->ReadSegments(AppendToSourceBuffer, this,
+                                           aCount, &bytesRead);
+
+  MOZ_ASSERT(bytesRead == aCount || rv == NS_ERROR_OUT_OF_MEMORY,
+             "AppendToSourceBuffer should consume everything unless "
+             "we run out of memory");
+
+  return rv;
+}
+
 void
 SourceBuffer::Complete(nsresult aStatus)
 {
   MutexAutoLock lock(mMutex);
 
   if (MOZ_UNLIKELY(mStatus)) {
     MOZ_ASSERT_UNREACHABLE("Called Complete more than once");
     return;
--- a/image/SourceBuffer.h
+++ b/image/SourceBuffer.h
@@ -16,16 +16,18 @@
 #include "mozilla/Mutex.h"
 #include "mozilla/Move.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/nsRefPtr.h"
 #include "nsTArray.h"
 
+class nsIInputStream;
+
 namespace mozilla {
 namespace image {
 
 class SourceBuffer;
 
 /**
  * IResumable is an interface for classes that can schedule themselves to resume
  * their work later. An implementation of IResumable generally should post a
@@ -202,22 +204,16 @@ private:
  * returns a series of pointers which remain stable for lifetime of the
  * SourceBuffer, and the data they point to is immutable, ensuring that the
  * producer never interferes with the consumers.
  *
  * In order to avoid blocking, SourceBuffer works with SourceBufferIterator to
  * keep a list of consumers which are waiting for new data, and to resume them
  * when the producer appends more. All consumers must implement the IResumable
  * interface to make this possible.
- *
- * XXX(seth): We should add support for compacting a SourceBuffer. To do this,
- * we need to have SourceBuffer keep track of how many live
- * SourceBufferIterator's point to it. When the SourceBuffer is complete and no
- * live SourceBufferIterator's for it remain, we can compact its contents into a
- * single chunk.
  */
 class SourceBuffer final
 {
 public:
   MOZ_DECLARE_REFCOUNTED_TYPENAME(image::SourceBuffer)
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(image::SourceBuffer)
 
   SourceBuffer();
@@ -230,16 +226,19 @@ public:
    * If the producer knows how long the source data will be, it should call
    * ExpectLength, which enables SourceBuffer to preallocate its buffer.
    */
   nsresult ExpectLength(size_t aExpectedLength);
 
   /// Append the provided data to the buffer.
   nsresult Append(const char* aData, size_t aLength);
 
+  /// Append the data available on the provided nsIInputStream to the buffer.
+  nsresult AppendFromInputStream(nsIInputStream* aInputStream, uint32_t aCount);
+
   /**
    * Mark the buffer complete, with a status that will be available to
    * consumers. Further calls to Append() are forbidden after Complete().
    */
   void Complete(nsresult aStatus);
 
   /// Returns true if the buffer is complete.
   bool IsComplete();
--- a/image/decoders/nsGIFDecoder2.cpp
+++ b/image/decoders/nsGIFDecoder2.cpp
@@ -901,16 +901,23 @@ nsGIFDecoder2::WriteInternal(const char*
 
         default:
           // 0,3-7 are yet to be defined netscape extension codes
           mGIFStruct.state = gif_error;
       }
       break;
 
     case gif_image_header: {
+      if (mGIFStruct.images_decoded > 0 && IsFirstFrameDecode()) {
+        // We're about to get a second frame, but we only want the first. Stop
+        // decoding now.
+        mGIFStruct.state = gif_done;
+        break;
+      }
+
       // Get image offsets, with respect to the screen origin
       mGIFStruct.x_offset = GETINT16(q);
       mGIFStruct.y_offset = GETINT16(q + 2);
 
       // Get image width and height.
       mGIFStruct.width  = GETINT16(q + 4);
       mGIFStruct.height = GETINT16(q + 6);
 
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -261,19 +261,20 @@ nsICODecoder::WriteInternal(const char* 
     aCount -= 2;
   }
 
   if (mNumIcons == 0) {
     return; // Nothing to do.
   }
 
   uint16_t colorDepth = 0;
-  nsIntSize prefSize = mImage->GetRequestedResolution();
-  if (prefSize.width == 0 && prefSize.height == 0) {
-    prefSize.SizeTo(PREFICONSIZE, PREFICONSIZE);
+
+  // If we didn't get a #-moz-resolution, default to PREFICONSIZE.
+  if (mResolution.width == 0 && mResolution.height == 0) {
+    mResolution.SizeTo(PREFICONSIZE, PREFICONSIZE);
   }
 
   // A measure of the difference in size between the entry we've found
   // and the requested size. We will choose the smallest image that is
   // >= requested size (i.e. we assume it's better to downscale a larger
   // icon than to upscale a smaller one).
   int32_t diff = INT_MIN;
 
@@ -301,18 +302,18 @@ nsICODecoder::WriteInternal(const char* 
                 (mCurrIcon * sizeof(mDirEntryArray))) {
       mCurrIcon++;
       ProcessDirEntry(e);
       // We can't use GetRealWidth and GetRealHeight here because those operate
       // on mDirEntry, here we are going through each item in the directory.
       // Calculate the delta between this image's size and the desired size,
       // so we can see if it is better than our current-best option.
       // In the case of several equally-good images, we use the last one.
-      int32_t delta = (e.mWidth == 0 ? 256 : e.mWidth) - prefSize.width +
-                      (e.mHeight == 0 ? 256 : e.mHeight) - prefSize.height;
+      int32_t delta = (e.mWidth == 0 ? 256 : e.mWidth) - mResolution.width +
+                      (e.mHeight == 0 ? 256 : e.mHeight) - mResolution.height;
       if (e.mBitCount >= colorDepth &&
           ((diff < 0 && delta >= diff) || (delta >= 0 && delta <= diff))) {
         diff = delta;
         mImageOffset = e.mImageOffset;
 
         // ensure mImageOffset is >= size of the direntry headers (bug #245631)
         uint32_t minImageOffset = DIRENTRYOFFSET +
                                   mNumIcons * sizeof(mDirEntryArray);
@@ -355,16 +356,19 @@ nsICODecoder::WriteInternal(const char* 
     aBuffer += toCopy;
 
     mIsPNG = !memcmp(mSignature, nsPNGDecoder::pngSignatureBytes,
                      PNGSIGNATURESIZE);
     if (mIsPNG) {
       mContainedDecoder = new nsPNGDecoder(mImage);
       mContainedDecoder->SetMetadataDecode(IsMetadataDecode());
       mContainedDecoder->SetSendPartialInvalidations(mSendPartialInvalidations);
+      if (mFirstFrameDecode) {
+        mContainedDecoder->SetIsFirstFrameDecode();
+      }
       mContainedDecoder->Init();
       if (!WriteToContainedDecoder(mSignature, PNGSIGNATURESIZE)) {
         return;
       }
     }
   }
 
   // If we have a PNG, let the PNG decoder do all of the rest of the work
@@ -432,16 +436,19 @@ nsICODecoder::WriteInternal(const char* 
     // Init the bitmap decoder which will do most of the work for us
     // It will do everything except the AND mask which isn't present in bitmaps
     // bmpDecoder is for local scope ease, it will be freed by mContainedDecoder
     nsBMPDecoder* bmpDecoder = new nsBMPDecoder(mImage);
     mContainedDecoder = bmpDecoder;
     bmpDecoder->SetUseAlphaData(true);
     mContainedDecoder->SetMetadataDecode(IsMetadataDecode());
     mContainedDecoder->SetSendPartialInvalidations(mSendPartialInvalidations);
+    if (mFirstFrameDecode) {
+      mContainedDecoder->SetIsFirstFrameDecode();
+    }
     mContainedDecoder->Init();
 
     // The ICO format when containing a BMP does not include the 14 byte
     // bitmap file header. To use the code of the BMP decoder we need to
     // generate this header ourselves and feed it to the BMP decoder.
     int8_t bfhBuffer[BMPFILEHEADERSIZE];
     if (!FillBitmapFileHeaderBuffer(bfhBuffer)) {
       PostDataError();
--- a/image/decoders/nsICODecoder.h
+++ b/image/decoders/nsICODecoder.h
@@ -31,16 +31,21 @@ public:
   }
 
   // Obtains the height of the icon directory entry
   uint32_t GetRealHeight() const
   {
     return mDirEntry.mHeight == 0 ? 256 : mDirEntry.mHeight;
   }
 
+  virtual void SetResolution(const gfx::IntSize& aResolution) override
+  {
+    mResolution = aResolution;
+  }
+
   virtual void WriteInternal(const char* aBuffer, uint32_t aCount) override;
   virtual void FinishInternal() override;
   virtual void FinishWithErrorInternal() override;
 
 private:
   friend class DecoderFactory;
 
   // Decoders should only be instantiated via DecoderFactory.
@@ -71,16 +76,17 @@ private:
   int32_t ExtractBIHSizeFromBitmap(int8_t* bih);
   // Extract bit count from BMP information header
   int32_t ExtractBPPFromBitmap(int8_t* bih);
   // Calculates the row size in bytes for the AND mask table
   uint32_t CalcAlphaRowSize();
   // Obtains the number of colors from the BPP, mBPP must be filled in
   uint16_t GetNumColors();
 
+  gfx::IntSize mResolution;  // The requested -moz-resolution for this icon.
   uint16_t mBPP; // Stores the images BPP
   uint32_t mPos; // Keeps track of the position we have decoded up until
   uint16_t mNumIcons; // Stores the number of icons in the ICO file
   uint16_t mCurrIcon; // Stores the current dir entry index we are processing
   uint32_t mImageOffset; // Stores the offset of the image data we want
   uint8_t* mRow;      // Holds one raw line of the image
   int32_t mCurLine;   // Line index of the image that's currently being decoded
   uint32_t mRowBytes; // How many bytes of the row were already received
--- a/image/decoders/nsJPEGDecoder.cpp
+++ b/image/decoders/nsJPEGDecoder.cpp
@@ -79,16 +79,17 @@ METHODDEF(void) my_error_exit (j_common_
 
 // Normal JFIF markers can't have more bytes than this.
 #define MAX_JPEG_MARKER_LENGTH  (((uint32_t)1 << 16) - 1)
 
 nsJPEGDecoder::nsJPEGDecoder(RasterImage* aImage,
                              Decoder::DecodeStyle aDecodeStyle)
  : Decoder(aImage)
  , mDecodeStyle(aDecodeStyle)
+ , mSampleSize(0)
 {
   mState = JPEG_HEADER;
   mReading = true;
   mImageData = nullptr;
 
   mBytesToSkip = 0;
   memset(&mInfo, 0, sizeof(jpeg_decompress_struct));
   memset(&mSourceMgr, 0, sizeof(mSourceMgr));
@@ -243,20 +244,20 @@ nsJPEGDecoder::WriteInternal(const char*
 
       // Step 3: read file parameters with jpeg_read_header()
       if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED) {
         MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
                ("} (JPEG_SUSPENDED)"));
         return; // I/O suspension
       }
 
-      int sampleSize = mImage->GetRequestedSampleSize();
-      if (sampleSize > 0) {
+      // If we have a sample size specified for -moz-sample-size, use it.
+      if (mSampleSize > 0) {
         mInfo.scale_num = 1;
-        mInfo.scale_denom = sampleSize;
+        mInfo.scale_denom = mSampleSize;
       }
 
       // Used to set up image size so arrays can be allocated
       jpeg_calc_output_dimensions(&mInfo);
 
       // Post our size to the superclass
       PostSize(mInfo.output_width, mInfo.output_height,
                ReadOrientationFromEXIF());
--- a/image/decoders/nsJPEGDecoder.h
+++ b/image/decoders/nsJPEGDecoder.h
@@ -52,16 +52,21 @@ struct Orientation;
 
 class nsJPEGDecoder : public Decoder
 {
 public:
   virtual ~nsJPEGDecoder();
 
   virtual nsresult SetTargetSize(const nsIntSize& aSize) override;
 
+  virtual void SetSampleSize(int aSampleSize) override
+  {
+    mSampleSize = aSampleSize;
+  }
+
   virtual void InitInternal() override;
   virtual void WriteInternal(const char* aBuffer, uint32_t aCount) override;
   virtual void FinishInternal() override;
 
   virtual Telemetry::ID SpeedHistogram() override;
   void NotifyDone();
 
 protected:
@@ -98,14 +103,16 @@ public:
   qcms_profile* mInProfile;
   qcms_transform* mTransform;
 
   bool mReading;
 
   const Decoder::DecodeStyle mDecodeStyle;
 
   uint32_t mCMSMode;
+
+  int mSampleSize;
 };
 
 } // namespace image
 } // namespace mozilla
 
 #endif // mozilla_image_decoders_nsJPEGDecoder_h
--- a/image/decoders/nsPNGDecoder.cpp
+++ b/image/decoders/nsPNGDecoder.cpp
@@ -110,16 +110,17 @@ nsPNGDecoder::nsPNGDecoder(RasterImage* 
  : Decoder(aImage),
    mPNG(nullptr), mInfo(nullptr),
    mCMSLine(nullptr), interlacebuf(nullptr),
    mInProfile(nullptr), mTransform(nullptr),
    format(gfx::SurfaceFormat::UNKNOWN),
    mHeaderBytesRead(0), mCMSMode(0),
    mChannels(0), mFrameIsHidden(false),
    mDisablePremultipliedAlpha(false),
+   mSuccessfulEarlyFinish(false),
    mNumFrames(0)
 {
 }
 
 nsPNGDecoder::~nsPNGDecoder()
 {
   if (mPNG) {
     png_destroy_read_struct(&mPNG, mInfo ? &mInfo : nullptr, nullptr);
@@ -171,19 +172,18 @@ nsPNGDecoder::CreateFrame(png_uint_32 aX
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   mFrameRect = frameRect;
 
   MOZ_LOG(GetPNGDecoderAccountingLog(), LogLevel::Debug,
          ("PNGDecoderAccounting: nsPNGDecoder::CreateFrame -- created "
-          "image frame with %dx%d pixels in container %p",
-          aWidth, aHeight,
-          &mImage));
+          "image frame with %dx%d pixels for decoder %p",
+          aWidth, aHeight, this));
 
 #ifdef PNG_APNG_SUPPORTED
   if (png_get_valid(mPNG, mInfo, PNG_INFO_acTL)) {
     mAnimInfo = AnimFrameInfo(mPNG, mInfo);
 
     if (mAnimInfo.mDispose == DisposalMethod::CLEAR) {
       // We may have to display the background under this image during
       // animation playback, so we regard it as transparent.
@@ -371,17 +371,17 @@ nsPNGDecoder::WriteInternal(const char* 
   // Otherwise, we're doing a standard decode
   } else {
 
     // libpng uses setjmp/longjmp for error handling - set the buffer
     if (setjmp(png_jmpbuf(mPNG))) {
 
       // We might not really know what caused the error, but it makes more
       // sense to blame the data.
-      if (!HasError()) {
+      if (!mSuccessfulEarlyFinish && !HasError()) {
         PostDataError();
       }
 
       png_destroy_read_struct(&mPNG, &mInfo, nullptr);
       return;
     }
 
     // Pass the data off to libpng
@@ -823,16 +823,24 @@ nsPNGDecoder::frame_info_callback(png_st
   int32_t width, height;
 
   nsPNGDecoder* decoder =
                static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
 
   // old frame is done
   decoder->EndImageFrame();
 
+  if (!decoder->mFrameIsHidden && decoder->IsFirstFrameDecode()) {
+    // We're about to get a second non-hidden frame, but we only want the first.
+    // Stop decoding now.
+    decoder->PostDecodeDone();
+    decoder->mSuccessfulEarlyFinish = true;
+    png_longjmp(decoder->mPNG, 1);
+  }
+
   // Only the first frame can be hidden, so unhide unconditionally here.
   decoder->mFrameIsHidden = false;
 
   x_offset = png_get_next_frame_x_offset(png_ptr, decoder->mInfo);
   y_offset = png_get_next_frame_y_offset(png_ptr, decoder->mInfo);
   width = png_get_next_frame_width(png_ptr, decoder->mInfo);
   height = png_get_next_frame_height(png_ptr, decoder->mInfo);
 
--- a/image/decoders/nsPNGDecoder.h
+++ b/image/decoders/nsPNGDecoder.h
@@ -90,16 +90,17 @@ public:
   uint32_t mHeaderBytesRead;
 
   // whether CMS or premultiplied alpha are forced off
   uint32_t mCMSMode;
 
   uint8_t mChannels;
   bool mFrameIsHidden;
   bool mDisablePremultipliedAlpha;
+  bool mSuccessfulEarlyFinish;
 
   struct AnimFrameInfo
   {
     AnimFrameInfo();
 #ifdef PNG_APNG_SUPPORTED
     AnimFrameInfo(png_structp aPNG, png_infop aInfo);
 #endif
 
--- a/image/imgFrame.cpp
+++ b/image/imgFrame.cpp
@@ -135,22 +135,22 @@ imgFrame::imgFrame()
   : mMonitor("imgFrame")
   , mDecoded(0, 0, 0, 0)
   , mLockCount(0)
   , mTimeout(100)
   , mDisposalMethod(DisposalMethod::NOT_SPECIFIED)
   , mBlendMethod(BlendMethod::OVER)
   , mHasNoAlpha(false)
   , mAborted(false)
+  , mOptimizable(false)
   , mPalettedImageData(nullptr)
   , mPaletteDepth(0)
   , mNonPremult(false)
   , mSinglePixel(false)
   , mCompositingFailed(false)
-  , mOptimizable(false)
 {
   static bool hasCheckedOptimize = false;
   if (!hasCheckedOptimize) {
     if (PR_GetEnv("MOZ_DISABLE_IMAGE_OPTIMIZE")) {
       gDisableOptimize = true;
     }
     hasCheckedOptimize = true;
   }
@@ -947,18 +947,18 @@ imgFrame::UnlockImageData()
   mLockCount--;
 
   return NS_OK;
 }
 
 void
 imgFrame::SetOptimizable()
 {
-  MOZ_ASSERT(NS_IsMainThread());
   AssertImageDataLocked();
+  MonitorAutoLock lock(mMonitor);
   mOptimizable = true;
 }
 
 Color
 imgFrame::SinglePixelColor() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mSinglePixelColor;
--- a/image/imgFrame.h
+++ b/image/imgFrame.h
@@ -337,16 +337,17 @@ private: // data
   int32_t mTimeout; // -1 means display forever.
 
   DisposalMethod mDisposalMethod;
   BlendMethod    mBlendMethod;
   SurfaceFormat  mFormat;
 
   bool mHasNoAlpha;
   bool mAborted;
+  bool mOptimizable;
 
 
   //////////////////////////////////////////////////////////////////////////////
   // Effectively const data, only mutated in the Init methods.
   //////////////////////////////////////////////////////////////////////////////
 
   IntSize      mImageSize;
   IntSize      mSize;
@@ -366,17 +367,16 @@ private: // data
   // Main-thread-only mutable data.
   //////////////////////////////////////////////////////////////////////////////
 
   // Note that the data stored in gfx::Color is *non-alpha-premultiplied*.
   Color        mSinglePixelColor;
 
   bool mSinglePixel;
   bool mCompositingFailed;
-  bool mOptimizable;
 };
 
 /**
  * A reference to an imgFrame that holds the imgFrame's surface in memory,
  * allowing drawing. If you have a DrawableFrameRef |ref| and |if (ref)| returns
  * true, then calls to Draw() and GetSurface() are guaranteed to succeed.
  */
 class DrawableFrameRef final
--- a/image/imgLoader.cpp
+++ b/image/imgLoader.cpp
@@ -784,17 +784,19 @@ NewImageChannel(nsIChannel** aResult,
                                               nullptr,   // loadGroup
                                               callbacks,
                                               aLoadFlags);
   } else {
     // either we are loading something inside a document, in which case
     // we should always have a requestingNode, or we are loading something
     // outside a document, in which case the triggeringPrincipal
     // should always be the systemPrincipal.
-    MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(triggeringPrincipal));
+    // However, there are two exceptions: one is Notifications and the
+    // other one is Favicons which create a channel in the parent prcoess
+    // in which case we can't get a requestingNode.
     rv = NS_NewChannel(aResult,
                        aURI,
                        triggeringPrincipal,
                        securityFlags,
                        aPolicyType,
                        nullptr,   // loadGroup
                        callbacks,
                        aLoadFlags);
--- a/image/imgTools.cpp
+++ b/image/imgTools.cpp
@@ -56,16 +56,18 @@ imgTools::DecodeImageData(nsIInputStream
   return DecodeImage(aInStr, aMimeType, aContainer);
 }
 
 NS_IMETHODIMP
 imgTools::DecodeImage(nsIInputStream* aInStr,
                       const nsACString& aMimeType,
                       imgIContainer** aContainer)
 {
+  MOZ_ASSERT(NS_IsMainThread());
+
   nsresult rv;
 
   NS_ENSURE_ARG_POINTER(aInStr);
 
   // Create a new image container to hold the decoded data.
   nsAutoCString mimeType(aMimeType);
   nsRefPtr<image::Image> image = ImageFactory::CreateAnonymousImage(mimeType);
   nsRefPtr<ProgressTracker> tracker = image->GetProgressTracker();
--- a/image/moz.build
+++ b/image/moz.build
@@ -1,15 +1,17 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['build', 'decoders', 'encoders']
+if CONFIG['ENABLE_TESTS']:
+    DIRS += ['test/gtest']
 
 with Files('**'):
     BUG_COMPONENT = ('Core', 'ImageLib')
 
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
 
 MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini']
 
new file mode 100644
--- /dev/null
+++ b/image/test/gtest/Common.cpp
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Common.h"
+
+#include <cstdlib>
+#include "gtest/gtest.h"
+
+#include "nsDirectoryServiceDefs.h"
+#include "nsIDirectoryService.h"
+#include "nsIFile.h"
+#include "nsIInputStream.h"
+#include "nsIProperties.h"
+#include "nsNetUtil.h"
+#include "mozilla/nsRefPtr.h"
+#include "nsString.h"
+
+namespace mozilla {
+
+using namespace gfx;
+
+using std::abs;
+
+///////////////////////////////////////////////////////////////////////////////
+// Helpers
+///////////////////////////////////////////////////////////////////////////////
+
+// These macros work like gtest's ASSERT_* macros, except that they can be used
+// in functions that return values.
+#define ASSERT_TRUE_OR_RETURN(e, rv) \
+  EXPECT_TRUE(e);                    \
+  if (!(e)) {                        \
+    return rv;                       \
+  }
+
+#define ASSERT_EQ_OR_RETURN(a, b, rv) \
+  EXPECT_EQ(a, b);                    \
+  if ((a) != (b)) {                   \
+    return rv;                        \
+  }
+
+#define ASSERT_LE_OR_RETURN(a, b, rv) \
+  EXPECT_LE(a, b);                    \
+  if (!((a) <= (b))) {                 \
+    return rv;                        \
+  }
+
+already_AddRefed<nsIInputStream>
+LoadFile(const char* aRelativePath)
+{
+  nsresult rv;
+
+  nsCOMPtr<nsIProperties> dirService =
+    do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
+  ASSERT_TRUE_OR_RETURN(dirService != nullptr, nullptr);
+
+  // Retrieve the current working directory.
+  nsCOMPtr<nsIFile> file;
+  rv = dirService->Get(NS_OS_CURRENT_WORKING_DIR,
+                       NS_GET_IID(nsIFile), getter_AddRefs(file));
+  ASSERT_TRUE_OR_RETURN(NS_SUCCEEDED(rv), nullptr);
+
+  // Construct the final path by appending the working path to the current
+  // working directory.
+  file->AppendNative(nsAutoCString(aRelativePath));
+
+  // Construct an input stream for the requested file.
+  nsCOMPtr<nsIInputStream> inputStream;
+  rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), file);
+  ASSERT_TRUE_OR_RETURN(NS_SUCCEEDED(rv), nullptr);
+
+  return inputStream.forget();
+}
+
+bool
+IsSolidColor(SourceSurface* aSurface, BGRAColor aColor, bool aFuzzy)
+{
+  nsRefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface();
+  ASSERT_TRUE_OR_RETURN(dataSurface != nullptr, false);
+
+  ASSERT_EQ_OR_RETURN(dataSurface->Stride(), aSurface->GetSize().width * 4,
+                      false);
+
+  DataSourceSurface::ScopedMap mapping(dataSurface,
+                                       DataSourceSurface::MapType::READ);
+  ASSERT_TRUE_OR_RETURN(mapping.IsMapped(), false);
+
+  uint8_t* data = dataSurface->GetData();
+  ASSERT_TRUE_OR_RETURN(data != nullptr, false);
+
+  int32_t length = dataSurface->Stride() * aSurface->GetSize().height;
+  for (int32_t i = 0 ; i < length ; i += 4) {
+    if (aFuzzy) {
+      ASSERT_LE_OR_RETURN(abs(aColor.mBlue - data[i + 0]), 1, false);
+      ASSERT_LE_OR_RETURN(abs(aColor.mGreen - data[i + 1]), 1, false);
+      ASSERT_LE_OR_RETURN(abs(aColor.mRed - data[i + 2]), 1, false);
+      ASSERT_LE_OR_RETURN(abs(aColor.mAlpha - data[i + 3]), 1, false);
+    } else {
+      ASSERT_EQ_OR_RETURN(aColor.mBlue,  data[i + 0], false);
+      ASSERT_EQ_OR_RETURN(aColor.mGreen, data[i + 1], false);
+      ASSERT_EQ_OR_RETURN(aColor.mRed,   data[i + 2], false);
+      ASSERT_EQ_OR_RETURN(aColor.mAlpha, data[i + 3], false);
+    }
+  }
+
+  return true;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Test Data
+///////////////////////////////////////////////////////////////////////////////
+
+ImageTestCase GreenPNGTestCase()
+{
+  return ImageTestCase("green.png", "image/png", IntSize(100, 100));
+}
+
+ImageTestCase GreenGIFTestCase()
+{
+  return ImageTestCase("green.gif", "image/gif", IntSize(100, 100));
+}
+
+ImageTestCase GreenJPGTestCase()
+{
+  return ImageTestCase("green.jpg", "image/jpeg", IntSize(100, 100),
+                       /* aFuzzy = */ true);
+}
+
+ImageTestCase GreenBMPTestCase()
+{
+  return ImageTestCase("green.bmp", "image/bmp", IntSize(100, 100));
+}
+
+ImageTestCase GreenICOTestCase()
+{
+  return ImageTestCase("green.ico", "image/x-icon", IntSize(100, 100));
+}
+
+ImageTestCase GreenFirstFrameAnimatedGIFTestCase()
+{
+  return ImageTestCase("first-frame-green.gif", "image/gif", IntSize(100, 100));
+}
+
+ImageTestCase GreenFirstFrameAnimatedPNGTestCase()
+{
+  return ImageTestCase("first-frame-green.png", "image/png", IntSize(100, 100));
+}
+
+ImageTestCase CorruptTestCase()
+{
+  return ImageTestCase("corrupt.jpg", "image/jpeg", IntSize(100, 100));
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/image/test/gtest/Common.h
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_image_test_gtest_Common_h
+#define mozilla_image_test_gtest_Common_h
+
+#include "mozilla/gfx/2D.h"
+#include "nsCOMPtr.h"
+
+class nsIInputStream;
+
+namespace mozilla {
+
+///////////////////////////////////////////////////////////////////////////////
+// Types
+///////////////////////////////////////////////////////////////////////////////
+
+struct ImageTestCase
+{
+  ImageTestCase(const char* aPath,
+                const char* aMimeType,
+                gfx::IntSize aSize,
+                bool aFuzzy = false)
+    : mPath(aPath)
+    , mMimeType(aMimeType)
+    , mSize(aSize)
+    , mFuzzy(aFuzzy)
+  { }
+
+  const char* mPath;
+  const char* mMimeType;
+  gfx::IntSize mSize;
+  bool mFuzzy;
+};
+
+struct BGRAColor
+{
+  BGRAColor(uint8_t aBlue, uint8_t aGreen, uint8_t aRed, uint8_t aAlpha)
+    : mBlue(aBlue)
+    , mGreen(aGreen)
+    , mRed(aRed)
+    , mAlpha(aAlpha)
+  { }
+
+  static BGRAColor Green() { return BGRAColor(0x00, 0xFF, 0x00, 0xFF); }
+
+  uint8_t mBlue;
+  uint8_t mGreen;
+  uint8_t mRed;
+  uint8_t mAlpha;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Helpers
+///////////////////////////////////////////////////////////////////////////////
+
+/// Loads a file from the current directory. @return an nsIInputStream for it.
+already_AddRefed<nsIInputStream> LoadFile(const char* aRelativePath);
+
+/**
+ * @returns true if every pixel of @aSurface is @aColor.
+ * 
+ * If @aFuzzy is true, a tolerance of 1 is allowed in each color component. This
+ * may be necessary for tests that involve JPEG images.
+ */
+bool IsSolidColor(gfx::SourceSurface* aSurface,
+                  BGRAColor aColor,
+                  bool aFuzzy = false);
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Test Data
+///////////////////////////////////////////////////////////////////////////////
+
+ImageTestCase GreenPNGTestCase();
+ImageTestCase GreenGIFTestCase();
+ImageTestCase GreenJPGTestCase();
+ImageTestCase GreenBMPTestCase();
+ImageTestCase GreenICOTestCase();
+
+ImageTestCase GreenFirstFrameAnimatedGIFTestCase();
+ImageTestCase GreenFirstFrameAnimatedPNGTestCase();
+
+ImageTestCase CorruptTestCase();
+
+} // namespace mozilla
+
+#endif // mozilla_image_test_gtest_Common_h
new file mode 100644
--- /dev/null
+++ b/image/test/gtest/TestDecodeToSurface.cpp
@@ -0,0 +1,119 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+
+#include "Common.h"
+#include "imgIContainer.h"
+#include "imgITools.h"
+#include "ImageOps.h"
+#include "mozilla/gfx/2D.h"
+#include "nsComponentManagerUtils.h"
+#include "nsCOMPtr.h"
+#include "nsIInputStream.h"
+#include "nsIRunnable.h"
+#include "nsIThread.h"
+#include "mozilla/nsRefPtr.h"
+#include "nsString.h"
+#include "nsThreadUtils.h"
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+using namespace mozilla::image;
+
+
+TEST(ImageDecodeToSurface, ImageModuleAvailable)
+{
+  // We can run into problems if XPCOM modules get initialized in the wrong
+  // order. It's important that this test run first, both as a sanity check and
+  // to ensure we get the module initialization order we want.
+  nsCOMPtr<imgITools> imgTools =
+    do_CreateInstance("@mozilla.org/image/tools;1");
+  EXPECT_TRUE(imgTools != nullptr);
+}
+
+class DecodeToSurfaceRunnable : public nsRunnable
+{
+public:
+  DecodeToSurfaceRunnable(nsIInputStream* aInputStream,
+                          const ImageTestCase& aTestCase)
+    : mInputStream(aInputStream)
+    , mTestCase(aTestCase)
+  { }
+
+  NS_IMETHOD Run()
+  {
+    Go();
+    return NS_OK;
+  }
+
+  void Go()
+  {
+    nsRefPtr<SourceSurface> surface =
+      ImageOps::DecodeToSurface(mInputStream,
+                                nsAutoCString(mTestCase.mMimeType),
+                                imgIContainer::DECODE_FLAGS_DEFAULT);
+    ASSERT_TRUE(surface != nullptr);
+
+    EXPECT_EQ(SurfaceType::DATA, surface->GetType());
+    EXPECT_TRUE(surface->GetFormat() == SurfaceFormat::B8G8R8X8 ||
+                surface->GetFormat() == SurfaceFormat::B8G8R8A8);
+    EXPECT_EQ(mTestCase.mSize, surface->GetSize());
+
+    EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Green(), mTestCase.mFuzzy));
+  }
+
+private:
+  nsCOMPtr<nsIInputStream> mInputStream;
+  ImageTestCase mTestCase;
+};
+
+static void
+RunDecodeToSurface(const ImageTestCase& aTestCase)
+{
+  nsCOMPtr<nsIInputStream> inputStream = LoadFile(aTestCase.mPath);
+  ASSERT_TRUE(inputStream != nullptr);
+
+  nsCOMPtr<nsIThread> thread;
+  nsresult rv = NS_NewThread(getter_AddRefs(thread), nullptr);
+  ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+  // We run the DecodeToSurface tests off-main-thread to ensure that
+  // DecodeToSurface doesn't require any main-thread-only code.
+  nsCOMPtr<nsIRunnable> runnable =
+    new DecodeToSurfaceRunnable(inputStream, aTestCase);
+  thread->Dispatch(runnable, nsIThread::DISPATCH_SYNC);
+
+  thread->Shutdown();
+}
+
+TEST(ImageDecodeToSurface, PNG) { RunDecodeToSurface(GreenPNGTestCase()); }
+TEST(ImageDecodeToSurface, GIF) { RunDecodeToSurface(GreenGIFTestCase()); }
+TEST(ImageDecodeToSurface, JPG) { RunDecodeToSurface(GreenJPGTestCase()); }
+TEST(ImageDecodeToSurface, BMP) { RunDecodeToSurface(GreenBMPTestCase()); }
+TEST(ImageDecodeToSurface, ICO) { RunDecodeToSurface(GreenICOTestCase()); }
+
+TEST(ImageDecodeToSurface, AnimatedGIF)
+{
+  RunDecodeToSurface(GreenFirstFrameAnimatedGIFTestCase());
+}
+
+TEST(ImageDecodeToSurface, AnimatedPNG)
+{
+  RunDecodeToSurface(GreenFirstFrameAnimatedPNGTestCase());
+}
+
+TEST(ImageDecodeToSurface, Corrupt)
+{
+  ImageTestCase testCase = CorruptTestCase();
+
+  nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath);
+  ASSERT_TRUE(inputStream != nullptr);
+
+  nsRefPtr<SourceSurface> surface =
+    ImageOps::DecodeToSurface(inputStream,
+                              nsAutoCString(testCase.mMimeType),
+                              imgIContainer::DECODE_FLAGS_DEFAULT);
+  EXPECT_TRUE(surface == nullptr);
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..555a416d7d8e6c0f835a756994a8efca17c55cd8
GIT binary patch
literal 2477
zc$}TldpOg59|!Q?%xp+3BytF&RFv}}hj2@CJ0Egv2~l<<6LN|yC8yFd84=0IDaU9?
z%rQ~Om_tU<)Mkho?%eCXp2I)SAJ6l=zt{Es=kxh~ug~lH?2hlw0wPvtkY@l84*-C;
z2iTni%mE0PmzNg|;a(63gb%t02IWRrK#+eATzKC;xG-EqbicHOsF;+v2>gKj0V!!2
zIXO8|2?d0LEJ9jVPWIO)AnsErA9ODawpUgRE++dwXSW@I!vK509t=_dc;Fx~9JEUY
z<hXM}Kz|4LM?gGaUhb4IegQ#lLxTvw0|JA2xbt%X+-e-R4)DSu`{dP4`9vKqLKQ;A
zG;U@V!W7MF-iSMXU?DVpFp2yE`y~!YN+~HHKB96|OIt@*Pv5}&H;XftXOUJ;&MxO%
z-P}EV{Vw?jT)q+*b}c+2@_JM>_EysEJIQxb9^f8k;j<s*5Q?4_KPw@YmOZbnt8Zw0
z+0^{1qm$g#-P7CGKRhz}af~uPL8Z;jfBv$t_?5o2vby$TeS^Kp+4|)I0btNS^B-Ms
zu8W7e7GCHt7l<eFR|A|EBCpQ3&(r~WF;rAR<0eeZEVHoY4ZotMBTL)|^FaWiMN?Y&
zCHoup-?<Y1FWA3a|7KBvJzx-bcVIYR0&FX&Jk5^8(;D-nWp5Y0erPG&irGRDWpjw8
zidI!?eQOwfBYNA(v9WgK@zn}@BG}08Nd--dt+(jjzyJ4hVHA|=gDKe9X`Q+NLPs{)
zb>DfUmU>0i{K0}JRkjPJG0%stmRKZxK3*E*$1V#G^6xRLU1R1+!Z@OaIIp`Nu9l;n
zLgF_1<(IE9;-9yiK(HgmXvsm}3nIZ_N%~E%^`7L)iU#v*)b%vx8A-k`&{esymPJpB
zwoPbipT3)|RW~u=*yGVkf`aSS6ZCv^k*co$kWRyOv!8>ymLD%b46U`Hq~VzbeR0cN
zKFT294Q~^34&`Z}1QH$W7fehrvWW#f+r&D3&_2MdP+Mrs*XcKS0MlOA?TEiCG=D)z
z^OIIQ^_&T!6#A)`w!#^!L%s8wExSOq=s!BNH99^vrL$@`K*o9Hk}u_E4GM(>YHC%T
zUN0?dY=0YGfqT`wpt{$W_O5j?MShqWVvo=n3Wbmlx*h)%n%Nl%y(+UQ=kevniR(Cf
z(q`J0flcjLcc_5-k)t)k12u8w)ATaTefQSUvF$MIeGNT2MVwrW3zSuQ*}8K6n?=Zi
z+SfUZq$y)0WqC$_pI=+8e1HRXQhRVI+Upg*NU0ecJFs0mB%gl7N6dC<mF(kE!b}x5
zYNNOv_e(Sz5Kkjv)lS{)Jv6^wt}BHvh@nkrmDZ03E8ljB!vB$>-lK@in>U^=x3m~e
z?|K{Jkol&)-C<nd?Z+VhnwF+|(6Gu2L84a%md<eBcAg%X*^hdsMm$FQ1Uip4)~NX~
zZytOiX9$1c(di*xHXYT<s-tBm8$!whDO-;RZ2WysnmNz*V~7!_K=%eqcLZviQs;O@
z%b}U(n5jM9l=2<qionxA%#QJ<pkX&m;ngMF_c>kOHe_dw92t5cnxhnZseBx180r=B
zGAGq4L$hzmd86v6NVwYkdv>AgL{FAy_VLm<WVI%%I@#enEj(NOg^b-HLPLCL8QP;~
zqGCbT%-gRG;%g9rC&@hghB`X=n3s@R_2h+RY>kD~1M4`q{G8JI-^n;fQvE2?97#Ij
z_9x92YuPwlBq5=D6+x6yoH6m}qSRA-m7j`}ZKIhgw|CUL%&rD^SLdABk}YFZ_cyM5
zBy@lJ=0>C(DxiB59Avz%`;5Pc*6N)lHPKwDO>&9U>B7ysMdneM!WaGg!PWJ%t|dQ*
z&k;6=wCz(y0$SH+d^d0{DwC7?3=b!^l%08Bw?_%__GbL~ZJj4lMlZ??8Q(aR=1qg2
zr%2wKq!f-Vx~yV3UlO*a=u?T!%tU=*g`GpEhCAv3k<~7yst)sm-|uZCwc=0Qd4<Xm
zuTy1=!iys^p9Z@COvK44jZn&Po6YDGyu{h_c8?Ydm(cXgm1WZvJ1jh$l>NR1iB|r~
zoU0Kn9zOtuG8ac0kG*LLD4wwJ`H2|Oj#?LV_jkj)Gt%~qh`49D9+r>EV~h9Paw?fZ
z-17<6NQu-csc&vzy~{5QA{n1`zaO2k?rFLr^rf=ntp6dEw*kYXcRX(+lT>{k1}n?w
zZOt_cp*!-?b?&_iH;_*6KiJmG%xf$;J`6hYn6UYL$f35Y*RkEt`$tuLm+|3##QxQw
zw2aiHW2r$V?zO&>$)VkmSL2TPb{fkPHW&e~<9hF$f`%~zn^nwb<QmEyFsZZCsEc#k
zny|HE37B&*^>=WO_765gb<S=teaj{*Yk;ke#(6?ly=Q^WW&Pz|`g(OPqM4OvB5L)G
z5KFbi)k9*uNXI~IQslz(SgWyx(H#e^^s=cycz3FFm~}3{y<U6YyzKgoA?m0t)$MaB
zM=|&rGGq@f+xLNO80s|(?d*whDUbw9Q?Qo$$2HK^tg14j`sY60u&T!D!Y;&bZ3kHk
zIAYF@`J7<XGK}njBE-_q_ia}n;)t@Q(2rJz?%LL=rl*NmqKQ{Z9cQS@Q_0A;(z^g$
zPcnG3!i|7bN}-N(vPCaSKtZOA0w+RcJX$+_#B&O$J@OgsfnggcRKzS|!^>ry%o99q
z)4nDc1l+%o6|vB3HNc@pr*OIlmtv5&8b^?V8EI*zRT+~#D5WHx_{&iV!t<wXq8d(W
zw9XD$9cZEsTb9kxlM2*0i_fg<CcbVIp_}KEfX_AE=sq>WD|3=R*O{N#_5wYvuUlGi
z1EglW|9Zq>F{d|njFb6lg0wTcKzewucBS7zXJhLq0kZeY*6=o-krtV`5aD+hD*{Kp
zZZXPK#XE^PyfvW-ouzM>Mllrp<StOzw<8qTV=}(*vbmw@T&~GU#hc&bEFDlOiD}Lb
zi=!>mL)N+Nx`b<TmopV#)fp;HlcF+p+h`*zT^{d$<mz3B9T0~)r4@8ERSREV^J4wU
zAQQCTH#X$-#aK(+N{kNrV`YotBA0PZ=8|R{F<p82XS7FNN6%>C_Uoi82fOmBgz9!D
G1pWd#D4b{j
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cd3c7d3db89085bbdbcb41247792bfc5fde9c492
GIT binary patch
literal 317
zc${<hbhEHbOkqf2_`txx@E?d76o0ZXaDnLm+<vYh!Oo5Wu10zW%#1)G9gsXoF#}U^
zOaIE#Z}}I`*>bCU^SwR4`P&|OOncV3?A57l@3@bD^11%4_xZ1L-~aLRaJ3&<^s&Q7
zYx<dGpE-NImS0)*wd-uw_B-pobMti{f3oRkkKgL+Z?^sB?LYne%dWqD=U;#Sv+qB@
kgocGjL`Fr&j1@ah+<5VWBQpZwG`Kq&>g($n2Ff+o0RC>C`Tzg`
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..115f035d897859b9ad8e47cb158d252e621096c2
GIT binary patch
literal 364
zc%17D@N?(olHy`uVBq!ia0vp^DIm<j3?$ucQqzDGM`Ch_50GX8VusJXlM8?pXMj(L
zD-#nF!+(bQ`uf)2X6Zmd#*!evU<QY0H$b|i(jdARU`8^)Knn8<28QVe`;~!gTTd6q
zkc@k8&oXi{Fz_%hSX=*ctA)&#hL?>VDngwuN)vHYpX?={8L10C=x=?9WE~@R>v%S$
zeh0E0(^4EmKwd$za^t^+*B=#JU|PnG&o(f1@_)*b|9*-Re#S9CL!?VwBT9nv(@M${
ni&7aJfg!2jSX`W%o0OAUq+qOP5a+5R19E_;tDnm{r-UW|#oJ$m
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f79dd672adfd43be0906e2ce5bb600b215517d27
GIT binary patch
literal 30138
zc%1Fbp$<WD6bImI%!YVplT0uZjVhQTDY78g{{>7FZc!BZHjiPVm+%m>%-zM9EPlUz
zzi`gk&UkuSM|pNxH(8gj7NSPJ?`8M6_UtG3w|p2+W~=0U>n@JXdTV<vj0S@^386Cz
zp?pZw%CLGVw&(l)_lHvSlRE$a000000000000000000000000000000006*$JOE67
B0m1+P
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ef215dfc94751a15cca5909a443632f5468041b1
GIT binary patch
literal 156
zc${<hbhEHbOkqf2_`txx@E?d76o0aSC<Yx60g_>0DsJgtdHOB?;yGJxb#K16=Qn@b
zBadm%I+wjVwe21E@lQV2zx6)<b?*B=ejcv&Ba1$E_-IW(v+Ofxuh;S`tG;%f&Dwrv
z-FI%j?&D83{p|5uef`b0-@N^&pMTl)x9|Mx?|=6F=a<m1@QBE$=$Nr$$B7#+esE+)
IFfdpH0Q_Q3xc~qF
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c5dfa8b5383c534df2f5e633e7d94d32cfd3b76a
GIT binary patch
literal 41662
zc%1FXp$&jg5JbU6BT3Lm%AlBE779fvbOlF9egWutlRL4=P+Cj<CFhaMN!GfWa^>6K
zwmq4~?|L@?0000000000000000000000000000000000000000000000MJR2^rHu<
C>)Sj4
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..48c454d27c9c46574597f80fdd64ecd4d254577d
GIT binary patch
literal 361
zc$}S%Jr2S!427SY62(c{IxR3UaS;ZjN^lMi!+jW87&rt!3pWYQNSWZXWLZz|+0M88
zg6zlL2%-urE#xP*Fjb*+qtv!8IBRE?o%igRee9wSZD4Lv({>_BeC&r_2A!oWp^`MU
z)1U+n@-z8@<Z!^j&>B@DlPF)Y&{y$^Re3H`6{;?Yrf$c@oxa@<L_>PVBy4b|?sS}5
I{)F=V4K5EK<NyEw
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7df25f33bdb26cc7f41138501ab399059839137d
GIT binary patch
literal 255
zc%17D@N?(olHy`uVBq!ia0vp^DIm<j1SJ1AFfjuu&H|6fVg?3oVGw3ym^DWND9B#o
z>FdgVmrY2>Os;yW$XlS$JWm(LkcwMxFBmd1FmNz0$ozjU>fm{HrGS|QSGZD6PEz%r
zro*}k!eEMoFdB8hjHM3Kz>FXTZ!kl1f-0CHassR?l5*|8wspoc9#?7J!~=9GgQu&X
J%Q~loCICH_Rq+4-
new file mode 100644
--- /dev/null
+++ b/image/test/gtest/moz.build
@@ -0,0 +1,31 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Library('imagetest')
+
+FAIL_ON_WARNINGS = True
+
+UNIFIED_SOURCES = [
+    'Common.cpp',
+    'TestDecodeToSurface.cpp',
+]
+
+TEST_HARNESS_FILES.gtest += [
+    'corrupt.jpg',
+    'first-frame-green.gif',
+    'first-frame-green.png',
+    'green.bmp',
+    'green.gif',
+    'green.ico',
+    'green.jpg',
+    'green.png',
+]
+
+LOCAL_INCLUDES += [
+    '/image',
+]
+
+FINAL_LIBRARY = 'xul-gtest'
--- a/ipc/chromium/chromium-config.mozbuild
+++ b/ipc/chromium/chromium-config.mozbuild
@@ -18,17 +18,16 @@ if CONFIG['OS_ARCH'] == 'WINNT':
         'psapi',
         'shell32',
         'dbghelp',
     ]
 
     DEFINES.update({
         'UNICODE': True,
         '_UNICODE': True,
-        'NOMINMAX': True,
         '_CRT_RAND_S': True,
         'CERT_CHAIN_PARA_HAS_EXTRA_FIELDS': True,
         '_SECURE_ATL': True,
         'CHROMIUM_BUILD': True,
         'U_STATIC_IMPLEMENTATION': True,
         'OS_WIN': 1,
         'WIN32': True,
         '_WIN32': True,
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -42,16 +42,17 @@
 #include "mozilla/sandboxing/sandboxLogging.h"
 #endif
 #endif
 
 #include "nsTArray.h"
 #include "nsClassHashtable.h"
 #include "nsHashKeys.h"
 #include "nsNativeCharsetUtils.h"
+#include "nscore.h" // for NS_FREE_PERMANENT_DATA
 
 using mozilla::MonitorAutoLock;
 using mozilla::ipc::GeckoChildProcessHost;
 
 #ifdef ANDROID
 // Like its predecessor in nsExceptionHandler.cpp, this is
 // the magic number of a file descriptor remapping we must
 // preserve for the child process.
@@ -120,17 +121,17 @@ GeckoChildProcessHost::~GeckoChildProces
 
   MOZ_COUNT_DTOR(GeckoChildProcessHost);
 
   if (mChildProcessHandle > 0) {
 #if defined(MOZ_WIDGET_COCOA)
     SharedMemoryBasic::CleanupForPid(mChildProcessHandle);
 #endif
     ProcessWatcher::EnsureProcessTerminated(mChildProcessHandle
-#if defined(NS_BUILD_REFCNT_LOGGING) || defined(MOZ_ASAN)
+#ifdef NS_FREE_PERMANENT_DATA
     // If we're doing leak logging, shutdown can be slow.
                                             , false // don't "force"
 #endif
     );
   }
 
 #if defined(MOZ_WIDGET_COCOA)
   if (mChildTask != MACH_PORT_NULL)
@@ -377,17 +378,17 @@ GeckoChildProcessHost::AsyncLaunch(std::
   return true;
 }
 
 bool
 GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs)
 {
   // NB: this uses a different mechanism than the chromium parent
   // class.
-  PRIntervalTime timeoutTicks = (aTimeoutMs > 0) ? 
+  PRIntervalTime timeoutTicks = (aTimeoutMs > 0) ?
     PR_MillisecondsToInterval(aTimeoutMs) : PR_INTERVAL_NO_TIMEOUT;
 
   MonitorAutoLock lock(mMonitor);
   PRIntervalTime waitStart = PR_IntervalNow();
   PRIntervalTime current;
 
   // We'll receive several notifications, we need to exit when we
   // have either successfully launched or have timed out.
@@ -558,36 +559,37 @@ AddAppDirToCommandLine(std::vector<std::
 static void
 MaybeAddNsprLogFileAccess(std::vector<std::wstring>& aAllowedFilesReadWrite)
 {
   const char* nsprLogFileEnv = PR_GetEnv("NSPR_LOG_FILE");
   if (!nsprLogFileEnv) {
     return;
   }
 
-  nsCOMPtr<nsIFile> file;
-  nsresult rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR,
-                                       getter_AddRefs(file));
-  if (NS_FAILED(rv) || !file) {
-    NS_WARNING("Failed to get current working directory");
-    return;
-  }
+  nsDependentCString nsprLogFilePath(nsprLogFileEnv);
+  nsCOMPtr<nsIFile> nsprLogFile;
+  nsresult rv = NS_NewNativeLocalFile(nsprLogFilePath, true,
+                                      getter_AddRefs(nsprLogFile));
+  if (NS_FAILED(rv)) {
+    // Not an absolute path, try it as a relative one.
+    nsresult rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR,
+                                         getter_AddRefs(nsprLogFile));
+    if (NS_FAILED(rv) || !nsprLogFile) {
+      NS_WARNING("Failed to get current working directory");
+      return;
+    }
 
-  nsDependentCString nsprLogFile(nsprLogFileEnv);
-  rv = file->AppendRelativeNativePath(nsprLogFile);
-  if (NS_FAILED(rv)) {
-    // Not a relative path, try it as an absolute one.
-    rv = file->InitWithNativePath(nsprLogFile);
+    rv = nsprLogFile->AppendRelativeNativePath(nsprLogFilePath);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return;
     }
   }
 
   nsAutoString resolvedFilePath;
-  rv = file->GetPath(resolvedFilePath);
+  rv = nsprLogFile->GetPath(resolvedFilePath);
   if (NS_WARN_IF(NS_FAILED(rv))) {
       return;
   }
 
   // Update the environment variable as well as adding the rule, because the
   // Chromium sandbox can only allow access to fully qualified file paths. This
   // only affects the environment for the child process we're about to create,
   // because this will get reset to the original value in PerformAsyncLaunch.
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -619,63 +619,55 @@ function ArrayIncludes(searchElement, fr
         // Step d.
         k++;
     }
 
     // Step 11.
     return false;
 }
 
-#define ARRAY_ITERATOR_SLOT_ITERATED_OBJECT 0
-#define ARRAY_ITERATOR_SLOT_NEXT_INDEX 1
-#define ARRAY_ITERATOR_SLOT_ITEM_KIND 2
-
-#define ITEM_KIND_VALUE 0
-#define ITEM_KIND_KEY_AND_VALUE 1
-#define ITEM_KIND_KEY 2
-
 // ES6 draft specification, section 22.1.5.1, version 2013-09-05.
 function CreateArrayIteratorAt(obj, kind, n) {
     var iteratedObject = ToObject(obj);
     var iterator = NewArrayIterator();
-    UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_ITERATED_OBJECT, iteratedObject);
-    UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_NEXT_INDEX, n);
-    UnsafeSetReservedSlot(iterator, ARRAY_ITERATOR_SLOT_ITEM_KIND, kind);
+    UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_TARGET, iteratedObject);
+    UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_INDEX, n);
+    UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_ITEM_KIND, kind);
     return iterator;
 }
 function CreateArrayIterator(obj, kind) {
     return CreateArrayIteratorAt(obj, kind, 0);
 }
 
 function ArrayIteratorIdentity() {
     return this;
 }
 
 function ArrayIteratorNext() {
     if (!IsObject(this) || !IsArrayIterator(this)) {
         return callFunction(CallArrayIteratorMethodIfWrapped, this,
                             "ArrayIteratorNext");
     }
 
-    var a = UnsafeGetObjectFromReservedSlot(this, ARRAY_ITERATOR_SLOT_ITERATED_OBJECT);
+    var a = UnsafeGetObjectFromReservedSlot(this, ITERATOR_SLOT_TARGET);
     // The index might not be an integer, so we have to do a generic get here.
-    var index = UnsafeGetReservedSlot(this, ARRAY_ITERATOR_SLOT_NEXT_INDEX);
-    var itemKind = UnsafeGetInt32FromReservedSlot(this, ARRAY_ITERATOR_SLOT_ITEM_KIND);
+    var index = UnsafeGetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX);
+    var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND);
     var result = { value: undefined, done: false };
 
     // FIXME: This should be ToLength, which clamps at 2**53.  Bug 924058.
     if (index >= TO_UINT32(a.length)) {
         // When the above is changed to ToLength, use +1/0 here instead
         // of MAX_UINT32.
-        UnsafeSetReservedSlot(this, ARRAY_ITERATOR_SLOT_NEXT_INDEX, 0xffffffff);
+        UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, 0xffffffff);
         result.done = true;
         return result;
     }
 
-    UnsafeSetReservedSlot(this, ARRAY_ITERATOR_SLOT_NEXT_INDEX, index + 1);
+    UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + 1);
 
     if (itemKind === ITEM_KIND_VALUE) {
         result.value = a[index];
         return result;
     }
 
     if (itemKind === ITEM_KIND_KEY_AND_VALUE) {
         var pair = NewDenseArray(2);
--- a/js/src/builtin/Map.js
+++ b/js/src/builtin/Map.js
@@ -28,13 +28,66 @@ function MapForEach(callbackfn, thisArg 
         var result = callFunction(std_Map_iterator_next, entries);
         if (result.done)
             break;
         var entry = result.value;
         callFunction(callbackfn, thisArg, entry[1], entry[0], M);
     }
 }
 
+var iteratorTemp = { mapIterationResultPair : null };
+
+function MapIteratorNext() {
+    // Step 1.
+    var O = this;
+
+    // Steps 2-3.
+    if (!IsObject(O) || !IsMapIterator(O))
+        return callFunction(CallMapIteratorMethodIfWrapped, O, "MapIteratorNext");
+
+    // Steps 4-5 (implemented in _GetNextMapEntryForIterator).
+    // Steps 8-9 (omitted).
+
+    var mapIterationResultPair = iteratorTemp.mapIterationResultPair;
+    if (!mapIterationResultPair) {
+        mapIterationResultPair = iteratorTemp.mapIterationResultPair = NewDenseArray(2);
+        mapIterationResultPair[0] = null;
+        mapIterationResultPair[1] = null;
+    }
+
+    var retVal = {value: undefined, done: true};
+
+    // Step 10.a, 11.
+    var done = _GetNextMapEntryForIterator(O, mapIterationResultPair);
+    if (!done) {
+        // Steps 10.b-c (omitted).
+
+        // Step 6.
+        var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND);
+
+        var result;
+        if (itemKind === ITEM_KIND_KEY) {
+            // Step 10.d.i.
+            result = mapIterationResultPair[0];
+        } else if (itemKind === ITEM_KIND_VALUE) {
+            // Step 10.d.ii.
+            result = mapIterationResultPair[1];
+        } else {
+            // Step 10.d.iii.
+            assert(itemKind === ITEM_KIND_KEY_AND_VALUE, itemKind);
+            result = [mapIterationResultPair[0], mapIterationResultPair[1]];
+        }
+
+        mapIterationResultPair[0] = null;
+        mapIterationResultPair[1] = null;
+        retVal.value = result;
+        retVal.done = false;
+    }
+
+    // Steps 7, 12.
+    return retVal;
+}
+
 // ES6 final draft 23.1.2.2.
 function MapSpecies() {
     // Step 1.
     return this;
 }
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -97,35 +97,16 @@ HashableValue::mark(JSTracer* trc) const
     return hv;
 }
 
 
 /*** MapIterator *********************************************************************************/
 
 namespace {
 
-class MapIteratorObject : public NativeObject
-{
-  public:
-    static const Class class_;
-
-    enum { TargetSlot, KindSlot, RangeSlot, SlotCount };
-    static const JSFunctionSpec methods[];
-    static MapIteratorObject* create(JSContext* cx, HandleObject mapobj, ValueMap* data,
-                                     MapObject::IteratorKind kind);
-    static bool next(JSContext* cx, unsigned argc, Value* vp);
-    static void finalize(FreeOp* fop, JSObject* obj);
-
-  private:
-    static inline bool is(HandleValue v);
-    inline ValueMap::Range* range();
-    inline MapObject::IteratorKind kind() const;
-    static bool next_impl(JSContext* cx, CallArgs args);
-};
-
 } /* anonymous namespace */
 
 const Class MapIteratorObject::class_ = {
     "Map Iterator",
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(MapIteratorObject::SlotCount),
     nullptr, /* addProperty */
     nullptr, /* delProperty */
@@ -135,24 +116,25 @@ const Class MapIteratorObject::class_ = 
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     nullptr, /* convert */
     MapIteratorObject::finalize
 };
 
 const JSFunctionSpec MapIteratorObject::methods[] = {
     JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0),
-    JS_FN("next", next, 0, 0),
+    JS_SELF_HOSTED_FN("next", "MapIteratorNext", 0, 0),
     JS_FS_END
 };
 
-inline ValueMap::Range*
-MapIteratorObject::range()
+static inline ValueMap::Range*
+MapIteratorObjectRange(NativeObject* obj)
 {
-    return static_cast<ValueMap::Range*>(getSlot(RangeSlot).toPrivate());
+    MOZ_ASSERT(obj->is<MapIteratorObject>());
+    return static_cast<ValueMap::Range*>(obj->getSlot(MapIteratorObject::RangeSlot).toPrivate());
 }
 
 inline MapObject::IteratorKind
 MapIteratorObject::kind() const
 {
     int32_t i = getSlot(KindSlot).toInt32();
     MOZ_ASSERT(i == MapObject::Keys || i == MapObject::Values || i == MapObject::Entries);
     return MapObject::IteratorKind(i);
@@ -189,85 +171,56 @@ MapIteratorObject::create(JSContext* cx,
         return nullptr;
 
     MapIteratorObject* iterobj = NewObjectWithGivenProto<MapIteratorObject>(cx, proto);
     if (!iterobj) {
         js_delete(range);
         return nullptr;
     }
     iterobj->setSlot(TargetSlot, ObjectValue(*mapobj));
+    iterobj->setSlot(RangeSlot, PrivateValue(range));
     iterobj->setSlot(KindSlot, Int32Value(int32_t(kind)));
-    iterobj->setSlot(RangeSlot, PrivateValue(range));
     return iterobj;
 }
 
 void
 MapIteratorObject::finalize(FreeOp* fop, JSObject* obj)
 {
-    fop->delete_(obj->as<MapIteratorObject>().range());
-}
-
-bool
-MapIteratorObject::is(HandleValue v)
-{
-    return v.isObject() && v.toObject().hasClass(&class_);
+    fop->delete_(MapIteratorObjectRange(static_cast<NativeObject*>(obj)));
 }
 
 bool
-MapIteratorObject::next_impl(JSContext* cx, CallArgs args)
+MapIteratorObject::next(JSContext* cx, Handle<MapIteratorObject*> mapIterator,
+                        HandleArrayObject resultPairObj)
 {
-    MapIteratorObject& thisobj = args.thisv().toObject().as<MapIteratorObject>();
-    ValueMap::Range* range = thisobj.range();
-    RootedValue value(cx);
-    bool done;
+    MOZ_ASSERT(resultPairObj->getDenseInitializedLength() == 2);
 
+    ValueMap::Range* range = MapIteratorObjectRange(mapIterator);
     if (!range || range->empty()) {
         js_delete(range);
-        thisobj.setReservedSlot(RangeSlot, PrivateValue(nullptr));
-        value.setUndefined();
-        done = true;
-    } else {
-        switch (thisobj.kind()) {
-          case MapObject::Keys:
-            value = range->front().key.get();
-            break;
-
-          case MapObject::Values:
-            value = range->front().value;
-            break;
-
-          case MapObject::Entries: {
-            JS::AutoValueArray<2> pair(cx);
-            pair[0].set(range->front().key.get());
-            pair[1].set(range->front().value);
+        mapIterator->setReservedSlot(RangeSlot, PrivateValue(nullptr));
+        return true;
+    }
+    switch (mapIterator->kind()) {
+      case MapObject::Keys:
+        resultPairObj->setDenseElementWithType(cx, 0, range->front().key.get());
+        break;
 
-            JSObject* pairobj = NewDenseCopiedArray(cx, pair.length(), pair.begin());
-            if (!pairobj)
-                return false;
-            value.setObject(*pairobj);
-            break;
-          }
-        }
-        range->popFront();
-        done = false;
-    }
+      case MapObject::Values:
+        resultPairObj->setDenseElementWithType(cx, 1, range->front().value);
+        break;
 
-    RootedObject result(cx, CreateItrResultObject(cx, value, done));
-    if (!result)
-        return false;
-    args.rval().setObject(*result);
-
-    return true;
-}
-
-bool
-MapIteratorObject::next(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod(cx, is, next_impl, args);
+      case MapObject::Entries: {
+        resultPairObj->setDenseElementWithType(cx, 0, range->front().key.get());
+        resultPairObj->setDenseElementWithType(cx, 1, range->front().value);
+        break;
+      }
+    }
+    range->popFront();
+    return false;
 }
 
 
 /*** Map *****************************************************************************************/
 
 const Class MapObject::class_ = {
     "Map",
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
@@ -1450,17 +1403,16 @@ SetObject::clear(JSContext* cx, unsigned
 
 JSObject*
 js::InitSetClass(JSContext* cx, HandleObject obj)
 {
     return SetObject::initClass(cx, obj);
 }
 
 const JSFunctionSpec selfhosting_collection_iterator_methods[] = {
-    JS_FN("std_Map_iterator_next", MapIteratorObject::next, 0, 0),
     JS_FN("std_Set_iterator_next", SetIteratorObject::next, 0, 0),
     JS_FS_END
 };
 
 bool
 js::InitSelfHostingCollectionIteratorFunctions(JSContext* cx, HandleObject obj)
 {
     return JS_DefineFunctions(cx, obj, selfhosting_collection_iterator_methods);
--- a/js/src/builtin/MapObject.h
+++ b/js/src/builtin/MapObject.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef builtin_MapObject_h
 #define builtin_MapObject_h
 
 #include "jsobj.h"
 
+#include "builtin/SelfHostingDefines.h"
 #include "vm/Runtime.h"
 
 namespace js {
 
 /*
  * Comparing two ropes for equality can fail. The js::HashTable template
  * requires infallible hash() and match() operations. Therefore we require
  * all values to be converted to hashable form before being used as a key
@@ -83,16 +84,23 @@ typedef OrderedHashMap<HashableValue,
 
 typedef OrderedHashSet<HashableValue,
                        HashableValue::Hasher,
                        RuntimeAllocPolicy> ValueSet;
 
 class MapObject : public NativeObject {
   public:
     enum IteratorKind { Keys, Values, Entries };
+    static_assert(Keys == ITEM_KIND_KEY,
+                  "IteratorKind Keys must match self-hosting define for item kind key.");
+    static_assert(Values == ITEM_KIND_VALUE,
+                  "IteratorKind Values must match self-hosting define for item kind value.");
+    static_assert(Entries == ITEM_KIND_KEY_AND_VALUE,
+                  "IteratorKind Entries must match self-hosting define for item kind "
+                  "key-and-value.");
 
     static JSObject* initClass(JSContext* cx, JSObject* obj);
     static const Class class_;
 
     static bool getKeysAndValuesInterleaved(JSContext* cx, HandleObject obj,
                                             JS::AutoValueVector* entries);
     static bool entries(JSContext* cx, unsigned argc, Value* vp);
     static bool has(JSContext* cx, unsigned argc, Value* vp);
@@ -141,16 +149,42 @@ class MapObject : public NativeObject {
     static bool keys(JSContext* cx, unsigned argc, Value* vp);
     static bool values_impl(JSContext* cx, CallArgs args);
     static bool values(JSContext* cx, unsigned argc, Value* vp);
     static bool entries_impl(JSContext* cx, CallArgs args);
     static bool clear_impl(JSContext* cx, CallArgs args);
     static bool clear(JSContext* cx, unsigned argc, Value* vp);
 };
 
+class MapIteratorObject : public NativeObject
+{
+  public:
+    static const Class class_;
+
+    enum { TargetSlot, RangeSlot, KindSlot, SlotCount };
+
+    static_assert(TargetSlot == ITERATOR_SLOT_TARGET,
+                  "TargetSlot must match self-hosting define for iterated object slot.");
+    static_assert(RangeSlot == ITERATOR_SLOT_RANGE,
+                  "RangeSlot must match self-hosting define for range or index slot.");
+    static_assert(KindSlot == ITERATOR_SLOT_ITEM_KIND,
+                  "KindSlot must match self-hosting define for item kind slot.");
+
+    static const JSFunctionSpec methods[];
+    static MapIteratorObject* create(JSContext* cx, HandleObject mapobj, ValueMap* data,
+                                     MapObject::IteratorKind kind);
+    static void finalize(FreeOp* fop, JSObject* obj);
+
+    static bool next(JSContext* cx, Handle<MapIteratorObject*> mapIterator,
+                     HandleArrayObject resultPairObj);
+
+  private:
+    inline MapObject::IteratorKind kind() const;
+};
+
 class SetObject : public NativeObject {
   public:
     enum IteratorKind { Values, Entries };
     static JSObject* initClass(JSContext* cx, JSObject* obj);
     static const Class class_;
 
     static bool keys(JSContext *cx, HandleObject obj, JS::AutoValueVector *keys);
     static bool values(JSContext *cx, unsigned argc, Value *vp);
--- a/js/src/builtin/SelfHostingDefines.h
+++ b/js/src/builtin/SelfHostingDefines.h
@@ -8,16 +8,17 @@
 
 #ifndef builtin_SelfHostingDefines_h
 #define builtin_SelfHostingDefines_h
 
 // Utility macros.
 #define TO_INT32(x) ((x) | 0)
 #define TO_UINT32(x) ((x) >>> 0)
 #define IS_UINT32(x) ((x) >>> 0 === (x))
+#define MAX_NUMERIC_INDEX 0x1fffffffffffff // == Math.pow(2, 53) - 1
 
 // Unforgeable versions of ARRAY.push(ELEMENT) and ARRAY.slice.
 #define ARRAY_PUSH(ARRAY, ELEMENT) \
   callFunction(std_Array_push, ARRAY, ELEMENT);
 #define ARRAY_SLICE(ARRAY, ELEMENT) \
   callFunction(std_Array_slice, ARRAY, ELEMENT);
 
 // Property descriptor attributes.
@@ -27,9 +28,20 @@
 
 #define ATTR_NONENUMERABLE      0x08
 #define ATTR_NONCONFIGURABLE    0x10
 #define ATTR_NONWRITABLE        0x20
 
 // Stores the private WeakMap slot used for WeakSets
 #define WEAKSET_MAP_SLOT 0
 
+#define ITERATOR_SLOT_TARGET 0
+// Used for collection iterators.
+#define ITERATOR_SLOT_RANGE 1
+// Used for list, i.e. Array and String, iterators.
+#define ITERATOR_SLOT_NEXT_INDEX 1
+#define ITERATOR_SLOT_ITEM_KIND 2
+
+#define ITEM_KIND_KEY 0
+#define ITEM_KIND_VALUE 1
+#define ITEM_KIND_KEY_AND_VALUE 2
+
 #endif
--- a/js/src/builtin/String.js
+++ b/js/src/builtin/String.js
@@ -184,44 +184,41 @@ function String_repeat(count) {
         if (n)
             S += S;
         else
             break;
     }
     return T;
 }
 
-#define STRING_ITERATOR_SLOT_ITERATED_STRING 0
-#define STRING_ITERATOR_SLOT_NEXT_INDEX 1
-
 // ES6 draft specification, section 21.1.3.27, version 2013-09-27.
 function String_iterator() {
     RequireObjectCoercible(this);
     var S = ToString(this);
     var iterator = NewStringIterator();
-    UnsafeSetReservedSlot(iterator, STRING_ITERATOR_SLOT_ITERATED_STRING, S);
-    UnsafeSetReservedSlot(iterator, STRING_ITERATOR_SLOT_NEXT_INDEX, 0);
+    UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_TARGET, S);
+    UnsafeSetReservedSlot(iterator, ITERATOR_SLOT_NEXT_INDEX, 0);
     return iterator;
 }
 
 function StringIteratorIdentity() {
     return this;
 }
 
 function StringIteratorNext() {
     if (!IsObject(this) || !IsStringIterator(this)) {
         return callFunction(CallStringIteratorMethodIfWrapped, this,
                             "StringIteratorNext");
     }
 
-    var S = UnsafeGetStringFromReservedSlot(this, STRING_ITERATOR_SLOT_ITERATED_STRING);
+    var S = UnsafeGetStringFromReservedSlot(this, ITERATOR_SLOT_TARGET);
     // We know that JSString::MAX_LENGTH <= INT32_MAX (and assert this in
     // SelfHostring.cpp) so our current index can never be anything other than
     // an Int32Value.
-    var index = UnsafeGetInt32FromReservedSlot(this, STRING_ITERATOR_SLOT_NEXT_INDEX);
+    var index = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX);
     var size = S.length;
     var result = { value: undefined, done: false };
 
     if (index >= size) {
         result.done = true;
         return result;
     }
 
@@ -229,17 +226,17 @@ function StringIteratorNext() {
     var first = callFunction(std_String_charCodeAt, S, index);
     if (first >= 0xD800 && first <= 0xDBFF && index + 1 < size) {
         var second = callFunction(std_String_charCodeAt, S, index + 1);
         if (second >= 0xDC00 && second <= 0xDFFF) {
             charCount = 2;
         }
     }
 
-    UnsafeSetReservedSlot(this, STRING_ITERATOR_SLOT_NEXT_INDEX, index + charCount);
+    UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + charCount);
     result.value = callFunction(std_String_substring, S, index, index + charCount);
 
     return result;
 }
 
 /**
  * Compare this String against that String, using the locale and collation
  * options provided.
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -39,16 +39,17 @@
 // The few items below here are either self-hosted or installing them under a
 // std_Foo name would require ugly contortions, so they just get aliased here.
 var std_Array_indexOf = ArrayIndexOf;
 var std_String_substring = String_substring;
 // WeakMap is a bare constructor without properties or methods.
 var std_WeakMap = WeakMap;
 // StopIteration is a bare constructor without properties or methods.
 var std_StopIteration = StopIteration;
+var std_Map_iterator_next = MapIteratorNext;
 
 
 /********** List specification type **********/
 
 
 /* Spec: ECMAScript Language Specification, 5.1 edition, 8.8 */
 function List() {
     this.length = 0;
--- a/js/src/devtools/rootAnalysis/build/gcc.manifest
+++ b/js/src/devtools/rootAnalysis/build/gcc.manifest
@@ -3,18 +3,10 @@
 "gcc_version": "4.7.2"
 },
 {
 "size": 79831648,
 "digest": "958d0dfb531ac6911187cf57907317144a547b884c79dcb483668f0e468ab9f031492ab49177edebf6a6437680b69f54a346a37b4316da78c0ff87aa39c5f2c3",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
-},
-{
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
-"algorithm": "sha512",
-"filename": "gtk3.tar.xz",
-"setup": "setup.sh",
-"unpack": true
 }
 ]
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -5856,17 +5856,16 @@ BytecodeEmitter::emitFunction(ParseNode*
 #ifdef DEBUG
         BindingIter bi(script);
         while (bi->name() != fun->atom())
             bi++;
         MOZ_ASSERT(bi->kind() == Binding::VARIABLE || bi->kind() == Binding::CONSTANT ||
                    bi->kind() == Binding::ARGUMENT);
         MOZ_ASSERT(bi.argOrLocalIndex() < JS_BIT(20));
 #endif
-        pn->pn_index = index;
         if (!emitIndexOp(JSOP_LAMBDA, index))
             return false;
         MOZ_ASSERT(pn->getOp() == JSOP_GETLOCAL || pn->getOp() == JSOP_GETARG);
         JSOp setOp = pn->getOp() == JSOP_GETLOCAL ? JSOP_SETLOCAL : JSOP_SETARG;
         if (!emitVarOp(pn, setOp))
             return false;
         if (!emit1(JSOP_POP))
             return false;
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -650,17 +650,16 @@ class ParseNode
     } pn_u;
 
 #define pn_modulebox    pn_u.name.modulebox
 #define pn_funbox       pn_u.name.funbox
 #define pn_body         pn_u.name.expr
 #define pn_cookie       pn_u.name.cookie
 #define pn_dflags       pn_u.name.dflags
 #define pn_blockid      pn_u.name.blockid
-#define pn_index        pn_u.name.blockid /* reuse as object table index */
 #define pn_head         pn_u.list.head
 #define pn_tail         pn_u.list.tail
 #define pn_count        pn_u.list.count
 #define pn_xflags       pn_u.list.xflags
 #define pn_kid1         pn_u.ternary.kid1
 #define pn_kid2         pn_u.ternary.kid2
 #define pn_kid3         pn_u.ternary.kid3
 #define pn_left         pn_u.binary.left
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -619,27 +619,29 @@ JitRuntime::Mark(JSTracer* trc)
         JitCode* code = i.get<JitCode>();
         TraceRoot(trc, &code, "wrapper");
     }
 }
 
 /* static */ void
 JitRuntime::MarkJitcodeGlobalTableUnconditionally(JSTracer* trc)
 {
-    if (trc->runtime()->hasJitRuntime() &&
+    if (trc->runtime()->spsProfiler.enabled() &&
+        trc->runtime()->hasJitRuntime() &&
         trc->runtime()->jitRuntime()->hasJitcodeGlobalTable())
     {
         trc->runtime()->jitRuntime()->getJitcodeGlobalTable()->markUnconditionally(trc);
     }
 }
 
 /* static */ bool
 JitRuntime::MarkJitcodeGlobalTableIteratively(JSTracer* trc)
 {
-    if (trc->runtime()->hasJitRuntime() &&
+    if (trc->runtime()->spsProfiler.enabled() &&
+        trc->runtime()->hasJitRuntime() &&
         trc->runtime()->jitRuntime()->hasJitcodeGlobalTable())
     {
         return trc->runtime()->jitRuntime()->getJitcodeGlobalTable()->markIteratively(trc);
     }
     return false;
 }
 
 /* static */ void
--- a/js/src/jit/JitcodeMap.cpp
+++ b/js/src/jit/JitcodeMap.cpp
@@ -758,16 +758,18 @@ struct Unconditionally
 };
 
 void
 JitcodeGlobalTable::markUnconditionally(JSTracer* trc)
 {
     // Mark all entries unconditionally. This is done during minor collection
     // to account for tenuring.
 
+    MOZ_ASSERT(trc->runtime()->spsProfiler.enabled());
+
     AutoSuppressProfilerSampling suppressSampling(trc->runtime());
     for (Range r(*this); !r.empty(); r.popFront())
         r.front()->mark<Unconditionally>(trc);
 }
 
 struct IfUnmarked
 {
     template <typename T>
@@ -801,24 +803,22 @@ JitcodeGlobalTable::markIteratively(JSTr
     // frame was pushed between incremental sweep slices. Frames of case 1)
     // are already marked. Frames of case 2) must have been reachable to have
     // been newly pushed, and thus are already marked.
     //
     // The approach above obviates the need for read barriers. The assumption
     // above is checked in JitcodeGlobalTable::lookupForSampler.
 
     MOZ_ASSERT(!trc->runtime()->isHeapMinorCollecting());
+    MOZ_ASSERT(trc->runtime()->spsProfiler.enabled());
 
     AutoSuppressProfilerSampling suppressSampling(trc->runtime());
     uint32_t gen = trc->runtime()->profilerSampleBufferGen();
     uint32_t lapCount = trc->runtime()->profilerSampleBufferLapCount();
 
-    if (!trc->runtime()->spsProfiler.enabled())
-        gen = UINT32_MAX;
-
     bool markedAny = false;
     for (Range r(*this); !r.empty(); r.popFront()) {
         JitcodeGlobalEntry* entry = r.front();
 
         // If an entry is not sampled, reset its generation to the invalid
         // generation, and conditionally mark the rest of the entry if its
         // JitCode is not already marked. This conditional marking ensures
         // that so long as the JitCode *may* be sampled, we keep any
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -219,16 +219,18 @@ IonBuilder::inlineNativeCall(CallInfo& c
     if (native == intrinsic_ToString)
         return inlineToString(callInfo);
     if (native == intrinsic_IsConstructing)
         return inlineIsConstructing(callInfo);
     if (native == intrinsic_SubstringKernel)
         return inlineSubstringKernel(callInfo);
     if (native == intrinsic_IsArrayIterator)
         return inlineHasClass(callInfo, &ArrayIteratorObject::class_);
+    if (native == intrinsic_IsMapIterator)
+        return inlineHasClass(callInfo, &MapIteratorObject::class_);
     if (native == intrinsic_IsStringIterator)
         return inlineHasClass(callInfo, &StringIteratorObject::class_);
 
     // TypedArray intrinsics.
     if (native == intrinsic_IsTypedArray)
         return inlineIsTypedArray(callInfo);
     if (native == intrinsic_IsPossiblyWrappedTypedArray)
         return inlineIsPossiblyWrappedTypedArray(callInfo);
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -764,16 +764,17 @@ bool intrinsic_UnsafeGetReservedSlot(JSC
 bool intrinsic_UnsafeGetObjectFromReservedSlot(JSContext* cx, unsigned argc, Value* vp);
 bool intrinsic_UnsafeGetInt32FromReservedSlot(JSContext* cx, unsigned argc, Value* vp);
 bool intrinsic_UnsafeGetStringFromReservedSlot(JSContext* cx, unsigned argc, Value* vp);
 bool intrinsic_UnsafeGetBooleanFromReservedSlot(JSContext* cx, unsigned argc, Value* vp);
 bool intrinsic_IsPackedArray(JSContext* cx, unsigned argc, Value* vp);
 
 bool intrinsic_IsSuspendedStarGenerator(JSContext* cx, unsigned argc, Value* vp);
 bool intrinsic_IsArrayIterator(JSContext* cx, unsigned argc, Value* vp);
+bool intrinsic_IsMapIterator(JSContext* cx, unsigned argc, Value* vp);
 bool intrinsic_IsStringIterator(JSContext* cx, unsigned argc, Value* vp);
 
 bool intrinsic_IsArrayBuffer(JSContext* cx, unsigned argc, Value* vp);
 
 bool intrinsic_IsTypedArray(JSContext* cx, unsigned argc, Value* vp);
 bool intrinsic_IsPossiblyWrappedTypedArray(JSContext* cx, unsigned argc, Value* vp);
 bool intrinsic_TypedArrayBuffer(JSContext* cx, unsigned argc, Value* vp);
 bool intrinsic_TypedArrayByteOffset(JSContext* cx, unsigned argc, Value* vp);
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -15,16 +15,17 @@
 #include "jsdate.h"
 #include "jsfriendapi.h"
 #include "jshashutil.h"
 #include "jsweakmap.h"
 #include "jswrapper.h"
 #include "selfhosted.out.h"
 
 #include "builtin/Intl.h"
+#include "builtin/MapObject.h"
 #include "builtin/Object.h"
 #include "builtin/Reflect.h"
 #include "builtin/SelfHostingDefines.h"
 #include "builtin/SIMD.h"
 #include "builtin/TypedObject.h"
 #include "builtin/WeakSetObject.h"
 #include "gc/Marking.h"
 #include "vm/Compression.h"
@@ -474,16 +475,42 @@ js::intrinsic_IsArrayIterator(JSContext*
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
     MOZ_ASSERT(args[0].isObject());
 
     args.rval().setBoolean(args[0].toObject().is<ArrayIteratorObject>());
     return true;
 }
 
+bool
+js::intrinsic_IsMapIterator(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 1);
+    MOZ_ASSERT(args[0].isObject());
+
+    args.rval().setBoolean(args[0].toObject().is<MapIteratorObject>());
+    return true;
+}
+
+bool
+intrinsic_GetNextMapEntryForIterator(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 2);
+    MOZ_ASSERT(args[0].toObject().is<MapIteratorObject>());
+    MOZ_ASSERT(args[1].isObject());
+
+    Rooted<MapIteratorObject*> mapIterator(cx, &args[0].toObject().as<MapIteratorObject>());
+    RootedArrayObject result(cx, &args[1].toObject().as<ArrayObject>());
+
+    args.rval().setBoolean(MapIteratorObject::next(cx, mapIterator, result));
+    return true;
+}
+
 static bool
 intrinsic_NewStringIterator(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 0);
 
     RootedObject proto(cx, GlobalObject::getOrCreateStringIteratorPrototype(cx, cx->global()));
     if (!proto)
@@ -1336,16 +1363,21 @@ static const JSFunctionSpec intrinsic_fu
 
     JS_FN("GetIteratorPrototype",    intrinsic_GetIteratorPrototype,    0,0),
 
     JS_FN("NewArrayIterator",        intrinsic_NewArrayIterator,        0,0),
     JS_FN("IsArrayIterator",         intrinsic_IsArrayIterator,         1,0),
     JS_FN("CallArrayIteratorMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>,      2,0),
 
+    JS_FN("IsMapIterator",           intrinsic_IsMapIterator,           1,0),
+    JS_FN("_GetNextMapEntryForIterator", intrinsic_GetNextMapEntryForIterator, 3,0),
+    JS_FN("CallMapIteratorMethodIfWrapped",
+          CallNonGenericSelfhostedMethod<Is<MapIteratorObject>>,        2,0),
+
 
     JS_FN("NewStringIterator",       intrinsic_NewStringIterator,       0,0),
     JS_FN("IsStringIterator",        intrinsic_IsStringIterator,        1,0),
     JS_FN("CallStringIteratorMethodIfWrapped",
           CallNonGenericSelfhostedMethod<Is<StringIteratorObject>>,     2,0),
 
     JS_FN("IsStarGeneratorObject",   intrinsic_IsStarGeneratorObject,   1,0),
     JS_FN("StarGeneratorObjectIsClosed", intrinsic_StarGeneratorObjectIsClosed, 1,0),
--- a/layout/base/MobileViewportManager.cpp
+++ b/layout/base/MobileViewportManager.cpp
@@ -21,16 +21,17 @@ static const nsLiteralCString BEFORE_FIR
 using namespace mozilla;
 using namespace mozilla::layers;
 
 MobileViewportManager::MobileViewportManager(nsIPresShell* aPresShell,
                                              nsIDocument* aDocument)
   : mDocument(aDocument)
   , mPresShell(aPresShell)
   , mIsFirstPaint(false)
+  , mPainted(false)
 {
   MOZ_ASSERT(mPresShell);
   MOZ_ASSERT(mDocument);
 
   MVM_LOG("%p: creating with presShell %p document %p\n", this, mPresShell, aDocument);
 
   if (nsCOMPtr<nsPIDOMWindow> window = mDocument->GetWindow()) {
     mEventTarget = window->GetChromeEventHandler();
@@ -80,30 +81,31 @@ MobileViewportManager::RequestReflow()
 NS_IMETHODIMP
 MobileViewportManager::HandleEvent(nsIDOMEvent* event)
 {
   nsAutoString type;
   event->GetType(type);
 
   if (type.Equals(DOM_META_ADDED)) {
     MVM_LOG("%p: got a dom-meta-added event\n", this);
-    RefreshViewportSize(true);
+    RefreshViewportSize(mPainted);
   } else if (type.Equals(FULL_ZOOM_CHANGE)) {
     MVM_LOG("%p: got a full-zoom-change event\n", this);
     RefreshViewportSize(false);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MobileViewportManager::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
 {
   if (SameCOMIdentity(aSubject, mDocument) && BEFORE_FIRST_PAINT.EqualsASCII(aTopic)) {
     MVM_LOG("%p: got a before-first-paint event\n", this);
     mIsFirstPaint = true;
+    mPainted = true;
     RefreshViewportSize(false);
   }
   return NS_OK;
 }
 
 CSSToScreenScale
 MobileViewportManager::UpdateResolution(const nsViewportInfo& aViewportInfo,
                                         const ScreenIntSize& aDisplaySize,
@@ -144,18 +146,18 @@ MobileViewportManager::UpdateResolution(
 
   // If this is not a first paint, then in some cases we want to update the pre-
   // existing resolution so as to maintain how much actual content is visible
   // within the display width. Note that "actual content" may be different with
   // respect to CSS pixels because of the CSS viewport size changing.
   //
   // aDisplayWidthChangeRatio is non-empty if:
   // (a) The meta-viewport tag information changes, and so the CSS viewport
-  //     might change as a result. In this case, we want to adjust the zoom to
-  //     compensate. OR
+  //     might change as a result. If this happens after the content has been
+  //     painted, we want to adjust the zoom to compensate. OR
   // (b) The display size changed from a nonzero value to another nonzero value.
   //     This covers the case where e.g. the device was rotated, and again we
   //     want to adjust the zoom to compensate.
   // Note in particular that aDisplayWidthChangeRatio will be None if all that
   // happened was a change in the full-zoom. In this case, we still want to
   // compute a new CSS viewport, but we don't want to update the resolution.
   //
   // Given the above, the algorithm below accounts for all types of changes I
--- a/layout/base/MobileViewportManager.h
+++ b/layout/base/MobileViewportManager.h
@@ -49,14 +49,15 @@ private:
                     const mozilla::CSSToScreenScale& aZoom);
   /* Updates the displayport margins for the presShell's root scrollable frame */
   void UpdateDisplayPortMargins();
 
   nsCOMPtr<nsIDocument> mDocument;
   nsIPresShell* MOZ_NON_OWNING_REF mPresShell; // raw ref since the presShell owns this
   nsCOMPtr<nsIDOMEventTarget> mEventTarget;
   bool mIsFirstPaint;
+  bool mPainted;
   mozilla::LayoutDeviceIntSize mDisplaySize;
   mozilla::CSSSize mMobileViewportSize;
 };
 
 #endif
 
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -12,17 +12,16 @@
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsIContent.h"
 #include "nsIContentViewerContainer.h"
 #include "nsIContentViewer.h"
 #include "nsIDocumentViewerPrint.h"
 #include "nsIDOMBeforeUnloadEvent.h"
 #include "nsIDocument.h"
-#include "nsIDOMWindowUtils.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsStyleSet.h"
 #include "nsIFrame.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsSubDocumentFrame.h"
 
 #include "nsILinkHandler.h"
@@ -64,16 +63,17 @@
 #ifdef MOZ_XUL
 #include "nsIXULDocument.h"
 #include "nsXULPopupManager.h"
 #endif
 
 #include "nsIClipboardHelper.h"
 
 #include "nsPIDOMWindow.h"
+#include "nsGlobalWindow.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsPIWindowRoot.h"
 #include "nsJSEnvironment.h"
 #include "nsFocusManager.h"
 
 #include "nsIScrollableFrame.h"
 #include "nsStyleSheetService.h"
 #include "nsRenderingContext.h"
@@ -1110,41 +1110,41 @@ nsDocumentViewer::PermitUnloadInternal(b
   // Dispatching to |window|, but using |document| as the target.
   event->SetTarget(mDocument);
   event->SetTrusted(true);
 
   // In evil cases we might be destroyed while handling the
   // onbeforeunload event, don't let that happen. (see also bug#331040)
   nsRefPtr<nsDocumentViewer> kungFuDeathGrip(this);
 
+  bool dialogsAreEnabled = false;
   {
     // Never permit popups from the beforeunload handler, no matter
     // how we get here.
     nsAutoPopupStatePusher popupStatePusher(openAbused, true);
 
     // Never permit dialogs from the beforeunload handler
-    nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
-    bool dialogsWereEnabled = false;
-    utils->AreDialogsEnabled(&dialogsWereEnabled);
-    utils->DisableDialogs();
+    nsGlobalWindow *globalWindow = static_cast<nsGlobalWindow*>(window);
+    dialogsAreEnabled = globalWindow->AreDialogsEnabled();
+    globalWindow->DisableDialogs();
 
     mInPermitUnload = true;
     EventDispatcher::DispatchDOMEvent(window, nullptr, event, mPresContext,
                                       nullptr);
     mInPermitUnload = false;
-    if (dialogsWereEnabled) {
-      utils->EnableDialogs();
+    if (dialogsAreEnabled) {
+      globalWindow->EnableDialogs();
     }
   }
 
   nsCOMPtr<nsIDocShell> docShell(mContainer);
   nsAutoString text;
   beforeUnload->GetReturnValue(text);
 
-  if (!sIsBeforeUnloadDisabled && *aShouldPrompt &&
+  if (!sIsBeforeUnloadDisabled && *aShouldPrompt && dialogsAreEnabled &&
       (event->GetInternalNSEvent()->mFlags.mDefaultPrevented ||
        !text.IsEmpty())) {
     // Ask the user if it's ok to unload the current page
 
     nsCOMPtr<nsIPrompt> prompt = do_GetInterface(docShell);
 
     if (prompt) {
       nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
--- a/layout/base/tests/browser.ini
+++ b/layout/base/tests/browser.ini
@@ -1,4 +1,5 @@
 [DEFAULT]
 
 [browser_bug617076.js]
 skip-if = e10s # Bug ?????? - test touches content (TypeError: doc.documentElement is null)
+[browser_disableDialogs_onbeforeunload.js]
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/browser_disableDialogs_onbeforeunload.js
@@ -0,0 +1,54 @@
+function pageScript() {
+  window.addEventListener("beforeunload", function (event) {
+    var str = "Some text that causes the beforeunload dialog to be shown";
+    event.returnValue = str;
+    return str;
+  }, true);
+}
+
+const PAGE_URL =
+  "data:text/html," + encodeURIComponent("<script>(" + pageScript.toSource() + ")();</script>");
+
+add_task(function* enableDialogs() {
+  // The onbeforeunload dialog should appear.
+  let dialogShown = false;
+  function onDialogShown(node) {
+    dialogShown = true;
+    let dismissButton = node.ui.button0;
+    dismissButton.click();
+  }
+  let obsName = "tabmodal-dialog-loaded";
+  Services.obs.addObserver(onDialogShown, obsName, false);
+  yield openPage(true);
+  Services.obs.removeObserver(onDialogShown, obsName);
+  Assert.ok(dialogShown);
+});
+
+add_task(function* disableDialogs() {
+  // The onbeforeunload dialog should NOT appear.
+  yield openPage(false);
+  info("If we time out here, then the dialog was shown...");
+});
+
+function* openPage(enableDialogs) {
+  // Open about:blank in a new tab.
+  yield BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank" }, function* (browser) {
+    // Load the content script in the frame.
+    let methodName = enableDialogs ? "enableDialogs" : "disableDialogs";
+    yield ContentTask.spawn(browser, methodName, function* (name) {
+      Components.utils.import("resource://gre/modules/Services.jsm");
+      Services.obs.addObserver(doc => {
+        if (content && doc == content.document) {
+          content.QueryInterface(Ci.nsIInterfaceRequestor).
+            getInterface(Ci.nsIDOMWindowUtils)[name]();
+        }
+      }, "document-element-inserted", false);
+    });
+    // Load the page.
+    yield BrowserTestUtils.loadURI(browser, PAGE_URL);
+    yield BrowserTestUtils.browserLoaded(browser);
+    // And then navigate away.
+    yield BrowserTestUtils.loadURI(browser, "http://example.com/");
+    yield BrowserTestUtils.browserLoaded(browser);
+  });
+}
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -535,17 +535,17 @@ load 849603.html
 asserts(0-12) load 850931.html # bug 569193
 load 851396-1.html
 load 854263-1.html
 load 862185.html
 load 862947-1.html
 load 863935.html
 needs-focus pref(accessibility.browsewithcaret,true) load 868906.html
 load 866547-1.html
-asserts-if(Android,0-4) asserts-if(!Android,1-4) load 876074-1.html # bug 876749
+asserts(0-5) load 876074-1.html # bug 876749
 load 885009-1.html
 load 893496-1.html
 load 893523.html
 asserts(0-3) load 898871.html # bug 479160
 test-pref(layout.css.sticky.enabled,true) load 914891.html
 test-pref(layout.css.sticky.enabled,true) load 915475.xhtml
 load 927558.html
 load 943509-1.html
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -3256,24 +3256,21 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
         // Note that aState.mBCoord should stay where it is: at the block-start
         // border-edge of the frame
       } else {
         // Advance aState.mBCoord to the block-start border-edge of the frame.
         aState.mBCoord += bStartMargin;
       }
     }
 
+    aLine->SetLineIsImpactedByFloat(false);
+
     // Here aState.mBCoord is the block-start border-edge of the block.
     // Compute the available space for the block
     nsFlowAreaRect floatAvailableSpace = aState.GetFloatAvailableSpace();
-#ifdef REALLY_NOISY_REFLOW
-    printf("setting line %p isImpacted to %s\n",
-           aLine.get(), floatAvailableSpace.mHasFloats?"true":"false");
-#endif
-    aLine->SetLineIsImpactedByFloat(floatAvailableSpace.mHasFloats);
     WritingMode wm = aState.mReflowState.GetWritingMode();
     LogicalRect availSpace(wm);
     aState.ComputeBlockAvailSpace(frame, display, floatAvailableSpace,
                                   replacedBlock != nullptr, availSpace);
 
     // The check for
     //   (!aState.mReflowState.mFlags.mIsTopOfPage || clearedFloats)
     // is to some degree out of paranoia:  if we reliably eat up block-start
@@ -3299,43 +3296,145 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
       } else {
         PushLines(aState, aLine.prev());
         NS_FRAME_SET_INCOMPLETE(aState.mReflowStatus);
       }
       return;
     }
 
     // Now put the block-dir coordinate back to the start of the
-    // block-start-margin + clearance, and flow the block.
+    // block-start-margin + clearance.
     aState.mBCoord -= bStartMargin;
     availSpace.BStart(wm) -= bStartMargin;
     if (NS_UNCONSTRAINEDSIZE != availSpace.BSize(wm)) {
       availSpace.BSize(wm) += bStartMargin;
     }
 
-    // Reflow the block into the available space
     // construct the html reflow state for the block. ReflowBlock
     // will initialize it
     nsHTMLReflowState
       blockHtmlRS(aState.mPresContext, aState.mReflowState, frame,
                   availSpace.Size(wm).ConvertTo(frame->GetWritingMode(), wm));
     blockHtmlRS.mFlags.mHasClearance = aLine->HasClearance();
 
     nsFloatManager::SavedState floatManagerState;
-    if (mayNeedRetry) {
-      blockHtmlRS.mDiscoveredClearance = &clearanceFrame;
-      aState.mFloatManager->PushState(&floatManagerState);
-    } else if (!applyBStartMargin) {
-      blockHtmlRS.mDiscoveredClearance = aState.mReflowState.mDiscoveredClearance;
-    }
-
-    nsReflowStatus frameReflowStatus = NS_FRAME_COMPLETE;
-    brc.ReflowBlock(availSpace, applyBStartMargin, aState.mPrevBEndMargin,
-                    clearance, aState.IsAdjacentWithTop(),
-                    aLine.get(), blockHtmlRS, frameReflowStatus, aState);
+    nsReflowStatus frameReflowStatus;
+    do {
+      if (floatAvailableSpace.mHasFloats) {
+        // Set if floatAvailableSpace.mHasFloats is true for any
+        // iteration of the loop.
+        aLine->SetLineIsImpactedByFloat(true);
+      }
+
+      // We might need to store into mDiscoveredClearance later if it's
+      // currently null; we want to overwrite any writes that
+      // brc.ReflowBlock() below does, so we need to remember now
+      // whether it's empty.
+      const bool shouldStoreClearance =
+        aState.mReflowState.mDiscoveredClearance &&
+        !*aState.mReflowState.mDiscoveredClearance;
+
+      // Reflow the block into the available space
+      if (mayNeedRetry || replacedBlock) {
+        aState.mFloatManager->PushState(&floatManagerState);
+      }
+
+      if (mayNeedRetry) {
+        blockHtmlRS.mDiscoveredClearance = &clearanceFrame;
+      } else if (!applyBStartMargin) {
+        blockHtmlRS.mDiscoveredClearance =
+          aState.mReflowState.mDiscoveredClearance;
+      }
+
+      frameReflowStatus = NS_FRAME_COMPLETE;
+      brc.ReflowBlock(availSpace, applyBStartMargin, aState.mPrevBEndMargin,
+                      clearance, aState.IsAdjacentWithTop(),
+                      aLine.get(), blockHtmlRS, frameReflowStatus, aState);
+
+      // Now the block has a height.  Using that height, get the
+      // available space again and call ComputeBlockAvailSpace again.
+      // If ComputeBlockAvailSpace gives a different result, we need to
+      // reflow again.
+      if (!replacedBlock) {
+        break;
+      }
+
+      LogicalRect oldFloatAvailableSpaceRect(floatAvailableSpace.mRect);
+      floatAvailableSpace = aState.GetFloatAvailableSpaceForBSize(
+                              aState.mBCoord + bStartMargin,
+                              brc.GetMetrics().Height(),
+                              &floatManagerState);
+      NS_ASSERTION(floatAvailableSpace.mRect.BStart(wm) ==
+                     oldFloatAvailableSpaceRect.BStart(wm),
+                   "yikes");
+      // Restore the height to the position of the next band.
+      floatAvailableSpace.mRect.BSize(wm) =
+        oldFloatAvailableSpaceRect.BSize(wm);
+      if (!AvailableSpaceShrunk(wm, oldFloatAvailableSpaceRect,
+                                floatAvailableSpace.mRect)) {
+        break;
+      }
+
+      bool advanced = false;
+      if (!aState.ReplacedBlockFitsInAvailSpace(replacedBlock,
+                                                floatAvailableSpace)) {
+        // Advance to the next band.
+        nscoord newBCoord = aState.mBCoord;
+        if (aState.AdvanceToNextBand(floatAvailableSpace.mRect, &newBCoord)) {
+          advanced = true;
+        }
+        // ClearFloats might be able to advance us further once we're there.
+        aState.mBCoord =
+          aState.ClearFloats(newBCoord, NS_STYLE_CLEAR_NONE, replacedBlock);
+        // Start over with a new available space rect at the new height.
+        floatAvailableSpace =
+          aState.GetFloatAvailableSpaceWithState(aState.mBCoord,
+                                                 &floatManagerState);
+      }
+
+      LogicalRect oldAvailSpace(availSpace);
+      aState.ComputeBlockAvailSpace(frame, display, floatAvailableSpace,
+                                    replacedBlock != nullptr, availSpace);
+
+      if (!advanced && availSpace.IsEqualEdges(oldAvailSpace)) {
+        break;
+      }
+
+      // We need another reflow.
+      aState.mFloatManager->PopState(&floatManagerState);
+
+      if (!treatWithClearance && !applyBStartMargin &&
+          aState.mReflowState.mDiscoveredClearance) {
+        // We set shouldStoreClearance above to record only the first
+        // frame that requires clearance.
+        if (shouldStoreClearance) {
+          *aState.mReflowState.mDiscoveredClearance = frame;
+        }
+        aState.mPrevChild = frame;
+        // Exactly what we do now is flexible since we'll definitely be
+        // reflowed.
+        return;
+      }
+
+      if (advanced) {
+        // We're pushing down the border-box, so we don't apply margin anymore.
+        // This should never cause us to move up since the call to
+        // GetFloatAvailableSpaceForBSize above included the margin.
+        applyBStartMargin = false;
+        bStartMargin = 0;
+        treatWithClearance = true; // avoid hitting test above
+        clearance = 0;
+      }
+
+      blockHtmlRS.~nsHTMLReflowState();
+      new (&blockHtmlRS) nsHTMLReflowState(aState.mPresContext,
+                           aState.mReflowState, frame,
+                           availSpace.Size(wm).ConvertTo(
+                             frame->GetWritingMode(), wm));
+    } while (true);
 
     if (mayNeedRetry && clearanceFrame) {
       aState.mFloatManager->PopState(&floatManagerState);
       aState.mBCoord = startingBCoord;
       aState.mPrevBEndMargin = incomingMargin;
       continue;
     }
 
@@ -7200,17 +7299,17 @@ nsBlockFrame::BlockCanIntersectFloats(ns
 }
 
 // Note that this width can vary based on the vertical position.
 // However, the cases where it varies are the cases where the width fits
 // in the available space given, which means that variation shouldn't
 // matter.
 /* static */
 nsBlockFrame::ReplacedElementISizeToClear
-nsBlockFrame::ISizeToClearPastFloats(nsBlockReflowState& aState,
+nsBlockFrame::ISizeToClearPastFloats(const nsBlockReflowState& aState,
                                      const LogicalRect& aFloatAvailableSpace,
                                      nsIFrame* aFrame)
 {
   nscoord inlineStartOffset, inlineEndOffset;
   WritingMode wm = aState.mReflowState.GetWritingMode();
   nsCSSOffsetState offsetState(aFrame, aState.mReflowState.rendContext,
                                wm, aState.mContentArea.ISize(wm));
 
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -319,17 +319,17 @@ public:
    * care about (which need not be its current mBCoord)
    */
   struct ReplacedElementISizeToClear {
     nscoord marginIStart, borderBoxISize, marginIEnd;
     nscoord MarginBoxISize() const
       { return marginIStart + borderBoxISize + marginIEnd; }
   };
   static ReplacedElementISizeToClear
-    ISizeToClearPastFloats(nsBlockReflowState& aState,
+    ISizeToClearPastFloats(const nsBlockReflowState& aState,
                            const mozilla::LogicalRect& aFloatAvailableSpace,
                            nsIFrame* aFrame);
 
   /**
    * Creates a contination for aFloat and adds it to the list of overflow floats.
    * Also updates aState.mReflowStatus to include the float's incompleteness.
    * Must only be called while this block frame is in reflow.
    * aFloatStatus must be the float's true, unmodified reflow status.
--- a/layout/generic/nsBlockReflowContext.cpp
+++ b/layout/generic/nsBlockReflowContext.cpp
@@ -252,16 +252,20 @@ nsBlockReflowContext::ReflowBlock(const 
       if (NS_UNCONSTRAINEDSIZE != aFrameRS.AvailableISize()) {
         aFrameRS.AvailableISize() -= mBStartMargin.get() + aClearance;
       }
     } else {
       if (NS_UNCONSTRAINEDSIZE != aFrameRS.AvailableBSize()) {
         aFrameRS.AvailableBSize() -= mBStartMargin.get() + aClearance;
       }
     }
+  } else {
+    // nsBlockFrame::ReflowBlock might call us multiple times with
+    // *different* values of aApplyBStartMargin.
+    mBStartMargin.Zero();
   }
 
   nscoord tI = 0, tB = 0;
   // The values of x and y do not matter for floats, so don't bother
   // calculating them. Floats are guaranteed to have their own float
   // manager, so tI and tB don't matter.  mICoord and mBCoord don't
   // matter becacuse they are only used in PlaceBlock, which is not used
   // for floats.
--- a/layout/generic/nsBlockReflowState.cpp
+++ b/layout/generic/nsBlockReflowState.cpp
@@ -156,17 +156,17 @@ nsBlockReflowState::GetConsumedBSize()
   return mConsumedBSize;
 }
 
 void
 nsBlockReflowState::ComputeReplacedBlockOffsetsForFloats(
                       nsIFrame* aFrame,
                       const LogicalRect& aFloatAvailableSpace,
                       nscoord& aIStartResult,
-                      nscoord& aIEndResult)
+                      nscoord& aIEndResult) const
 {
   WritingMode wm = mReflowState.GetWritingMode();
   // The frame is clueless about the float manager and therefore we
   // only give it free space. An example is a table frame - the
   // tables do not flow around floats.
   // However, we can let its margins intersect floats.
   NS_ASSERTION(aFloatAvailableSpace.IStart(wm) >= mContentArea.IStart(wm),
                "bad avail space rect inline-coord");
@@ -297,16 +297,40 @@ nsBlockReflowState::ComputeBlockAvailSpa
   }
 
 #ifdef REALLY_NOISY_REFLOW
   printf("  CBAS: result %d %d %d %d\n", aResult.IStart(wm), aResult.BStart(wm),
          aResult.ISize(wm), aResult.BSize(wm));
 #endif
 }
 
+bool
+nsBlockReflowState::ReplacedBlockFitsInAvailSpace(nsIFrame* aReplacedBlock,
+                            const nsFlowAreaRect& aFloatAvailableSpace) const
+{
+  if (!aFloatAvailableSpace.mHasFloats) {
+    // If there aren't any floats here, then we always fit.
+    // We check this before calling ISizeToClearPastFloats, which is
+    // somewhat expensive.
+    return true;
+  }
+  WritingMode wm = mReflowState.GetWritingMode();
+  nsBlockFrame::ReplacedElementISizeToClear replacedISize =
+    nsBlockFrame::ISizeToClearPastFloats(*this, aFloatAvailableSpace.mRect,
+                                         aReplacedBlock);
+  return std::max(aFloatAvailableSpace.mRect.IStart(wm) -
+                    mContentArea.IStart(wm),
+                  replacedISize.marginIStart) +
+           replacedISize.borderBoxISize +
+           std::max(mContentArea.IEnd(wm) -
+                      aFloatAvailableSpace.mRect.IEnd(wm),
+                    replacedISize.marginIEnd) <=
+         mContentArea.ISize(wm);
+}
+
 nsFlowAreaRect
 nsBlockReflowState::GetFloatAvailableSpaceWithState(
                       nscoord aBCoord,
                       nsFloatManager::SavedState *aState) const
 {
   WritingMode wm = mReflowState.GetWritingMode();
 #ifdef DEBUG
   // Verify that the caller setup the coordinate system properly
@@ -1073,56 +1097,32 @@ nsBlockReflowState::ClearFloats(nscoord 
   mFloatManager->List(stdout);
 #endif
 
   if (!mFloatManager->HasAnyFloats()) {
     return aBCoord;
   }
 
   nscoord newBCoord = aBCoord;
-  WritingMode wm = mReflowState.GetWritingMode();
 
   if (aBreakType != NS_STYLE_CLEAR_NONE) {
     newBCoord = mFloatManager->ClearFloats(newBCoord, aBreakType, aFlags);
   }
 
   if (aReplacedBlock) {
     for (;;) {
       nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(newBCoord);
-      if (!floatAvailableSpace.mHasFloats) {
-        // If there aren't any floats here, then we always fit.
-        // We check this before calling ISizeToClearPastFloats, which is
-        // somewhat expensive.
-        break;
-      }
-      nsBlockFrame::ReplacedElementISizeToClear replacedISize =
-        nsBlockFrame::ISizeToClearPastFloats(*this, floatAvailableSpace.mRect,
-                                             aReplacedBlock);
-      if (std::max(floatAvailableSpace.mRect.IStart(wm) -
-                    mContentArea.IStart(wm),
-                   replacedISize.marginIStart) +
-            replacedISize.borderBoxISize +
-            std::max(mContentArea.IEnd(wm) -
-                     floatAvailableSpace.mRect.IEnd(wm),
-                     replacedISize.marginIEnd) <=
-          mContentArea.ISize(wm)) {
+      if (ReplacedBlockFitsInAvailSpace(aReplacedBlock, floatAvailableSpace)) {
         break;
       }
       // See the analogous code for inlines in nsBlockFrame::DoReflowInlineFrames
-      if (floatAvailableSpace.mRect.BSize(wm) > 0) {
-        // See if there's room in the next band.
-        newBCoord += floatAvailableSpace.mRect.BSize(wm);
-      } else {
-        if (mReflowState.AvailableHeight() != NS_UNCONSTRAINEDSIZE) {
-          // Stop trying to clear here; we'll just get pushed to the
-          // next column or page and try again there.
-          break;
-        }
-        NS_NOTREACHED("avail space rect with zero height!");
-        newBCoord += 1;
+      if (!AdvanceToNextBand(floatAvailableSpace.mRect, &newBCoord)) {
+        // Stop trying to clear here; we'll just get pushed to the
+        // next column or page and try again there.
+        break;
       }
     }
   }
 
 #ifdef DEBUG
   if (nsBlockFrame::gNoisyReflow) {
     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
     printf("clear floats: out: y=%d\n", newBCoord);
--- a/layout/generic/nsBlockReflowState.h
+++ b/layout/generic/nsBlockReflowState.h
@@ -88,16 +88,42 @@ public:
 
   // Returns the first coordinate >= aBCoord that clears the
   // floats indicated by aBreakType and has enough inline size between floats
   // (or no floats remaining) to accomodate aReplacedBlock.
   nscoord ClearFloats(nscoord aBCoord, uint8_t aBreakType,
                       nsIFrame *aReplacedBlock = nullptr,
                       uint32_t aFlags = 0);
 
+  // Advances to the next band, i.e., the next horizontal stripe in
+  // which there is a different set of floats.
+  // Return false if it did not advance, which only happens for
+  // constrained heights (and means that we should get pushed to the
+  // next column/page).
+  bool AdvanceToNextBand(const mozilla::LogicalRect& aFloatAvailableSpace,
+                         nscoord *aBCoord) const {
+    mozilla::WritingMode wm = mReflowState.GetWritingMode();
+    if (aFloatAvailableSpace.BSize(wm) > 0) {
+      // See if there's room in the next band.
+      *aBCoord += aFloatAvailableSpace.BSize(wm);
+    } else {
+      if (mReflowState.AvailableHeight() != NS_UNCONSTRAINEDSIZE) {
+        // Stop trying to clear here; we'll just get pushed to the
+        // next column or page and try again there.
+        return false;
+      }
+      NS_NOTREACHED("avail space rect with zero height!");
+      *aBCoord += 1;
+    }
+    return true;
+  }
+
+  bool ReplacedBlockFitsInAvailSpace(nsIFrame* aReplacedBlock,
+                            const nsFlowAreaRect& aFloatAvailableSpace) const;
+
   bool IsAdjacentWithTop() const {
     return mBCoord == mBorderPadding.BStart(mReflowState.GetWritingMode());
   }
 
   /**
    * Return mBlock's computed physical border+padding with GetSkipSides applied.
    */
   const mozilla::LogicalMargin& BorderPadding() const {
@@ -112,17 +138,17 @@ public:
   // Reconstruct the previous block-end margin that goes before |aLine|.
   void ReconstructMarginBefore(nsLineList::iterator aLine);
 
   // Caller must have called GetAvailableSpace for the correct position
   // (which need not be the current mBCoord).
   void ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame,
                           const mozilla::LogicalRect& aFloatAvailableSpace,
                                             nscoord&  aIStartResult,
-                                            nscoord&  aIEndResult);
+                                            nscoord&  aIEndResult) const;
 
   // Caller must have called GetAvailableSpace for the current mBCoord
   void ComputeBlockAvailSpace(nsIFrame* aFrame,
                               const nsStyleDisplay* aDisplay,
                               const nsFlowAreaRect& aFloatAvailableSpace,
                               bool aBlockAvoidsFloats,
                               mozilla::LogicalRect& aResult);
 
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -41,24 +41,24 @@ asserts(2) skip-if(!cocoaWidget) HTTP(..
 == 25888-1l.html 25888-1l-ref.html
 != 25888-1l.html 25888-1l-notref.html
 == 25888-1r.html 25888-1r-ref.html
 != 25888-1r.html 25888-1r-notref.html
 == 25888-2l.html 25888-2l-ref.html
 == 25888-2r.html 25888-2r-ref.html
 == 25888-3l.html 25888-3l-ref.html
 == 25888-3r.html 25888-3r-ref.html
-fails == 25888-1l-block.html 25888-1l-ref.html # Bug 25888
-fails != 25888-1l-block.html 25888-1l-notref.html # Bug 25888
-fails == 25888-1r-block.html 25888-1r-ref.html # Bug 25888
-fails != 25888-1r-block.html 25888-1r-notref.html # Bug 25888
-fails == 25888-2l-block.html 25888-2l-ref.html # Bug 25888
-fails == 25888-2r-block.html 25888-2r-ref.html # Bug 25888
-fails == 25888-3l-block.html 25888-3l-ref.html # Bug 25888
-fails == 25888-3r-block.html 25888-3r-ref.html # Bug 25888
+== 25888-1l-block.html 25888-1l-ref.html
+!= 25888-1l-block.html 25888-1l-notref.html
+== 25888-1r-block.html 25888-1r-ref.html
+!= 25888-1r-block.html 25888-1r-notref.html
+== 25888-2l-block.html 25888-2l-ref.html
+== 25888-2r-block.html 25888-2r-ref.html
+== 25888-3l-block.html 25888-3l-ref.html
+== 25888-3r-block.html 25888-3r-ref.html
 skip-if(B2G||Mulet) == 28811-1a.html 28811-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 fuzzy-if(gtkWidget,6,26200) == 28811-1b.html 28811-1-ref.html  # Bug 1128229
 skip-if(B2G||Mulet) == 28811-2a.html 28811-2-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
 fuzzy-if(gtkWidget,6,26200) == 28811-2b.html 28811-2-ref.html  # Bug 1128229
 == 40596-1a.html 40596-1-ref.html
 != 40596-1b.html 40596-1-ref.html
 == 40596-1c.html 40596-1-ref.html
 != 40596-1d.html 40596-1-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/bfc-displace-1a-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<title>Test of block formatting context displacement by floats</title>
+<style>
+
+.contain {
+  border: medium solid;
+  width: 400px;
+  height: 400px;
+  background: yellow;
+}
+
+.float {
+  float: left;
+  clear: left;
+  height: 20px;
+  background: blue;
+}
+
+.bfc {
+  float: left;
+  width: 250px;
+  margin-top: 7px;
+  height: 13px; /* fits exactly */
+  background: fuchsia;
+}
+
+</style>
+
+
+<div class="contain">
+  <div class="float" style="width: 100px"></div>
+  <div class="bfc"></div>
+  <div class="float" style="width: 200px"></div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/bfc-displace-1a.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<title>Test of block formatting context displacement by floats</title>
+<link rel="help" href="https://drafts.csswg.org/css2/visuren.html#floats">
+<meta name="assert" content="The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself.">
+<style>
+
+.contain {
+  border: medium solid;
+  width: 400px;
+  height: 400px;
+  background: yellow;
+}
+
+.float {
+  float: left;
+  clear: left;
+  height: 20px;
+  background: blue;
+}
+
+.bfc {
+  overflow: hidden;
+  width: 250px;
+  margin-top: 7px;
+  height: 13px; /* fits exactly */
+  margin-bottom: 20px;
+  background: fuchsia;
+}
+
+</style>
+
+
+<div class="contain">
+  <div class="float" style="width: 100px"></div>
+  <div class="float" style="width: 200px"></div>
+  <div class="bfc"></div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/bfc-displace-1b-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<title>Test of block formatting context displacement by floats</title>
+<style>
+
+.contain {
+  border: medium solid;
+  width: 400px;
+  height: 400px;
+  background: yellow;
+}
+
+.float {
+  float: left;
+  clear: left;
+  height: 20px;
+  background: blue;
+}
+
+.bfc {
+  float: left;
+  clear: left;
+  width: 250px;
+  height: 14px; /* one pixel too tall to fit next to first float */
+  background: fuchsia;
+}
+
+</style>
+
+
+<div class="contain">
+  <div class="float" style="width: 100px"></div>
+  <div class="float" style="width: 200px"></div>
+  <div class="bfc"></div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/bfc-displace-1b.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<title>Test of block formatting context displacement by floats</title>
+<link rel="help" href="https://drafts.csswg.org/css2/visuren.html#floats">
+<meta name="assert" content="The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself.">
+<style>
+
+.contain {
+  border: medium solid;
+  width: 400px;
+  height: 400px;
+  background: yellow;
+}
+
+.float {
+  float: left;
+  clear: left;
+  height: 20px;
+  background: blue;
+}
+
+.bfc {
+  overflow: hidden;
+  width: 250px;
+  margin-top: 7px;
+  height: 14px; /* one pixel too tall to fit next to first float */
+  margin-bottom: 20px;
+  background: fuchsia;
+}
+
+</style>
+
+<div class="contain">
+  <div class="float" style="width: 100px"></div>
+  <div class="float" style="width: 200px"></div>
+  <div class="bfc"></div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/bfc-displace-2a-ref.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<title>Test of block formatting context displacement by floats</title>
+<style>
+
+.contain {
+  border: medium solid;
+  width: 400px;
+  height: 400px;
+  background: yellow;
+}
+
+.block {
+  height: 10px;
+  background: aqua;
+}
+
+.float {
+  float: left;
+  clear: left;
+  height: 20px;
+  background: blue;
+}
+
+.bfc {
+  float: left;
+  width: 250px;
+  margin-top: 7px;
+  height: 13px; /* fits exactly */
+  background: fuchsia;
+}
+
+</style>
+
+
+<div class="contain">
+  <div class="block"></div>
+  <div class="float" style="width: 100px"></div>
+  <div class="bfc"></div>
+  <div class="float" style="width: 200px"></div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/bfc-displace-2a.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<title>Test of block formatting context displacement by floats</title>
+<link rel="help" href="https://drafts.csswg.org/css2/visuren.html#floats">
+<meta name="assert" content="The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself.">
+<style>
+
+.contain {
+  border: medium solid;
+  width: 400px;
+  height: 400px;
+  background: yellow;
+}
+
+.block {
+  height: 10px;
+  background: aqua;
+}
+
+.float {
+  float: left;
+  clear: left;
+  height: 20px;
+  background: blue;
+}
+
+.bfc {
+  overflow: hidden;
+  width: 250px;
+  margin-top: 7px;
+  height: 13px; /* fits exactly */
+  margin-bottom: 20px;
+  background: fuchsia;
+}
+
+</style>
+
+
+<div class="contain">
+  <div class="block"></div>
+  <div class="float" style="width: 100px"></div>
+  <div class="float" style="width: 200px"></div>
+  <div class="bfc"></div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/bfc-displace-2b-ref.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<title>Test of block formatting context displacement by floats</title>
+<style>
+
+.contain {
+  border: medium solid;
+  width: 400px;
+  height: 400px;
+  background: yellow;
+}
+
+.block {
+  height: 10px;
+  background: aqua;
+}
+
+.float {
+  float: left;
+  clear: left;
+  height: 20px;
+  background: blue;
+}
+
+.bfc {
+  float: left;
+  clear: left;
+  width: 250px;
+  height: 14px; /* one pixel too tall to fit next to first float */
+  background: fuchsia;
+}
+
+</style>
+
+
+<div class="contain">
+  <div class="block"></div>
+  <div class="float" style="width: 100px"></div>
+  <div class="float" style="width: 200px"></div>
+  <div class="bfc"></div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/bfc-displace-2b.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<title>Test of block formatting context displacement by floats</title>
+<link rel="help" href="https://drafts.csswg.org/css2/visuren.html#floats">
+<meta name="assert" content="The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself.">
+<style>
+
+.contain {
+  border: medium solid;
+  width: 400px;
+  height: 400px;
+  background: yellow;
+}
+
+.block {
+  height: 10px;
+  background: aqua;
+}
+
+.float {
+  float: left;
+  clear: left;
+  height: 20px;
+  background: blue;
+}
+
+.bfc {
+  overflow: hidden;
+  width: 250px;
+  margin-top: 7px;
+  height: 14px; /* one pixel too tall to fit next to first float */
+  margin-bottom: 20px;
+  background: fuchsia;
+}
+
+</style>
+
+<div class="contain">
+  <div class="block"></div>
+  <div class="float" style="width: 100px"></div>
+  <div class="float" style="width: 200px"></div>
+  <div class="bfc"></div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/bfc-displace-3a-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<title>Test of block formatting context displacement by floats</title>
+<style>
+
+.contain {
+  border: medium solid;
+  width: 400px;
+  height: 400px;
+  background: yellow;
+}
+
+.float {
+  float: left;
+  clear: left;
+  height: 20px;
+  background: blue;
+}
+
+.bfc {
+  float: left;
+  width: 250px;
+  height: 20px; /* fits exactly */
+  background: fuchsia;
+}
+
+</style>
+
+
+<div class="contain">
+  <div class="float" style="width: 100px; margin-top: 7px;"></div>
+  <div class="bfc" style="margin-top: 7px"></div>
+  <div class="float" style="width: 200px"></div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/bfc-displace-3a.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<title>Test of block formatting context displacement by floats</title>
+<link rel="help" href="https://drafts.csswg.org/css2/visuren.html#floats">
+<meta name="assert" content="The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself.">
+<style>
+
+.contain {
+  border: medium solid;
+  width: 400px;
+  height: 400px;
+  background: yellow;
+}
+
+.margin {
+  margin-top: 3px;
+}
+
+.float {
+  float: left;
+  clear: left;
+  height: 20px;
+  background: blue;
+}
+
+.bfc {
+  overflow: hidden;
+  width: 250px;
+  margin-top: 7px; /* collapses */
+  height: 20px; /* fits exactly */
+  margin-bottom: 20px;
+  background: fuchsia;
+}
+
+</style>
+
+
+<div class="contain">
+  <div class="margin">
+    <div class="float" style="width: 100px"></div>
+    <div class="float" style="width: 200px"></div>
+    <div class="bfc"></div>
+  </div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/bfc-displace-3b-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<title>Test of block formatting context displacement by floats</title>
+<style>
+
+.contain {
+  border: medium solid;
+  width: 400px;
+  height: 400px;
+  background: yellow;
+}
+
+.float {
+  float: left;
+  clear: left;
+  height: 20px;
+  background: blue;
+}
+
+.bfc {
+  float: left;
+  clear: left;
+  width: 250px;
+  height: 21px; /* one pixel too tall to fit next to first float */
+  background: fuchsia;
+}
+
+</style>
+
+
+<div class="contain">
+  <div class="float" style="width: 100px; margin-top: 3px"></div>
+  <div class="float" style="width: 200px"></div>
+  <div class="bfc"></div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/bfc-displace-3b.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<title>Test of block formatting context displacement by floats</title>
+<link rel="help" href="https://drafts.csswg.org/css2/visuren.html#floats">
+<meta name="assert" content="The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself.">
+<style>
+
+.contain {
+  border: medium solid;
+  width: 400px;
+  height: 400px;
+  background: yellow;
+}
+
+.margin {
+  margin-top: 3px;
+}
+
+.float {
+  float: left;
+  clear: left;
+  height: 20px;
+  background: blue;
+}
+
+.bfc {
+  overflow: hidden;
+  width: 250px;
+  margin-top: 7px; /* does not collapse, due to clearance */
+  height: 21px; /* fits exactly */
+  margin-bottom: 20px;
+  background: fuchsia;
+}
+
+</style>
+
+
+<div class="contain">
+  <div class="margin">
+    <div class="float" style="width: 100px"></div>
+    <div class="float" style="width: 200px"></div>
+    <div class="bfc"></div>
+  </div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/bfc-shrink-1-ref.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<title>Test of block formatting context displacement by floats</title>
+<link rel="help" href="https://drafts.csswg.org/css2/visuren.html#floats">
+<meta name="assert" content="The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself.">
+<style>
+
+.contain {
+  border: medium solid;
+  width: 400px;
+  height: 400px;
+  background: yellow;
+}
+
+.float {
+  float: left;
+  clear: left;
+  height: 20px;
+  background: blue;
+}
+
+.bfc {
+  float: right;
+  width: 200px;
+  height: 50px;
+  background: fuchsia;
+}
+
+</style>
+
+
+<div class="contain">
+  <div class="bfc"></div>
+  <div class="float" style="width: 100px"></div>
+  <div class="float" style="width: 200px"></div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/bfc-shrink-1.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<title>Test of block formatting context displacement by floats</title>
+<link rel="help" href="https://drafts.csswg.org/css2/visuren.html#floats">
+<meta name="assert" content="The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself.">
+<style>
+
+.contain {
+  border: medium solid;
+  width: 400px;
+  height: 400px;
+  background: yellow;
+}
+
+.float {
+  float: left;
+  clear: left;
+  height: 20px;
+  background: blue;
+}
+
+.bfc {
+  overflow: hidden;
+  height: 50px;
+  background: fuchsia;
+}
+
+</style>
+
+
+<div class="contain">
+  <div class="float" style="width: 100px"></div>
+  <div class="float" style="width: 200px"></div>
+  <div class="bfc"></div>
+</div>
--- a/layout/reftests/floats/reftest.list
+++ b/layout/reftests/floats/reftest.list
@@ -32,16 +32,24 @@ fails == 345369-2.html 345369-2-ref.html
 == float-in-rtl-3b.html float-in-rtl-3-ref.html
 == float-in-rtl-3c.html float-in-rtl-3-ref.html
 == float-in-rtl-3d.html float-in-rtl-3-ref.html
 == float-in-rtl-4a.html float-in-rtl-4-ref.html
 == float-in-rtl-4b.html float-in-rtl-4-ref.html
 == float-in-rtl-4c.html float-in-rtl-4-ref.html
 == float-in-rtl-4d.html float-in-rtl-4-ref.html
 
+== bfc-displace-1a.html bfc-displace-1a-ref.html
+== bfc-displace-1b.html bfc-displace-1b-ref.html
+== bfc-displace-2a.html bfc-displace-2a-ref.html
+== bfc-displace-2b.html bfc-displace-2b-ref.html
+== bfc-displace-3a.html bfc-displace-3a-ref.html
+== bfc-displace-3b.html bfc-displace-3b-ref.html
+== bfc-shrink-1.html bfc-shrink-1-ref.html
+
 # Testcases that involve vertical writing mode.
 #
 # XXX The default-preferences setting here can be removed after the
 #     pref has been made true by default for all channels (bug 1138384).
 
 default-preferences pref(layout.css.vertical-text.enabled,true)
 
 == float-in-rtl-vlr-1a.html float-in-rtl-vlr-1-ref.html
--- a/layout/reftests/text-decoration/reftest.list
+++ b/layout/reftests/text-decoration/reftest.list
@@ -91,17 +91,17 @@ fuzzy-if(B2G,255,1) == dynamic-underline
 == text-decoration-zorder-1-standards.html text-decoration-zorder-1-ref.html
 == text-decoration-zorder-1-quirks.html text-decoration-zorder-1-ref.html
 == table-quirk-1.html table-quirk-1-ref.html
 == table-quirk-2.html table-quirk-2-ref.html
 == text-decoration-propagation-1-quirks.html text-decoration-propagation-1-quirks-ref.html
 == text-decoration-propagation-1-standards.html text-decoration-propagation-1-standards-ref.html
 skip-if(B2G||Mulet) == 641444-1.html 641444-1-ref.html # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop
 == decoration-css21.html decoration-css21-ref.html
-== decoration-color-override-quirks.html decoration-color-override-quirks-ref.html
+fuzzy-if(cocoaWidget,1,5) == decoration-color-override-quirks.html decoration-color-override-quirks-ref.html
 == decoration-color-override-standards.html decoration-color-override-standards-ref.html
 != decoration-color-override-standards-ref.html decoration-color-override-quirks-ref.html
 == decoration-css21-block.html decoration-css21-block-ref.html
 != inline-baseline-almost-standards.html inline-baseline-almost-standards-ref.html
 != inline-baseline-quirks.html inline-baseline-quirks-ref.html
 == 676538-1.html 676538-1-ref.html
 == underline-button-1.html underline-button-1-ref.html
 == underline-button-2.html underline-button-2-ref.html
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -53,16 +53,19 @@
 
 using namespace mozilla;
 
 typedef nsCSSProps::KTableValue KTableValue;
 
 // pref-backed bool values (hooked up in nsCSSParser::Startup)
 static bool sOpentypeSVGEnabled;
 static bool sUnprefixingServiceEnabled;
+#ifdef NIGHTLY_BUILD
+static bool sUnprefixingServiceGloballyWhitelisted;
+#endif
 static bool sMozGradientsEnabled;
 
 const uint32_t
 nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = {
 #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, \
                  stylestruct_, stylestructoffset_, animtype_)                 \
   parsevariant_,
 #define CSS_PROP_LIST_INCLUDE_LOGICAL
@@ -6661,16 +6664,23 @@ CSSParserImpl::LookupKeywordPrefixAware(
 bool
 CSSParserImpl::ShouldUseUnprefixingService()
 {
   if (!sUnprefixingServiceEnabled) {
     // Unprefixing is globally disabled.
     return false;
   }
 
+#ifdef NIGHTLY_BUILD
+  if (sUnprefixingServiceGloballyWhitelisted) {
+    // Unprefixing is globally whitelisted,
+    // so no need to check mSheetPrincipal.
+    return true;
+  }
+#endif
   // Unprefixing enabled; see if our principal is whitelisted for unprefixing.
   return mSheetPrincipal && mSheetPrincipal->IsOnCSSUnprefixingWhitelist();
 }
 
 bool
 CSSParserImpl::ParsePropertyWithUnprefixingService(
   const nsAString& aPropertyName,
   css::Declaration* aDeclaration,
@@ -15672,16 +15682,20 @@ static CSSParserImpl* gFreeList = nullpt
 
 /* static */ void
 nsCSSParser::Startup()
 {
   Preferences::AddBoolVarCache(&sOpentypeSVGEnabled,
                                "gfx.font_rendering.opentype_svg.enabled");
   Preferences::AddBoolVarCache(&sUnprefixingServiceEnabled,
                                "layout.css.unprefixing-service.enabled");
+#ifdef NIGHTLY_BUILD
+  Preferences::AddBoolVarCache(&sUnprefixingServiceGloballyWhitelisted,
+                               "layout.css.unprefixing-service.globally-whitelisted");
+#endif
   Preferences::AddBoolVarCache(&sMozGradientsEnabled,
                                "layout.css.prefixes.gradients");
 }
 
 nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader,
                          CSSStyleSheet* aSheet)
 {
   CSSParserImpl *impl = gFreeList;
--- a/layout/xul/nsStackLayout.cpp
+++ b/layout/xul/nsStackLayout.cpp
@@ -293,47 +293,49 @@ nsStackLayout::Layout(nsIFrame* aBox, ns
           //   left only - offset from left edge, preferred width
           //   right only - offset from right edge, preferred width
           //   left and right - offset from left and right edges, width in between this
           //   neither - no offset, full width of stack
           // Vertical direction is similar.
           //
           // Margins on the child are also included in the edge offsets
           if (offsetSpecified) {
+            nsSize min = child->GetMinSize(aState);
+            nsSize max = child->GetMaxSize(aState);
             if (offsetSpecified & SPECIFIED_LEFT) {
               childRect.x = clientRect.x + offset.left + margin.left;
               if (offsetSpecified & SPECIFIED_RIGHT) {
-                nsSize min = child->GetMinSize(aState);
-                nsSize max = child->GetMaxSize(aState);
                 nscoord width = clientRect.width - offset.LeftRight() - margin.LeftRight();
                 childRect.width = clamped(width, min.width, max.width);
               }
               else {
-                childRect.width = child->GetPrefSize(aState).width;
+                nscoord width = child->GetPrefSize(aState).width;
+                childRect.width = clamped(width, min.width, max.width);
               }
             }
             else if (offsetSpecified & SPECIFIED_RIGHT) {
-              childRect.width = child->GetPrefSize(aState).width;
+              nscoord width = child->GetPrefSize(aState).width;
+              childRect.width = clamped(width, min.width, max.width);
               childRect.x = clientRect.XMost() - offset.right - margin.right - childRect.width;
             }
 
             if (offsetSpecified & SPECIFIED_TOP) {
               childRect.y = clientRect.y + offset.top + margin.top;
               if (offsetSpecified & SPECIFIED_BOTTOM) {
-                nsSize min = child->GetMinSize(aState);
-                nsSize max = child->GetMaxSize(aState);
                 nscoord height = clientRect.height - offset.TopBottom() - margin.TopBottom();
                 childRect.height = clamped(height, min.height, max.height);
               }
               else {
-                childRect.height = child->GetPrefSize(aState).height;
+                nscoord height = child->GetPrefSize(aState).height;
+                childRect.height = clamped(height, min.height, max.height);
               }
             }
             else if (offsetSpecified & SPECIFIED_BOTTOM) {
-              childRect.height = child->GetPrefSize(aState).height;
+              nscoord height = child->GetPrefSize(aState).height;
+              childRect.height = clamped(height, min.height, max.height);
               childRect.y = clientRect.YMost() - offset.bottom - margin.bottom - childRect.height;
             }
           }
 
           // Now place the child.
           child->SetBounds(aState, childRect);
 
           // Flow the child.
--- a/media/libcubeb/src/cubeb_opensl.c
+++ b/media/libcubeb/src/cubeb_opensl.c
@@ -666,20 +666,18 @@ opensl_stream_init(cubeb * ctx, cubeb_st
 
   *stream = stm;
   return CUBEB_OK;
 }
 
 static void
 opensl_stream_destroy(cubeb_stream * stm)
 {
-  if (stm->playerObj) {
-    (*stm->bufq)->Clear(stm->bufq);
+  if (stm->playerObj)
     (*stm->playerObj)->Destroy(stm->playerObj);
-  }
   int i;
   for (i = 0; i < NBUFS; i++) {
     free(stm->queuebuf[i]);
   }