merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 13 Jan 2015 14:24:21 +0100
changeset 223526 a5700bec72e1e279ceb2d8255bee5e688cda8b3e
parent 223427 60558300fd6ab64cb43d3e7a0fd9e4f4c610b0f6 (current diff)
parent 223525 a638073e104d6b17af554b98485fe6e84db5dbef (diff)
child 223537 0500f1032ea1f51c42b940cc6b25696cb9064c3e
push id28095
push usercbook@mozilla.com
push dateTue, 13 Jan 2015 13:24:48 +0000
treeherdermozilla-central@a5700bec72e1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
dom/base/test/test_DOMException.html
layout/generic/RubyReflowState.cpp
layout/generic/RubyReflowState.h
testing/web-platform/meta/XMLHttpRequest/open-method-responsetype-set-sync.htm.ini
testing/web-platform/meta/XMLHttpRequest/responsetype.html.ini
testing/web-platform/meta/XMLHttpRequest/responsexml-non-document-types.htm.ini
--- a/accessible/base/nsAccessibilityService.h
+++ b/accessible/base/nsAccessibilityService.h
@@ -6,16 +6,17 @@
 #ifndef __nsAccessibilityService_h__
 #define __nsAccessibilityService_h__
 
 #include "nsIAccessibilityService.h"
 
 #include "mozilla/a11y/DocManager.h"
 #include "mozilla/a11y/FocusManager.h"
 #include "mozilla/a11y/SelectionManager.h"
+#include "mozilla/Preferences.h"
 
 #include "nsIObserver.h"
 
 class nsImageFrame;
 class nsPluginFrame;
 class nsITreeView;
 
 namespace mozilla {
@@ -249,17 +250,18 @@ GetAccService()
  * Return true if we're in a content process and not B2G.
  */
 inline bool
 IPCAccessibilityActive()
 {
 #ifdef MOZ_B2G
   return false;
 #else
-  return XRE_GetProcessType() == GeckoProcessType_Content;
+  return XRE_GetProcessType() == GeckoProcessType_Content &&
+    mozilla::Preferences::GetBool("accessibility.ipc_architecture.enabled", true);
 #endif
 }
 
 /**
  * Map nsIAccessibleEvents constants to strings. Used by
  * nsIAccessibleRetrieval::getStringEventType() method.
  */
 static const char kEventTypeNames[][40] = {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1090,19 +1090,16 @@ var gBrowserInit = {
     // will be fired.
     gBrowser.addEventListener("MozApplicationManifest",
                               OfflineApps, false);
     // listen for offline apps on social
     let socialBrowser = document.getElementById("social-sidebar-browser");
     socialBrowser.addEventListener("MozApplicationManifest",
                               OfflineApps, false);
 
-    let uriToLoad = this._getUriToLoad();
-    var isLoadingBlank = isBlankPageURL(uriToLoad);
-
     // This pageshow listener needs to be registered before we may call
     // swapBrowsersAndCloseOther() to receive pageshow events fired by that.
     let mm = window.messageManager;
     mm.addMessageListener("PageVisibility:Show", function(message) {
       if (message.target == gBrowser.selectedBrowser) {
         setTimeout(pageShowEventHandlers, 0, message.data.persisted);
       }
     });
@@ -1130,16 +1127,17 @@ var gBrowserInit = {
       if (event.detail.sendCrashReport) {
         TabCrashReporter.submitCrashReport(browser);
       }
 #endif
       let tab = gBrowser.getTabForBrowser(browser);
       SessionStore.reviveCrashedTab(tab);
     }, false, true);
 
+    let uriToLoad = this._getUriToLoad();
     if (uriToLoad && uriToLoad != "about:blank") {
       if (uriToLoad instanceof Ci.nsISupportsArray) {
         let count = uriToLoad.Count();
         let specs = [];
         for (let i = 0; i < count; i++) {
           let urisstring = uriToLoad.GetElementAt(i).QueryInterface(Ci.nsISupportsString);
           specs.push(urisstring.data);
         }
@@ -1214,18 +1212,20 @@ var gBrowserInit = {
     if (mustLoadSidebar) {
       let sidebar = document.getElementById("sidebar");
       let sidebarBox = document.getElementById("sidebar-box");
       sidebar.setAttribute("src", sidebarBox.getAttribute("src"));
     }
 
     UpdateUrlbarSearchSplitterState();
 
-    if (!isLoadingBlank || !focusAndSelectUrlBar())
+    if (!(isBlankPageURL(uriToLoad) || uriToLoad == "about:privatebrowsing") ||
+        !focusAndSelectUrlBar()) {
       gBrowser.selectedBrowser.focus();
+    }
 
     // Set up Sanitize Item
     this._initializeSanitizer();
 
     // Enable/Disable auto-hide tabbar
     gBrowser.tabContainer.updateVisibility();
 
     BookmarkingUI.init();
--- a/browser/base/content/test/general/browser_bug767836_perwindowpb.js
+++ b/browser/base/content/test/general/browser_bug767836_perwindowpb.js
@@ -24,23 +24,18 @@ function test() {
       is(aWindow.gBrowser.selectedBrowser.currentURI.spec, newTabURL,
         "URL of NewTab should be " + newTabURL + " in " + mode +  " mode");
       // Set the custom newtab url
       Services.prefs.setCharPref(newTabPrefName, testURL);
       ok(Services.prefs.prefHasUserValue(newTabPrefName), "Custom newtab url is set");
 
       // Open a newtab after setting the custom newtab url
       openNewTab(aWindow, function () {
-        if (aIsPrivateMode) {
-          is(aWindow.gBrowser.selectedBrowser.currentURI.spec, newTabURL,
-             "URL of NewTab should always be " + newTabURL + " in " + mode +  " mode");
-        } else {
-          is(aWindow.gBrowser.selectedBrowser.currentURI.spec, testURL,
-             "URL of NewTab should be the custom url");
-        }
+        is(aWindow.gBrowser.selectedBrowser.currentURI.spec, testURL,
+           "URL of NewTab should be the custom url");
 
         // clear the custom url preference
         Services.prefs.clearUserPref(newTabPrefName);
         ok(!Services.prefs.prefHasUserValue(newTabPrefName), "No custom newtab url is set");
 
         aWindow.gBrowser.removeTab(aWindow.gBrowser.selectedTab);
         aWindow.gBrowser.removeTab(aWindow.gBrowser.selectedTab);
         aWindow.close();
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -9,17 +9,18 @@ Components.utils.import("resource://gre/
 Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 Components.utils.import("resource:///modules/RecentWindow.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "BROWSER_NEW_TAB_URL", function () {
   const PREF = "browser.newtab.url";
 
   function getNewTabPageURL() {
     if (PrivateBrowsingUtils.isWindowPrivate(window) &&
-        !PrivateBrowsingUtils.permanentPrivateBrowsing) {
+        !PrivateBrowsingUtils.permanentPrivateBrowsing &&
+        !Services.prefs.prefHasUserValue(PREF)) {
       return "about:privatebrowsing";
     }
 
     let url = Services.prefs.getComplexValue(PREF, Ci.nsISupportsString).data;
     return url || "about:blank";
   }
 
   function update() {
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -468,30 +468,35 @@ class ShutdownLeaks(object):
   def process(self):
     if not self.seenShutdown:
       self.logger.warning("TEST-UNEXPECTED-FAIL | ShutdownLeaks | process() called before end of test suite")
 
     for test in self._parseLeakingTests():
       for url, count in self._zipLeakedWindows(test["leakedWindows"]):
         self.logger.warning("TEST-UNEXPECTED-FAIL | %s | leaked %d window(s) until shutdown [url = %s]" % (test["fileName"], count, url))
 
+      if test["leakedWindowsString"]:
+        self.logger.info("TEST-INFO | %s | windows(s) leaked: %s" % (test["fileName"], test["leakedWindowsString"]))
+
       if test["leakedDocShells"]:
         self.logger.warning("TEST-UNEXPECTED-FAIL | %s | leaked %d docShell(s) until shutdown" % (test["fileName"], len(test["leakedDocShells"])))
+        self.logger.info("TEST-INFO | %s | docShell(s) leaked: %s" % (test["fileName"],
+                                                                      ', '.join(["[pid = %s] [id = %s]" % x for x in test["leakedDocShells"]])))
 
   def _logWindow(self, line):
     created = line[:2] == "++"
     pid = self._parseValue(line, "pid")
     serial = self._parseValue(line, "serial")
 
     # log line has invalid format
     if not pid or not serial:
       self.logger.warning("TEST-UNEXPECTED-FAIL | ShutdownLeaks | failed to parse line <%s>" % line)
       return
 
-    key = pid + "." + serial
+    key = (pid, serial)
 
     if self.currentTest:
       windows = self.currentTest["windows"]
       if created:
         windows.add(key)
       else:
         windows.discard(key)
     elif self.seenShutdown and not created:
@@ -502,17 +507,17 @@ class ShutdownLeaks(object):
     pid = self._parseValue(line, "pid")
     id = self._parseValue(line, "id")
 
     # log line has invalid format
     if not pid or not id:
       self.logger.warning("TEST-UNEXPECTED-FAIL | ShutdownLeaks | failed to parse line <%s>" % line)
       return
 
-    key = pid + "." + id
+    key = (pid, id)
 
     if self.currentTest:
       docShells = self.currentTest["docShells"]
       if created:
         docShells.add(key)
       else:
         docShells.discard(key)
     elif self.seenShutdown and not created:
@@ -523,17 +528,19 @@ class ShutdownLeaks(object):
     if match:
       return match.group(1)
     return None
 
   def _parseLeakingTests(self):
     leakingTests = []
 
     for test in self.tests:
-      test["leakedWindows"] = [self.leakedWindows[id] for id in test["windows"] if id in self.leakedWindows]
+      leakedWindows = [id for id in test["windows"] if id in self.leakedWindows]
+      test["leakedWindows"] = [self.leakedWindows[id] for id in leakedWindows]
+      test["leakedWindowsString"] = ', '.join(["[pid = %s] [serial = %s]" % x for x in leakedWindows])
       test["leakedDocShells"] = [id for id in test["docShells"] if id in self.leakedDocShells]
       test["leakCount"] = len(test["leakedWindows"]) + len(test["leakedDocShells"])
 
       if test["leakCount"]:
         leakingTests.append(test)
 
     return sorted(leakingTests, key=itemgetter("leakCount"), reverse=True)
 
--- a/caps/nsNullPrincipalURI.h
+++ b/caps/nsNullPrincipalURI.h
@@ -26,18 +26,18 @@
 class nsNullPrincipalURI MOZ_FINAL : public nsIURI
                                    , public nsISizeOf
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIURI
 
   // nsISizeOf
-  virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
-  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+  virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
+  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
 
   explicit nsNullPrincipalURI(const nsCString &aSpec);
 
 private:
   ~nsNullPrincipalURI() {}
 
   nsCString mScheme;
   nsCString mPath;
--- a/caps/nsPrincipal.h
+++ b/caps/nsPrincipal.h
@@ -44,35 +44,35 @@ protected:
   nsCOMPtr<nsIContentSecurityPolicy> mCSP;
 };
 
 class nsPrincipal MOZ_FINAL : public nsBasePrincipal
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSISERIALIZABLE
-  NS_IMETHOD Equals(nsIPrincipal* other, bool* _retval);
-  NS_IMETHOD EqualsConsideringDomain(nsIPrincipal* other, bool* _retval);
-  NS_IMETHOD GetHashValue(uint32_t* aHashValue);
-  NS_IMETHOD GetURI(nsIURI** aURI);
-  NS_IMETHOD GetDomain(nsIURI** aDomain);
-  NS_IMETHOD SetDomain(nsIURI* aDomain);
-  NS_IMETHOD GetOrigin(char** aOrigin);
-  NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval);
-  NS_IMETHOD SubsumesConsideringDomain(nsIPrincipal* other, bool* _retval);
-  NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal);
-  NS_IMETHOD GetJarPrefix(nsACString& aJarPrefix);
-  NS_IMETHOD GetAppStatus(uint16_t* aAppStatus);
-  NS_IMETHOD GetAppId(uint32_t* aAppStatus);
-  NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
-  NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId);
-  NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal);
-  NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain);
+  NS_IMETHOD Equals(nsIPrincipal* other, bool* _retval) MOZ_OVERRIDE;
+  NS_IMETHOD EqualsConsideringDomain(nsIPrincipal* other, bool* _retval) MOZ_OVERRIDE;
+  NS_IMETHOD GetHashValue(uint32_t* aHashValue) MOZ_OVERRIDE;
+  NS_IMETHOD GetURI(nsIURI** aURI) MOZ_OVERRIDE;
+  NS_IMETHOD GetDomain(nsIURI** aDomain) MOZ_OVERRIDE;
+  NS_IMETHOD SetDomain(nsIURI* aDomain) MOZ_OVERRIDE;
+  NS_IMETHOD GetOrigin(char** aOrigin) MOZ_OVERRIDE;
+  NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval) MOZ_OVERRIDE;
+  NS_IMETHOD SubsumesConsideringDomain(nsIPrincipal* other, bool* _retval) MOZ_OVERRIDE;
+  NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal) MOZ_OVERRIDE;
+  NS_IMETHOD GetJarPrefix(nsACString& aJarPrefix) MOZ_OVERRIDE;
+  NS_IMETHOD GetAppStatus(uint16_t* aAppStatus) MOZ_OVERRIDE;
+  NS_IMETHOD GetAppId(uint32_t* aAppStatus) MOZ_OVERRIDE;
+  NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement) MOZ_OVERRIDE;
+  NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId) MOZ_OVERRIDE;
+  NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal) MOZ_OVERRIDE;
+  NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) MOZ_OVERRIDE;
 #ifdef DEBUG
-  virtual void dumpImpl();
+  virtual void dumpImpl() MOZ_OVERRIDE;
 #endif
 
   nsPrincipal();
 
   // Init() must be called before the principal is in a usable state.
   nsresult Init(nsIURI* aCodebase,
                 uint32_t aAppId,
                 bool aInMozBrowser);
@@ -127,35 +127,35 @@ public:
 
 protected:
   virtual ~nsExpandedPrincipal();
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIEXPANDEDPRINCIPAL
   NS_DECL_NSISERIALIZABLE
-  NS_IMETHOD Equals(nsIPrincipal* other, bool* _retval);
-  NS_IMETHOD EqualsConsideringDomain(nsIPrincipal* other, bool* _retval);
-  NS_IMETHOD GetHashValue(uint32_t* aHashValue);
-  NS_IMETHOD GetURI(nsIURI** aURI);
-  NS_IMETHOD GetDomain(nsIURI** aDomain);
-  NS_IMETHOD SetDomain(nsIURI* aDomain);
-  NS_IMETHOD GetOrigin(char** aOrigin);
-  NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval);
-  NS_IMETHOD SubsumesConsideringDomain(nsIPrincipal* other, bool* _retval);
-  NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal);
-  NS_IMETHOD GetJarPrefix(nsACString& aJarPrefix);
-  NS_IMETHOD GetAppStatus(uint16_t* aAppStatus);
-  NS_IMETHOD GetAppId(uint32_t* aAppStatus);
-  NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement);
-  NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId);
-  NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal);
-  NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain);
+  NS_IMETHOD Equals(nsIPrincipal* other, bool* _retval) MOZ_OVERRIDE;
+  NS_IMETHOD EqualsConsideringDomain(nsIPrincipal* other, bool* _retval) MOZ_OVERRIDE;
+  NS_IMETHOD GetHashValue(uint32_t* aHashValue) MOZ_OVERRIDE;
+  NS_IMETHOD GetURI(nsIURI** aURI) MOZ_OVERRIDE;
+  NS_IMETHOD GetDomain(nsIURI** aDomain) MOZ_OVERRIDE;
+  NS_IMETHOD SetDomain(nsIURI* aDomain) MOZ_OVERRIDE;
+  NS_IMETHOD GetOrigin(char** aOrigin) MOZ_OVERRIDE;
+  NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval) MOZ_OVERRIDE;
+  NS_IMETHOD SubsumesConsideringDomain(nsIPrincipal* other, bool* _retval) MOZ_OVERRIDE;
+  NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal) MOZ_OVERRIDE;
+  NS_IMETHOD GetJarPrefix(nsACString& aJarPrefix) MOZ_OVERRIDE;
+  NS_IMETHOD GetAppStatus(uint16_t* aAppStatus) MOZ_OVERRIDE;
+  NS_IMETHOD GetAppId(uint32_t* aAppStatus) MOZ_OVERRIDE;
+  NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement) MOZ_OVERRIDE;
+  NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId) MOZ_OVERRIDE;
+  NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal) MOZ_OVERRIDE;
+  NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) MOZ_OVERRIDE;
 #ifdef DEBUG
-  virtual void dumpImpl();
+  virtual void dumpImpl() MOZ_OVERRIDE;
 #endif
   
   virtual void GetScriptLocation(nsACString &aStr) MOZ_OVERRIDE;
 
 private:
   nsTArray< nsCOMPtr<nsIPrincipal> > mPrincipals;
 };
 
--- a/chrome/nsChromeRegistry.h
+++ b/chrome/nsChromeRegistry.h
@@ -42,26 +42,26 @@ class nsChromeRegistry : public nsIToolk
 #endif
                          public nsIObserver,
                          public nsSupportsWeakReference
 {
 public:
   NS_DECL_ISUPPORTS
 
   // nsIXULChromeRegistry methods:
-  NS_IMETHOD ReloadChrome();
-  NS_IMETHOD RefreshSkins();
+  NS_IMETHOD ReloadChrome() MOZ_OVERRIDE;
+  NS_IMETHOD RefreshSkins() MOZ_OVERRIDE;
   NS_IMETHOD AllowScriptsForPackage(nsIURI* url,
-                                    bool* _retval);
+                                    bool* _retval) MOZ_OVERRIDE;
   NS_IMETHOD AllowContentToAccess(nsIURI* url,
-                                  bool* _retval);
+                                  bool* _retval) MOZ_OVERRIDE;
 
   // nsIChromeRegistry methods:
-  NS_IMETHOD_(bool) WrappersEnabled(nsIURI *aURI);
-  NS_IMETHOD ConvertChromeURL(nsIURI* aChromeURI, nsIURI* *aResult);
+  NS_IMETHOD_(bool) WrappersEnabled(nsIURI *aURI) MOZ_OVERRIDE;
+  NS_IMETHOD ConvertChromeURL(nsIURI* aChromeURI, nsIURI* *aResult) MOZ_OVERRIDE;
 
   // nsChromeRegistry methods:
   nsChromeRegistry() : mInitialized(false) { }
 
   virtual nsresult Init();
 
   static already_AddRefed<nsIChromeRegistry> GetService();
 
--- a/chrome/nsChromeRegistryChrome.h
+++ b/chrome/nsChromeRegistryChrome.h
@@ -162,30 +162,30 @@ class nsChromeRegistryChrome : public ns
   nsCString mSelectedLocale;
   nsCString mSelectedSkin;
 
   // Hash of package names ("global") to PackageEntry objects
   nsClassHashtable<nsCStringHashKey, PackageEntry> mPackagesHash;
 
   virtual void ManifestContent(ManifestProcessingContext& cx, int lineno,
                                char *const * argv, bool platform,
-                               bool contentaccessible);
+                               bool contentaccessible) MOZ_OVERRIDE;
   virtual void ManifestLocale(ManifestProcessingContext& cx, int lineno,
                               char *const * argv, bool platform,
-                              bool contentaccessible);
+                              bool contentaccessible) MOZ_OVERRIDE;
   virtual void ManifestSkin(ManifestProcessingContext& cx, int lineno,
                             char *const * argv, bool platform,
-                            bool contentaccessible);
+                            bool contentaccessible) MOZ_OVERRIDE;
   virtual void ManifestOverlay(ManifestProcessingContext& cx, int lineno,
                                char *const * argv, bool platform,
-                               bool contentaccessible);
+                               bool contentaccessible) MOZ_OVERRIDE;
   virtual void ManifestStyle(ManifestProcessingContext& cx, int lineno,
                              char *const * argv, bool platform,
-                             bool contentaccessible);
+                             bool contentaccessible) MOZ_OVERRIDE;
   virtual void ManifestOverride(ManifestProcessingContext& cx, int lineno,
                                 char *const * argv, bool platform,
-                                bool contentaccessible);
+                                bool contentaccessible) MOZ_OVERRIDE;
   virtual void ManifestResource(ManifestProcessingContext& cx, int lineno,
                                 char *const * argv, bool platform,
-                                bool contentaccessible);
+                                bool contentaccessible) MOZ_OVERRIDE;
 };
 
 #endif // nsChromeRegistryChrome_h
--- a/chrome/nsChromeRegistryContent.h
+++ b/chrome/nsChromeRegistryContent.h
@@ -61,30 +61,30 @@ class nsChromeRegistryContent : public n
                      const nsCString& aPath) MOZ_OVERRIDE;
   nsresult GetFlagsFromPackage(const nsCString& aPackage, uint32_t* aFlags) MOZ_OVERRIDE;
 
   nsClassHashtable<nsCStringHashKey, PackageEntry> mPackagesHash;
   nsCString mLocale;
 
   virtual void ManifestContent(ManifestProcessingContext& cx, int lineno,
                                char *const * argv, bool platform,
-                               bool contentaccessible);
+                               bool contentaccessible) MOZ_OVERRIDE;
   virtual void ManifestLocale(ManifestProcessingContext& cx, int lineno,
                               char *const * argv, bool platform,
-                              bool contentaccessible);
+                              bool contentaccessible) MOZ_OVERRIDE;
   virtual void ManifestSkin(ManifestProcessingContext& cx, int lineno,
                             char *const * argv, bool platform,
-                            bool contentaccessible);
+                            bool contentaccessible) MOZ_OVERRIDE;
   virtual void ManifestOverlay(ManifestProcessingContext& cx, int lineno,
                                char *const * argv, bool platform,
-                               bool contentaccessible);
+                               bool contentaccessible) MOZ_OVERRIDE;
   virtual void ManifestStyle(ManifestProcessingContext& cx, int lineno,
                              char *const * argv, bool platform,
-                             bool contentaccessible);
+                             bool contentaccessible) MOZ_OVERRIDE;
   virtual void ManifestOverride(ManifestProcessingContext& cx, int lineno,
                                 char *const * argv, bool platform,
-                                bool contentaccessible);
+                                bool contentaccessible) MOZ_OVERRIDE;
   virtual void ManifestResource(ManifestProcessingContext& cx, int lineno,
                                 char *const * argv, bool platform,
-                                bool contentaccessible);
+                                bool contentaccessible) MOZ_OVERRIDE;
 };
 
 #endif // nsChromeRegistryContent_h
--- a/docshell/base/IHistory.h
+++ b/docshell/base/IHistory.h
@@ -127,20 +127,20 @@ public:
      */
     NS_IMETHOD NotifyVisited(nsIURI* aURI) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(IHistory, IHISTORY_IID)
 
 #define NS_DECL_IHISTORY \
     NS_IMETHOD RegisterVisitedCallback(nsIURI *aURI, \
-                                       mozilla::dom::Link *aContent); \
+                                       mozilla::dom::Link *aContent) MOZ_OVERRIDE; \
     NS_IMETHOD UnregisterVisitedCallback(nsIURI *aURI, \
-                                         mozilla::dom::Link *aContent); \
+                                         mozilla::dom::Link *aContent) MOZ_OVERRIDE; \
     NS_IMETHOD VisitURI(nsIURI *aURI, \
                         nsIURI *aLastVisitedURI, \
-                        uint32_t aFlags); \
-    NS_IMETHOD SetURITitle(nsIURI* aURI, const nsAString& aTitle); \
-    NS_IMETHOD NotifyVisited(nsIURI* aURI);
+                        uint32_t aFlags) MOZ_OVERRIDE; \
+    NS_IMETHOD SetURITitle(nsIURI* aURI, const nsAString& aTitle) MOZ_OVERRIDE; \
+    NS_IMETHOD NotifyVisited(nsIURI* aURI) MOZ_OVERRIDE;
 
 } // namespace mozilla
 
 #endif // mozilla_IHistory_h_
--- a/dom/audiochannel/tests/TestAudioChannelService.cpp
+++ b/dom/audiochannel/tests/TestAudioChannelService.cpp
@@ -98,24 +98,24 @@ public:
   nsresult SetVisibilityState(bool visible)
   {
     if (mRegistered) {
       mWaitCallback = true;
     }
     return mAgent->SetVisibilityState(visible);
   }
 
-  NS_IMETHODIMP CanPlayChanged(int32_t canPlay)
+  NS_IMETHODIMP CanPlayChanged(int32_t canPlay) MOZ_OVERRIDE
   {
     mCanPlay = static_cast<AudioChannelState>(canPlay);
     mWaitCallback = false;
     return NS_OK;
   }
 
-  NS_IMETHODIMP WindowVolumeChanged()
+  NS_IMETHODIMP WindowVolumeChanged() MOZ_OVERRIDE
   {
     return NS_OK;
   }
 
   nsresult GetCanPlay(AudioChannelState *_ret, bool aWaitCallback = false)
   {
     if (aWaitCallback) {
       mWaitCallback = true;
--- a/dom/base/Link.cpp
+++ b/dom/base/Link.cpp
@@ -436,18 +436,20 @@ Link::GetHash(nsAString &_hash, ErrorRes
     // Do not throw!  Not having a valid URI should result in an empty
     // string.
     return;
   }
 
   nsAutoCString ref;
   nsresult rv = uri->GetRef(ref);
   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
-    NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
     _hash.Assign(char16_t('#'));
+    if (nsContentUtils::EncodeDecodeURLHash()) {
+      NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
+    }
     AppendUTF8toUTF16(ref, _hash);
   }
 }
 
 void
 Link::ResetLinkState(bool aNotify, bool aHasHref)
 {
   nsLinkState defaultState;
--- a/dom/base/URL.cpp
+++ b/dom/base/URL.cpp
@@ -509,18 +509,20 @@ URL::SetSearchParams(URLSearchParams& aS
 void
 URL::GetHash(nsString& aHash, ErrorResult& aRv) const
 {
   aHash.Truncate();
 
   nsAutoCString ref;
   nsresult rv = mURI->GetRef(ref);
   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
-    NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
     aHash.Assign(char16_t('#'));
+    if (nsContentUtils::EncodeDecodeURLHash()) {
+      NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
+    }
     AppendUTF8toUTF16(ref, aHash);
   }
 }
 
 void
 URL::SetHash(const nsAString& aHash, ErrorResult& aRv)
 {
   mURI->SetRef(NS_ConvertUTF16toUTF8(aHash));
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -238,16 +238,17 @@ nsString* nsContentUtils::sModifierSepar
 
 bool nsContentUtils::sInitialized = false;
 bool nsContentUtils::sIsFullScreenApiEnabled = false;
 bool nsContentUtils::sTrustedFullScreenOnly = true;
 bool nsContentUtils::sFullscreenApiIsContentOnly = false;
 bool nsContentUtils::sIsPerformanceTimingEnabled = false;
 bool nsContentUtils::sIsResourceTimingEnabled = false;
 bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false;
+bool nsContentUtils::sEncodeDecodeURLHash = false;
 
 uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
 
 nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr;
 nsIParser* nsContentUtils::sXMLFragmentParser = nullptr;
 nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr;
 bool nsContentUtils::sFragmentParsingActive = false;
 
@@ -515,16 +516,19 @@ nsContentUtils::Init()
                                "dom.enable_performance", true);
 
   Preferences::AddBoolVarCache(&sIsResourceTimingEnabled,
                                "dom.enable_resource_timing", true);
 
   Preferences::AddBoolVarCache(&sIsExperimentalAutocompleteEnabled,
                                "dom.forms.autocomplete.experimental", false);
 
+  Preferences::AddBoolVarCache(&sEncodeDecodeURLHash,
+                               "dom.url.encode_decode_hash", false);
+
   Preferences::AddUintVarCache(&sHandlingInputTimeout,
                                "dom.event.handling-user-input-time-limit",
                                1000);
 
 #if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
   Preferences::AddBoolVarCache(&sDOMWindowDumpEnabled,
                                "browser.dom.window.dump.enabled");
 #endif
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1855,16 +1855,25 @@ public:
   /*
    * Returns true if the performance timing APIs are enabled.
    */
   static bool IsResourceTimingEnabled()
   {
     return sIsResourceTimingEnabled;
   }
 
+  /*
+   * Returns true if URL setters should percent encode the Hash/Ref segment
+   * and getters should return the percent decoded value of the segment
+   */
+  static bool EncodeDecodeURLHash()
+  {
+    return sEncodeDecodeURLHash;
+  }
+
   /**
    * Returns true if the doc tree branch which contains aDoc contains any
    * plugins which we don't control event dispatch for, i.e. do any plugins
    * in the same tab as this document receive key events outside of our
    * control? This always returns false on MacOSX.
    */
   static bool HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc);
 
@@ -2318,16 +2327,17 @@ private:
   static bool sAllowXULXBL_for_file;
   static bool sIsFullScreenApiEnabled;
   static bool sTrustedFullScreenOnly;
   static bool sFullscreenApiIsContentOnly;
   static uint32_t sHandlingInputTimeout;
   static bool sIsPerformanceTimingEnabled;
   static bool sIsResourceTimingEnabled;
   static bool sIsExperimentalAutocompleteEnabled;
+  static bool sEncodeDecodeURLHash;
 
   static nsHtml5StringParser* sHTMLFragmentParser;
   static nsIParser* sXMLFragmentParser;
   static nsIFragmentContentSink* sXMLFragmentSink;
 
   /**
    * True if there's a fragment parser activation on the stack.
    */
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -2300,17 +2300,17 @@ nsFrameLoader::CreateStaticClone(nsIFram
 
   viewer->SetDOMDocument(clonedDOMDoc);
   return NS_OK;
 }
 
 bool
 nsFrameLoader::DoLoadFrameScript(const nsAString& aURL, bool aRunInGlobalScope)
 {
-  mozilla::dom::PBrowserParent* tabParent = GetRemoteBrowser();
+  auto* tabParent = static_cast<TabParent*>(GetRemoteBrowser());
   if (tabParent) {
     return tabParent->SendLoadRemoteScript(nsString(aURL), aRunInGlobalScope);
   }
   nsRefPtr<nsInProcessTabChildGlobal> tabChild =
     static_cast<nsInProcessTabChildGlobal*>(GetTabChildGlobalAsEventTarget());
   if (tabChild) {
     tabChild->LoadFrameScript(aURL, aRunInGlobalScope);
   }
--- a/dom/base/nsLocation.cpp
+++ b/dom/base/nsLocation.cpp
@@ -293,38 +293,46 @@ nsLocation::GetHash(nsAString& aHash)
   if (NS_FAILED(rv) || !uri) {
     return rv;
   }
 
   nsAutoCString ref;
   nsAutoString unicodeRef;
 
   rv = uri->GetRef(ref);
-  if (NS_SUCCEEDED(rv)) {
-    nsCOMPtr<nsITextToSubURI> textToSubURI(
-        do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
 
+  if (nsContentUtils::EncodeDecodeURLHash()) {
     if (NS_SUCCEEDED(rv)) {
-      nsAutoCString charset;
-      uri->GetOriginCharset(charset);
-        
-      rv = textToSubURI->UnEscapeURIForUI(charset, ref, unicodeRef);
+      nsCOMPtr<nsITextToSubURI> textToSubURI(
+          do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
+
+      if (NS_SUCCEEDED(rv)) {
+        nsAutoCString charset;
+        uri->GetOriginCharset(charset);
+
+        rv = textToSubURI->UnEscapeURIForUI(charset, ref, unicodeRef);
+      }
+
+      if (NS_FAILED(rv)) {
+        // Oh, well.  No intl here!
+        NS_UnescapeURL(ref);
+        CopyASCIItoUTF16(ref, unicodeRef);
+        rv = NS_OK;
+      }
     }
-      
-    if (NS_FAILED(rv)) {
-      // Oh, well.  No intl here!
-      NS_UnescapeURL(ref);
-      CopyASCIItoUTF16(ref, unicodeRef);
-      rv = NS_OK;
+
+    if (NS_SUCCEEDED(rv) && !unicodeRef.IsEmpty()) {
+      aHash.Assign(char16_t('#'));
+      aHash.Append(unicodeRef);
     }
-  }
-
-  if (NS_SUCCEEDED(rv) && !unicodeRef.IsEmpty()) {
-    aHash.Assign(char16_t('#'));
-    aHash.Append(unicodeRef);
+  } else { // URL Hash should simply return the value of the Ref segment
+    if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
+      aHash.Assign(char16_t('#'));
+      AppendUTF8toUTF16(ref, aHash);
+    }
   }
 
   if (aHash == mCachedHash) {
     // Work around ShareThis stupidly polling location.hash every
     // 5ms all the time by handing out the same exact string buffer
     // we handed out last time.
     aHash = mCachedHash;
   } else {
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -283,17 +283,18 @@ nsXMLHttpRequestUpload::WrapObject(JSCon
 /////////////////////////////////////////////
 
 bool
 nsXMLHttpRequest::sDontWarnAboutSyncXHR = false;
 
 nsXMLHttpRequest::nsXMLHttpRequest()
   : mResponseBodyDecodedPos(0),
     mResponseType(XML_HTTP_RESPONSE_TYPE_DEFAULT),
-    mRequestObserver(nullptr), mState(XML_HTTP_REQUEST_UNSENT),
+    mRequestObserver(nullptr),
+    mState(XML_HTTP_REQUEST_UNSENT | XML_HTTP_REQUEST_ASYNC),
     mUploadTransferred(0), mUploadTotal(0), mUploadComplete(true),
     mProgressSinceLastProgressEvent(false),
     mRequestSentTime(0), mTimeoutMilliseconds(0),
     mErrorLoad(false), mWaitingForOnStopRequest(false),
     mProgressTimerIsActive(false),
     mIsHtml(false),
     mWarnAboutSyncHtml(false),
     mLoadLengthComputable(false), mLoadTotal(0),
@@ -910,20 +911,19 @@ nsXMLHttpRequest::SetResponseType(XMLHtt
 {
   SetResponseType(ResponseTypeEnum(static_cast<int>(aType)), aRv);
 }
 
 void
 nsXMLHttpRequest::SetResponseType(nsXMLHttpRequest::ResponseTypeEnum aResponseType,
                                   ErrorResult& aRv)
 {
-  // If the state is not OPENED or HEADERS_RECEIVED raise an
-  // INVALID_STATE_ERR exception and terminate these steps.
-  if (!(mState & (XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT |
-                  XML_HTTP_REQUEST_HEADERS_RECEIVED))) {
+  // If the state is LOADING or DONE raise an INVALID_STATE_ERR exception
+  // and terminate these steps.
+  if ((mState & (XML_HTTP_REQUEST_LOADING | XML_HTTP_REQUEST_DONE))) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   // sync request is not allowed setting responseType in window context
   if (HasOrHasHadOwner() &&
       !(mState & (XML_HTTP_REQUEST_UNSENT | XML_HTTP_REQUEST_ASYNC))) {
     LogMessage("ResponseTypeSyncXHRWarning", GetOwner());
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -318,17 +318,16 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_window_indexing.html]
 [test_window_named_frame_enumeration.html]
 [test_writable-replaceable.html]
 [test_navigatorPrefOverride.html]
 [test_CrossSiteXHR.html]
 [test_CrossSiteXHR_cache.html]
 [test_CrossSiteXHR_origin.html]
 skip-if = buildapp == 'b2g' || e10s # last test fails to trigger onload on e10s/b2g
-[test_DOMException.html]
 [test_EventSource_redirects.html]
 [test_NodeIterator_basics_filters.xhtml]
 [test_NodeIterator_mutations_1.xhtml]
 [test_NodeIterator_mutations_2.html]
 [test_NodeIterator_mutations_3.html]
 [test_XHR.html]
 [test_XHRDocURI.html]
 [test_XHRResponseURL.html]
deleted file mode 100644
--- a/dom/base/test/test_DOMException.html
+++ /dev/null
@@ -1,67 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Test for DOMException constants</title>
-  <script src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<p id="display"></p>
-<div id="content" style="display: none">
-</div>
-<pre id="test">
-<script>
-var constants = [
-  null,
-  "INDEX_SIZE_ERR",
-  "DOMSTRING_SIZE_ERR",
-  "HIERARCHY_REQUEST_ERR",
-  "WRONG_DOCUMENT_ERR",
-  "INVALID_CHARACTER_ERR",
-  "NO_DATA_ALLOWED_ERR",
-  "NO_MODIFICATION_ALLOWED_ERR",
-  "NOT_FOUND_ERR",
-  "NOT_SUPPORTED_ERR",
-  "INUSE_ATTRIBUTE_ERR",
-  "INVALID_STATE_ERR",
-  "SYNTAX_ERR",
-  "INVALID_MODIFICATION_ERR",
-  "NAMESPACE_ERR",
-  "INVALID_ACCESS_ERR",
-  "VALIDATION_ERR",
-  "TYPE_MISMATCH_ERR",
-  "SECURITY_ERR",
-  "NETWORK_ERR",
-  "ABORT_ERR",
-  "URL_MISMATCH_ERR",
-  "QUOTA_EXCEEDED_ERR",
-  "TIMEOUT_ERR",
-  "INVALID_NODE_TYPE_ERR",
-  "DATA_CLONE_ERR"
-];
-for (var i = 0; i < constants.length; ++i) {
-  var constant = constants[i];
-  if (constant)
-    is(DOMException[constant], i, constant)
-}
-
-var ex = new DOMException();
-ise(ex.name, "Error",
-    "Not passing a name should end up with 'Error' as the name");
-ise(ex.message, "",
-    "Not passing a message should end up with empty string as the message");
-
-ex = new DOMException("foo");
-ise(ex.name, "Error",
-    "Not passing a name should still end up with 'Error' as the name");
-ise(ex.message, "foo", "Should be using passed-in message");
-
-ex = new DOMException("bar", "NotSupportedError");
-ise(ex.name, "NotSupportedError", "Should be using the passed-in name");
-ise(ex.message, "bar", "Should still be using passed-in message");
-ise(ex.code, DOMException.NOT_SUPPORTED_ERR,
-    "Should have the right exception code");
-</script>
-</pre>
-</body>
-</html>
--- a/dom/base/test/test_XHR.html
+++ b/dom/base/test/test_XHR.html
@@ -99,27 +99,45 @@ function checkResponseTextAccessThrows(x
   try { xhr.responseText } catch (e) { didthrow = true; }
   ok(didthrow, "should have thrown when accessing responseText");
 }
 function checkResponseXMLAccessThrows(xhr) {
   var didthrow = false;
   try { xhr.responseXML } catch (e) { didthrow = true; }
   ok(didthrow, "should have thrown when accessing responseXML");
 }
+function checkSetResponseType(xhr, type) {
+  var didthrow = false;
+  try { xhr.responseType = type; } catch (e) { didthrow = true; }
+  ise(xhr.responseType, type, "responseType should be " + type);
+  ok(!didthrow, "should not have thrown when setting responseType");
+}
 function checkSetResponseTypeThrows(xhr, type) {
   var didthrow = false;
   try { xhr.responseType = type; } catch (e) { didthrow = true; }
   ok(didthrow, "should have thrown when setting responseType");
 }
 function checkOpenThrows(xhr, method, url, async) {
   var didthrow = false;
   try { xhr.open(method, url, async); } catch (e) { didthrow = true; }
   ok(didthrow, "should have thrown when open is called");
 }
 
+// test if setting responseType before calling open() works
+xhr = new XMLHttpRequest();
+checkSetResponseType(xhr, "");
+checkSetResponseType(xhr, "text");
+checkSetResponseType(xhr, "document");
+checkSetResponseType(xhr, "arraybuffer");
+checkSetResponseType(xhr, "blob");
+checkSetResponseType(xhr, "json");
+checkSetResponseType(xhr, "moz-chunked-text");
+checkSetResponseType(xhr, "moz-chunked-arraybuffer");
+checkOpenThrows(xhr, "GET", "file_XHR_pass2.txt", false);
+
 // test response (sync, responseType is not changeable)
 xhr = new XMLHttpRequest();
 xhr.open("GET", 'file_XHR_pass2.txt', false); 
 checkSetResponseTypeThrows(xhr, "");
 checkSetResponseTypeThrows(xhr, "text");
 checkSetResponseTypeThrows(xhr, "document");
 checkSetResponseTypeThrows(xhr, "arraybuffer");
 checkSetResponseTypeThrows(xhr, "blob");
--- a/dom/base/test/test_url.html
+++ b/dom/base/test/test_url.html
@@ -112,17 +112,17 @@
       port: '',
       pathname: '/',
       search: '?test',
       hash: ''
     },
     { url: 'http://example.com/carrot#question%3f',
       base: undefined,
       error: false,
-      hash: '#question?'
+      hash: '#question%3f'
     },
     { url: 'https://example.com:4443?',
       base: undefined,
       error: false,
       protocol: 'https:',
       port: '4443',
       pathname: '/',
       hash: '',
--- a/dom/canvas/WebGL2ContextFramebuffers.cpp
+++ b/dom/canvas/WebGL2ContextFramebuffers.cpp
@@ -1,28 +1,337 @@
 /* -*- 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 "WebGL2Context.h"
+
 #include "GLContext.h"
+#include "WebGLContextUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
+// Returns one of FLOAT, INT, UNSIGNED_INT.
+// Fixed-points (normalized ints) are considered FLOAT.
+static GLenum
+ValueTypeForFormat(GLenum internalFormat)
+{
+    switch (internalFormat) {
+    // Fixed-point
+    case LOCAL_GL_R8:
+    case LOCAL_GL_RG8:
+    case LOCAL_GL_RGB565:
+    case LOCAL_GL_RGB8:
+    case LOCAL_GL_RGBA4:
+    case LOCAL_GL_RGB5_A1:
+    case LOCAL_GL_RGBA8:
+    case LOCAL_GL_RGB10_A2:
+    case LOCAL_GL_ALPHA8:
+    case LOCAL_GL_LUMINANCE8:
+    case LOCAL_GL_LUMINANCE8_ALPHA8:
+    case LOCAL_GL_SRGB8:
+    case LOCAL_GL_SRGB8_ALPHA8:
+    case LOCAL_GL_R8_SNORM:
+    case LOCAL_GL_RG8_SNORM:
+    case LOCAL_GL_RGB8_SNORM:
+    case LOCAL_GL_RGBA8_SNORM:
+
+    // Floating-point
+    case LOCAL_GL_R16F:
+    case LOCAL_GL_RG16F:
+    case LOCAL_GL_RGB16F:
+    case LOCAL_GL_RGBA16F:
+    case LOCAL_GL_ALPHA16F_EXT:
+    case LOCAL_GL_LUMINANCE16F_EXT:
+    case LOCAL_GL_LUMINANCE_ALPHA16F_EXT:
+
+    case LOCAL_GL_R32F:
+    case LOCAL_GL_RG32F:
+    case LOCAL_GL_RGB32F:
+    case LOCAL_GL_RGBA32F:
+    case LOCAL_GL_ALPHA32F_EXT:
+    case LOCAL_GL_LUMINANCE32F_EXT:
+    case LOCAL_GL_LUMINANCE_ALPHA32F_EXT:
+
+    case LOCAL_GL_R11F_G11F_B10F:
+    case LOCAL_GL_RGB9_E5:
+        return LOCAL_GL_FLOAT;
+
+    // Int
+    case LOCAL_GL_R8I:
+    case LOCAL_GL_RG8I:
+    case LOCAL_GL_RGB8I:
+    case LOCAL_GL_RGBA8I:
+
+    case LOCAL_GL_R16I:
+    case LOCAL_GL_RG16I:
+    case LOCAL_GL_RGB16I:
+    case LOCAL_GL_RGBA16I:
+
+    case LOCAL_GL_R32I:
+    case LOCAL_GL_RG32I:
+    case LOCAL_GL_RGB32I:
+    case LOCAL_GL_RGBA32I:
+        return LOCAL_GL_INT;
+
+    // Unsigned int
+    case LOCAL_GL_R8UI:
+    case LOCAL_GL_RG8UI:
+    case LOCAL_GL_RGB8UI:
+    case LOCAL_GL_RGBA8UI:
+
+    case LOCAL_GL_R16UI:
+    case LOCAL_GL_RG16UI:
+    case LOCAL_GL_RGB16UI:
+    case LOCAL_GL_RGBA16UI:
+
+    case LOCAL_GL_R32UI:
+    case LOCAL_GL_RG32UI:
+    case LOCAL_GL_RGB32UI:
+    case LOCAL_GL_RGBA32UI:
+
+    case LOCAL_GL_RGB10_A2UI:
+        return LOCAL_GL_UNSIGNED_INT;
+
+    default:
+        MOZ_CRASH("Bad `internalFormat`.");
+    }
+}
+
 // -------------------------------------------------------------------------
 // Framebuffer objects
 
+static bool
+GetFBInfoForBlit(const WebGLFramebuffer* fb, WebGLContext* webgl,
+                 const char* const fbInfo, GLsizei* const out_samples,
+                 GLenum* const out_colorFormat, GLenum* const out_depthFormat,
+                 GLenum* const out_stencilFormat)
+{
+    auto status = fb->PrecheckFramebufferStatus();
+    if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
+        webgl->ErrorInvalidOperation("blitFramebuffer: %s is not"
+                                     " framebuffer-complete.", fbInfo);
+        return false;
+    }
+
+    *out_samples = 1; // TODO
+
+    if (fb->ColorAttachment(0).IsDefined()) {
+        const auto& attachement = fb->ColorAttachment(0);
+        *out_colorFormat = attachement.EffectiveInternalFormat().get();
+    } else {
+        *out_colorFormat = 0;
+    }
+
+    if (fb->DepthStencilAttachment().IsDefined()) {
+        const auto& attachement = fb->DepthStencilAttachment();
+        *out_depthFormat = attachement.EffectiveInternalFormat().get();
+        *out_stencilFormat = *out_depthFormat;
+    } else {
+        if (fb->DepthAttachment().IsDefined()) {
+            const auto& attachement = fb->DepthAttachment();
+            *out_depthFormat = attachement.EffectiveInternalFormat().get();
+        } else {
+            *out_depthFormat = 0;
+        }
+
+        if (fb->StencilAttachment().IsDefined()) {
+            const auto& attachement = fb->StencilAttachment();
+            *out_stencilFormat = attachement.EffectiveInternalFormat().get();
+        } else {
+            *out_stencilFormat = 0;
+        }
+    }
+    return true;
+}
+
 void
 WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
                                GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
                                GLbitfield mask, GLenum filter)
 {
-    MOZ_CRASH("Not Implemented.");
+    const GLbitfield validBits = LOCAL_GL_COLOR_BUFFER_BIT |
+                                 LOCAL_GL_DEPTH_BUFFER_BIT |
+                                 LOCAL_GL_STENCIL_BUFFER_BIT;
+    if ((mask | validBits) != validBits) {
+        ErrorInvalidValue("blitFramebuffer: Invalid bit set in mask.");
+        return;
+    }
+
+    switch (filter) {
+    case LOCAL_GL_NEAREST:
+    case LOCAL_GL_LINEAR:
+        break;
+    default:
+        ErrorInvalidEnumInfo("blitFramebuffer: Bad `filter`:", filter);
+        return;
+    }
+
+    const GLbitfield depthAndStencilBits = LOCAL_GL_DEPTH_BUFFER_BIT |
+                                           LOCAL_GL_STENCIL_BUFFER_BIT;
+    if (mask & depthAndStencilBits &&
+        filter != LOCAL_GL_NEAREST)
+    {
+        ErrorInvalidOperation("blitFramebuffer: DEPTH_BUFFER_BIT and"
+                              " STENCIL_BUFFER_BIT can only be used with"
+                              " NEAREST filtering.");
+        return;
+    }
+
+    if (mBoundReadFramebuffer == mBoundDrawFramebuffer) {
+        // TODO: It's actually more complicated than this. We need to check that
+        // the underlying buffers are not the same, not the framebuffers
+        // themselves.
+        ErrorInvalidOperation("blitFramebuffer: Source and destination must"
+                              " differ.");
+        return;
+    }
+
+    GLsizei srcSamples;
+    GLenum srcColorFormat;
+    GLenum srcDepthFormat;
+    GLenum srcStencilFormat;
+
+    if (mBoundReadFramebuffer) {
+        if (!GetFBInfoForBlit(mBoundReadFramebuffer, this, "READ_FRAMEBUFFER",
+                              &srcSamples, &srcColorFormat, &srcDepthFormat,
+                              &srcStencilFormat))
+        {
+            return;
+        }
+    } else {
+        srcSamples = 1; // Always 1.
+
+        // TODO: Don't hardcode these.
+        srcColorFormat = mOptions.alpha ? LOCAL_GL_RGBA8 : LOCAL_GL_RGB8;
+
+        if (mOptions.depth && mOptions.stencil) {
+            srcDepthFormat = LOCAL_GL_DEPTH24_STENCIL8;
+            srcStencilFormat = srcDepthFormat;
+        } else {
+            if (mOptions.depth) {
+                srcDepthFormat = LOCAL_GL_DEPTH_COMPONENT16;
+            }
+            if (mOptions.stencil) {
+                srcStencilFormat = LOCAL_GL_STENCIL_INDEX8;
+            }
+        }
+    }
+
+    GLsizei dstSamples;
+    GLenum dstColorFormat;
+    GLenum dstDepthFormat;
+    GLenum dstStencilFormat;
+
+    if (mBoundDrawFramebuffer) {
+        if (!GetFBInfoForBlit(mBoundDrawFramebuffer, this, "DRAW_FRAMEBUFFER",
+                              &dstSamples, &dstColorFormat, &dstDepthFormat,
+                              &dstStencilFormat))
+        {
+            return;
+        }
+    } else {
+        dstSamples = gl->Screen()->Samples();
+
+        // TODO: Don't hardcode these.
+        dstColorFormat = mOptions.alpha ? LOCAL_GL_RGBA8 : LOCAL_GL_RGB8;
+
+        if (mOptions.depth && mOptions.stencil) {
+            dstDepthFormat = LOCAL_GL_DEPTH24_STENCIL8;
+            dstStencilFormat = dstDepthFormat;
+        } else {
+            if (mOptions.depth) {
+                dstDepthFormat = LOCAL_GL_DEPTH_COMPONENT16;
+            }
+            if (mOptions.stencil) {
+                dstStencilFormat = LOCAL_GL_STENCIL_INDEX8;
+            }
+        }
+    }
+
+
+    if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
+        const GLenum srcColorType = srcColorFormat ? ValueTypeForFormat(srcColorFormat)
+                                                   : 0;
+        const GLenum dstColorType = dstColorFormat ? ValueTypeForFormat(dstColorFormat)
+                                                   : 0;
+        if (dstColorType != srcColorType) {
+            ErrorInvalidOperation("blitFramebuffer: Color buffer value type"
+                                  " mismatch.");
+            return;
+        }
+
+        const bool srcIsInt = srcColorType == LOCAL_GL_INT ||
+                              srcColorType == LOCAL_GL_UNSIGNED_INT;
+        if (srcIsInt && filter != LOCAL_GL_NEAREST) {
+            ErrorInvalidOperation("blitFramebuffer: Integer read buffers can only"
+                                  " be filtered with NEAREST.");
+            return;
+        }
+    }
+
+    /* GLES 3.0.4, p199:
+     *   Calling BlitFramebuffer will result in an INVALID_OPERATION error if
+     *   mask includes DEPTH_BUFFER_BIT or STENCIL_BUFFER_BIT, and the source
+     *   and destination depth and stencil buffer formats do not match.
+     *
+     * jgilbert: The wording is such that if only DEPTH_BUFFER_BIT is specified,
+     * the stencil formats must match. This seems wrong. It could be a spec bug,
+     * or I could be missing an interaction in one of the earlier paragraphs.
+     */
+    if (mask & LOCAL_GL_DEPTH_BUFFER_BIT &&
+        dstDepthFormat != srcDepthFormat)
+    {
+        ErrorInvalidOperation("blitFramebuffer: Depth buffer formats must match"
+                              " if selected.");
+        return;
+    }
+
+    if (mask & LOCAL_GL_STENCIL_BUFFER_BIT &&
+        dstStencilFormat != srcStencilFormat)
+    {
+        ErrorInvalidOperation("blitFramebuffer: Stencil buffer formats must"
+                              " match if selected.");
+        return;
+    }
+
+    if (dstSamples != 1) {
+        ErrorInvalidOperation("blitFramebuffer: DRAW_FRAMEBUFFER may not have"
+                              " multiple samples.");
+        return;
+    }
+
+    if (srcSamples != 1) {
+        if (mask & LOCAL_GL_COLOR_BUFFER_BIT &&
+            dstColorFormat != srcColorFormat)
+        {
+            ErrorInvalidOperation("blitFramebuffer: Color buffer formats must"
+                                  " match if selected, when reading from a"
+                                  " multisampled source.");
+            return;
+        }
+
+        if (dstX0 != srcX0 ||
+            dstX1 != srcX1 ||
+            dstY0 != srcY0 ||
+            dstY1 != srcY1)
+        {
+            ErrorInvalidOperation("blitFramebuffer: If the source is"
+                                  " multisampled, then the source and dest"
+                                  " regions must match exactly.");
+            return;
+        }
+    }
+
+    MakeContextCurrent();
+    gl->fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1,
+                         dstX0, dstY0, dstX1, dstY1,
+                         mask, filter);
 }
 
 void
 WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)
 {
     MOZ_CRASH("Not Implemented.");
 }
 
@@ -52,50 +361,96 @@ TranslateDefaultAttachments(const dom::S
     }
 }
 
 void
 WebGL2Context::InvalidateFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments)
 {
     if (IsContextLost())
         return;
+
     MakeContextCurrent();
 
-    if (target != LOCAL_GL_FRAMEBUFFER)
-        return ErrorInvalidEnumInfo("invalidateFramebuffer: target", target);
-    for (size_t i = 0; i < attachments.Length(); i++) {
-        if (!ValidateFramebufferAttachment(attachments[i], "invalidateFramebuffer"))
-            return;
+    if (!ValidateFramebufferTarget(target, "framebufferRenderbuffer"))
+        return;
+
+    const WebGLFramebuffer* fb;
+    bool isDefaultFB;
+    switch (target) {
+    case LOCAL_GL_FRAMEBUFFER:
+    case LOCAL_GL_DRAW_FRAMEBUFFER:
+        fb = mBoundDrawFramebuffer;
+        isDefaultFB = gl->Screen()->IsDrawFramebufferDefault();
+        break;
+
+    case LOCAL_GL_READ_FRAMEBUFFER:
+        fb = mBoundReadFramebuffer;
+        isDefaultFB = gl->Screen()->IsReadFramebufferDefault();
+        break;
+
+    default:
+        MOZ_CRASH("Bad target.");
     }
 
-    if (!mBoundFramebuffer && !gl->IsDrawingToDefaultFramebuffer()) {
+    for (size_t i = 0; i < attachments.Length(); i++) {
+        if (!ValidateFramebufferAttachment(fb, attachments[i],
+                                           "invalidateFramebuffer"))
+        {
+            return;
+        }
+    }
+
+    if (!fb && !isDefaultFB) {
         dom::Sequence<GLenum> tmpAttachments;
         TranslateDefaultAttachments(attachments, &tmpAttachments);
         gl->fInvalidateFramebuffer(target, tmpAttachments.Length(), tmpAttachments.Elements());
     } else {
         gl->fInvalidateFramebuffer(target, attachments.Length(), attachments.Elements());
     }
 }
 
 void
 WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments,
                                         GLint x, GLint y, GLsizei width, GLsizei height)
 {
     if (IsContextLost())
         return;
+
     MakeContextCurrent();
 
-    if (target != LOCAL_GL_FRAMEBUFFER)
-        return ErrorInvalidEnumInfo("invalidateFramebuffer: target", target);
-    for (size_t i = 0; i < attachments.Length(); i++) {
-        if (!ValidateFramebufferAttachment(attachments[i], "invalidateSubFramebuffer"))
-            return;
+    if (!ValidateFramebufferTarget(target, "framebufferRenderbuffer"))
+        return;
+
+    const WebGLFramebuffer* fb;
+    bool isDefaultFB;
+    switch (target) {
+    case LOCAL_GL_FRAMEBUFFER:
+    case LOCAL_GL_DRAW_FRAMEBUFFER:
+        fb = mBoundDrawFramebuffer;
+        isDefaultFB = gl->Screen()->IsDrawFramebufferDefault();
+        break;
+
+    case LOCAL_GL_READ_FRAMEBUFFER:
+        fb = mBoundReadFramebuffer;
+        isDefaultFB = gl->Screen()->IsReadFramebufferDefault();
+        break;
+
+    default:
+        MOZ_CRASH("Bad target.");
     }
 
-    if (!mBoundFramebuffer && !gl->IsDrawingToDefaultFramebuffer()) {
+    for (size_t i = 0; i < attachments.Length(); i++) {
+        if (!ValidateFramebufferAttachment(fb, attachments[i],
+                                           "invalidateSubFramebuffer"))
+        {
+            return;
+        }
+    }
+
+    if (!fb && !isDefaultFB) {
         dom::Sequence<GLenum> tmpAttachments;
         TranslateDefaultAttachments(attachments, &tmpAttachments);
         gl->fInvalidateSubFramebuffer(target, tmpAttachments.Length(), tmpAttachments.Elements(),
                                       x, y, width, height);
     } else {
         gl->fInvalidateSubFramebuffer(target, attachments.Length(), attachments.Elements(),
                                       x, y, width, height);
     }
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -325,17 +325,18 @@ WebGLContext::DestroyResourcesAndContext
     mBoundArrayBuffer = nullptr;
     mBoundCopyReadBuffer = nullptr;
     mBoundCopyWriteBuffer = nullptr;
     mBoundPixelPackBuffer = nullptr;
     mBoundPixelUnpackBuffer = nullptr;
     mBoundTransformFeedbackBuffer = nullptr;
     mBoundUniformBuffer = nullptr;
     mCurrentProgram = nullptr;
-    mBoundFramebuffer = nullptr;
+    mBoundDrawFramebuffer = nullptr;
+    mBoundReadFramebuffer = nullptr;
     mActiveOcclusionQuery = nullptr;
     mBoundRenderbuffer = nullptr;
     mBoundVertexArray = nullptr;
     mDefaultVertexArray = nullptr;
     mBoundTransformFeedback = nullptr;
     mDefaultTransformFeedback = nullptr;
 
     if (mBoundTransformFeedbackBuffers) {
@@ -1882,17 +1883,18 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(We
   mBoundArrayBuffer,
   mBoundCopyReadBuffer,
   mBoundCopyWriteBuffer,
   mBoundPixelPackBuffer,
   mBoundPixelUnpackBuffer,
   mBoundTransformFeedbackBuffer,
   mBoundUniformBuffer,
   mCurrentProgram,
-  mBoundFramebuffer,
+  mBoundDrawFramebuffer,
+  mBoundReadFramebuffer,
   mBoundRenderbuffer,
   mBoundVertexArray,
   mDefaultVertexArray,
   mActiveOcclusionQuery,
   mActiveTransformFeedbackQuery)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLContext)
     NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -307,17 +307,18 @@ public:
 
     bool PresentScreenBuffer();
 
     // a number that increments every time we have an event that causes
     // all context resources to be lost.
     uint32_t Generation() { return mGeneration.value(); }
 
     // Returns null if the current bound FB is not likely complete.
-    const WebGLRectangleObject* CurValidFBRectObject() const;
+    const WebGLRectangleObject* CurValidDrawFBRectObject() const;
+    const WebGLRectangleObject* CurValidReadFBRectObject() const;
 
     static const size_t kMaxColorAttachments = 16;
 
     // This is similar to GLContext::ClearSafely, but tries to minimize the
     // amount of work it does.
     // It only clears the buffers we specify, and can reset its state without
     // first having to query anything, as WebGL knows its state at all times.
     void ForceClearFramebufferWithDefaultValues(GLbitfield mask,
@@ -410,17 +411,18 @@ public:
     void Finish();
     void FramebufferRenderbuffer(GLenum target, GLenum attachment,
                                  GLenum rbTarget, WebGLRenderbuffer* rb);
     void FramebufferTexture2D(GLenum target, GLenum attachment,
                               GLenum texImageTarget, WebGLTexture* tex,
                               GLint level);
 
     // Framebuffer validation
-    bool ValidateFramebufferAttachment(GLenum attachment, const char* funcName);
+    bool ValidateFramebufferAttachment(const WebGLFramebuffer* fb,
+                                       GLenum attachment, const char* funcName);
 
     void FrontFace(GLenum mode);
     void GenerateMipmap(GLenum target);
     already_AddRefed<WebGLActiveInfo> GetActiveAttrib(WebGLProgram* prog,
                                                       GLuint index);
     already_AddRefed<WebGLActiveInfo> GetActiveUniform(WebGLProgram* prog,
                                                        GLuint index);
 
@@ -1399,17 +1401,20 @@ protected:
     nsTArray<WebGLRefPtr<WebGLTexture> > mBound2DTextures;
     nsTArray<WebGLRefPtr<WebGLTexture> > mBoundCubeMapTextures;
     nsTArray<WebGLRefPtr<WebGLTexture> > mBound3DTextures;
 
     WebGLRefPtr<WebGLProgram> mCurrentProgram;
 
     uint32_t mMaxFramebufferColorAttachments;
 
-    WebGLRefPtr<WebGLFramebuffer> mBoundFramebuffer;
+    bool ValidateFramebufferTarget(GLenum target, const char* const info);
+
+    WebGLRefPtr<WebGLFramebuffer> mBoundDrawFramebuffer;
+    WebGLRefPtr<WebGLFramebuffer> mBoundReadFramebuffer;
     WebGLRefPtr<WebGLRenderbuffer> mBoundRenderbuffer;
     WebGLRefPtr<WebGLTransformFeedback> mBoundTransformFeedback;
     WebGLRefPtr<WebGLVertexArray> mBoundVertexArray;
 
     LinkedList<WebGLTexture> mTextures;
     LinkedList<WebGLBuffer> mBuffers;
     LinkedList<WebGLProgram> mPrograms;
     LinkedList<WebGLQuery> mQueries;
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -94,18 +94,18 @@ bool WebGLContext::DrawArrays_check(GLin
 
     if (uint32_t(primcount) > mMaxFetchedInstances) {
         ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
         return false;
     }
 
     MakeContextCurrent();
 
-    if (mBoundFramebuffer) {
-        if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
+    if (mBoundDrawFramebuffer) {
+        if (!mBoundDrawFramebuffer->CheckAndInitializeAttachments()) {
             ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
             return false;
         }
     } else {
         ClearBackbufferIfNeeded();
     }
 
     if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) {
@@ -275,18 +275,18 @@ WebGLContext::DrawElements_check(GLsizei
         GenerateWarning("%s: bound element array buffer previously used with a type other than "
                         "%s, this will affect performance.",
                         info,
                         WebGLContext::EnumName(type));
     }
 
     MakeContextCurrent();
 
-    if (mBoundFramebuffer) {
-        if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
+    if (mBoundDrawFramebuffer) {
+        if (!mBoundDrawFramebuffer->CheckAndInitializeAttachments()) {
             ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
             return false;
         }
     } else {
         ClearBackbufferIfNeeded();
     }
 
     if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
@@ -365,17 +365,17 @@ WebGLContext::DrawElementsInstanced(GLen
     Draw_cleanup();
 }
 
 void WebGLContext::Draw_cleanup()
 {
     UndoFakeVertexAttrib0();
     UnbindFakeBlackTextures();
 
-    if (!mBoundFramebuffer) {
+    if (!mBoundDrawFramebuffer) {
         Invalidate();
         mShouldPresent = true;
         MOZ_ASSERT(!mBackbufferNeedsClear);
     }
 
     if (gl->WorkAroundDriverBugs()) {
         if (gl->Renderer() == gl::GLRenderer::Tegra) {
             mDrawCallsSinceLastFlush++;
@@ -383,17 +383,17 @@ void WebGLContext::Draw_cleanup()
             if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
                 gl->fFlush();
                 mDrawCallsSinceLastFlush = 0;
             }
         }
     }
 
     // Let's check the viewport
-    const WebGLRectangleObject* rect = CurValidFBRectObject();
+    const WebGLRectangleObject* rect = CurValidDrawFBRectObject();
     if (rect) {
         if (mViewportWidth > rect->Width() ||
             mViewportHeight > rect->Height())
         {
             if (!mAlreadyWarnedAboutViewportLargerThanDest) {
                 GenerateWarning("Drawing to a destination rect smaller than the viewport rect. "
                                 "(This warning will only be given once)");
                 mAlreadyWarnedAboutViewportLargerThanDest = true;
--- a/dom/canvas/WebGLContextFramebufferOperations.cpp
+++ b/dom/canvas/WebGLContextFramebufferOperations.cpp
@@ -24,18 +24,18 @@ WebGLContext::Clear(GLbitfield mask)
         return ErrorInvalidValue("clear: invalid mask bits");
 
     if (mask == 0) {
         GenerateWarning("Calling gl.clear(0) has no effect.");
     } else if (mRasterizerDiscardEnabled) {
         GenerateWarning("Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects.");
     }
 
-    if (mBoundFramebuffer) {
-        if (!mBoundFramebuffer->CheckAndInitializeAttachments())
+    if (mBoundDrawFramebuffer) {
+        if (!mBoundDrawFramebuffer->CheckAndInitializeAttachments())
             return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer");
 
         gl->fClear(mask);
         return;
     } else {
         ClearBackbufferIfNeeded();
     }
 
@@ -126,22 +126,21 @@ WebGLContext::DepthMask(WebGLboolean b)
 void
 WebGLContext::DrawBuffers(const dom::Sequence<GLenum>& buffers)
 {
     if (IsContextLost())
         return;
 
     const size_t buffersLength = buffers.Length();
 
-    if (buffersLength == 0) {
+    if (!buffersLength) {
         return ErrorInvalidValue("drawBuffers: invalid <buffers> (buffers must not be empty)");
     }
 
-    if (mBoundFramebuffer == 0)
-    {
+    if (!mBoundDrawFramebuffer) {
         // OK: we are rendering in the default framebuffer
 
         /* EXT_draw_buffers :
          If the GL is bound to the default framebuffer, then <buffersLength> must be 1
          and the constant must be BACK or NONE. When draw buffer zero is
          BACK, color values are written into the sole buffer for single-
          buffered contexts, or into the back buffer for double-buffered
          contexts. If DrawBuffersEXT is supplied with a constant other than
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -53,34 +53,47 @@
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gl;
 using namespace mozilla::gfx;
 
 static bool BaseTypeAndSizeFromUniformType(GLenum uType, GLenum* baseType,
                                            GLint* unitSize);
 
-const WebGLRectangleObject*
-WebGLContext::CurValidFBRectObject() const
+static const WebGLRectangleObject*
+CurValidFBRectObject(const WebGLContext* webgl,
+                     const WebGLFramebuffer* boundFB)
 {
     const WebGLRectangleObject* rect = nullptr;
 
-    if (mBoundFramebuffer) {
+    if (boundFB) {
         // We don't really need to ask the driver.
         // Use 'precheck' to just check that our internal state looks good.
-        FBStatus precheckStatus = mBoundFramebuffer->PrecheckFramebufferStatus();
+        FBStatus precheckStatus = boundFB->PrecheckFramebufferStatus();
         if (precheckStatus == LOCAL_GL_FRAMEBUFFER_COMPLETE)
-            rect = &mBoundFramebuffer->RectangleObject();
+            rect = &boundFB->RectangleObject();
     } else {
-        rect = static_cast<const WebGLRectangleObject*>(this);
+        rect = static_cast<const WebGLRectangleObject*>(webgl);
     }
 
     return rect;
 }
 
+const WebGLRectangleObject*
+WebGLContext::CurValidDrawFBRectObject() const
+{
+    return CurValidFBRectObject(this, mBoundDrawFramebuffer);
+}
+
+const WebGLRectangleObject*
+WebGLContext::CurValidReadFBRectObject() const
+{
+    return CurValidFBRectObject(this, mBoundReadFramebuffer);
+}
+
 //
 //  WebGL API
 //
 
 void
 WebGLContext::ActiveTexture(GLenum texture)
 {
     if (IsContextLost())
@@ -159,18 +172,18 @@ WebGLContext::BindAttribLocation(WebGLPr
 }
 
 void
 WebGLContext::BindFramebuffer(GLenum target, WebGLFramebuffer* wfb)
 {
     if (IsContextLost())
         return;
 
-    if (target != LOCAL_GL_FRAMEBUFFER)
-        return ErrorInvalidEnum("bindFramebuffer: target must be GL_FRAMEBUFFER");
+    if (!ValidateFramebufferTarget(target, "bindFramebuffer"))
+        return;
 
     if (!ValidateObjectAllowDeletedOrNull("bindFramebuffer", wfb))
         return;
 
     // silently ignore a deleted frame buffer
     if (wfb && wfb->IsDeleted())
         return;
 
@@ -179,17 +192,30 @@ WebGLContext::BindFramebuffer(GLenum tar
     if (!wfb) {
         gl->fBindFramebuffer(target, 0);
     } else {
         wfb->BindTo(target);
         GLuint framebuffername = wfb->GLName();
         gl->fBindFramebuffer(target, framebuffername);
     }
 
-    mBoundFramebuffer = wfb;
+    switch (target) {
+    case LOCAL_GL_FRAMEBUFFER:
+        mBoundDrawFramebuffer = wfb;
+        mBoundReadFramebuffer = wfb;
+        break;
+    case LOCAL_GL_DRAW_FRAMEBUFFER:
+        mBoundDrawFramebuffer = wfb;
+        break;
+    case LOCAL_GL_READ_FRAMEBUFFER:
+        mBoundReadFramebuffer = wfb;
+        break;
+    default:
+        break;
+    }
 }
 
 void
 WebGLContext::BindRenderbuffer(GLenum target, WebGLRenderbuffer* wrb)
 {
     if (IsContextLost())
         return;
 
@@ -346,40 +372,48 @@ WebGLContext::BlendFuncSeparate(GLenum s
 }
 
 GLenum
 WebGLContext::CheckFramebufferStatus(GLenum target)
 {
     if (IsContextLost())
         return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
 
-    if (target != LOCAL_GL_FRAMEBUFFER) {
-        ErrorInvalidEnum("checkFramebufferStatus: target must be FRAMEBUFFER");
+    if (!ValidateFramebufferTarget(target, "invalidateFramebuffer"))
         return 0;
+
+    WebGLFramebuffer* fb;
+    switch (target) {
+    case LOCAL_GL_FRAMEBUFFER:
+    case LOCAL_GL_DRAW_FRAMEBUFFER:
+        fb = mBoundDrawFramebuffer;
+        break;
+
+    case LOCAL_GL_READ_FRAMEBUFFER:
+        fb = mBoundReadFramebuffer;
+        break;
+
+    default:
+        MOZ_CRASH("Bad target.");
     }
 
-    if (!mBoundFramebuffer)
+    if (!fb)
         return LOCAL_GL_FRAMEBUFFER_COMPLETE;
 
-    return mBoundFramebuffer->CheckFramebufferStatus().get();
+    return fb->CheckFramebufferStatus().get();
 }
 
 void
-WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget,
-                                     GLint level,
+WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
                                      TexInternalFormat internalformat,
-                                     GLint xoffset,
-                                     GLint yoffset,
-                                     GLint x,
-                                     GLint y,
-                                     GLsizei width,
-                                     GLsizei height,
+                                     GLint xoffset, GLint yoffset, GLint x,
+                                     GLint y, GLsizei width, GLsizei height,
                                      bool sub)
 {
-    const WebGLRectangleObject* framebufferRect = CurValidFBRectObject();
+    const WebGLRectangleObject* framebufferRect = CurValidReadFBRectObject();
     GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
     GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
 
     WebGLTexImageFunc func = sub
                              ? WebGLTexImageFunc::CopyTexSubImage
                              : WebGLTexImageFunc::CopyTexImage;
     WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
     const char* info = InfoFrom(func, dims);
@@ -394,35 +428,35 @@ WebGLContext::CopyTexSubImage2D_base(Tex
                           func, dims))
     {
         return;
     }
 
     if (!ValidateCopyTexImage(internalformat.get(), func, dims))
         return;
 
-    if (!mBoundFramebuffer)
+    if (!mBoundReadFramebuffer)
         ClearBackbufferIfNeeded();
 
     MakeContextCurrent();
 
     WebGLTexture* tex = ActiveBoundTextureForTexImageTarget(texImageTarget);
 
     if (!tex)
         return ErrorInvalidOperation("%s: no texture is bound to this target");
 
     if (tex->IsImmutable()) {
         if (!sub) {
             return ErrorInvalidOperation("copyTexImage2D: disallowed because the texture bound to this target has already been made immutable by texStorage2D");
         }
     }
 
     TexType framebuffertype = LOCAL_GL_NONE;
-    if (mBoundFramebuffer) {
-        TexInternalFormat framebuffereffectiveformat = mBoundFramebuffer->ColorAttachment(0).EffectiveInternalFormat();
+    if (mBoundReadFramebuffer) {
+        TexInternalFormat framebuffereffectiveformat = mBoundReadFramebuffer->ColorAttachment(0).EffectiveInternalFormat();
         framebuffertype = TypeFromInternalFormat(framebuffereffectiveformat);
     } else {
         // FIXME - here we're assuming that the default framebuffer is backed by UNSIGNED_BYTE
         // that might not always be true, say if we had a 16bpp default framebuffer.
         framebuffertype = LOCAL_GL_UNSIGNED_BYTE;
     }
 
     TexInternalFormat effectiveInternalFormat =
@@ -536,17 +570,17 @@ WebGLContext::CopyTexImage2D(GLenum rawT
                           func, dims))
     {
         return;
     }
 
     if (!ValidateCopyTexImage(internalformat, func, dims))
         return;
 
-    if (!mBoundFramebuffer)
+    if (!mBoundReadFramebuffer)
         ClearBackbufferIfNeeded();
 
     CopyTexSubImage2D_base(rawTexImgTarget, level, internalformat, 0, 0, x, y, width, height, false);
 }
 
 void
 WebGLContext::CopyTexSubImage2D(GLenum rawTexImgTarget,
                                 GLint level,
@@ -600,17 +634,17 @@ WebGLContext::CopyTexSubImage2D(GLenum r
     GLsizei texHeight = imageInfo.Height();
 
     if (xoffset + width > texWidth || xoffset + width < 0)
       return ErrorInvalidValue("copyTexSubImage2D: xoffset+width is too large");
 
     if (yoffset + height > texHeight || yoffset + height < 0)
       return ErrorInvalidValue("copyTexSubImage2D: yoffset+height is too large");
 
-    if (!mBoundFramebuffer)
+    if (!mBoundReadFramebuffer)
         ClearBackbufferIfNeeded();
 
     if (imageInfo.HasUninitializedImageData()) {
         bool coversWholeImage = xoffset == 0 &&
                                 yoffset == 0 &&
                                 width == texWidth &&
                                 height == texHeight;
         if (coversWholeImage) {
@@ -676,35 +710,47 @@ WebGLContext::DeleteFramebuffer(WebGLFra
     if (!ValidateObjectAllowDeletedOrNull("deleteFramebuffer", fbuf))
         return;
 
     if (!fbuf || fbuf->IsDeleted())
         return;
 
     fbuf->RequestDelete();
 
-    if (mBoundFramebuffer == fbuf)
-        BindFramebuffer(LOCAL_GL_FRAMEBUFFER,
+    if (mBoundReadFramebuffer == mBoundDrawFramebuffer) {
+        if (mBoundDrawFramebuffer == fbuf) {
+            BindFramebuffer(LOCAL_GL_FRAMEBUFFER,
+                            static_cast<WebGLFramebuffer*>(nullptr));
+        }
+    } else if (mBoundDrawFramebuffer == fbuf) {
+        BindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER,
                         static_cast<WebGLFramebuffer*>(nullptr));
+    } else if (mBoundReadFramebuffer == fbuf) {
+        BindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER,
+                        static_cast<WebGLFramebuffer*>(nullptr));
+    }
 }
 
 void
 WebGLContext::DeleteRenderbuffer(WebGLRenderbuffer* rbuf)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObjectAllowDeletedOrNull("deleteRenderbuffer", rbuf))
         return;
 
     if (!rbuf || rbuf->IsDeleted())
         return;
 
-    if (mBoundFramebuffer)
-        mBoundFramebuffer->DetachRenderbuffer(rbuf);
+    if (mBoundDrawFramebuffer)
+        mBoundDrawFramebuffer->DetachRenderbuffer(rbuf);
+
+    if (mBoundReadFramebuffer)
+        mBoundReadFramebuffer->DetachRenderbuffer(rbuf);
 
     // Invalidate framebuffer status cache
     rbuf->NotifyFBsStatusChanged();
 
     if (mBoundRenderbuffer == rbuf)
         BindRenderbuffer(LOCAL_GL_RENDERBUFFER,
                          static_cast<WebGLRenderbuffer*>(nullptr));
 
@@ -718,18 +764,21 @@ WebGLContext::DeleteTexture(WebGLTexture
         return;
 
     if (!ValidateObjectAllowDeletedOrNull("deleteTexture", tex))
         return;
 
     if (!tex || tex->IsDeleted())
         return;
 
-    if (mBoundFramebuffer)
-        mBoundFramebuffer->DetachTexture(tex);
+    if (mBoundDrawFramebuffer)
+        mBoundDrawFramebuffer->DetachTexture(tex);
+
+    if (mBoundReadFramebuffer)
+        mBoundReadFramebuffer->DetachTexture(tex);
 
     // Invalidate framebuffer status cache
     tex->NotifyFBsStatusChanged();
 
     GLuint activeTexture = mActiveTexture;
     for (int32_t i = 0; i < mGLMaxTextureUnits; i++) {
         if ((mBound2DTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_2D) ||
             (mBoundCubeMapTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP) ||
@@ -818,58 +867,98 @@ WebGLContext::DepthRange(GLfloat zNear, 
 
 void
 WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment,
                                       GLenum rbtarget, WebGLRenderbuffer* wrb)
 {
     if (IsContextLost())
         return;
 
-    if (!mBoundFramebuffer)
-        return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
-
-    if (target != LOCAL_GL_FRAMEBUFFER)
-        return ErrorInvalidEnumInfo("framebufferRenderbuffer: target", target);
-
-    if (rbtarget != LOCAL_GL_RENDERBUFFER)
-        return ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget);
-
-    if (!ValidateFramebufferAttachment(attachment, "framebufferRenderbuffer"))
+    if (!ValidateFramebufferTarget(target, "framebufferRenderbuffer"))
         return;
 
-    return mBoundFramebuffer->FramebufferRenderbuffer(attachment, rbtarget, wrb);
+    WebGLFramebuffer* fb;
+    switch (target) {
+    case LOCAL_GL_FRAMEBUFFER:
+    case LOCAL_GL_DRAW_FRAMEBUFFER:
+        fb = mBoundDrawFramebuffer;
+        break;
+
+    case LOCAL_GL_READ_FRAMEBUFFER:
+        fb = mBoundReadFramebuffer;
+        break;
+
+    default:
+        MOZ_CRASH("Bad target.");
+    }
+
+    if (!fb) {
+        return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify"
+                                     " framebuffer 0.");
+    }
+
+    if (rbtarget != LOCAL_GL_RENDERBUFFER) {
+        return ErrorInvalidEnumInfo("framebufferRenderbuffer: rbtarget:",
+                                    rbtarget);
+    }
+
+    if (!ValidateFramebufferAttachment(fb, attachment,
+                                       "framebufferRenderbuffer"))
+    {
+        return;
+    }
+
+    fb->FramebufferRenderbuffer(attachment, rbtarget, wrb);
 }
 
 void
 WebGLContext::FramebufferTexture2D(GLenum target,
                                    GLenum attachment,
                                    GLenum textarget,
                                    WebGLTexture* tobj,
                                    GLint level)
 {
     if (IsContextLost())
         return;
 
-    if (!mBoundFramebuffer)
-        return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
-
-    if (target != LOCAL_GL_FRAMEBUFFER)
-        return ErrorInvalidEnumInfo("framebufferTexture2D: target", target);
+    if (!ValidateFramebufferTarget(target, "framebufferTexture2D"))
+        return;
+
+    WebGLFramebuffer* fb;
+    switch (target) {
+    case LOCAL_GL_FRAMEBUFFER:
+    case LOCAL_GL_DRAW_FRAMEBUFFER:
+        fb = mBoundDrawFramebuffer;
+        break;
+
+    case LOCAL_GL_READ_FRAMEBUFFER:
+        fb = mBoundReadFramebuffer;
+        break;
+
+    default:
+        MOZ_CRASH("Bad target.");
+    }
+
+    if (!fb) {
+        return ErrorInvalidOperation("framebufferTexture2D: cannot modify"
+                                     " framebuffer 0.");
+    }
 
     if (textarget != LOCAL_GL_TEXTURE_2D &&
         (textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
          textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
     {
-        return ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget);
+        return ErrorInvalidEnumInfo("framebufferTexture2D: textarget:",
+                                    textarget);
     }
 
-    if (!ValidateFramebufferAttachment(attachment, "framebufferTexture2D"))
+    if (!ValidateFramebufferAttachment(fb, attachment, "framebufferTexture2D"))
         return;
 
-    return mBoundFramebuffer->FramebufferTexture2D(attachment, textarget, tobj, level);
+    fb->FramebufferTexture2D(attachment, textarget, tobj, level);
 }
 
 void
 WebGLContext::FrontFace(GLenum mode)
 {
     if (IsContextLost())
         return;
 
@@ -1143,35 +1232,52 @@ WebGLContext::GetFramebufferAttachmentPa
                                                 GLenum target,
                                                 GLenum attachment,
                                                 GLenum pname,
                                                 ErrorResult& rv)
 {
     if (IsContextLost())
         return JS::NullValue();
 
-    if (target != LOCAL_GL_FRAMEBUFFER) {
-        ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: target", target);
+    if (!ValidateFramebufferTarget(target, "getFramebufferAttachmentParameter"))
         return JS::NullValue();
+
+    WebGLFramebuffer* fb;
+    switch (target) {
+    case LOCAL_GL_FRAMEBUFFER:
+    case LOCAL_GL_DRAW_FRAMEBUFFER:
+        fb = mBoundDrawFramebuffer;
+        break;
+
+    case LOCAL_GL_READ_FRAMEBUFFER:
+        fb = mBoundReadFramebuffer;
+        break;
+
+    default:
+        MOZ_CRASH("Bad target.");
     }
 
-    if (!mBoundFramebuffer) {
-        ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot query framebuffer 0");
+    if (!fb) {
+        ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot query"
+                              " framebuffer 0.");
         return JS::NullValue();
     }
 
-    if (!ValidateFramebufferAttachment(attachment, "getFramebufferAttachmentParameter"))
+    if (!ValidateFramebufferAttachment(fb, attachment,
+                                       "getFramebufferAttachmentParameter"))
+    {
         return JS::NullValue();
+    }
 
     if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
-        mBoundFramebuffer->EnsureColorAttachments(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
+        fb->EnsureColorAttachments(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
 
     MakeContextCurrent();
 
-    const WebGLFramebuffer::Attachment& fba = mBoundFramebuffer->GetAttachment(attachment);
+    const WebGLFramebuffer::Attachment& fba = fb->GetAttachment(attachment);
 
     if (fba.Renderbuffer()) {
         switch (pname) {
             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
                 if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)) {
                     const GLenum internalFormat = fba.Renderbuffer()->InternalFormat();
                     return (internalFormat == LOCAL_GL_SRGB_EXT ||
                             internalFormat == LOCAL_GL_SRGB_ALPHA_EXT ||
@@ -2251,17 +2357,17 @@ WebGLContext::ReadPixels(GLint x, GLint 
     }
 
     if (width < 0 || height < 0)
         return ErrorInvalidValue("readPixels: negative size passed");
 
     if (pixels.IsNull())
         return ErrorInvalidValue("readPixels: null destination buffer");
 
-    const WebGLRectangleObject* framebufferRect = CurValidFBRectObject();
+    const WebGLRectangleObject* framebufferRect = CurValidReadFBRectObject();
     GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
     GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
 
     uint32_t channels = 0;
 
     // Check the format param
     switch (format) {
         case LOCAL_GL_ALPHA:
@@ -2339,36 +2445,36 @@ WebGLContext::ReadPixels(GLint x, GLint 
 
     void* data = pixbuf.Data();
     if (!data) {
         ErrorOutOfMemory("readPixels: buffer storage is null. Did we run out of memory?");
         return rv.Throw(NS_ERROR_OUT_OF_MEMORY);
     }
 
     bool isSourceTypeFloat = false;
-    if (mBoundFramebuffer &&
-        mBoundFramebuffer->ColorAttachmentCount() &&
-        mBoundFramebuffer->ColorAttachment(0).IsDefined())
+    if (mBoundReadFramebuffer &&
+        mBoundReadFramebuffer->ColorAttachmentCount() &&
+        mBoundReadFramebuffer->ColorAttachment(0).IsDefined())
     {
-        isSourceTypeFloat = mBoundFramebuffer->ColorAttachment(0).IsReadableFloat();
+        isSourceTypeFloat = mBoundReadFramebuffer->ColorAttachment(0).IsReadableFloat();
     }
 
     if (isReadTypeFloat != isSourceTypeFloat)
         return ErrorInvalidOperation("readPixels: Invalid type floatness");
 
     // Check the format and type params to assure they are an acceptable pair (as per spec)
     MakeContextCurrent();
 
-    if (mBoundFramebuffer) {
+    if (mBoundReadFramebuffer) {
         // prevent readback of arbitrary video memory through uninitialized renderbuffers!
-        if (!mBoundFramebuffer->CheckAndInitializeAttachments())
+        if (!mBoundReadFramebuffer->CheckAndInitializeAttachments())
             return ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
 
         GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
-        if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
+        if (!mBoundReadFramebuffer->HasCompletePlanes(readPlaneBits)) {
             return ErrorInvalidOperation("readPixels: Read source attachment doesn't have the"
                                          " correct color/depth/stencil type.");
         }
     } else {
       ClearBackbufferIfNeeded();
     }
 
     bool isFormatAndTypeValid = false;
@@ -2481,18 +2587,18 @@ WebGLContext::ReadPixels(GLint x, GLint 
     // GL_ALPHA to readpixels currently, but we had the code written for it already.
 
     const bool formatHasAlpha = format == LOCAL_GL_ALPHA ||
                                 format == LOCAL_GL_RGBA;
     if (!formatHasAlpha)
         return;
 
     bool needAlphaFilled;
-    if (mBoundFramebuffer) {
-        needAlphaFilled = !mBoundFramebuffer->ColorAttachment(0).HasAlpha();
+    if (mBoundReadFramebuffer) {
+        needAlphaFilled = !mBoundReadFramebuffer->ColorAttachment(0).HasAlpha();
     } else {
         needAlphaFilled = !mOptions.alpha;
     }
 
     if (!needAlphaFilled)
         return;
 
     size_t stride = checked_alignedRowSize.value(); // In bytes!
--- a/dom/canvas/WebGLContextState.cpp
+++ b/dom/canvas/WebGLContextState.cpp
@@ -69,25 +69,25 @@ StringValue(JSContext* cx, const char* c
 
     return JS::StringValue(str);
 }
 
 bool
 WebGLContext::GetStencilBits(GLint* out_stencilBits)
 {
     *out_stencilBits = 0;
-    if (mBoundFramebuffer) {
-        if (mBoundFramebuffer->HasDepthStencilConflict()) {
+    if (mBoundDrawFramebuffer) {
+        if (mBoundDrawFramebuffer->HasDepthStencilConflict()) {
             // Error, we don't know which stencil buffer's bits to use
             ErrorInvalidFramebufferOperation("getParameter: framebuffer has two stencil buffers bound");
             return false;
         }
 
-        if (mBoundFramebuffer->StencilAttachment().IsDefined() ||
-            mBoundFramebuffer->DepthStencilAttachment().IsDefined())
+        if (mBoundDrawFramebuffer->StencilAttachment().IsDefined() ||
+            mBoundDrawFramebuffer->DepthStencilAttachment().IsDefined())
         {
             *out_stencilBits = 8;
         }
     } else if (mOptions.stencil) {
         *out_stencilBits = 8;
     }
 
     return true;
@@ -145,17 +145,17 @@ WebGLContext::GetParameter(JSContext* cx
             return JS::Int32Value(mGLMaxColorAttachments);
 
         } else if (pname == LOCAL_GL_MAX_DRAW_BUFFERS) {
             return JS::Int32Value(mGLMaxDrawBuffers);
 
         } else if (pname >= LOCAL_GL_DRAW_BUFFER0 &&
                    pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + mGLMaxDrawBuffers))
         {
-            if (mBoundFramebuffer) {
+            if (mBoundDrawFramebuffer) {
                 GLint iv = 0;
                 gl->fGetIntegerv(pname, &iv);
                 return JS::Int32Value(iv);
             }
 
             GLint iv = 0;
             gl->fGetIntegerv(pname, &iv);
 
@@ -185,16 +185,20 @@ WebGLContext::GetParameter(JSContext* cx
                 GLint val;
                 gl->fGetIntegerv(pname, &val);
                 return JS::NumberValue(uint32_t(val));
             }
 
             case LOCAL_GL_TEXTURE_BINDING_3D: {
                 return WebGLObjectAsJSValue(cx, mBound3DTextures[mActiveTexture].get(), rv);
             }
+
+            // DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING.
+            case LOCAL_GL_READ_FRAMEBUFFER_BINDING:
+                return WebGLObjectAsJSValue(cx, mBoundReadFramebuffer.get(), rv);
         }
     }
 
     switch (pname) {
         //
         // String params
         //
         case LOCAL_GL_VENDOR:
@@ -504,18 +508,19 @@ WebGLContext::GetParameter(JSContext* cx
         case LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING: {
             return WebGLObjectAsJSValue(cx, mBoundVertexArray->mElementArrayBuffer.get(), rv);
         }
 
         case LOCAL_GL_RENDERBUFFER_BINDING: {
             return WebGLObjectAsJSValue(cx, mBoundRenderbuffer.get(), rv);
         }
 
+        // DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING.
         case LOCAL_GL_FRAMEBUFFER_BINDING: {
-            return WebGLObjectAsJSValue(cx, mBoundFramebuffer.get(), rv);
+            return WebGLObjectAsJSValue(cx, mBoundDrawFramebuffer.get(), rv);
         }
 
         case LOCAL_GL_CURRENT_PROGRAM: {
             return WebGLObjectAsJSValue(cx, mCurrentProgram.get(), rv);
         }
 
         case LOCAL_GL_TEXTURE_BINDING_2D: {
             return WebGLObjectAsJSValue(cx, mBound2DTextures[mActiveTexture].get(), rv);
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -593,21 +593,24 @@ WebGLContext::EnumName(GLenum glenum)
         XX(COMPRESSED_RGB_PVRTC_2BPPV1);
         XX(COMPRESSED_RGB_PVRTC_4BPPV1);
         XX(COMPRESSED_RGB_S3TC_DXT1_EXT);
         XX(DEPTH_COMPONENT);
         XX(DEPTH_COMPONENT16);
         XX(DEPTH_COMPONENT32);
         XX(DEPTH_STENCIL);
         XX(DEPTH24_STENCIL8);
+        XX(DRAW_FRAMEBUFFER);
         XX(ETC1_RGB8_OES);
         XX(FLOAT);
+        XX(FRAMEBUFFER);
         XX(HALF_FLOAT);
         XX(LUMINANCE);
         XX(LUMINANCE_ALPHA);
+        XX(READ_FRAMEBUFFER);
         XX(RGB);
         XX(RGB16F);
         XX(RGB32F);
         XX(RGBA);
         XX(RGBA16F);
         XX(RGBA32F);
         XX(SRGB);
         XX(SRGB_ALPHA);
@@ -766,18 +769,16 @@ WebGLContext::EnumName(GLenum glenum)
         XX(FRAMEBUFFER_ATTACHMENT_BLUE_SIZE);
         XX(FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE);
         XX(FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE);
         XX(FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE);
         XX(FRAMEBUFFER_DEFAULT);
         XX(DEPTH_STENCIL_ATTACHMENT);
         XX(UNSIGNED_NORMALIZED);
         XX(DRAW_FRAMEBUFFER_BINDING);
-        XX(READ_FRAMEBUFFER);
-        XX(DRAW_FRAMEBUFFER);
         XX(READ_FRAMEBUFFER_BINDING);
         XX(RENDERBUFFER_SAMPLES);
         XX(FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER);
         XX(MAX_COLOR_ATTACHMENTS);
         XX(COLOR_ATTACHMENT1);
         XX(COLOR_ATTACHMENT2);
         XX(COLOR_ATTACHMENT3);
         XX(COLOR_ATTACHMENT4);
@@ -1023,20 +1024,31 @@ WebGLContext::AssertCachedBindings()
     GetAndFlushUnderlyingGLErrors();
 
     if (IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
         GLuint bound = mBoundVertexArray ? mBoundVertexArray->GLName() : 0;
         AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, bound);
     }
 
     // Bound object state
-    GLuint bound = mBoundFramebuffer ? mBoundFramebuffer->GLName() : 0;
-    AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound);
+    if (IsWebGL2()) {
+        GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->GLName()
+                                             : 0;
+        AssertUintParamCorrect(gl, LOCAL_GL_DRAW_FRAMEBUFFER_BINDING, bound);
 
-    bound = mCurrentProgram ? mCurrentProgram->GLName() : 0;
+        bound = mBoundReadFramebuffer ? mBoundReadFramebuffer->GLName() : 0;
+        AssertUintParamCorrect(gl, LOCAL_GL_READ_FRAMEBUFFER_BINDING, bound);
+    } else {
+        MOZ_ASSERT(mBoundDrawFramebuffer == mBoundReadFramebuffer);
+        GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->GLName()
+                                             : 0;
+        AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound);
+    }
+
+    GLuint bound = mCurrentProgram ? mCurrentProgram->GLName() : 0;
     AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound);
 
     // Textures
     GLenum activeTexture = mActiveTexture + LOCAL_GL_TEXTURE0;
     AssertUintParamCorrect(gl, LOCAL_GL_ACTIVE_TEXTURE, activeTexture);
 
     WebGLTexture* curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_2D);
     bound = curTex ? curTex->GLName() : 0;
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -411,20 +411,20 @@ bool WebGLContext::ValidateGLSLString(co
     return true;
 }
 
 /**
  * Return true if the framebuffer attachment is valid. Attachment must
  * be one of depth/stencil/depth_stencil/color attachment.
  */
 bool
-WebGLContext::ValidateFramebufferAttachment(GLenum attachment,
+WebGLContext::ValidateFramebufferAttachment(const WebGLFramebuffer* fb, GLenum attachment,
                                             const char* funcName)
 {
-    if (!mBoundFramebuffer) {
+    if (!fb) {
         switch (attachment) {
         case LOCAL_GL_COLOR:
         case LOCAL_GL_DEPTH:
         case LOCAL_GL_STENCIL:
             return true;
 
         default:
             ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
@@ -1323,37 +1323,36 @@ bool
 WebGLContext::ValidateCopyTexImage(GLenum format, WebGLTexImageFunc func,
                                    WebGLTexDimensions dims)
 {
     MOZ_ASSERT(IsCopyFunc(func));
 
     // Default framebuffer format
     GLenum fboFormat = mOptions.alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
 
-    if (mBoundFramebuffer) {
-        if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
+    if (mBoundReadFramebuffer) {
+        if (!mBoundReadFramebuffer->CheckAndInitializeAttachments()) {
             ErrorInvalidFramebufferOperation("%s: Incomplete framebuffer.",
                                              InfoFrom(func, dims));
             return false;
         }
 
         GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
-        if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
+        if (!mBoundReadFramebuffer->HasCompletePlanes(readPlaneBits)) {
             ErrorInvalidOperation("%s: Read source attachment doesn't have the"
                                   " correct color/depth/stencil type.",
                                   InfoFrom(func, dims));
             return false;
         }
 
-        // Get the correct format for the framebuffer, as it's not the default
-        // one.
+        // Get the correct format for the framebuffer, as it's not the default one.
         const WebGLFramebuffer::Attachment& color0 =
-            mBoundFramebuffer->GetAttachment(LOCAL_GL_COLOR_ATTACHMENT0);
+            mBoundReadFramebuffer->GetAttachment(LOCAL_GL_COLOR_ATTACHMENT0);
 
-        fboFormat = mBoundFramebuffer->GetFormatForAttachment(color0);
+        fboFormat = mBoundReadFramebuffer->GetFormatForAttachment(color0);
     }
 
     // Make sure the format of the framebuffer is a superset of the format
     // requested by the CopyTex[Sub]Image2D functions.
     const GLComponents formatComps = GLComponents(format);
     const GLComponents fboComps = GLComponents(fboFormat);
     if (!formatComps.IsSubsetOf(fboComps)) {
         ErrorInvalidOperation("%s: Format %s is not a subset of the current"
@@ -1944,17 +1943,18 @@ WebGLContext::InitAndValidateGL()
     mBound2DTextures.Clear();
     mBoundCubeMapTextures.Clear();
     mBound3DTextures.Clear();
 
     mBoundArrayBuffer = nullptr;
     mBoundTransformFeedbackBuffer = nullptr;
     mCurrentProgram = nullptr;
 
-    mBoundFramebuffer = nullptr;
+    mBoundDrawFramebuffer = nullptr;
+    mBoundReadFramebuffer = nullptr;
     mBoundRenderbuffer = nullptr;
 
     MakeContextCurrent();
 
     // on desktop OpenGL, we always keep vertex attrib 0 array enabled
     if (!gl->IsGLES())
         gl->fEnableVertexAttribArray(0);
 
@@ -2138,9 +2138,37 @@ WebGLContext::InitAndValidateGL()
     mBoundVertexArray = mDefaultVertexArray;
 
     if (mLoseContextOnMemoryPressure)
         mContextObserver->RegisterMemoryPressureEvent();
 
     return true;
 }
 
+bool
+WebGLContext::ValidateFramebufferTarget(GLenum target,
+                                        const char* const info)
+{
+    bool isValid = true;
+    switch (target) {
+    case LOCAL_GL_FRAMEBUFFER:
+        break;
+
+    case LOCAL_GL_DRAW_FRAMEBUFFER:
+    case LOCAL_GL_READ_FRAMEBUFFER:
+        isValid = IsWebGL2();
+        break;
+
+    default:
+        isValid = false;
+        break;
+    }
+
+    if (MOZ_LIKELY(isValid)) {
+        return true;
+    }
+
+    ErrorInvalidEnum("%s: Invalid target: %s (0x%04x).", info, EnumName(target),
+                     target);
+    return false;
+}
+
 } // namespace mozilla
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -450,17 +450,18 @@ WebGLFramebuffer::DetachAllAttachments()
     DetachAttachment(mDepthStencilAttachment);
 }
 
 void
 WebGLFramebuffer::FramebufferRenderbuffer(FBAttachment attachPoint,
                                           RBTarget rbtarget,
                                           WebGLRenderbuffer* rb)
 {
-    MOZ_ASSERT(mContext->mBoundFramebuffer == this);
+    MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
+               mContext->mBoundReadFramebuffer == this);
 
     if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer",
                                            rb))
     {
         return;
     }
 
     /* Get the requested attachment. If result is NULL, attachment is invalid
@@ -491,17 +492,18 @@ WebGLFramebuffer::FramebufferRenderbuffe
     attachment->SetRenderbuffer(rb);
 }
 
 void
 WebGLFramebuffer::FramebufferTexture2D(FBAttachment attachPoint,
                                        TexImageTarget texImageTarget,
                                        WebGLTexture* tex, GLint level)
 {
-    MOZ_ASSERT(mContext->mBoundFramebuffer == this);
+    MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
+               mContext->mBoundReadFramebuffer == this);
 
     if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture",
                                            tex))
     {
         return;
     }
 
     if (tex) {
@@ -559,17 +561,17 @@ WebGLFramebuffer::GetAttachmentOrNull(FB
 
     case LOCAL_GL_STENCIL_ATTACHMENT:
         return &mStencilAttachment;
 
     default:
         break;
     }
 
-    if (!mContext->ValidateFramebufferAttachment(attachPoint.get(),
+    if (!mContext->ValidateFramebufferAttachment(this, attachPoint.get(),
                                                  "getAttachmentOrNull"))
     {
         return nullptr;
     }
 
     size_t colorAttachmentId = attachPoint.get() - LOCAL_GL_COLOR_ATTACHMENT0;
     EnsureColorAttachments(colorAttachmentId);
 
@@ -588,17 +590,17 @@ WebGLFramebuffer::GetAttachment(FBAttach
 
     case LOCAL_GL_STENCIL_ATTACHMENT:
         return mStencilAttachment;
 
     default:
         break;
     }
 
-    if (!mContext->ValidateFramebufferAttachment(attachPoint.get(),
+    if (!mContext->ValidateFramebufferAttachment(this, attachPoint.get(),
                                                  "getAttachment"))
     {
         MOZ_ASSERT(false);
         return mColorAttachments[0];
     }
 
     size_t colorAttachmentId = attachPoint.get() - LOCAL_GL_COLOR_ATTACHMENT0;
     if (colorAttachmentId >= mColorAttachments.Length()) {
@@ -761,17 +763,18 @@ WebGLFramebuffer::RectangleObject() cons
     // has a consistent rect.
     MOZ_ASSERT(AllImageRectsMatch(), "Did you mean `GetAnyRectObject`?");
     return GetAnyRectObject();
 }
 
 FBStatus
 WebGLFramebuffer::PrecheckFramebufferStatus() const
 {
-    MOZ_ASSERT(mContext->mBoundFramebuffer == this);
+    MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
+               mContext->mBoundReadFramebuffer == this);
 
     if (!HasDefinedAttachments())
         return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; // No attachments
 
     if (HasIncompleteAttachments())
         return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
 
     if (!AllImageRectsMatch())
@@ -804,17 +807,19 @@ WebGLFramebuffer::CheckFramebufferStatus
 }
 
 bool
 WebGLFramebuffer::HasCompletePlanes(GLbitfield mask)
 {
     if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
         return false;
 
-    MOZ_ASSERT(mContext->mBoundFramebuffer == this);
+    MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
+               mContext->mBoundReadFramebuffer == this);
+
     bool hasPlanes = true;
     if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
         hasPlanes &= ColorAttachmentCount() &&
                      ColorAttachment(0).IsDefined();
     }
 
     if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) {
         hasPlanes &= DepthAttachment().IsDefined() ||
@@ -827,17 +832,18 @@ WebGLFramebuffer::HasCompletePlanes(GLbi
     }
 
     return hasPlanes;
 }
 
 bool
 WebGLFramebuffer::CheckAndInitializeAttachments()
 {
-    MOZ_ASSERT(mContext->mBoundFramebuffer == this);
+    MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
+               mContext->mBoundReadFramebuffer == this);
 
     if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
         return false;
 
     // Cool! We've checked out ok. Just need to initialize.
     const size_t colorAttachmentCount = mColorAttachments.Length();
 
     // Check if we need to initialize anything
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -573,10 +573,11 @@ skip-if = toolkit == 'android'
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(needs control of popup window size) b2g-debug(needs control of popup window size) b2g-desktop(needs control of popup window size)
 [test_non-ascii-cookie.html]
 skip-if = buildapp == 'b2g' || e10s
 [test_bug765780.html]
 [test_bug871161.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || e10s #Bug 931116, b2g desktop specific, initial triage
 support-files = file_bug871161-1.html file_bug871161-2.html
 [test_bug1013316.html]
+[test_hash_encoded.html]
 [test_bug1081037.html]
 
new file mode 100644
--- /dev/null
+++ b/dom/html/test/test_hash_encoded.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<html>
+<head>
+<title>Test link.hash attribute</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<a id="target1" href="http://www.example.com/#q=♥â¥#hello"></a>
+<a id="target2" href="http://www.example.com/#q=%E2%99%A5%C3%A2%C2%A5"></a>
+<a id="target3" href="http://www.example.com/#/search/%23important"></a>
+<a id="target4" href='http://www.example.com/#{"a":[13, 42], "b":{"key":"value"}}'></a>
+
+<pre id="test">
+
+<script>
+  // Tests Link::GetHash
+
+  // Check that characters aren't being encoded
+  var target = document.getElementById("target1");
+  is(target.hash, '#q=♥â¥#hello', 'Unexpected link hash');
+
+  // Check that encoded characters aren't being decoded
+  target = document.getElementById("target2");
+  is(target.hash, '#q=%E2%99%A5%C3%A2%C2%A5', 'Unexpected link hash');
+
+  // A more regular use case
+  target = document.getElementById("target3");
+  is(target.hash, '#/search/%23important', 'Unexpected link hash');
+
+  // Some JSON
+  target = document.getElementById("target4");
+  is(target.hash, '#{"a":[13, 42], "b":{"key":"value"}}', 'Unexpected link hash');
+</script>
+
+<script>
+  // Tests URL::GetHash
+
+  var url = new URL("http://www.example.com/#q=♥â¥#hello")
+  is(url.hash, '#q=♥â¥#hello', 'Unexpected url hash');
+
+  url = new URL("http://www.example.com/#q=%E2%99%A5%C3%A2%C2%A5")
+  is(url.hash, '#q=%E2%99%A5%C3%A2%C2%A5', 'Unexpected url hash');
+
+  url = new URL("http://www.example.com/#/search/%23important")
+  is(url.hash, '#/search/%23important', 'Unexpected url hash');
+
+  // Test getters and setters
+
+  url = new URL("http://www.example.com/");
+  url.hash = "#q=♥â¥#hello%E2%99%A5%C3%A2%C2%A5#/search/%23important"
+  is(url.hash, '#q=♥â¥#hello%E2%99%A5%C3%A2%C2%A5#/search/%23important', 'Unexpected url hash');
+
+  // codepath in nsStandardUrl::SetRef is different if the path is non-empty
+  url = new URL("http://www.example.com/test/");
+  url.hash = "#q=♥â¥#hello%E2%99%A5%C3%A2%C2%A5#/search/%23important"
+  is(url.hash, '#q=♥â¥#hello%E2%99%A5%C3%A2%C2%A5#/search/%23important', 'Unexpected url hash');
+
+  url = new URL("http://www.example.com/");
+  url.hash = '#{"a":[13, 42], "b":{"key":"value"}}';
+  is(target.hash, '#{"a":[13, 42], "b":{"key":"value"}}', 'Unexpected url hash');
+  var parsed = JSON.parse(target.hash.substring(1));
+  is(parsed.b.key, 'value', 'JSON not parsed correctly');
+
+  url = new URL("http://www.example.com/test/");
+  url.hash = '#{"a":[13, 42], "b":{"key":"value"}}';
+  is(target.hash, '#{"a":[13, 42], "b":{"key":"value"}}', 'Unexpected url hash');
+  parsed = JSON.parse(target.hash.substring(1));
+  is(parsed.b.key, 'value', 'JSON not parsed correctly');
+</script>
+
+<script>
+  // Tests nsLocation::GetHash
+
+  window.history.pushState(1, document.title, '#q=♥â¥#hello');
+  is(location.hash,'#q=♥â¥#hello', 'Unexpected location hash');
+
+  window.history.pushState(1, document.title, '#q=%E2%99%A5%C3%A2%C2%A5');
+  is(location.hash,'#q=%E2%99%A5%C3%A2%C2%A5', 'Unexpected location hash');
+
+  window.history.pushState(1, document.title, '#/search/%23important');
+  is(location.hash,'#/search/%23important', 'Unexpected location hash');
+
+  window.history.pushState(1, document.title, '#{"a":[13, 42], "b":{"key":"value"}}');
+  is(location.hash,'#{"a":[13, 42], "b":{"key":"value"}}', 'Unexpected location hash');
+</script>
+
+</pre>
+</body>
+</html>
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -989,16 +989,21 @@ ContentParent::RecvFindPlugins(const uin
 ContentParent::CreateBrowserOrApp(const TabContext& aContext,
                                   Element* aFrameElement,
                                   ContentParent* aOpenerContentParent)
 {
     if (!sCanLaunchSubprocesses) {
         return nullptr;
     }
 
+    if (TabParent* parent = TabParent::GetNextTabParent()) {
+        parent->SetOwnerElement(aFrameElement);
+        return parent;
+    }
+
     ProcessPriority initialPriority = GetInitialProcessPriority(aFrameElement);
     bool isInContentProcess = (XRE_GetProcessType() != GeckoProcessType_Default);
     TabId tabId;
 
     nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement);
     TabId openerTabId;
     if (docShell) {
         openerTabId = TabParent::GetTabIdFrom(docShell);
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -74,16 +74,22 @@ struct ShowInfo
 {
   nsString name;
   bool fullscreenAllowed;
   bool isPrivate;
   float dpi;
   double defaultScale;
 };
 
+struct FrameScriptInfo
+{
+    nsString url;
+    bool runInGlobalScope;
+};
+
 prio(normal upto urgent) intr protocol PBrowser
 {
     manager PContent or PContentBridge;
 
     manages PColorPicker;
     manages PDocumentRenderer;
     manages PContentPermissionRequest;
     manages PFilePicker;
@@ -112,25 +118,26 @@ parent:
     /**
      * When child sends this message, parent should move focus to
      * the next or previous focusable element.
      */
     MoveFocus(bool forward);
 
     Event(RemoteDOMEvent aEvent);
 
-    intr CreateWindow(uint32_t aChromeFlags,
+    sync CreateWindow(PBrowser aNewTab,
+                      uint32_t aChromeFlags,
                       bool aCalledFromJS,
                       bool aPositionSpecified,
                       bool aSizeSpecified,
                       nsString aURI,
                       nsString aName,
                       nsString aFeatures,
                       nsString aBaseURI)
-      returns (bool windowIsNew, PBrowser window);
+      returns (bool windowOpened, FrameScriptInfo[] frameScripts);
 
     sync SyncMessage(nsString aMessage, ClonedMessageData aData,
                      CpowEntry[] aCpows, Principal aPrincipal)
       returns (nsString[] retval);
 
     prio(high) sync RpcMessage(nsString aMessage, ClonedMessageData aData,
                                CpowEntry[] aCpows, Principal aPrincipal)
       returns (nsString[] retval);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1424,103 +1424,63 @@ TabChild::ProvideWindow(nsIDOMWindow* aP
                         nsIDOMWindow** aReturn)
 {
     *aReturn = nullptr;
 
     // If aParent is inside an <iframe mozbrowser> or <iframe mozapp> and this
     // isn't a request to open a modal-type window, we're going to create a new
     // <iframe mozbrowser/mozapp> and return its window here.
     nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent);
-    if (docshell && docshell->GetIsInBrowserOrApp() &&
-        !(aChromeFlags & (nsIWebBrowserChrome::CHROME_MODAL |
-                          nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
-                          nsIWebBrowserChrome::CHROME_OPENAS_CHROME))) {
-
-      // Note that BrowserFrameProvideWindow may return NS_ERROR_ABORT if the
-      // open window call was canceled.  It's important that we pass this error
-      // code back to our caller.
-      return BrowserFrameProvideWindow(aParent, aURI, aName, aFeatures,
-                                       aWindowIsNew, aReturn);
-    }
-
-    int32_t openLocation =
-      nsWindowWatcher::GetWindowOpenLocation(aParent, aChromeFlags, aCalledFromJS,
-                                             aPositionSpecified, aSizeSpecified);
-
-    // If it turns out we're opening in the current browser, just hand over the
-    // current browser's docshell.
-    if (openLocation == nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) {
-      nsCOMPtr<nsIWebBrowser> browser = do_GetInterface(WebNavigation());
-      *aWindowIsNew = false;
-      return browser->GetContentDOMWindow(aReturn);
-    }
-
-    // Otherwise, we're opening a new tab or a new window. We have to contact
-    // TabParent in order to do either.
-
-    PBrowserChild* newChild;
-
-    nsAutoCString uriString;
-    if (aURI) {
-      aURI->GetSpec(uriString);
+    bool iframeMoz = (docshell && docshell->GetIsInBrowserOrApp() &&
+                      !(aChromeFlags & (nsIWebBrowserChrome::CHROME_MODAL |
+                                        nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
+                                        nsIWebBrowserChrome::CHROME_OPENAS_CHROME)));
+
+    if (!iframeMoz) {
+      int32_t openLocation =
+        nsWindowWatcher::GetWindowOpenLocation(aParent, aChromeFlags, aCalledFromJS,
+                                               aPositionSpecified, aSizeSpecified);
+
+      // If it turns out we're opening in the current browser, just hand over the
+      // current browser's docshell.
+      if (openLocation == nsIBrowserDOMWindow::OPEN_CURRENTWINDOW) {
+        nsCOMPtr<nsIWebBrowser> browser = do_GetInterface(WebNavigation());
+        *aWindowIsNew = false;
+        return browser->GetContentDOMWindow(aReturn);
+      }
     }
 
-    nsCOMPtr<nsIDOMDocument> domDoc;
-    aParent->GetDocument(getter_AddRefs(domDoc));
-    if (!domDoc) {
-      NS_ERROR("Could retrieve document from nsIBaseWindow");
-      return NS_ERROR_FAILURE;
-    }
-
-    nsCOMPtr<nsIDocument> doc;
-    doc = do_QueryInterface(domDoc);
-    if (!doc) {
-      NS_ERROR("Document from nsIBaseWindow didn't QI to nsIDocument");
-      return NS_ERROR_FAILURE;
-    }
-
-    nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
-    if (!baseURI) {
-      NS_ERROR("nsIDocument didn't return a base URI");
-      return NS_ERROR_FAILURE;
-    }
-
-    nsAutoCString baseURIString;
-    baseURI->GetSpec(baseURIString);
-
-    nsAutoString nameString;
-    nameString.Assign(aName);
-    nsAutoCString features;
-
-    // We can assume that if content is requesting to open a window from a remote
-    // tab, then we want to enforce that the new window is also a remote tab.
-    features.Assign(aFeatures);
-    features.Append(",remote");
-
-    if (!CallCreateWindow(aChromeFlags, aCalledFromJS, aPositionSpecified,
-                          aSizeSpecified, NS_ConvertUTF8toUTF16(uriString),
-                          nameString, NS_ConvertUTF8toUTF16(features),
-                          NS_ConvertUTF8toUTF16(baseURIString),
-                          aWindowIsNew, &newChild)) {
-        return NS_ERROR_NOT_AVAILABLE;
-    }
-
-    nsCOMPtr<nsIDOMWindow> win =
-        do_GetInterface(static_cast<TabChild*>(newChild)->WebNavigation());
-    win.forget(aReturn);
-    return NS_OK;
+    // Note that ProvideWindowCommon may return NS_ERROR_ABORT if the
+    // open window call was canceled.  It's important that we pass this error
+    // code back to our caller.
+    return ProvideWindowCommon(aParent,
+                               iframeMoz,
+                               aChromeFlags,
+                               aCalledFromJS,
+                               aPositionSpecified,
+                               aSizeSpecified,
+                               aURI,
+                               aName,
+                               aFeatures,
+                               aWindowIsNew,
+                               aReturn);
 }
 
 nsresult
-TabChild::BrowserFrameProvideWindow(nsIDOMWindow* aOpener,
-                                    nsIURI* aURI,
-                                    const nsAString& aName,
-                                    const nsACString& aFeatures,
-                                    bool* aWindowIsNew,
-                                    nsIDOMWindow** aReturn)
+TabChild::ProvideWindowCommon(nsIDOMWindow* aOpener,
+                              bool aIframeMoz,
+                              uint32_t aChromeFlags,
+                              bool aCalledFromJS,
+                              bool aPositionSpecified,
+                              bool aSizeSpecified,
+                              nsIURI* aURI,
+                              const nsAString& aName,
+                              const nsACString& aFeatures,
+                              bool* aWindowIsNew,
+                              nsIDOMWindow** aReturn)
 {
   *aReturn = nullptr;
 
   ContentChild* cc = ContentChild::GetSingleton();
   const TabId openerTabId = GetTabId();
 
   // We must use PopupIPCTabContext here; ContentParent will not accept the
   // result of this->AsIPCTabContext() (which will be a
@@ -1534,38 +1494,80 @@ TabChild::BrowserFrameProvideWindow(nsID
 
   TabId tabId;
   cc->SendAllocateTabId(openerTabId,
                         ipcContext,
                         cc->GetID(),
                         &tabId);
 
   nsRefPtr<TabChild> newChild = new TabChild(ContentChild::GetSingleton(), tabId,
-                                             /* TabContext */ *this, /* chromeFlags */ 0);
+                                             /* TabContext */ *this, aChromeFlags);
   if (NS_FAILED(newChild->Init())) {
     return NS_ERROR_ABORT;
   }
 
   context.opener() = this;
   unused << Manager()->SendPBrowserConstructor(
       // We release this ref in DeallocPBrowserChild
       nsRefPtr<TabChild>(newChild).forget().take(),
-      tabId, IPCTabContext(context, mScrolling), /* chromeFlags */ 0,
+      tabId, IPCTabContext(context, mScrolling), aChromeFlags,
       cc->GetID(), cc->IsForApp(), cc->IsForBrowser());
 
   nsAutoCString spec;
   if (aURI) {
     aURI->GetSpec(spec);
   }
 
   NS_ConvertUTF8toUTF16 url(spec);
   nsString name(aName);
-  NS_ConvertUTF8toUTF16 features(aFeatures);
-  newChild->SendBrowserFrameOpenWindow(this, url, name,
-                                       features, aWindowIsNew);
+  nsAutoCString features(aFeatures);
+  nsTArray<FrameScriptInfo> frameScripts;
+
+  if (aIframeMoz) {
+    newChild->SendBrowserFrameOpenWindow(this, url, name,
+                                         NS_ConvertUTF8toUTF16(features),
+                                         aWindowIsNew);
+  } else {
+    nsCOMPtr<nsIDOMDocument> domDoc;
+    aOpener->GetDocument(getter_AddRefs(domDoc));
+    if (!domDoc) {
+      NS_ERROR("Could retrieve document from nsIBaseWindow");
+      return NS_ERROR_FAILURE;
+    }
+
+    nsCOMPtr<nsIDocument> doc;
+    doc = do_QueryInterface(domDoc);
+    if (!doc) {
+      NS_ERROR("Document from nsIBaseWindow didn't QI to nsIDocument");
+      return NS_ERROR_FAILURE;
+    }
+
+    nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
+    if (!baseURI) {
+      NS_ERROR("nsIDocument didn't return a base URI");
+      return NS_ERROR_FAILURE;
+    }
+
+    nsAutoCString baseURIString;
+    baseURI->GetSpec(baseURIString);
+
+    // We can assume that if content is requesting to open a window from a remote
+    // tab, then we want to enforce that the new window is also a remote tab.
+    features.AppendLiteral(",remote");
+
+    if (!SendCreateWindow(newChild,
+                          aChromeFlags, aCalledFromJS, aPositionSpecified,
+                          aSizeSpecified, url,
+                          name, NS_ConvertUTF8toUTF16(features),
+                          NS_ConvertUTF8toUTF16(baseURIString),
+                          aWindowIsNew,
+                          &frameScripts)) {
+      return NS_ERROR_NOT_AVAILABLE;
+    }
+  }
   if (!*aWindowIsNew) {
     PBrowserChild::Send__delete__(newChild);
     return NS_ERROR_ABORT;
   }
 
   ScrollingBehavior scrolling = DEFAULT_SCROLLING;
   TextureFactoryIdentifier textureFactoryIdentifier;
   uint64_t layersId = 0;
@@ -1578,16 +1580,23 @@ TabChild::BrowserFrameProvideWindow(nsID
     PRenderFrameChild::Send__delete__(renderFrame);
     renderFrame = nullptr;
   }
 
   // Unfortunately we don't get a window unless we've shown the frame.  That's
   // pretty bogus; see bug 763602.
   newChild->DoFakeShow(scrolling, textureFactoryIdentifier, layersId, renderFrame);
 
+  for (size_t i = 0; i < frameScripts.Length(); i++) {
+    FrameScriptInfo& info = frameScripts[i];
+    if (!newChild->RecvLoadRemoteScript(info.url(), info.runInGlobalScope())) {
+      MOZ_CRASH();
+    }
+  }
+
   nsCOMPtr<nsIDOMWindow> win = do_GetInterface(newChild->WebNavigation());
   win.forget(aReturn);
   return NS_OK;
 }
 
 bool
 TabChild::HasValidInnerSize()
 {
@@ -1909,17 +1918,24 @@ TabChild::DoFakeShow(const ScrollingBeha
 }
 
 void
 TabChild::ApplyShowInfo(const ShowInfo& aInfo)
 {
   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
   if (docShell) {
     nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(docShell);
-    item->SetName(aInfo.name());
+    if (IsBrowserOrApp()) {
+      // B2G allows window.name to be set by changing the name attribute on the
+      // <iframe mozbrowser> element. window.open calls cause this attribute to
+      // be set to the correct value. A normal <xul:browser> element has no such
+      // attribute. The data we get here comes from reading the attribute, so we
+      // shouldn't trust it for <xul:browser> elements.
+      item->SetName(aInfo.name());
+    }
     docShell->SetFullscreenAllowed(aInfo.fullscreenAllowed());
     if (aInfo.isPrivate()) {
       bool nonBlank;
       docShell->GetHasLoadedNonBlankURI(&nonBlank);
       if (nonBlank) {
         nsContentUtils::ReportToConsoleNonLocalized(
           NS_LITERAL_STRING("We should not switch to Private Browsing after loading a document."),
           nsIScriptError::warningFlag,
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -569,22 +569,27 @@ private:
     // isn't a tap, then we CancelTapTracking().  In the meantime, we
     // may detect a context-menu event, and if so we
     // FireContextMenuEvent().
     void FireContextMenuEvent();
     void CancelTapTracking();
     void UpdateTapState(const WidgetTouchEvent& aEvent, nsEventStatus aStatus);
 
     nsresult
-    BrowserFrameProvideWindow(nsIDOMWindow* aOpener,
-                              nsIURI* aURI,
-                              const nsAString& aName,
-                              const nsACString& aFeatures,
-                              bool* aWindowIsNew,
-                              nsIDOMWindow** aReturn);
+    ProvideWindowCommon(nsIDOMWindow* aOpener,
+                        bool aIframeMoz,
+                        uint32_t aChromeFlags,
+                        bool aCalledFromJS,
+                        bool aPositionSpecified,
+                        bool aSizeSpecified,
+                        nsIURI* aURI,
+                        const nsAString& aName,
+                        const nsACString& aFeatures,
+                        bool* aWindowIsNew,
+                        nsIDOMWindow** aReturn);
 
     bool HasValidInnerSize();
 
     void SendPendingTouchPreventedResponse(bool aPreventDefault,
                                            const ScrollableLayerGuid& aGuid);
 
     // Adds the scrollable layer target to the target list, and returns whether
     // or not the caller should wait for a refresh to send a target
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -267,16 +267,17 @@ TabParent::TabParent(nsIContentParent* a
   , mManager(aManager)
   , mMarkedDestroying(false)
   , mIsDestroyed(false)
   , mAppPackageFileDescriptorSent(false)
   , mSendOfflineStatus(true)
   , mChromeFlags(aChromeFlags)
   , mInitedByParent(false)
   , mTabId(aTabId)
+  , mSkipLoad(false)
 {
   MOZ_ASSERT(aManager);
 }
 
 TabParent::~TabParent()
 {
 }
 
@@ -444,75 +445,107 @@ TabParent::RecvEvent(const RemoteDOMEven
 
   event->SetOwner(target);
 
   bool dummy;
   target->DispatchEvent(event, &dummy);
   return true;
 }
 
+struct MOZ_STACK_CLASS TabParent::AutoUseNewTab MOZ_FINAL
+{
+public:
+  AutoUseNewTab(TabParent* aNewTab, bool* aWindowIsNew)
+   : mNewTab(aNewTab), mWindowIsNew(aWindowIsNew)
+  {
+    MOZ_ASSERT(!TabParent::sNextTabParent);
+    TabParent::sNextTabParent = aNewTab;
+    aNewTab->mSkipLoad = true;
+  }
+
+  ~AutoUseNewTab()
+  {
+    mNewTab->mSkipLoad = false;
+
+    if (TabParent::sNextTabParent) {
+      MOZ_ASSERT(TabParent::sNextTabParent == mNewTab);
+      TabParent::sNextTabParent = nullptr;
+      *mWindowIsNew = false;
+    }
+  }
+
+private:
+  TabParent* mNewTab;
+  bool* mWindowIsNew;
+};
+
 bool
-TabParent::AnswerCreateWindow(const uint32_t& aChromeFlags,
-                              const bool& aCalledFromJS,
-                              const bool& aPositionSpecified,
-                              const bool& aSizeSpecified,
-                              const nsString& aURI,
-                              const nsString& aName,
-                              const nsString& aFeatures,
-                              const nsString& aBaseURI,
-                              bool* aWindowIsNew,
-                              PBrowserParent** aRetVal)
+TabParent::RecvCreateWindow(PBrowserParent* aNewTab,
+                            const uint32_t& aChromeFlags,
+                            const bool& aCalledFromJS,
+                            const bool& aPositionSpecified,
+                            const bool& aSizeSpecified,
+                            const nsString& aURI,
+                            const nsString& aName,
+                            const nsString& aFeatures,
+                            const nsString& aBaseURI,
+                            bool* aWindowIsNew,
+                            InfallibleTArray<FrameScriptInfo>* aFrameScripts)
 {
+  // We always expect to open a new window here. If we don't, it's an error.
+  *aWindowIsNew = true;
+
   if (IsBrowserOrApp()) {
     return false;
   }
 
   nsresult rv;
   nsCOMPtr<nsPIWindowWatcher> pwwatch =
     do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, false);
 
+  TabParent* newTab = static_cast<TabParent*>(aNewTab);
+
   nsCOMPtr<nsIContent> frame(do_QueryInterface(mFrameElement));
   NS_ENSURE_TRUE(frame, false);
 
   nsCOMPtr<nsIDOMWindow> parent = do_QueryInterface(frame->OwnerDoc()->GetWindow());
   NS_ENSURE_TRUE(parent, false);
 
   int32_t openLocation =
     nsWindowWatcher::GetWindowOpenLocation(parent, aChromeFlags, aCalledFromJS,
                                            aPositionSpecified, aSizeSpecified);
 
   MOZ_ASSERT(openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
              openLocation == nsIBrowserDOMWindow::OPEN_NEWWINDOW);
 
-  *aWindowIsNew = true;
-
   // Opening new tabs is the easy case...
   if (openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB) {
     NS_ENSURE_TRUE(mBrowserDOMWindow, false);
 
     bool isPrivate;
     nsCOMPtr<nsILoadContext> loadContext = GetLoadContext();
     loadContext->GetUsePrivateBrowsing(&isPrivate);
 
     nsCOMPtr<nsIOpenURIInFrameParams> params = new nsOpenURIInFrameParams();
     params->SetReferrer(aBaseURI);
     params->SetIsPrivate(isPrivate);
 
+    AutoUseNewTab aunt(newTab, aWindowIsNew);
+
     nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner;
     mBrowserDOMWindow->OpenURIInFrame(nullptr, params,
-                                      nsIBrowserDOMWindow::OPEN_NEWTAB,
+                                      openLocation,
                                       nsIBrowserDOMWindow::OPEN_NEW,
                                       getter_AddRefs(frameLoaderOwner));
-    NS_ENSURE_TRUE(frameLoaderOwner, false);
+    if (!frameLoaderOwner) {
+      *aWindowIsNew = false;
+    }
 
-    nsRefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
-    NS_ENSURE_TRUE(frameLoader, false);
-
-    *aRetVal = frameLoader->GetRemoteBrowser();
+    aFrameScripts->SwapElements(newTab->mDelayedFrameScripts);
     return true;
   }
 
   // WindowWatcher is going to expect a valid URI to open a window
   // to. If it can't find one, it's going to attempt to figure one
   // out on its own, which is problematic because it can't access
   // the document for the remote browser we're opening. Luckily,
   // TabChild has sent us a baseURI with which we can ensure that
@@ -525,40 +558,72 @@ TabParent::AnswerCreateWindow(const uint
   rv = NS_NewURI(getter_AddRefs(finalURI), NS_ConvertUTF16toUTF8(aURI).get(), baseURI);
   NS_ENSURE_SUCCESS(rv, false);
 
   nsAutoCString finalURIString;
   finalURI->GetSpec(finalURIString);
 
   nsCOMPtr<nsIDOMWindow> window;
 
+  AutoUseNewTab aunt(newTab, aWindowIsNew);
+
   rv = pwwatch->OpenWindow2(parent, finalURIString.get(),
                             NS_ConvertUTF16toUTF8(aName).get(),
                             NS_ConvertUTF16toUTF8(aFeatures).get(), aCalledFromJS,
                             false, false, this, nullptr, getter_AddRefs(window));
   NS_ENSURE_SUCCESS(rv, false);
 
   nsCOMPtr<nsPIDOMWindow> pwindow = do_QueryInterface(window);
   NS_ENSURE_TRUE(pwindow, false);
 
   nsRefPtr<nsIDocShell> newDocShell = pwindow->GetDocShell();
   NS_ENSURE_TRUE(newDocShell, false);
 
   nsCOMPtr<nsITabParent> newRemoteTab = newDocShell->GetOpenedRemote();
   NS_ENSURE_TRUE(newRemoteTab, false);
 
-  *aRetVal = static_cast<TabParent*>(newRemoteTab.get());
+  MOZ_ASSERT(static_cast<TabParent*>(newRemoteTab.get()) == newTab);
+
+  aFrameScripts->SwapElements(newTab->mDelayedFrameScripts);
   return true;
 }
 
+TabParent* TabParent::sNextTabParent;
+
+/* static */ TabParent*
+TabParent::GetNextTabParent()
+{
+  TabParent* result = sNextTabParent;
+  sNextTabParent = nullptr;
+  return result;
+}
+
+bool
+TabParent::SendLoadRemoteScript(const nsString& aURL,
+                                const bool& aRunInGlobalScope)
+{
+  if (mSkipLoad) {
+    mDelayedFrameScripts.AppendElement(FrameScriptInfo(aURL, aRunInGlobalScope));
+    return true;
+  }
+
+  MOZ_ASSERT(mDelayedFrameScripts.IsEmpty());
+  return PBrowserParent::SendLoadRemoteScript(aURL, aRunInGlobalScope);
+}
+
 void
 TabParent::LoadURL(nsIURI* aURI)
 {
     MOZ_ASSERT(aURI);
 
+    if (mSkipLoad) {
+        // Don't send the message if the child wants to load its own URL.
+        return;
+    }
+
     if (mIsDestroyed) {
         return;
     }
 
     nsCString spec;
     aURI->GetSpec(spec);
 
     if (!mShown) {
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -129,26 +129,27 @@ public:
     virtual bool RecvEvent(const RemoteDOMEvent& aEvent) MOZ_OVERRIDE;
     virtual bool RecvReplyKeyEvent(const WidgetKeyboardEvent& aEvent) MOZ_OVERRIDE;
     virtual bool RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& aEvent) MOZ_OVERRIDE;
     virtual bool RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
                                             const nsString& aURL,
                                             const nsString& aName,
                                             const nsString& aFeatures,
                                             bool* aOutWindowOpened) MOZ_OVERRIDE;
-    virtual bool AnswerCreateWindow(const uint32_t& aChromeFlags,
-                                    const bool& aCalledFromJS,
-                                    const bool& aPositionSpecified,
-                                    const bool& aSizeSpecified,
-                                    const nsString& aURI,
-                                    const nsString& aName,
-                                    const nsString& aFeatures,
-                                    const nsString& aBaseURI,
-                                    bool* aWindowIsNew,
-                                    PBrowserParent** aRetVal) MOZ_OVERRIDE;
+    virtual bool RecvCreateWindow(PBrowserParent* aOpener,
+                                  const uint32_t& aChromeFlags,
+                                  const bool& aCalledFromJS,
+                                  const bool& aPositionSpecified,
+                                  const bool& aSizeSpecified,
+                                  const nsString& aURI,
+                                  const nsString& aName,
+                                  const nsString& aFeatures,
+                                  const nsString& aBaseURI,
+                                  bool* aWindowIsNew,
+                                  InfallibleTArray<FrameScriptInfo>* aFrameScripts) MOZ_OVERRIDE;
     virtual bool RecvSyncMessage(const nsString& aMessage,
                                  const ClonedMessageData& aData,
                                  const InfallibleTArray<CpowEntry>& aCpows,
                                  const IPC::Principal& aPrincipal,
                                  InfallibleTArray<nsString>* aJSONRetVal) MOZ_OVERRIDE;
     virtual bool RecvRpcMessage(const nsString& aMessage,
                                 const ClonedMessageData& aData,
                                 const InfallibleTArray<CpowEntry>& aCpows,
@@ -347,16 +348,21 @@ public:
      * Native widget remoting protocol for use with windowed plugins with e10s.
      */
     virtual PPluginWidgetParent* AllocPPluginWidgetParent() MOZ_OVERRIDE;
     virtual bool DeallocPPluginWidgetParent(PPluginWidgetParent* aActor) MOZ_OVERRIDE;
 
     void SetInitedByParent() { mInitedByParent = true; }
     bool IsInitedByParent() const { return mInitedByParent; }
 
+    static TabParent* GetNextTabParent();
+
+    bool SendLoadRemoteScript(const nsString& aURL,
+                              const bool& aRunInGlobalScope);
+
 protected:
     bool ReceiveMessage(const nsString& aMessage,
                         bool aSync,
                         const StructuredCloneData* aCloneData,
                         CpowHolder* aCpows,
                         nsIPrincipal* aPrincipal,
                         InfallibleTArray<nsString>* aJSONRetVal = nullptr);
 
@@ -463,16 +469,45 @@ private:
     // When true, the TabParent is initialized without child side's request.
     // When false, the TabParent is initialized by window.open() from child side.
     bool mInitedByParent;
 
     nsCOMPtr<nsILoadContext> mLoadContext;
 
     TabId mTabId;
 
+    // Helper class for RecvCreateWindow.
+    struct AutoUseNewTab;
+
+    // When loading a new tab or window via window.open, the child process sends
+    // a new PBrowser to use. We store that tab in sNextTabParent and then
+    // proceed through the browser's normal paths to create a new
+    // window/tab. When it comes time to create a new TabParent, we instead use
+    // sNextTabParent.
+    static TabParent* sNextTabParent;
+
+    // When loading a new tab or window via window.open, the child is
+    // responsible for loading the URL it wants into the new
+    // TabChild. Simultaneously, though, the parent sends a LoadURL message to
+    // every new PBrowser (usually for about:blank). This message usually
+    // arrives after the child has started to load the URL it wants, and
+    // overrides it. To prevent this, we set mSkipLoad to true when creating the
+    // new tab. This flag prevents the unwanted LoadURL message from being sent
+    // by the parent.
+    bool mSkipLoad;
+
+    // When loading a new tab or window via window.open, we want to ensure that
+    // frame scripts for that tab are loaded before any scripts start to run in
+    // the window. We can't load the frame scripts the normal way, using
+    // separate IPC messages, since they won't be processed by the child until
+    // returning to the event loop, which is too late. Instead, we queue up
+    // frame scripts that we intend to load and send them as part of the
+    // CreateWindow response. Then TabChild loads them immediately.
+    nsTArray<FrameScriptInfo> mDelayedFrameScripts;
+
 private:
     // This is used when APZ needs to find the TabParent associated with a layer
     // to dispatch events.
     typedef nsDataHashtable<nsUint64HashKey, TabParent*> LayerToTabParentTable;
     static LayerToTabParentTable* sLayerToTabParentTable;
 
     static void AddTabParentToTable(uint64_t aLayersId, TabParent* aTabParent);
     static void RemoveTabParentFromTable(uint64_t aLayersId);
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1184,17 +1184,23 @@ void MediaDecoderStateMachine::SetSyncPo
   AssertCurrentThreadInMonitor();
 
   DecodedStreamData* stream = mDecoder->GetDecodedStream();
   if (!stream) {
     return;
   }
 
   mSyncPointInMediaStream = stream->GetLastOutputTime();
-  mSyncPointInDecodedStream = mStartTime + mPlayDuration;
+  TimeDuration timeSincePlayStart = mPlayStartTime.IsNull() ? TimeDuration(0) :
+                                    TimeStamp::Now() - mPlayStartTime;
+  mSyncPointInDecodedStream = mStartTime + mPlayDuration +
+                              timeSincePlayStart.ToMicroseconds();
+
+  DECODER_LOG("SetSyncPointForMediaStream MediaStream=%lldus, DecodedStream=%lldus",
+              mSyncPointInMediaStream, mSyncPointInDecodedStream);
 }
 
 void MediaDecoderStateMachine::ResyncMediaStreamClock()
 {
   AssertCurrentThreadInMonitor();
   MOZ_ASSERT(mDecoder->GetDecodedStream());
 
   if (IsPlaying()) {
@@ -1348,16 +1354,23 @@ void MediaDecoderStateMachine::SetAudioC
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   if (!mAudioCaptured && aCaptured && !mStopAudioThread) {
     // Make sure the state machine runs as soon as possible. That will
     // stop the audio sink.
     // If mStopAudioThread is true then we're already stopping the audio sink
     // and since we set mAudioCaptured to true, nothing can start it again.
     ScheduleStateMachine();
+
+    if (HasAudio()) {
+      // The audio clock is active so force a resync now in case the audio
+      // clock is ahead of us (observed on Android), since after mAudioCaptured
+      // gets set can't call GetAudioClock().
+      ResyncAudioClock();
+    }
   }
   mAudioCaptured = aCaptured;
 }
 
 double MediaDecoderStateMachine::GetCurrentTime() const
 {
   NS_ASSERTION(NS_IsMainThread() ||
                OnStateMachineThread() ||
@@ -1437,16 +1450,25 @@ void MediaDecoderStateMachine::SetDorman
 
   if (!mReader) {
     return;
   }
 
   DECODER_LOG("SetDormant=%d", aDormant);
 
   if (aDormant) {
+    if (mState == DECODER_STATE_SEEKING && !mQueuedSeekTarget.IsValid()) {
+      if (mSeekTarget.IsValid()) {
+        mQueuedSeekTarget = mSeekTarget;
+      } else if (mCurrentSeekTarget.IsValid()) {
+        mQueuedSeekTarget = mCurrentSeekTarget;
+      }
+    }
+    mSeekTarget.Reset();
+    mCurrentSeekTarget.Reset();
     ScheduleStateMachine();
     SetState(DECODER_STATE_DORMANT);
     mDecoder->GetReentrantMonitor().NotifyAll();
   } else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
     mDecodingFrozenAtStateMetadata = true;
     mDecodingFrozenAtStateDecoding = true;
     ScheduleStateMachine();
     mCurrentFrameTime = 0;
@@ -2911,26 +2933,25 @@ int64_t MediaDecoderStateMachine::GetClo
 
   // Determine the clock time. If we've got audio, and we've not reached
   // the end of the audio, use the audio clock. However if we've finished
   // audio, or don't have audio, use the system clock. If our output is being
   // fed to a MediaStream, use that stream as the source of the clock.
   int64_t clock_time = -1;
   if (!IsPlaying()) {
     clock_time = mPlayDuration + mStartTime;
-  } else if (mDecoder->GetDecodedStream()) {
-    clock_time = GetCurrentTimeViaMediaStreamSync();
   } else {
-    if (HasAudio() && !mAudioCompleted && !mAudioCaptured) {
+    if (mDecoder->GetDecodedStream()) {
+      clock_time = GetCurrentTimeViaMediaStreamSync();
+    } else if (HasAudio() && !mAudioCompleted && !mAudioCaptured) {
       clock_time = GetAudioClock();
     } else {
       // Audio is disabled on this system. Sync to the system clock.
       clock_time = GetVideoStreamPosition();
     }
-    // FIXME: This assertion should also apply the case of decoding to a stream.
     // Ensure the clock can never go backwards.
     NS_ASSERTION(GetMediaTime() <= clock_time || mPlaybackRate <= 0,
       "Clock should go forwards if the playback rate is > 0.");
   }
 
   return clock_time;
 }
 
@@ -2946,16 +2967,24 @@ void MediaDecoderStateMachine::AdvanceFr
   }
 
   // If playbackRate is 0.0, we should stop the progress, but not be in paused
   // state, per spec.
   if (mPlaybackRate == 0.0) {
     return;
   }
 
+  DecodedStreamData* stream = mDecoder->GetDecodedStream();
+  if (stream && !stream->mStreamInitialized) {
+    // Output streams exist but are not initialized yet.
+    // Send the data we already have to allow stream clock to progress and
+    // avoid stalling playback.
+    SendStreamData();
+  }
+
   const int64_t clock_time = GetClock();
   TimeStamp nowTime = TimeStamp::Now();
   // Skip frames up to the frame at the playback position, and figure out
   // the time remaining until it's time to display the next frame.
   int64_t remainingTime = AUDIO_DURATION_USECS;
   NS_ASSERTION(clock_time >= mStartTime, "Should have positive clock time.");
   nsRefPtr<VideoData> currentFrame;
   if (VideoQueue().GetSize() > 0) {
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MP4Reader.h"
 #include "MP4Stream.h"
 #include "MediaResource.h"
+#include "nsPrintfCString.h"
 #include "nsSize.h"
 #include "VideoUtils.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "ImageContainer.h"
 #include "Layers.h"
 #include "SharedThreadPool.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/TimeRanges.h"
@@ -83,42 +84,28 @@ InvokeAndRetry(ThisType* aThisVal, Retur
   AutoPinned<MP4Stream> stream(aStream);
   MP4Stream::ReadRecord prevFailure(-1, 0);
   while (true) {
     ReturnType result = ((*aThisVal).*aMethod)();
     if (result) {
       return result;
     }
     MP4Stream::ReadRecord failure(-1, 0);
-    if (!stream->LastReadFailed(&failure) || failure == prevFailure) {
+    if (NS_WARN_IF(!stream->LastReadFailed(&failure))) {
       return result;
     }
-    prevFailure = failure;
 
-    // Our goal here is to forcibly read the data we want into the cache: since
-    // the stream is pinned, the data is guaranteed to stay in the cache once
-    // it's there, which means that retrying the non-blocking read from inside
-    // the demuxer should succeed.
-    //
-    // But there's one wrinkle: if we read less than an entire cache line and
-    // the data ends up in MediaCacheStream's mPartialBlockBuffer, the data can
-    // be returned by a blocking read but never actually committed to the cache,
-    // and abandoned by a subsequent seek (possibly by another stream accessing
-    // the same underlying resource).
-    //
-    // The way to work around this problem is to round our "priming" read up to the
-    // size of an entire cache block. Note that this may hit EOS for bytes that the
-    // original demuxer read never actually requested. This is OK though because the
-    // call to BlockingReadAt will still return true (just with a less-than-expected
-    // number of actually read bytes, which we ignore).
-    size_t bufferSize = failure.mCount + (MediaCacheStream::BLOCK_SIZE - failure.mCount % MediaCacheStream::BLOCK_SIZE);
-    nsAutoArrayPtr<uint8_t> dummyBuffer(new uint8_t[bufferSize]);
-    MonitorAutoUnlock unlock(*aMonitor);
-    size_t ignored;
-    if (NS_WARN_IF(!stream->BlockingReadAt(failure.mOffset, dummyBuffer, bufferSize, &ignored))) {
+    if (NS_WARN_IF(failure == prevFailure)) {
+      NS_WARNING(nsPrintfCString("Failed reading the same block twice: offset=%lld, count=%lu",
+                                 failure.mOffset, failure.mCount).get());
+      return result;
+    }
+
+    prevFailure = failure;
+    if (NS_WARN_IF(!stream->BlockingReadIntoCache(failure.mOffset, failure.mCount, aMonitor))) {
       return result;
     }
   }
 }
 
 
 MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
   : MediaDecoderReader(aDecoder)
--- a/dom/media/fmp4/MP4Stream.cpp
+++ b/dom/media/fmp4/MP4Stream.cpp
@@ -6,43 +6,52 @@
 
 #include "MP4Stream.h"
 #include "MediaResource.h"
 
 namespace mozilla {
 
 MP4Stream::MP4Stream(MediaResource* aResource)
   : mResource(aResource)
+  , mPinCount(0)
 {
   MOZ_COUNT_CTOR(MP4Stream);
   MOZ_ASSERT(aResource);
 }
 
 MP4Stream::~MP4Stream()
 {
   MOZ_COUNT_DTOR(MP4Stream);
+  MOZ_ASSERT(mPinCount == 0);
 }
 
 bool
-MP4Stream::BlockingReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
-                          size_t* aBytesRead)
+MP4Stream::BlockingReadIntoCache(int64_t aOffset, size_t aCount, Monitor* aToUnlock)
 {
+  MOZ_ASSERT(mPinCount > 0);
+  CacheBlock block(aOffset, aCount);
+
   uint32_t sum = 0;
   uint32_t bytesRead = 0;
   do {
     uint64_t offset = aOffset + sum;
-    char* buffer = reinterpret_cast<char*>(aBuffer) + sum;
+    char* buffer = reinterpret_cast<char*>(block.mBuffer.get()) + sum;
     uint32_t toRead = aCount - sum;
+    MonitorAutoUnlock unlock(*aToUnlock);
     nsresult rv = mResource->ReadAt(offset, buffer, toRead, &bytesRead);
     if (NS_FAILED(rv)) {
       return false;
     }
     sum += bytesRead;
   } while (sum < aCount && bytesRead > 0);
-  *aBytesRead = sum;
+
+  MOZ_ASSERT(block.mCount >= sum);
+  block.mCount = sum;
+
+  mCache.AppendElement(block);
   return true;
 }
 
 // We surreptitiously reimplement the supposedly-blocking ReadAt as a non-
 // blocking CachedReadAt, and record when it fails. This allows MP4Reader
 // to retry the read as an actual blocking read without holding the lock.
 bool
 MP4Stream::ReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
@@ -59,16 +68,24 @@ MP4Stream::ReadAt(int64_t aOffset, void*
 
   return true;
 }
 
 bool
 MP4Stream::CachedReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
                         size_t* aBytesRead)
 {
+  // First, check our local cache.
+  for (size_t i = 0; i < mCache.Length(); ++i) {
+    if (mCache[i].mOffset == aOffset && mCache[i].mCount >= aCount) {
+      memcpy(aBuffer, mCache[i].mBuffer, aCount);
+      *aBytesRead = aCount;
+      return true;
+    }
+  }
 
   nsresult rv = mResource->ReadFromCache(reinterpret_cast<char*>(aBuffer),
                                          aOffset, aCount);
   if (NS_FAILED(rv)) {
     *aBytesRead = 0;
     return false;
   }
   *aBytesRead = aCount;
--- a/dom/media/fmp4/MP4Stream.h
+++ b/dom/media/fmp4/MP4Stream.h
@@ -7,26 +7,27 @@
 #ifndef MP4_STREAM_H_
 #define MP4_STREAM_H_
 
 #include "mp4_demuxer/mp4_demuxer.h"
 
 #include "MediaResource.h"
 
 #include "mozilla/Maybe.h"
+#include "mozilla/Monitor.h"
 
 namespace mozilla {
 
 class Monitor;
 
 class MP4Stream : public mp4_demuxer::Stream {
 public:
   explicit MP4Stream(MediaResource* aResource);
   virtual ~MP4Stream();
-  bool BlockingReadAt(int64_t aOffset, void* aBuffer, size_t aCount, size_t* aBytesRead);
+  bool BlockingReadIntoCache(int64_t aOffset, size_t aCount, Monitor* aToUnlock);
   virtual bool ReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
                       size_t* aBytesRead) MOZ_OVERRIDE;
   virtual bool CachedReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
                             size_t* aBytesRead) MOZ_OVERRIDE;
   virtual bool Length(int64_t* aSize) MOZ_OVERRIDE;
 
   struct ReadRecord {
     ReadRecord(int64_t aOffset, size_t aCount) : mOffset(aOffset), mCount(aCount) {}
@@ -39,19 +40,42 @@ public:
     if (mFailedRead.isSome()) {
       *aOut = mFailedRead.ref();
       return true;
     }
 
     return false;
   }
 
-  void Pin() { mResource->Pin(); }
-  void Unpin() { mResource->Unpin(); }
+  void Pin()
+  {
+    mResource->Pin();
+    ++mPinCount;
+  }
+
+  void Unpin()
+  {
+    mResource->Unpin();
+    MOZ_ASSERT(mPinCount);
+    --mPinCount;
+    if (mPinCount == 0) {
+      mCache.Clear();
+    }
+  }
 
 private:
   nsRefPtr<MediaResource> mResource;
   Maybe<ReadRecord> mFailedRead;
+  uint32_t mPinCount;
+
+  struct CacheBlock {
+    CacheBlock(int64_t aOffset, size_t aCount)
+      : mOffset(aOffset), mCount(aCount), mBuffer(new uint8_t[aCount]) {}
+    int64_t mOffset;
+    size_t mCount;
+    nsAutoArrayPtr<uint8_t> mBuffer;
+  };
+  nsTArray<CacheBlock> mCache;
 };
 
 }
 
 #endif
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -333,16 +333,17 @@ skip-if = (toolkit == 'android' && proce
 [test_bug726904.html]
 [test_bug874897.html]
 [test_bug883173.html]
 [test_bug895091.html]
 [test_bug895305.html]
 [test_bug919265.html]
 [test_bug957847.html]
 [test_bug1018933.html]
+[test_bug1113600.html]
 [test_can_play_type.html]
 [test_can_play_type_mpeg.html]
 skip-if = buildapp == 'b2g' || (toolkit == 'android' && processor == 'x86') # bug 1021675 #x86 only bug 914439
 [test_can_play_type_no_ogg.html]
 [test_can_play_type_ogg.html]
 [test_chaining.html]
 [test_clone_media_element.html]
 skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
new file mode 100644
--- /dev/null
+++ b/dom/media/test/test_bug1113600.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test that a video element captured to a stream mid-playback can be played to the end</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+  var v = document.createElement('video');
+  v.style = "background-color:#aca;";
+  v.width = 160;
+  v.height = 120;
+
+  manager.started(token);
+
+  v.src = test.name;
+
+  v.ontimeupdate = function() {
+    if (v.currentTime < test.duration / 4) {
+      // Allow some time to pass before starting the capture.
+      return;
+    }
+    v.ontimeupdate = null;
+    v.mozCaptureStreamUntilEnded();
+    info(test.name + " capture started at " + v.currentTime + ". Duration=" + test.duration);
+  };
+
+  v.onended = function() {
+    ok(true, test.name + " ended");
+    removeNodeAndSource(v);
+    manager.finished(token);
+  };
+
+  document.body.appendChild(v);
+  v.play();
+}
+
+manager.runTests(gSmallTests, startTest);
+</script>
+</pre>
+</body>
+</html>
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -372,26 +372,26 @@ PluginModuleChromeParent::LoadModule(con
     parent->mSubprocess->SetCallRunnableImmediately(!parent->mIsStartingAsync);
     TimeStamp launchStart = TimeStamp::Now();
     bool launched = parent->mSubprocess->Launch(Move(onLaunchedRunnable));
     if (!launched) {
         // We never reached open
         parent->mShutdown = true;
         return nullptr;
     }
+    parent->mIsFlashPlugin = aPluginTag->mIsFlashPlugin;
     if (!parent->mIsStartingAsync) {
         int32_t launchTimeoutSecs = Preferences::GetInt(kLaunchTimeoutPref, 0);
         if (!parent->mSubprocess->WaitUntilConnected(launchTimeoutSecs * 1000)) {
             parent->mShutdown = true;
             return nullptr;
         }
     }
     TimeStamp launchEnd = TimeStamp::Now();
     parent->mTimeBlocked = (launchEnd - launchStart);
-    parent->mIsFlashPlugin = aPluginTag->mIsFlashPlugin;
     return parent.forget();
 }
 
 void
 PluginModuleChromeParent::OnProcessLaunched(const bool aSucceeded)
 {
     if (!aSucceeded) {
         mShutdown = true;
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -413,43 +413,47 @@ Promise::JSCallback(JSContext* aCx, unsi
     }
   } else {
     promise->MaybeRejectInternal(aCx, args.get(0));
     if (!promise->CaptureStack(aCx, promise->mRejectionStack)) {
       return false;
     }
   }
 
+  args.rval().setUndefined();
   return true;
 }
 
 /*
  * Common bits of (JSCallbackThenableResolver/JSCallbackThenableRejecter).
  * Resolves/rejects the Promise if it is ok to do so, based on whether either of
  * the callbacks have been called before or not.
  */
 /* static */ bool
 Promise::ThenableResolverCommon(JSContext* aCx, uint32_t aTask,
                                 unsigned aArgc, JS::Value* aVp)
 {
   JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
   JS::Rooted<JSObject*> thisFunc(aCx, &args.callee());
   if (!MarkAsCalledIfNotCalledBefore(aCx, thisFunc)) {
     // A function from this pair has been called before.
+    args.rval().setUndefined();
     return true;
   }
 
   Promise* promise = GetPromise(aCx, thisFunc);
   MOZ_ASSERT(promise);
 
   if (aTask == PromiseCallback::Resolve) {
     promise->ResolveInternal(aCx, args.get(0));
   } else {
     promise->RejectInternal(aCx, args.get(0));
   }
+
+  args.rval().setUndefined();
   return true;
 }
 
 /* static */ bool
 Promise::JSCallbackThenableResolver(JSContext* aCx,
                                     unsigned aArgc, JS::Value* aVp)
 {
   return ThenableResolverCommon(aCx, PromiseCallback::Resolve, aArgc, aVp);
--- a/dom/promise/tests/mochitest.ini
+++ b/dom/promise/tests/mochitest.ini
@@ -1,7 +1,8 @@
 [DEFAULT]
 
+[test_abortable_promise.html]
 [test_bug883683.html]
 [test_promise.html]
 [test_promise_utils.html]
 [test_resolve.html]
-[test_abortable_promise.html]
+[test_resolver_return_value.html]
new file mode 100644
--- /dev/null
+++ b/dom/promise/tests/test_resolver_return_value.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1120235
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1120235</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 1120235 **/
+  var res, rej;
+  var p = new Promise(function(resolve, reject) { res = resolve; rej = reject; });
+  ise(res(1), undefined, "Resolve function should return undefined");
+  ise(rej(2), undefined, "Reject function should return undefined");
+
+  var thenable = {
+    then: function(resolve, reject) {
+      ise(resolve(3), undefined, "Thenable resolve argument should return undefined");
+      ise(reject(4), undefined, "Thenable reject argument should return undefined");
+      SimpleTest.finish();
+    }
+  };
+
+  SimpleTest.waitForExplicitFinish();
+  p = Promise.resolve(thenable);
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1120235">Mozilla Bug 1120235</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/dom/tests/mochitest/bugs/test_onerror_message.html
+++ b/dom/tests/mochitest/bugs/test_onerror_message.html
@@ -24,17 +24,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 var expected = [
 { name: "Error", message: "foo", filename: location, lineNumber: 45 },
 { name: "Error", message: "foo", filename: "bar", lineNumber: 123 },
 { name: "", message: "uncaught exception: [object Object]" },
 { name: "DuckError", message: "foo", filename: "bar", lineNumber: 123 },
 { name: "", message: "uncaught exception: [object Object]" },
 { name: "", message: "foo", filename: "baz", lineNumber: 123 },
 { name: "", message: "uncaught exception: [object Object]" },
-{ name: "InvalidStateError", message: "An attempt was made to use an object that is not, or is no longer, usable", filename: location, lineNumber: 60 },
+{ name: "InvalidStateError", message: "An attempt was made to use an object that is not, or is no longer, usable", filename: location, lineNumber: 62 },
 { name: "ReferenceError", message: "xxx is not defined", filename: location, lineNumber: 64 },
 { name: "ReferenceError", message: "xxx is not defined", filename: location, lineNumber: 66 }
 ];
 
 var counter = 0;
 var origin = location.protocol + "//" + location.host;
 postMessage(counter, origin);
 window.onmessage = function(e) {
@@ -52,19 +52,19 @@ window.onmessage = function(e) {
 		} else if (e.data == 4) {
 			throw {name:"DuckError",filename:"bar",lineNumber:123};
 		} else if (e.data == 5) {
 			throw {message:"foo",fileName:"baz",lineNumber:123};
 		} else if (e.data == 6) {
 			throw {name:3,message:4,lineNumber:123};
 		} else if (e.data == 7) {
 			var x = new XMLHttpRequest();
-			x.responseType = "arraybuffer";
 			x.open("GET", location, false);
 			var a = x.send();
+			x.responseType = "arraybuffer";
 		} else if (e.data == 8) {
 			throw new ReferenceError("xxx is not defined");
 		} else if (e.data == 9) {
 			new xxx;
 		} else {
 			SimpleTest.finish();
 			return;
 		}
--- a/dom/workers/test/urlApi_worker.js
+++ b/dom/workers/test/urlApi_worker.js
@@ -106,17 +106,17 @@ onmessage = function() {
       port: '',
       pathname: '/',
       search: '?test',
       hash: ''
     },
     { url: 'http://example.com/carrot#question%3f',
       base: undefined,
       error: false,
-      hash: '#question?'
+      hash: '#question%3f'
     },
     { url: 'https://example.com:4443?',
       base: undefined,
       error: false,
       protocol: 'https:',
       port: '4443',
       pathname: '/',
       hash: '',
--- a/editor/libeditor/nsHTMLEditRules.cpp
+++ b/editor/libeditor/nsHTMLEditRules.cpp
@@ -7393,17 +7393,18 @@ nsHTMLEditRules::SplitAsNeeded(nsIAtom& 
  *
  * Returns the point where they're merged, or (nullptr, -1) on failure.
  */
 ::DOMPoint
 nsHTMLEditRules::JoinNodesSmart(nsIContent& aNodeLeft, nsIContent& aNodeRight)
 {
   // Caller responsible for left and right node being the same type
   nsCOMPtr<nsINode> parent = aNodeLeft.GetParentNode();
-  int32_t parOffset = parent ? parent->IndexOf(&aNodeLeft) : -1;
+  NS_ENSURE_TRUE(parent, ::DOMPoint());
+  int32_t parOffset = parent->IndexOf(&aNodeLeft);
   nsCOMPtr<nsINode> rightParent = aNodeRight.GetParentNode();
 
   // If they don't have the same parent, first move the right node to after the
   // left one
   nsresult res;
   if (parent != rightParent) {
     NS_ENSURE_TRUE(mHTMLEditor, ::DOMPoint());
     res = mHTMLEditor->MoveNode(&aNodeRight, parent, parOffset);
--- a/embedding/browser/nsDocShellTreeOwner.h
+++ b/embedding/browser/nsDocShellTreeOwner.h
@@ -150,17 +150,17 @@ class ChromeTooltipListener MOZ_FINAL : 
 protected:
   virtual ~ChromeTooltipListener();
 
 public:
   NS_DECL_ISUPPORTS
 
   ChromeTooltipListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome);
 
-  NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
+  NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) MOZ_OVERRIDE;
   NS_IMETHOD MouseMove(nsIDOMEvent* aMouseEvent);
 
     // Add/remove the relevant listeners, based on what interfaces
     // the embedding chrome implements.
   NS_IMETHOD AddChromeListeners();
   NS_IMETHOD RemoveChromeListeners();
 
 private:
@@ -222,17 +222,17 @@ protected:
   virtual ~ChromeContextMenuListener();
 
 public:
   NS_DECL_ISUPPORTS
 
   ChromeContextMenuListener(nsWebBrowser* inBrowser, nsIWebBrowserChrome* inChrome);
 
   // nsIDOMContextMenuListener
-  NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
+  NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) MOZ_OVERRIDE;
 
   // Add/remove the relevant listeners, based on what interfaces
   // the embedding chrome implements.
   NS_IMETHOD AddChromeListeners();
   NS_IMETHOD RemoveChromeListeners();
 
 private:
 
--- a/embedding/components/find/nsFind.cpp
+++ b/embedding/components/find/nsFind.cpp
@@ -89,36 +89,36 @@ public:
   {
   }
 
   // nsISupports
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(nsFindContentIterator)
 
   // nsIContentIterator
-  virtual nsresult Init(nsINode* aRoot)
+  virtual nsresult Init(nsINode* aRoot) MOZ_OVERRIDE
   {
     NS_NOTREACHED("internal error");
     return NS_ERROR_NOT_IMPLEMENTED;
   }
-  virtual nsresult Init(nsIDOMRange* aRange)
+  virtual nsresult Init(nsIDOMRange* aRange) MOZ_OVERRIDE
   {
     NS_NOTREACHED("internal error");
     return NS_ERROR_NOT_IMPLEMENTED;
   }
   // Not a range because one of the endpoints may be anonymous.
   nsresult Init(nsIDOMNode* aStartNode, int32_t aStartOffset,
                 nsIDOMNode* aEndNode, int32_t aEndOffset);
-  virtual void First();
-  virtual void Last();
-  virtual void Next();
-  virtual void Prev();
-  virtual nsINode* GetCurrentNode();
-  virtual bool IsDone();
-  virtual nsresult PositionAt(nsINode* aCurNode);
+  virtual void First() MOZ_OVERRIDE;
+  virtual void Last() MOZ_OVERRIDE;
+  virtual void Next() MOZ_OVERRIDE;
+  virtual void Prev() MOZ_OVERRIDE;
+  virtual nsINode* GetCurrentNode() MOZ_OVERRIDE;
+  virtual bool IsDone() MOZ_OVERRIDE;
+  virtual nsresult PositionAt(nsINode* aCurNode) MOZ_OVERRIDE;
 
 protected:
   virtual ~nsFindContentIterator()
   {
   }
 
 private:
   nsCOMPtr<nsIContentIterator> mOuterIterator;
--- a/embedding/components/printingui/ipc/PrintProgressDialogChild.h
+++ b/embedding/components/printingui/ipc/PrintProgressDialogChild.h
@@ -20,21 +20,21 @@ class PrintProgressDialogChild MOZ_FINAL
 {
   NS_DECL_ISUPPORTS
   NS_DECL_NSIWEBPROGRESSLISTENER
   NS_DECL_NSIPRINTPROGRESSPARAMS
 
 public:
   MOZ_IMPLICIT PrintProgressDialogChild(nsIObserver* aOpenObserver);
 
-  virtual bool RecvDialogOpened();
+  virtual bool RecvDialogOpened() MOZ_OVERRIDE;
 
 private:
   virtual ~PrintProgressDialogChild();
   nsCOMPtr<nsIObserver> mOpenObserver;
   nsString mDocTitle;
   nsString mDocURL;
 };
 
 } // namespace embedding
 } // namespace mozilla
 
-#endif
\ No newline at end of file
+#endif
--- a/embedding/components/printingui/ipc/PrintProgressDialogParent.h
+++ b/embedding/components/printingui/ipc/PrintProgressDialogParent.h
@@ -24,36 +24,36 @@ public:
 
   void SetWebProgressListener(nsIWebProgressListener* aListener);
 
   void SetPrintProgressParams(nsIPrintProgressParams* aParams);
 
   virtual bool
   RecvStateChange(
           const long& stateFlags,
-          const nsresult& status);
+          const nsresult& status) MOZ_OVERRIDE;
 
   virtual bool
   RecvProgressChange(
           const long& curSelfProgress,
           const long& maxSelfProgress,
           const long& curTotalProgress,
-          const long& maxTotalProgress);
+          const long& maxTotalProgress) MOZ_OVERRIDE;
 
   virtual bool
-  RecvDocTitleChange(const nsString& newTitle);
+  RecvDocTitleChange(const nsString& newTitle) MOZ_OVERRIDE;
 
   virtual bool
-  RecvDocURLChange(const nsString& newURL);
+  RecvDocURLChange(const nsString& newURL) MOZ_OVERRIDE;
 
   virtual void
-  ActorDestroy(ActorDestroyReason aWhy);
+  ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
   virtual bool
-  Recv__delete__();
+  Recv__delete__() MOZ_OVERRIDE;
 
 private:
   virtual ~PrintProgressDialogParent();
 
   nsCOMPtr<nsIWebProgressListener> mWebProgressListener;
   nsCOMPtr<nsIPrintProgressParams> mPrintProgressParams;
   bool mActive;
 };
--- a/embedding/components/printingui/ipc/nsPrintingPromptServiceProxy.h
+++ b/embedding/components/printingui/ipc/nsPrintingPromptServiceProxy.h
@@ -18,16 +18,16 @@ public:
     nsPrintingPromptServiceProxy();
 
     nsresult Init();
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIPRINTINGPROMPTSERVICE
 
     virtual PPrintProgressDialogChild*
-    AllocPPrintProgressDialogChild();
+    AllocPPrintProgressDialogChild() MOZ_OVERRIDE;
 
     virtual bool
-    DeallocPPrintProgressDialogChild(PPrintProgressDialogChild* aActor);
+    DeallocPPrintProgressDialogChild(PPrintProgressDialogChild* aActor) MOZ_OVERRIDE;
 };
 
 #endif
 
--- a/embedding/components/webbrowserpersist/nsWebBrowserPersist.h
+++ b/embedding/components/webbrowserpersist/nsWebBrowserPersist.h
@@ -216,17 +216,17 @@ private:
 
 // Helper class does node fixup during persistence
 class nsEncoderNodeFixup : public nsIDocumentEncoderNodeFixup
 {
 public:
     nsEncoderNodeFixup();
 
     NS_DECL_ISUPPORTS
-    NS_IMETHOD FixupNode(nsIDOMNode *aNode, bool *aSerializeCloneKids, nsIDOMNode **aOutNode);
+    NS_IMETHOD FixupNode(nsIDOMNode *aNode, bool *aSerializeCloneKids, nsIDOMNode **aOutNode) MOZ_OVERRIDE;
 
     nsWebBrowserPersist *mWebBrowserPersist;
 
 protected:
     virtual ~nsEncoderNodeFixup();
 };
 
 #endif
--- a/embedding/components/windowwatcher/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/nsWindowWatcher.cpp
@@ -138,18 +138,18 @@ void nsWatcherWindowEntry::ReferenceSelf
 /****************************************************************
  ****************** nsWatcherWindowEnumerator *******************
  ****************************************************************/
 
 class nsWatcherWindowEnumerator : public nsISimpleEnumerator {
 
 public:
   explicit nsWatcherWindowEnumerator(nsWindowWatcher *inWatcher);
-  NS_IMETHOD HasMoreElements(bool *retval);
-  NS_IMETHOD GetNext(nsISupports **retval);
+  NS_IMETHOD HasMoreElements(bool *retval) MOZ_OVERRIDE;
+  NS_IMETHOD GetNext(nsISupports **retval) MOZ_OVERRIDE;
 
   NS_DECL_ISUPPORTS
 
 protected:
   virtual ~nsWatcherWindowEnumerator();
 
 private:
   friend class nsWindowWatcher;
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -188,17 +188,17 @@ GetNextSubDomainForHost(const nsACString
 class AppClearDataObserver MOZ_FINAL : public nsIObserver {
   ~AppClearDataObserver() {}
 
 public:
   NS_DECL_ISUPPORTS
 
   // nsIObserver implementation.
   NS_IMETHODIMP
-  Observe(nsISupports *aSubject, const char *aTopic, const char16_t *data)
+  Observe(nsISupports *aSubject, const char *aTopic, const char16_t *data) MOZ_OVERRIDE
   {
     MOZ_ASSERT(!nsCRT::strcmp(aTopic, "webapps-clear-data"));
 
     nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
       do_QueryInterface(aSubject);
     if (!params) {
       NS_ERROR("'webapps-clear-data' notification's subject should be a mozIApplicationClearPrivateDataParams");
       return NS_ERROR_UNEXPECTED;
--- a/extensions/universalchardet/src/xpcom/nsUdetXPCOMWrapper.h
+++ b/extensions/universalchardet/src/xpcom/nsUdetXPCOMWrapper.h
@@ -24,40 +24,40 @@
 //=====================================================================
 class nsXPCOMDetector :  
       public nsUniversalDetector,
       public nsICharsetDetector
 {
   NS_DECL_ISUPPORTS
   public:
     nsXPCOMDetector();
-    NS_IMETHOD Init(nsICharsetDetectionObserver* aObserver);
-    NS_IMETHOD DoIt(const char* aBuf, uint32_t aLen, bool *oDontFeedMe);
-    NS_IMETHOD Done();
+    NS_IMETHOD Init(nsICharsetDetectionObserver* aObserver) MOZ_OVERRIDE;
+    NS_IMETHOD DoIt(const char* aBuf, uint32_t aLen, bool *oDontFeedMe) MOZ_OVERRIDE;
+    NS_IMETHOD Done() MOZ_OVERRIDE;
   protected:
     virtual ~nsXPCOMDetector();
-    virtual void Report(const char* aCharset);
+    virtual void Report(const char* aCharset) MOZ_OVERRIDE;
   private:
     nsCOMPtr<nsICharsetDetectionObserver> mObserver;
 };
 
 
 //=====================================================================
 class nsXPCOMStringDetector :  
       public nsUniversalDetector,
       public nsIStringCharsetDetector
 {
   NS_DECL_ISUPPORTS
   public:
     nsXPCOMStringDetector();
     NS_IMETHOD DoIt(const char* aBuf, uint32_t aLen, 
-                    const char** oCharset, nsDetectionConfident &oConf);
+                    const char** oCharset, nsDetectionConfident &oConf) MOZ_OVERRIDE;
   protected:
     virtual ~nsXPCOMStringDetector();
-    virtual void Report(const char* aCharset);
+    virtual void Report(const char* aCharset) MOZ_OVERRIDE;
   private:
     nsCOMPtr<nsICharsetDetectionObserver> mObserver;
     const char* mResult;
 };
 
 //=====================================================================
 
 class nsJAPSMDetector : public nsXPCOMDetector
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -615,17 +615,21 @@ DrawBuffer::Create(GLContext* const gl,
 
     CreateRenderbuffersForOffscreen(gl, formats, size, caps.antialias,
                                     pColorMSRB, pDepthRB, pStencilRB);
 
     GLuint fb = 0;
     gl->fGenFramebuffers(1, &fb);
     gl->AttachBuffersToFB(0, colorMSRB, depthRB, stencilRB, fb);
 
-    UniquePtr<DrawBuffer> ret( new DrawBuffer(gl, size, fb, colorMSRB,
+    GLsizei samples = formats.samples;
+    if (!samples)
+        samples = 1;
+
+    UniquePtr<DrawBuffer> ret( new DrawBuffer(gl, size, samples, fb, colorMSRB,
                                               depthRB, stencilRB) );
 
     GLenum err = localError.GetError();
     MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_OUT_OF_MEMORY);
     if (err || !gl->IsFramebufferComplete(fb))
         return false;
 
     *out_buffer = Move(ret);
--- a/gfx/gl/GLScreenBuffer.h
+++ b/gfx/gl/GLScreenBuffer.h
@@ -41,30 +41,33 @@ public:
                        const GLFormats& formats,
                        const gfx::IntSize& size,
                        UniquePtr<DrawBuffer>* out_buffer);
 
 protected:
     GLContext* const mGL;
 public:
     const gfx::IntSize mSize;
+    const GLsizei mSamples;
     const GLuint mFB;
 protected:
     const GLuint mColorMSRB;
     const GLuint mDepthRB;
     const GLuint mStencilRB;
 
     DrawBuffer(GLContext* gl,
                const gfx::IntSize& size,
+               GLsizei samples,
                GLuint fb,
                GLuint colorMSRB,
                GLuint depthRB,
                GLuint stencilRB)
         : mGL(gl)
         , mSize(size)
+        , mSamples(samples)
         , mFB(fb)
         , mColorMSRB(colorMSRB)
         , mDepthRB(depthRB)
         , mStencilRB(stencilRB)
     {}
 
 public:
     virtual ~DrawBuffer();
@@ -193,16 +196,23 @@ public:
 
         return mDraw->mFB;
     }
 
     GLuint ReadFB() const {
         return mRead->mFB;
     }
 
+    GLsizei Samples() const {
+        if (!mDraw)
+            return 1;
+
+        return mDraw->mSamples;
+    }
+
     void DeletingFB(GLuint fb);
 
     const gfx::IntSize& Size() const {
         MOZ_ASSERT(mRead);
         MOZ_ASSERT(!mDraw || mDraw->mSize == mRead->Size());
         return mRead->Size();
     }
 
--- a/gfx/layers/basic/BasicImageLayer.cpp
+++ b/gfx/layers/basic/BasicImageLayer.cpp
@@ -52,22 +52,16 @@ public:
   virtual TemporaryRef<SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE;
 
 protected:
   BasicLayerManager* BasicManager()
   {
     return static_cast<BasicLayerManager*>(mManager);
   }
 
-  // only paints the image if aContext is non-null
-  void
-  GetAndPaintCurrentImage(DrawTarget* aTarget,
-                          float aOpacity,
-                          SourceSurface* aMaskSurface);
-
   gfx::IntSize mSize;
 };
 
 void
 BasicImageLayer::Paint(DrawTarget* aDT,
                        const gfx::Point& aDeviceOffset,
                        Layer* aMaskLayer)
 {
@@ -92,56 +86,16 @@ BasicImageLayer::Paint(DrawTarget* aDT,
                    surface, ToFilter(mFilter),
                    DrawOptions(GetEffectiveOpacity(), GetEffectiveOperator(this)),
                    aMaskLayer);
 
   mContainer->SetImageFactory(originalIF);
   GetContainer()->NotifyPaintedImage(image);
 }
 
-void
-BasicImageLayer::GetAndPaintCurrentImage(DrawTarget* aTarget,
-                                         float aOpacity,
-                                         SourceSurface* aMaskSurface)
-{
-  if (!mContainer) {
-    return;
-  }
-
-  nsRefPtr<ImageFactory> originalIF = mContainer->GetImageFactory();
-  mContainer->SetImageFactory(mManager->IsCompositingCheap() ?
-                              nullptr :
-                              BasicManager()->GetImageFactory());
-  IntSize size;
-  Image* image = nullptr;
-  RefPtr<SourceSurface> surf =
-    mContainer->LockCurrentAsSourceSurface(&size, &image);
-
-  if (!surf) {
-    mContainer->SetImageFactory(originalIF);
-    return;
-  }
-
-  if (aTarget) {
-    // The visible region can extend outside the image, so just draw
-    // within the image bounds.
-    SurfacePattern pat(surf, ExtendMode::CLAMP, Matrix(), ToFilter(mFilter));
-    CompositionOp op = GetEffectiveOperator(this);
-    DrawOptions opts(aOpacity, op);
-
-    aTarget->MaskSurface(pat, aMaskSurface, Point(0, 0), opts);
-
-    GetContainer()->NotifyPaintedImage(image);
-  }
-
-  mContainer->SetImageFactory(originalIF);
-
-  mContainer->UnlockCurrentImage();
-}
-
 TemporaryRef<SourceSurface>
 BasicImageLayer::GetAsSourceSurface()
 {
   if (!mContainer) {
     return nullptr;
   }
 
   gfx::IntSize dontCare;
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -416,20 +416,31 @@ ContentClientRemoteBuffer::SwapBuffers(c
 }
 
 void
 ContentClientRemoteBuffer::Dump(std::stringstream& aStream,
                                 const char* aPrefix,
                                 bool aDumpHtml)
 {
   // TODO We should combine the OnWhite/OnBlack here an just output a single image.
+  aStream << "\n" << aPrefix << "Surface: ";
   CompositableClient::DumpTextureClient(aStream, mTextureClient);
 }
 
 void
+ContentClientDoubleBuffered::Dump(std::stringstream& aStream,
+                                const char* aPrefix,
+                                bool aDumpHtml)
+{
+  // TODO We should combine the OnWhite/OnBlack here an just output a single image.
+  aStream << "\n" << aPrefix << "Surface: ";
+  CompositableClient::DumpTextureClient(aStream, mFrontClient);
+}
+
+void
 ContentClientDoubleBuffered::DestroyFrontBuffer()
 {
   if (mFrontClient) {
     mOldTextures.AppendElement(mFrontClient);
     mFrontClient = nullptr;
   }
 
   if (mFrontClientOnWhite) {
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -342,16 +342,19 @@ public:
 
   virtual void EnsureBackBufferIfFrontBuffer() MOZ_OVERRIDE;
 
   virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE
   {
     return TextureInfo(CompositableType::CONTENT_DOUBLE, mTextureFlags);
   }
 
+  virtual void Dump(std::stringstream& aStream,
+                    const char* aPrefix="",
+                    bool aDumpHtml=false) MOZ_OVERRIDE;
 protected:
   virtual void DestroyFrontBuffer() MOZ_OVERRIDE;
 
 private:
   void UpdateDestinationFrom(const RotatedBuffer& aSource,
                              const nsIntRegion& aUpdateRegion);
 
   virtual void AbortTextureClientCreation() MOZ_OVERRIDE
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -502,16 +502,17 @@ TextureClient::KeepUntilFullDeallocation
   MOZ_ASSERT(!mActor->mKeep);
   mActor->mKeep = aKeep;
 }
 
 void TextureClient::ForceRemove()
 {
   if (mValid && mActor) {
     if (GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
+      MOZ_PERFORMANCE_WARNING("gfx", "TextureClient/Host pair requires synchronous deallocation");
       if (mActor->IPCOpen()) {
         mActor->SendClearTextureHostSync();
         mActor->SendRemoveTexture();
       }
     } else {
       if (mActor->IPCOpen()) {
         mActor->SendRemoveTexture();
       }
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -277,17 +277,27 @@ public:
   virtual gfx::DrawTarget* BorrowDrawTarget() { return nullptr; }
 
   // TextureClients that can expose a DrawTarget should override this method.
   virtual gfx::SurfaceFormat GetFormat() const
   {
     return gfx::SurfaceFormat::UNKNOWN;
   }
 
-  virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() { return nullptr; }
+  /**
+   * This method is strictly for debugging. It causes locking and
+   * needless copies.
+   */
+  virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() {
+    Lock(OpenMode::OPEN_READ);
+    RefPtr<gfx::SourceSurface> surf = BorrowDrawTarget()->Snapshot();
+    RefPtr<gfx::DataSourceSurface> data = surf->GetDataSurface();
+    Unlock();
+    return data;
+  }
 
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
 
   /**
    * Copies a rectangle from this texture client to a position in aTarget.
    * It is assumed that the necessary locks are in place; so this should at
    * least have a read lock and aTarget should at least have a write lock.
    */
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -47,16 +47,22 @@ TiledLayerBufferComposite::TiledLayerBuf
   mIsValid = true;
   mHasDoubleBufferedTiles = false;
   mValidRegion = aDescriptor.validRegion();
   mPaintedRegion = aDescriptor.paintedRegion();
   mRetainedWidth = aDescriptor.retainedWidth();
   mRetainedHeight = aDescriptor.retainedHeight();
   mResolution = aDescriptor.resolution();
   mFrameResolution = CSSToParentLayerScale(aDescriptor.frameResolution());
+  if (mResolution == 0 || IsNaN(mResolution)) {
+    // There are divisions by mResolution so this protects the compositor process
+    // against malicious content processes and fuzzing.
+    mIsValid = false;
+    return;
+  }
 
   // Combine any valid content that wasn't already uploaded
   nsIntRegion oldPaintedRegion(aOldPaintedRegion);
   oldPaintedRegion.And(oldPaintedRegion, mValidRegion);
   mPaintedRegion.Or(mPaintedRegion, oldPaintedRegion);
 
   bool isSameProcess = aAllocator->IsSameProcess();
 
--- a/gfx/thebes/VsyncSource.h
+++ b/gfx/thebes/VsyncSource.h
@@ -25,16 +25,24 @@ public:
   // Controls vsync unique to each display and unique on each platform
   class Display {
     public:
       Display();
       virtual ~Display();
       void AddCompositorVsyncDispatcher(mozilla::CompositorVsyncDispatcher* aCompositorVsyncDispatcher);
       void RemoveCompositorVsyncDispatcher(mozilla::CompositorVsyncDispatcher* aCompositorVsyncDispatcher);
       // Notified when this display's vsync occurs, on the vsync thread
+      // The aVsyncTimestamp should normalize to the Vsync time that just occured
+      // However, different platforms give different vsync notification times.
+      // b2g - The vsync timestamp of the previous frame that was just displayed
+      // OSX - The vsync timestamp of the upcoming frame, in the future
+      // TODO: Windows / Linux. DOCUMENT THIS WHEN IMPLEMENTING ON THOSE PLATFORMS
+      // Android: TODO
+      // All platforms should normalize to the vsync that just occured.
+      // Large parts of Gecko assume TimeStamps should not be in the future such as animations
       virtual void NotifyVsync(mozilla::TimeStamp aVsyncTimestamp);
 
       // These should all only be called on the main thread
       virtual void EnableVsync() = 0;
       virtual void DisableVsync() = 0;
       virtual bool IsVsyncEnabled() = 0;
 
     private:
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -70,16 +70,17 @@ UsingClearType()
 // gfxDWriteFont
 gfxDWriteFont::gfxDWriteFont(gfxFontEntry *aFontEntry,
                              const gfxFontStyle *aFontStyle,
                              bool aNeedsBold,
                              AntialiasOption anAAOption)
     : gfxFont(aFontEntry, aFontStyle, anAAOption)
     , mCairoFontFace(nullptr)
     , mMetrics(nullptr)
+    , mSpaceGlyph(0)
     , mNeedsOblique(false)
     , mNeedsBold(aNeedsBold)
     , mUseSubpixelPositions(false)
     , mAllowManualShowGlyphs(true)
 {
     gfxDWriteFontEntry *fe =
         static_cast<gfxDWriteFontEntry*>(aFontEntry);
     nsresult rv;
@@ -223,18 +224,25 @@ gfxDWriteFont::ComputeMetrics(AntialiasO
             mMetrics->maxAdvance =
                 uint16_t(hhea->advanceWidthMax) * mFUnitsConvFactor;
         }
     }
 
     mMetrics->internalLeading = std::max(mMetrics->maxHeight - mMetrics->emHeight, 0.0);
     mMetrics->externalLeading = ceil(fontMetrics.lineGap * mFUnitsConvFactor);
 
-    UINT16 glyph = (uint16_t)GetSpaceGlyph();
-    mMetrics->spaceWidth = MeasureGlyphWidth(glyph);
+    UINT32 ucs = L' ';
+    UINT16 glyph;
+    HRESULT hr = mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph);
+    if (FAILED(hr)) {
+        mMetrics->spaceWidth = 0;
+    } else {
+        mSpaceGlyph = glyph;
+        mMetrics->spaceWidth = MeasureGlyphWidth(glyph);
+    }
 
     // try to get aveCharWidth from the OS/2 table, fall back to measuring 'x'
     // if the table is not available or if using hinted/pixel-snapped widths
     if (mUseSubpixelPositions) {
         mMetrics->aveCharWidth = 0;
         gfxFontEntry::AutoTable os2Table(GetFontEntry(),
                                          TRUETYPE_TAG('O','S','/','2'));
         if (os2Table) {
@@ -246,17 +254,16 @@ gfxDWriteFont::ComputeMetrics(AntialiasO
                 // versions of the table have different sizes; we only need the first
                 // two 16-bit fields here.
                 mMetrics->aveCharWidth =
                     int16_t(os2->xAvgCharWidth) * mFUnitsConvFactor;
             }
         }
     }
 
-    UINT32 ucs;
     if (mMetrics->aveCharWidth < 1) {
         ucs = L'x';
         if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph))) {
             mMetrics->aveCharWidth = MeasureGlyphWidth(glyph);
         }
         if (mMetrics->aveCharWidth < 1) {
             // Let's just assume the X is square.
             mMetrics->aveCharWidth = fontMetrics.xHeight * mFUnitsConvFactor;
@@ -437,24 +444,17 @@ gfxDWriteFont::HasBitmapStrikeForSize(ui
     mFontFace->ReleaseFontTable(tableContext);
 
     return hasStrike;
 }
 
 uint32_t
 gfxDWriteFont::GetSpaceGlyph()
 {
-    UINT32 ucs = L' ';
-    UINT16 glyph;
-    HRESULT hr;
-    hr = mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph);
-    if (FAILED(hr)) {
-        return 0;
-    }
-    return glyph;
+    return mSpaceGlyph;
 }
 
 bool
 gfxDWriteFont::SetupCairoFont(gfxContext *aContext)
 {
     cairo_scaled_font_t *scaledFont = GetCairoScaledFont();
     if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
         // Don't cairo_set_scaled_font as that would propagate the error to
--- a/gfx/thebes/gfxDWriteFonts.h
+++ b/gfx/thebes/gfxDWriteFonts.h
@@ -93,16 +93,18 @@ protected:
     nsRefPtr<IDWriteFontFace> mFontFace;
     cairo_font_face_t *mCairoFontFace;
 
     Metrics *mMetrics;
 
     // cache of glyph widths in 16.16 fixed-point pixels
     nsAutoPtr<nsDataHashtable<nsUint32HashKey,int32_t> > mGlyphWidths;
 
+    uint32_t mSpaceGlyph;
+
     bool mNeedsOblique;
     bool mNeedsBold;
     bool mUseSubpixelPositions;
     bool mAllowManualShowGlyphs;
     bool mAzureScaledFontIsCairo;
 };
 
 #endif
--- a/gfx/thebes/gfxFT2FontBase.cpp
+++ b/gfx/thebes/gfxFT2FontBase.cpp
@@ -111,17 +111,17 @@ gfxFT2FontBase::GetGlyphExtents(uint32_t
 const gfxFont::Metrics&
 gfxFT2FontBase::GetHorizontalMetrics()
 {
     if (mHasMetrics)
         return mMetrics;
 
     if (MOZ_UNLIKELY(GetStyle()->size <= 0.0)) {
         new(&mMetrics) gfxFont::Metrics(); // zero initialize
-        mSpaceGlyph = 0;
+        mSpaceGlyph = GetGlyph(' ');
     } else {
         gfxFT2LockedFace face(this);
         face.GetMetrics(&mMetrics, &mSpaceGlyph);
     }
 
     SanitizeMetrics(&mMetrics, false);
 
 #if 0
@@ -139,18 +139,16 @@ gfxFT2FontBase::GetHorizontalMetrics()
     mHasMetrics = true;
     return mMetrics;
 }
 
 // Get the glyphID of a space
 uint32_t
 gfxFT2FontBase::GetSpaceGlyph()
 {
-    NS_ASSERTION(GetStyle()->size != 0,
-                 "forgot to short-circuit a text run with zero-sized font?");
     GetHorizontalMetrics();
     return mSpaceGlyph;
 }
 
 uint32_t
 gfxFT2FontBase::GetGlyph(uint32_t unicode, uint32_t variation_selector)
 {
     if (variation_selector) {
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -2109,16 +2109,33 @@ UnionRange(gfxFloat aX, gfxFloat* aDestM
 // on overflowing glyphs.
 static bool
 NeedsGlyphExtents(gfxFont *aFont, gfxTextRun *aTextRun)
 {
     return (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX) ||
         aFont->GetFontEntry()->IsUserFont();
 }
 
+bool
+gfxFont::IsSpaceGlyphInvisible(gfxContext *aRefContext, gfxTextRun *aTextRun)
+{
+    if (!mFontEntry->mSpaceGlyphIsInvisibleInitialized &&
+        GetAdjustedSize() >= 1.0) {
+        gfxGlyphExtents *extents =
+            GetOrCreateGlyphExtents(aTextRun->GetAppUnitsPerDevUnit());
+        gfxRect glyphExtents;
+        mFontEntry->mSpaceGlyphIsInvisible =
+            extents->GetTightGlyphExtentsAppUnits(this, eHorizontal,
+                aRefContext, GetSpaceGlyph(), &glyphExtents) &&
+            glyphExtents.IsEmpty();
+        mFontEntry->mSpaceGlyphIsInvisibleInitialized = true;
+    }
+    return mFontEntry->mSpaceGlyphIsInvisible;
+}
+
 gfxFont::RunMetrics
 gfxFont::Measure(gfxTextRun *aTextRun,
                  uint32_t aStart, uint32_t aEnd,
                  BoundingBoxType aBoundingBoxType,
                  gfxContext *aRefContext,
                  Spacing *aSpacing,
                  uint16_t aOrientation)
 {
@@ -2184,26 +2201,32 @@ gfxFont::Measure(gfxTextRun *aTextRun,
             !needsGlyphExtents &&
             !aTextRun->HasDetailedGlyphs()) ||
          (MOZ_UNLIKELY(GetStyle()->size == 0))) ? nullptr
         : GetOrCreateGlyphExtents(aTextRun->GetAppUnitsPerDevUnit());
     double x = 0;
     if (aSpacing) {
         x += direction*aSpacing[0].mBefore;
     }
+    uint32_t spaceGlyph = GetSpaceGlyph();
+    bool allGlyphsInvisible = true;
     uint32_t i;
     for (i = aStart; i < aEnd; ++i) {
         const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[i];
         if (glyphData->IsSimpleGlyph()) {
             double advance = glyphData->GetSimpleAdvance();
+            uint32_t glyphIndex = glyphData->GetSimpleGlyph();
+            if (glyphIndex != spaceGlyph ||
+                !IsSpaceGlyphInvisible(aRefContext, aTextRun)) {
+                allGlyphsInvisible = false;
+            }
             // Only get the real glyph horizontal extent if we were asked
             // for the tight bounding box or we're in quality mode
             if ((aBoundingBoxType != LOOSE_INK_EXTENTS || needsGlyphExtents) &&
-                extents) {
-                uint32_t glyphIndex = glyphData->GetSimpleGlyph();
+                extents){
                 uint16_t extentsWidth = extents->GetContainedGlyphWidthAppUnits(glyphIndex);
                 if (extentsWidth != gfxGlyphExtents::INVALID_WIDTH &&
                     aBoundingBoxType == LOOSE_INK_EXTENTS) {
                     UnionRange(x, &advanceMin, &advanceMax);
                     UnionRange(x + direction*extentsWidth, &advanceMin, &advanceMax);
                 } else {
                     gfxRect glyphRect;
                     if (!extents->GetTightGlyphExtentsAppUnits(this,
@@ -2216,16 +2239,17 @@ gfxFont::Measure(gfxTextRun *aTextRun,
                         glyphRect -= gfxPoint(advance, 0);
                     }
                     glyphRect += gfxPoint(x, 0);
                     metrics.mBoundingBox = metrics.mBoundingBox.Union(glyphRect);
                 }
             }
             x += direction*advance;
         } else {
+            allGlyphsInvisible = false;
             uint32_t glyphCount = glyphData->GetGlyphCount();
             if (glyphCount > 0) {
                 const gfxTextRun::DetailedGlyph *details =
                     aTextRun->GetDetailedGlyphs(i);
                 NS_ASSERTION(details != nullptr,
                              "detaiedGlyph record should not be missing!");
                 uint32_t j;
                 for (j = 0; j < glyphCount; ++j, ++details) {
@@ -2256,24 +2280,28 @@ gfxFont::Measure(gfxTextRun *aTextRun,
             double space = aSpacing[i - aStart].mAfter;
             if (i + 1 < aEnd) {
                 space += aSpacing[i + 1 - aStart].mBefore;
             }
             x += direction*space;
         }
     }
 
-    if (aBoundingBoxType == LOOSE_INK_EXTENTS) {
-        UnionRange(x, &advanceMin, &advanceMax);
-        gfxRect fontBox(advanceMin, -metrics.mAscent,
-                        advanceMax - advanceMin, metrics.mAscent + metrics.mDescent);
-        metrics.mBoundingBox = metrics.mBoundingBox.Union(fontBox);
-    }
-    if (isRTL) {
-        metrics.mBoundingBox -= gfxPoint(x, 0);
+    if (allGlyphsInvisible) {
+        metrics.mBoundingBox.SetEmpty();
+    } else {
+        if (aBoundingBoxType == LOOSE_INK_EXTENTS) {
+            UnionRange(x, &advanceMin, &advanceMax);
+            gfxRect fontBox(advanceMin, -metrics.mAscent,
+                            advanceMax - advanceMin, metrics.mAscent + metrics.mDescent);
+            metrics.mBoundingBox = metrics.mBoundingBox.Union(fontBox);
+        }
+        if (isRTL) {
+            metrics.mBoundingBox -= gfxPoint(x, 0);
+        }
     }
 
     // If the font may be rendered with a fake-italic effect, we need to allow
     // for the top-right of the glyphs being skewed to the right, and the
     // bottom-left being skewed further left.
     if (mStyle.style != NS_FONT_STYLE_NORMAL && !mFontEntry->IsItalic()) {
         gfxFloat extendLeftEdge =
             ceil(OBLIQUE_SKEW_FACTOR * metrics.mBoundingBox.YMost());
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -1841,16 +1841,18 @@ protected:
     }
 
     // The return value is interpreted as a horizontal advance in 16.16 fixed
     // point format.
     virtual int32_t GetGlyphWidth(DrawTarget& aDrawTarget, uint16_t aGID) {
         return -1;
     }
 
+    bool IsSpaceGlyphInvisible(gfxContext *aRefContext, gfxTextRun *aTextRun);
+
     void AddGlyphChangeObserver(GlyphChangeObserver *aObserver);
     void RemoveGlyphChangeObserver(GlyphChangeObserver *aObserver);
 
     // whether font contains substitution lookups containing spaces
     bool HasSubstitutionRulesWithSpaceLookups(int32_t aRunScript);
 
     // do spaces participate in shaping rules? if so, can't used word cache
     bool SpaceMayParticipateInShaping(int32_t aRunScript);
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -80,16 +80,18 @@ gfxFontEntry::gfxFontEntry() :
     mIgnoreGSUB(false),
     mSVGInitialized(false),
     mMathInitialized(false),
     mHasSpaceFeaturesInitialized(false),
     mHasSpaceFeatures(false),
     mHasSpaceFeaturesKerning(false),
     mHasSpaceFeaturesNonKerning(false),
     mSkipDefaultFeatureSpaceCheck(false),
+    mSpaceGlyphIsInvisible(false),
+    mSpaceGlyphIsInvisibleInitialized(false),
     mCheckedForGraphiteTables(false),
     mHasCmapTable(false),
     mGrFaceInitialized(false),
     mCheckedForColorGlyph(false),
     mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
     mUVSOffset(0), mUVSData(nullptr),
     mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
     mCOLR(nullptr),
@@ -115,16 +117,18 @@ gfxFontEntry::gfxFontEntry(const nsAStri
     mIgnoreGSUB(false),
     mSVGInitialized(false),
     mMathInitialized(false),
     mHasSpaceFeaturesInitialized(false),
     mHasSpaceFeatures(false),
     mHasSpaceFeaturesKerning(false),
     mHasSpaceFeaturesNonKerning(false),
     mSkipDefaultFeatureSpaceCheck(false),
+    mSpaceGlyphIsInvisible(false),
+    mSpaceGlyphIsInvisibleInitialized(false),
     mCheckedForGraphiteTables(false),
     mHasCmapTable(false),
     mGrFaceInitialized(false),
     mCheckedForColorGlyph(false),
     mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
     mUVSOffset(0), mUVSData(nullptr),
     mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
     mCOLR(nullptr),
--- a/gfx/thebes/gfxFontEntry.h
+++ b/gfx/thebes/gfxFontEntry.h
@@ -398,16 +398,18 @@ public:
     bool             mIgnoreGSUB  : 1;
     bool             mSVGInitialized : 1;
     bool             mMathInitialized : 1;
     bool             mHasSpaceFeaturesInitialized : 1;
     bool             mHasSpaceFeatures : 1;
     bool             mHasSpaceFeaturesKerning : 1;
     bool             mHasSpaceFeaturesNonKerning : 1;
     bool             mSkipDefaultFeatureSpaceCheck : 1;
+    bool             mSpaceGlyphIsInvisible : 1;
+    bool             mSpaceGlyphIsInvisibleInitialized : 1;
     bool             mHasGraphiteTables : 1;
     bool             mCheckedForGraphiteTables : 1;
     bool             mHasCmapTable : 1;
     bool             mGrFaceInitialized : 1;
     bool             mCheckedForColorGlyph : 1;
 
     // bitvector of substitution space features per script, one each
     // for default and non-default features
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -413,38 +413,30 @@ gfxPlatformMac::UseProgressivePaint()
 }
 
 // This is the renderer output callback function, called on the vsync thread
 static CVReturn VsyncCallback(CVDisplayLinkRef aDisplayLink,
                               const CVTimeStamp* aNow,
                               const CVTimeStamp* aOutputTime,
                               CVOptionFlags aFlagsIn,
                               CVOptionFlags* aFlagsOut,
-                              void* aDisplayLinkContext)
-{
-  VsyncSource::Display* display = (VsyncSource::Display*) aDisplayLinkContext;
-  int64_t timestamp = aOutputTime->hostTime;
-  mozilla::TimeStamp vsyncTime = mozilla::TimeStamp::FromSystemTime(timestamp);
-  display->NotifyVsync(vsyncTime);
-  return kCVReturnSuccess;
-}
+                              void* aDisplayLinkContext);
 
 class OSXVsyncSource MOZ_FINAL : public VsyncSource
 {
 public:
   OSXVsyncSource()
   {
   }
 
   virtual Display& GetGlobalDisplay() MOZ_OVERRIDE
   {
     return mGlobalDisplay;
   }
 
-protected:
   class OSXDisplay MOZ_FINAL : public VsyncSource::Display
   {
   public:
     OSXDisplay()
     {
       EnableVsync();
     }
 
@@ -466,16 +458,17 @@ protected:
         return;
       }
 
       if (CVDisplayLinkSetOutputCallback(mDisplayLink, &VsyncCallback, this) != kCVReturnSuccess) {
         NS_WARNING("Could not set displaylink output callback");
         return;
       }
 
+      mPreviousTimestamp = TimeStamp::Now();
       if (CVDisplayLinkStart(mDisplayLink) != kCVReturnSuccess) {
         NS_WARNING("Could not activate the display link");
         mDisplayLink = nullptr;
       }
     }
 
     virtual void DisableVsync() MOZ_OVERRIDE
     {
@@ -489,29 +482,56 @@ protected:
     }
 
     virtual bool IsVsyncEnabled() MOZ_OVERRIDE
     {
       MOZ_ASSERT(NS_IsMainThread());
       return mDisplayLink != nullptr;
     }
 
+    // The vsync timestamps given by the CVDisplayLinkCallback are
+    // in the future for the NEXT frame. Large parts of Gecko, such
+    // as animations assume a timestamp at either now or in the past.
+    // Normalize the timestamps given to the VsyncDispatchers to the vsync
+    // that just occured, not the vsync that is upcoming.
+    TimeStamp mPreviousTimestamp;
+
   private:
     // Manages the display link render thread
     CVDisplayLinkRef   mDisplayLink;
   }; // OSXDisplay
 
 private:
   virtual ~OSXVsyncSource()
   {
   }
 
   OSXDisplay mGlobalDisplay;
 }; // OSXVsyncSource
 
+static CVReturn VsyncCallback(CVDisplayLinkRef aDisplayLink,
+                              const CVTimeStamp* aNow,
+                              const CVTimeStamp* aOutputTime,
+                              CVOptionFlags aFlagsIn,
+                              CVOptionFlags* aFlagsOut,
+                              void* aDisplayLinkContext)
+{
+  // Executed on OS X hardware vsync thread
+  OSXVsyncSource::OSXDisplay* display = (OSXVsyncSource::OSXDisplay*) aDisplayLinkContext;
+  int64_t nextVsyncTimestamp = aOutputTime->hostTime;
+  mozilla::TimeStamp nextVsync = mozilla::TimeStamp::FromSystemTime(nextVsyncTimestamp);
+
+  mozilla::TimeStamp previousVsync = display->mPreviousTimestamp;
+  display->mPreviousTimestamp = nextVsync;
+  MOZ_ASSERT(TimeStamp::Now() > previousVsync);
+
+  display->NotifyVsync(previousVsync);
+  return kCVReturnSuccess;
+}
+
 already_AddRefed<mozilla::gfx::VsyncSource>
 gfxPlatformMac::CreateHardwareVsyncSource()
 {
   nsRefPtr<VsyncSource> osxVsyncSource = new OSXVsyncSource();
   return osxVsyncSource.forget();
 }
 
 void
--- a/gfx/ycbcr/moz.build
+++ b/gfx/ycbcr/moz.build
@@ -33,25 +33,19 @@ if CONFIG['INTEL_ARCHITECTURE']:
                 'yuv_convert_mmx.cpp',
             ]
     else:
         SOURCES += ['yuv_convert_mmx.cpp']
         SOURCES['yuv_convert_mmx.cpp'].flags += CONFIG['MMX_FLAGS']
 
 if CONFIG['_MSC_VER']:
     if CONFIG['OS_TEST'] == 'x86_64':
-        if CONFIG['_MSC_VER'] == '1400':
-            # VC8 doesn't support some SSE2 built-in functions
-            SOURCES += [
-                'yuv_row_win.cpp',
-            ]
-        else:
-            SOURCES += [
-                'yuv_row_win64.cpp',
-            ]
+        SOURCES += [
+            'yuv_row_win64.cpp',
+        ]
     else:
         SOURCES += [
             'yuv_row_win.cpp',
         ]
 elif CONFIG['OS_ARCH'] in ('Linux', 'SunOS', 'Darwin', 'DragonFly',
                            'FreeBSD', 'NetBSD', 'OpenBSD'):
     SOURCES += [
         'yuv_row_posix.cpp',
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -565,17 +565,17 @@ public:
   }
 
   virtual bool
   RecvGetCurrentNetworkInformation(NetworkInformation* aNetworkInfo) MOZ_OVERRIDE {
     hal::GetCurrentNetworkInformation(aNetworkInfo);
     return true;
   }
 
-  void Notify(const NetworkInformation& aNetworkInfo) {
+  void Notify(const NetworkInformation& aNetworkInfo) MOZ_OVERRIDE {
     unused << SendNotifyNetworkChange(aNetworkInfo);
   }
 
   virtual bool
   RecvEnableScreenConfigurationNotifications() MOZ_OVERRIDE {
     // Screen configuration is used to implement CSS and DOM
     // properties, so all content already has access to this.
     hal::RegisterScreenConfigurationObserver(this);
@@ -607,17 +607,17 @@ public:
 
   virtual bool
   RecvUnlockScreenOrientation() MOZ_OVERRIDE
   {
     hal::UnlockScreenOrientation();
     return true;
   }
 
-  void Notify(const ScreenConfiguration& aScreenConfiguration) {
+  void Notify(const ScreenConfiguration& aScreenConfiguration) MOZ_OVERRIDE {
     unused << SendNotifyScreenConfigurationChange(aScreenConfiguration);
   }
 
   virtual bool
   RecvGetScreenEnabled(bool* aEnabled) MOZ_OVERRIDE
   {
     if (!AssertAppProcessPermission(this, "power")) {
       return false;
@@ -773,17 +773,17 @@ public:
   }
    
   virtual bool
   RecvDisableSensorNotifications(const SensorType &aSensor) MOZ_OVERRIDE {
     hal::UnregisterSensorObserver(aSensor, this);
     return true;
   }
   
-  void Notify(const SensorData& aSensorData) {
+  void Notify(const SensorData& aSensorData) MOZ_OVERRIDE {
     unused << SendNotifySensorChange(aSensorData);
   }
 
   virtual bool
   RecvModifyWakeLock(const nsString& aTopic,
                      const WakeLockControl& aLockAdjust,
                      const WakeLockControl& aHiddenAdjust,
                      const uint64_t& aProcessID) MOZ_OVERRIDE
@@ -812,17 +812,17 @@ public:
 
   virtual bool
   RecvGetWakeLockInfo(const nsString &aTopic, WakeLockInformation *aWakeLockInfo) MOZ_OVERRIDE
   {
     hal::GetWakeLockInfo(aTopic, aWakeLockInfo);
     return true;
   }
   
-  void Notify(const WakeLockInformation& aWakeLockInfo)
+  void Notify(const WakeLockInformation& aWakeLockInfo) MOZ_OVERRIDE
   {
     unused << SendNotifyWakeLockChange(aWakeLockInfo);
   }
 
   virtual bool
   RecvEnableSwitchNotifications(const SwitchDevice& aDevice) MOZ_OVERRIDE
   {
     // Content has no reason to listen to switch events currently.
@@ -832,35 +832,35 @@ public:
 
   virtual bool
   RecvDisableSwitchNotifications(const SwitchDevice& aDevice) MOZ_OVERRIDE
   {
     hal::UnregisterSwitchObserver(aDevice, this);
     return true;
   }
 
-  void Notify(const SwitchEvent& aSwitchEvent)
+  void Notify(const SwitchEvent& aSwitchEvent) MOZ_OVERRIDE
   {
     unused << SendNotifySwitchChange(aSwitchEvent);
   }
 
   virtual bool
   RecvGetCurrentSwitchState(const SwitchDevice& aDevice, hal::SwitchState *aState) MOZ_OVERRIDE
   {
     // Content has no reason to listen to switch events currently.
     *aState = hal::GetCurrentSwitchState(aDevice);
     return true;
   }
 
-  void Notify(const int64_t& aClockDeltaMS)
+  void Notify(const int64_t& aClockDeltaMS) MOZ_OVERRIDE
   {
     unused << SendNotifySystemClockChange(aClockDeltaMS);
   }
 
-  void Notify(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
+  void Notify(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo) MOZ_OVERRIDE
   {
     unused << SendNotifySystemTimezoneChange(aSystemTimezoneChangeInfo);
   }
 
   virtual bool
   RecvFactoryReset(const nsString& aReason) MOZ_OVERRIDE
   {
     if (!AssertAppProcessPermission(this, "power")) {
@@ -933,24 +933,24 @@ public:
 
   virtual bool
   RecvNotifySwitchChange(const mozilla::hal::SwitchEvent& aEvent) MOZ_OVERRIDE {
     hal::NotifySwitchChange(aEvent);
     return true;
   }
 
   virtual bool
-  RecvNotifySystemClockChange(const int64_t& aClockDeltaMS) {
+  RecvNotifySystemClockChange(const int64_t& aClockDeltaMS) MOZ_OVERRIDE {
     hal::NotifySystemClockChange(aClockDeltaMS);
     return true;
   }
 
   virtual bool
   RecvNotifySystemTimezoneChange(
-    const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo) {
+    const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo) MOZ_OVERRIDE {
     hal::NotifySystemTimezoneChange(aSystemTimezoneChangeInfo);
     return true;
   }
 };
 
 bool
 HalChild::RecvNotifySensorChange(const hal::SensorData &aSensorData) {
   hal::NotifySensorChange(aSensorData);
--- a/image/src/MultipartImage.cpp
+++ b/image/src/MultipartImage.cpp
@@ -13,17 +13,17 @@ namespace image {
 ///////////////////////////////////////////////////////////////////////////////
 // Helpers
 ///////////////////////////////////////////////////////////////////////////////
 
 class NextPartObserver : public IProgressObserver
 {
 public:
   MOZ_DECLARE_REFCOUNTED_TYPENAME(NextPartObserver)
-  NS_INLINE_DECL_REFCOUNTING(NextPartObserver)
+  NS_INLINE_DECL_REFCOUNTING(NextPartObserver, MOZ_OVERRIDE)
 
   explicit NextPartObserver(MultipartImage* aOwner)
     : mOwner(aOwner)
   {
     MOZ_ASSERT(mOwner);
   }
 
   void BeginObserving(Image* aImage)
--- a/ipc/app/sha256.c
+++ b/ipc/app/sha256.c
@@ -63,43 +63,21 @@ static const PRUint32 K256[64] = {
 };
 
 /* SHA-256 initial hash values */
 static const PRUint32 H256[8] = {
     0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 
     0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
 };
 
-#if (_MSC_VER >= 1300)
+#if defined(_MSC_VER)
 #include <stdlib.h>
 #pragma intrinsic(_byteswap_ulong)
 #define SHA_HTONL(x) _byteswap_ulong(x)
 #define BYTESWAP4(x)  x = SHA_HTONL(x)
-#elif defined(_MSC_VER) && defined(NSS_X86_OR_X64)
-#ifndef FORCEINLINE
-#if (_MSC_VER >= 1200)
-#define FORCEINLINE __forceinline
-#else
-#define FORCEINLINE __inline
-#endif
-#endif
-#define FASTCALL __fastcall
-
-static FORCEINLINE PRUint32 FASTCALL 
-swap4b(PRUint32 dwd) 
-{
-    __asm {
-    	mov   eax,dwd
-	bswap eax
-    }
-}
-
-#define SHA_HTONL(x) swap4b(x)
-#define BYTESWAP4(x)  x = SHA_HTONL(x)
-
 #elif defined(__GNUC__) && defined(NSS_X86_OR_X64)
 static __inline__ PRUint32 swap4b(PRUint32 value)
 {
     __asm__("bswap %0" : "+r" (value));
     return (value);
 }
 #define SHA_HTONL(x) swap4b(x)
 #define BYTESWAP4(x)  x = SHA_HTONL(x)
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1447,18 +1447,18 @@ ScanTypeObject(GCMarker *gcmarker, types
         PushMarkStack(gcmarker, type->singleton());
 
     if (type->newScript())
         type->newScript()->trace(gcmarker);
 
     if (TypeDescr *descr = type->maybeTypeDescr())
         PushMarkStack(gcmarker, descr);
 
-    if (type->interpretedFunction)
-        PushMarkStack(gcmarker, type->interpretedFunction);
+    if (JSFunction *fun = type->maybeInterpretedFunction())
+        PushMarkStack(gcmarker, fun);
 }
 
 static void
 gc::MarkChildren(JSTracer *trc, types::TypeObject *type)
 {
     unsigned count = type->getPropertyCount();
     for (unsigned i = 0; i < count; i++) {
         types::Property *prop = type->getProperty(i);
@@ -1475,18 +1475,20 @@ gc::MarkChildren(JSTracer *trc, types::T
     if (type->newScript())
         type->newScript()->trace(trc);
 
     if (JSObject *descr = type->maybeTypeDescr()) {
         MarkObjectUnbarriered(trc, &descr, "type_descr");
         type->setTypeDescr(&descr->as<TypeDescr>());
     }
 
-    if (type->interpretedFunction)
-        MarkObject(trc, &type->interpretedFunction, "type_function");
+    if (JSObject *fun = type->maybeInterpretedFunction()) {
+        MarkObjectUnbarriered(trc, &fun, "type_function");
+        type->setInterpretedFunction(&fun->as<JSFunction>());
+    }
 }
 
 static void
 gc::MarkChildren(JSTracer *trc, jit::JitCode *code)
 {
     code->trace(trc);
 }
 
--- a/js/src/jit/BaselineFrame.h
+++ b/js/src/jit/BaselineFrame.h
@@ -276,16 +276,19 @@ class BaselineFrame
     }
 
     bool prevUpToDate() const {
         return flags_ & PREV_UP_TO_DATE;
     }
     void setPrevUpToDate() {
         flags_ |= PREV_UP_TO_DATE;
     }
+    void unsetPrevUpToDate() {
+        flags_ &= ~PREV_UP_TO_DATE;
+    }
 
     bool isDebuggee() const {
         return flags_ & DEBUGGEE;
     }
     void setIsDebuggee() {
         flags_ |= DEBUGGEE;
     }
     inline void unsetIsDebuggee();
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -291,22 +291,23 @@ IonBuilder::getPolyCallTargets(types::Te
 
     if (!targets.reserve(objCount))
         return false;
     for(unsigned i = 0; i < objCount; i++) {
         JSObject *obj = calleeTypes->getSingleObject(i);
         if (!obj) {
             types::TypeObject *typeObj = calleeTypes->getTypeObject(i);
             MOZ_ASSERT(typeObj);
-            if (!typeObj->interpretedFunction) {
+            obj = typeObj->maybeInterpretedFunction();
+
+            if (!obj) {
                 targets.clear();
                 return true;
             }
 
-            obj = typeObj->interpretedFunction;
             *gotLambda = true;
         }
 
         // Don't optimize if the callee is not callable or constructable per
         // the manner it is being invoked, so that CallKnown does not have to
         // handle these cases (they will always throw).
         if (constructing ? !obj->isConstructor() : !obj->isCallable()) {
             targets.clear();
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -2958,17 +2958,17 @@ class MSimdBox
     InlineTypedObject *templateObject() const {
         return templateObject_;
     }
 
     gc::InitialHeap initialHeap() const {
         return initialHeap_;
     }
 
-    AliasSet getAliasSet() const {
+    AliasSet getAliasSet() const MOZ_OVERRIDE {
         return AliasSet::None();
     }
 };
 
 // Creates a new derived type object. At runtime, this is just a call
 // to `BinaryBlock::createDerived()`. That is, the MIR itself does not
 // compile to particularly optimized code. However, using a distinct
 // MIR for creating derived type objects allows the compiler to
--- a/js/src/jit/RematerializedFrame.h
+++ b/js/src/jit/RematerializedFrame.h
@@ -71,16 +71,19 @@ class RematerializedFrame
     static void MarkInVector(JSTracer *trc, Vector<RematerializedFrame *> &frames);
 
     bool prevUpToDate() const {
         return prevUpToDate_;
     }
     void setPrevUpToDate() {
         prevUpToDate_ = true;
     }
+    void unsetPrevUpToDate() {
+        prevUpToDate_ = false;
+    }
 
     bool isDebuggee() const {
         return isDebuggee_;
     }
     void setIsDebuggee() {
         isDebuggee_ = true;
     }
     void unsetIsDebuggee() {
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -865,17 +865,17 @@ CreateFunctionPrototype(JSContext *cx, J
     if (!script || !JSScript::fullyInitTrivial(cx, script))
         return nullptr;
 
     functionProto->initScript(script);
     types::TypeObject* protoType = functionProto->getType(cx);
     if (!protoType)
         return nullptr;
 
-    protoType->interpretedFunction = functionProto;
+    protoType->setInterpretedFunction(functionProto);
     script->setFunction(functionProto);
 
     /*
      * The default 'new' type of Function.prototype is required by type
      * inference to have unknown properties, to simplify handling of e.g.
      * CloneFunctionObject.
      */
     if (!JSObject::setNewTypeUnknown(cx, &JSFunction::class_, functionProto))
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -3339,17 +3339,17 @@ TypeObject::print()
         if (!hasAnyFlags(OBJECT_FLAG_SPARSE_INDEXES))
             fprintf(stderr, " dense");
         if (!hasAnyFlags(OBJECT_FLAG_NON_PACKED))
             fprintf(stderr, " packed");
         if (!hasAnyFlags(OBJECT_FLAG_LENGTH_OVERFLOW))
             fprintf(stderr, " noLengthOverflow");
         if (hasAnyFlags(OBJECT_FLAG_ITERATED))
             fprintf(stderr, " iterated");
-        if (interpretedFunction)
+        if (maybeInterpretedFunction())
             fprintf(stderr, " ifun");
     }
 
     unsigned count = getPropertyCount();
 
     if (count == 0) {
         fprintf(stderr, " {}\n");
         return;
@@ -3744,17 +3744,17 @@ JSFunction::setTypeForScriptedFunction(E
         RootedObject funProto(cx, fun->getProto());
         Rooted<TaggedProto> taggedProto(cx, TaggedProto(funProto));
         TypeObject *type =
             cx->compartment()->types.newTypeObject(cx, &JSFunction::class_, taggedProto);
         if (!type)
             return false;
 
         fun->setType(type);
-        type->interpretedFunction = fun;
+        type->setInterpretedFunction(fun);
     }
 
     return true;
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeNewScript
 /////////////////////////////////////////////////////////////////////
@@ -4314,17 +4314,17 @@ JSObject::makeLazyType(JSContext *cx, Ha
 
     AutoEnterAnalysis enter(cx);
 
     /* Fill in the type according to the state of this object. */
 
     type->initSingleton(obj);
 
     if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted())
-        type->interpretedFunction = &obj->as<JSFunction>();
+        type->setInterpretedFunction(&obj->as<JSFunction>());
 
     obj->type_ = type;
 
     return type;
 }
 
 /* static */ inline HashNumber
 NewTypeObjectEntry::hash(const Lookup &lookup)
@@ -4945,22 +4945,24 @@ TypeObject::fixupAfterMovingGC()
         switch (addendumKind()) {
           case Addendum_NewScript:
             newScript()->fixupAfterMovingGC();
             break;
           case Addendum_TypeDescr:
             if (IsForwarded(&typeDescr()))
                 addendum_ = Forwarded(&typeDescr());
             break;
+          case Addendum_InterpretedFunction:
+            if (IsForwarded(maybeInterpretedFunction()))
+                addendum_ = Forwarded(maybeInterpretedFunction());
+            break;
           default:
             MOZ_CRASH();
         }
     }
-    if (interpretedFunction && IsForwarded(interpretedFunction.get()))
-        interpretedFunction = Forwarded(interpretedFunction.get());
 }
 
 #endif // JSGC_COMPACTING
 
 #ifdef JSGC_HASH_TABLE_CHECKS
 
 void
 JSCompartment::checkTypeObjectTablesAfterMovingGC()
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -508,23 +508,23 @@ enum MOZ_ENUM_TYPE(uint32_t) {
     OBJECT_FLAG_DYNAMIC_MASK          = 0x03ff0000,
 
     /* Mask for objects created with unknown properties. */
     OBJECT_FLAG_UNKNOWN_MASK =
         OBJECT_FLAG_DYNAMIC_MASK
       | OBJECT_FLAG_SETS_MARKED_UNKNOWN,
 
     // Mask/shift for the kind of addendum attached to this type object.
-    OBJECT_FLAG_ADDENDUM_MASK         = 0x04000000,
+    OBJECT_FLAG_ADDENDUM_MASK         = 0x0c000000,
     OBJECT_FLAG_ADDENDUM_SHIFT        = 26,
 
     // Mask/shift for this type object's generation. If out of sync with the
     // TypeZone's generation, this TypeObject hasn't been swept yet.
-    OBJECT_FLAG_GENERATION_MASK       = 0x08000000,
-    OBJECT_FLAG_GENERATION_SHIFT      = 27,
+    OBJECT_FLAG_GENERATION_MASK       = 0x10000000,
+    OBJECT_FLAG_GENERATION_SHIFT      = 28,
 };
 typedef uint32_t TypeObjectFlags;
 
 class StackTypeSet;
 class HeapTypeSet;
 class TemporaryTypeSet;
 
 /*
@@ -1102,18 +1102,29 @@ struct TypeObject : public gc::TenuredCe
      */
     static const size_t LAZY_SINGLETON = 1;
     bool lazy() const { return singleton() == (JSObject *) LAZY_SINGLETON; }
 
   private:
     /* Flags for this object. */
     TypeObjectFlags flags_;
 
+    // Kinds of addendums which can be attached to TypeObjects.
     enum AddendumKind {
+        Addendum_None,
+
+        // When used by interpreted function, the addendum stores the
+        // canonical JSFunction object.
+        Addendum_InterpretedFunction,
+
+        // When used by the 'new' type when constructing an interpreted
+        // function, the addendum stores a TypeNewScript.
         Addendum_NewScript,
+
+        // When used by typed objects, the addendum stores a TypeDescr.
         Addendum_TypeDescr
     };
 
     // If non-null, holds additional information about this object, whose
     // format is indicated by the object's addendum kind.
     void *addendum_;
 
     void setAddendum(AddendumKind kind, void *addendum);
@@ -1167,16 +1178,28 @@ struct TypeObject : public gc::TenuredCe
         MOZ_ASSERT(addendumKind() == Addendum_TypeDescr);
         return *maybeTypeDescr();
     }
 
     void setTypeDescr(TypeDescr *descr) {
         setAddendum(Addendum_TypeDescr, descr);
     }
 
+    JSFunction *maybeInterpretedFunction() {
+        // Note: as with type descriptors, there is no need to sweep when
+        // accessing the interpreted function associated with an object.
+        if (addendumKind() == Addendum_InterpretedFunction)
+            return reinterpret_cast<JSFunction *>(addendum_);
+        return nullptr;
+    }
+
+    void setInterpretedFunction(JSFunction *fun) {
+        setAddendum(Addendum_InterpretedFunction, fun);
+    }
+
   private:
     /*
      * Properties of this object. This may contain JSID_VOID, representing the
      * types of all integer indexes of the object, and/or JSID_EMPTY, holding
      * constraints listening to changes to the object's state.
      *
      * The type sets in the properties of a type object describe the possible
      * values that can be read out of that property in actual JS objects.
@@ -1212,23 +1235,16 @@ struct TypeObject : public gc::TenuredCe
      *
      * We establish these by using write barriers on calls to setProperty and
      * defineProperty which are on native properties, and on any jitcode which
      * might update the property with a new type.
      */
     Property **propertySet;
   public:
 
-    /* If this is an interpreted function, the function object. */
-    HeapPtrFunction interpretedFunction;
-
-#if JS_BITS_PER_WORD == 32
-    uint32_t padding;
-#endif
-
     inline TypeObject(const Class *clasp, TaggedProto proto, TypeObjectFlags initialFlags);
 
     bool hasAnyFlags(TypeObjectFlags flags) {
         MOZ_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
         return !!(this->flags() & flags);
     }
     bool hasAllFlags(TypeObjectFlags flags) {
         MOZ_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -756,24 +756,24 @@ ToUpperCase(JSContext *cx, JSLinearStrin
         }
 
         if (resultIsLatin1) {
             Latin1CharPtr buf = cx->make_pod_array<Latin1Char>(length + 1);
             if (!buf)
                 return nullptr;
 
             ToUpperCaseImpl(buf.get(), chars, i, length);
-            newChars.construct<Latin1CharPtr>(buf);
+            newChars.construct<Latin1CharPtr>(Move(buf));
         } else {
             TwoByteCharPtr buf = cx->make_pod_array<char16_t>(length + 1);
             if (!buf)
                 return nullptr;
 
             ToUpperCaseImpl(buf.get(), chars, i, length);
-            newChars.construct<TwoByteCharPtr>(buf);
+            newChars.construct<TwoByteCharPtr>(Move(buf));
         }
     }
 
     JSString *res;
     if (newChars.constructed<Latin1CharPtr>()) {
         res = NewStringDontDeflate<CanGC>(cx, newChars.ref<Latin1CharPtr>().get(), length);
         if (!res)
             return nullptr;
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -2380,16 +2380,41 @@ DebugScopes::hasLiveScope(ScopeObject &s
 
     if (LiveScopeMap::Ptr p = scopes->liveScopes.lookup(&scope))
         return &p->value();
 
     return nullptr;
 }
 
 /* static */ void
+DebugScopes::unsetPrevUpToDateUntil(JSContext *cx, AbstractFramePtr until)
+{
+    // This is the one exception where fp->prevUpToDate() is cleared without
+    // popping the frame. When a frame is rematerialized, all frames younger
+    // than the rematerialized frame have their prevUpToDate set to
+    // false. This is because unrematerialized Ion frames have no usable
+    // AbstractFramePtr, and so are skipped by the updateLiveScopes. If in the
+    // future a frame suddenly gains a usable AbstractFramePtr via
+    // rematerialization, the prevUpToDate invariant will no longer hold.
+    for (AllFramesIter i(cx); !i.done(); ++i) {
+        if (!i.hasUsableAbstractFramePtr())
+            continue;
+
+        AbstractFramePtr frame = i.abstractFramePtr();
+        if (frame == until)
+            return;
+
+        if (frame.scopeChain()->compartment() != cx->compartment())
+            continue;
+
+        frame.unsetPrevUpToDate();
+    }
+}
+
+/* static */ void
 DebugScopes::forwardLiveFrame(JSContext *cx, AbstractFramePtr from, AbstractFramePtr to)
 {
     DebugScopes *scopes = cx->compartment()->debugScopes;
     if (!scopes)
         return;
 
     for (MissingScopeMap::Enum e(scopes->missingScopes); !e.empty(); e.popFront()) {
         ScopeIterKey key = e.front().key();
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -937,16 +937,17 @@ class DebugScopes
     static DebugScopeObject *hasDebugScope(JSContext *cx, ScopeObject &scope);
     static bool addDebugScope(JSContext *cx, ScopeObject &scope, DebugScopeObject &debugScope);
 
     static DebugScopeObject *hasDebugScope(JSContext *cx, const ScopeIter &si);
     static bool addDebugScope(JSContext *cx, const ScopeIter &si, DebugScopeObject &debugScope);
 
     static bool updateLiveScopes(JSContext *cx);
     static ScopeIterVal *hasLiveScope(ScopeObject &scope);
+    static void unsetPrevUpToDateUntil(JSContext *cx, AbstractFramePtr frame);
 
     // When a frame bails out from Ion to Baseline, there might be missing
     // scopes keyed on, and live scopes containing, the old
     // RematerializedFrame. Forward those values to the new BaselineFrame.
     static void forwardLiveFrame(JSContext *cx, AbstractFramePtr from, AbstractFramePtr to);
 
     // In debug-mode, these must be called whenever exiting a scope that might
     // have stack-allocated locals.
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -770,16 +770,30 @@ AbstractFramePtr::setPrevUpToDate() cons
     }
     if (isBaselineFrame()) {
         asBaselineFrame()->setPrevUpToDate();
         return;
     }
     asRematerializedFrame()->setPrevUpToDate();
 }
 
+inline void
+AbstractFramePtr::unsetPrevUpToDate() const
+{
+    if (isInterpreterFrame()) {
+        asInterpreterFrame()->unsetPrevUpToDate();
+        return;
+    }
+    if (isBaselineFrame()) {
+        asBaselineFrame()->unsetPrevUpToDate();
+        return;
+    }
+    asRematerializedFrame()->unsetPrevUpToDate();
+}
+
 inline Value &
 AbstractFramePtr::thisValue() const
 {
     if (isInterpreterFrame())
         return asInterpreterFrame()->thisValue();
     if (isBaselineFrame())
         return asBaselineFrame()->thisValue();
     return asRematerializedFrame()->thisValue();
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1472,18 +1472,16 @@ jit::JitActivation::clearRematerializedF
         RematerializedFrame::FreeInVector(e.front().value());
         e.removeFront();
     }
 }
 
 jit::RematerializedFrame *
 jit::JitActivation::getRematerializedFrame(JSContext *cx, const JitFrameIterator &iter, size_t inlineDepth)
 {
-    // Only allow rematerializing from the same thread.
-    MOZ_ASSERT(cx->perThreadData == cx_->perThreadData);
     MOZ_ASSERT(iter.activation() == this);
     MOZ_ASSERT(iter.isIonScripted());
 
     if (!rematerializedFrames_) {
         rematerializedFrames_ = cx->new_<RematerializedFrameTable>(cx);
         if (!rematerializedFrames_ || !rematerializedFrames_->init()) {
             rematerializedFrames_ = nullptr;
             return nullptr;
@@ -1510,16 +1508,20 @@ jit::JitActivation::getRematerializedFra
         // be in the activation's compartment.
         AutoCompartment ac(cx, compartment_);
 
         if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, recover,
                                                             p->value()))
         {
             return nullptr;
         }
+
+        // All frames younger than the rematerialized frame need to have their
+        // prevUpToDate flag cleared.
+        DebugScopes::unsetPrevUpToDateUntil(cx, p->value()[inlineDepth]);
     }
 
     return p->value()[inlineDepth];
 }
 
 jit::RematerializedFrame *
 jit::JitActivation::lookupRematerializedFrame(uint8_t *top, size_t inlineDepth)
 {
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -212,16 +212,17 @@ class AbstractFramePtr
 
     inline Value &unaliasedLocal(uint32_t i);
     inline Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
     inline Value &unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
     template <class Op> inline void unaliasedForEachActual(JSContext *cx, Op op);
 
     inline bool prevUpToDate() const;
     inline void setPrevUpToDate() const;
+    inline void unsetPrevUpToDate() const;
 
     inline bool isDebuggee() const;
     inline void setIsDebuggee();
     inline void unsetIsDebuggee();
 
     JSObject *evalPrevScopeChain(JSContext *cx) const;
 
     inline HandleValue returnValue() const;
@@ -828,16 +829,20 @@ class InterpreterFrame
     bool prevUpToDate() const {
         return !!(flags_ & PREV_UP_TO_DATE);
     }
 
     void setPrevUpToDate() {
         flags_ |= PREV_UP_TO_DATE;
     }
 
+    void unsetPrevUpToDate() {
+        flags_ &= ~PREV_UP_TO_DATE;
+    }
+
     bool isDebuggee() const {
         return !!(flags_ & DEBUGGEE);
     }
 
     void setIsDebuggee() {
         flags_ |= DEBUGGEE;
     }
 
deleted file mode 100644
--- a/layout/generic/RubyReflowState.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* states and methods used while laying out a ruby segment */
-
-#include "RubyReflowState.h"
-
-using namespace mozilla;
-
-RubyReflowState::RubyReflowState(
-  WritingMode aLineWM,
-  const nsTArray<nsRubyTextContainerFrame*>& aTextContainers)
-  : mCurrentContainerIndex(kBaseContainerIndex)
-{
-  uint32_t rtcCount = aTextContainers.Length();
-  mTextContainers.SetCapacity(rtcCount);
-  for (uint32_t i = 0; i < rtcCount; i++) {
-    mTextContainers.AppendElement(
-      TextContainerInfo(aLineWM, aTextContainers[i]));
-  }
-}
deleted file mode 100644
--- a/layout/generic/RubyReflowState.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* states and methods used while laying out a ruby segment */
-
-#ifndef mozilla_RubyReflowState_h_
-#define mozilla_RubyReflowState_h_
-
-#include "mozilla/Attributes.h"
-#include "WritingModes.h"
-#include "nsTArray.h"
-
-#define RTC_ARRAY_SIZE 1
-
-class nsRubyTextContainerFrame;
-
-namespace mozilla {
-
-class MOZ_STACK_CLASS RubyReflowState MOZ_FINAL
-{
-public:
-  explicit RubyReflowState(
-    WritingMode aLineWM,
-    const nsTArray<nsRubyTextContainerFrame*>& aTextContainers);
-
-  struct TextContainerInfo
-  {
-    nsRubyTextContainerFrame* mFrame;
-    LogicalSize mLineSize;
-
-    TextContainerInfo(WritingMode aLineWM, nsRubyTextContainerFrame* aFrame)
-      : mFrame(aFrame)
-      , mLineSize(aLineWM) { }
-  };
-
-  void AdvanceCurrentContainerIndex() { mCurrentContainerIndex++; }
-
-  void SetTextContainerInfo(int32_t aIndex,
-                            nsRubyTextContainerFrame* aContainer,
-                            const LogicalSize& aLineSize)
-  {
-    MOZ_ASSERT(mTextContainers[aIndex].mFrame == aContainer);
-    mTextContainers[aIndex].mLineSize = aLineSize;
-  }
-
-  const TextContainerInfo&
-    GetCurrentTextContainerInfo(nsRubyTextContainerFrame* aFrame) const
-  {
-    MOZ_ASSERT(mTextContainers[mCurrentContainerIndex].mFrame == aFrame);
-    return mTextContainers[mCurrentContainerIndex];
-  }
-
-private:
-  static MOZ_CONSTEXPR_VAR int32_t kBaseContainerIndex = -1;
-  // The index of the current reflowing container. When it equals to
-  // kBaseContainerIndex, we are reflowing ruby base. Otherwise, it
-  // stands for the index of text containers in the ruby segment.
-  int32_t mCurrentContainerIndex;
-
-  nsAutoTArray<TextContainerInfo, RTC_ARRAY_SIZE> mTextContainers;
-};
-
-}
-
-#endif // mozilla_RubyReflowState_h_
--- a/layout/generic/moz.build
+++ b/layout/generic/moz.build
@@ -90,17 +90,16 @@ UNIFIED_SOURCES += [
     'nsSimplePageSequenceFrame.cpp',
     'nsSplittableFrame.cpp',
     'nsSubDocumentFrame.cpp',
     'nsTextFrame.cpp',
     'nsTextFrameUtils.cpp',
     'nsTextRunTransformations.cpp',
     'nsVideoFrame.cpp',
     'nsViewportFrame.cpp',
-    'RubyReflowState.cpp',
     'RubyUtils.cpp',
     'ScrollbarActivity.cpp',
     'StickyScrollContainer.cpp',
     'TextOverflow.cpp',
 ]
 
 # nsLineLayout.cpp needs to be built separately because it uses plarena.h.
 # nsPluginFrame.cpp needs to be built separately because of name clashes in the OS X headers.
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -403,16 +403,19 @@ FRAME_STATE_BIT(Text, 31, TEXT_HAS_NONCO
 FRAME_STATE_BIT(Text, 32, TEXT_IS_IN_TOKEN_MATHML)
 
 // Set when this text frame is mentioned in the userdata for the
 // uninflated textrun property
 FRAME_STATE_BIT(Text, 60, TEXT_IN_UNINFLATED_TEXTRUN_USER_DATA)
 
 FRAME_STATE_BIT(Text, 61, TEXT_HAS_FONT_INFLATION)
 
+// Set when this text frame contains nothing that will actually render
+FRAME_STATE_BIT(Text, 62, TEXT_NO_RENDERED_GLYPHS)
+
 // Whether this frame is cached in the Offset Frame Cache
 // (OffsetToFrameProperty)
 FRAME_STATE_BIT(Text, 63, TEXT_IN_OFFSET_CACHE)
 
 
 // == Frame state bits that apply to block frames =============================
 
 FRAME_STATE_GROUP(Block, nsBlockFrame)
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -67,17 +67,16 @@ nsHTMLReflowState::nsHTMLReflowState(nsP
   MOZ_ASSERT(aPresContext, "no pres context");
   MOZ_ASSERT(aFrame, "no frame");
   MOZ_ASSERT(aPresContext == aFrame->PresContext(), "wrong pres context");
   parentReflowState = nullptr;
   AvailableISize() = aAvailableSpace.ISize(mWritingMode);
   AvailableBSize() = aAvailableSpace.BSize(mWritingMode);
   mFloatManager = nullptr;
   mLineLayout = nullptr;
-  mRubyReflowState = nullptr;
   memset(&mFlags, 0, sizeof(mFlags));
   mDiscoveredClearance = nullptr;
   mPercentHeightObserver = nullptr;
 
   if (aFlags & DUMMY_PARENT_REFLOW_STATE) {
     mFlags.mDummyParentReflowState = true;
   }
 
@@ -203,17 +202,16 @@ nsHTMLReflowState::nsHTMLReflowState(nsP
     }
   }
 
   mFloatManager = aParentReflowState.mFloatManager;
   if (frame->IsFrameOfType(nsIFrame::eLineParticipant))
     mLineLayout = aParentReflowState.mLineLayout;
   else
     mLineLayout = nullptr;
-  mRubyReflowState = nullptr;
 
   // Note: mFlags was initialized as a copy of aParentReflowState.mFlags up in
   // this constructor's init list, so the only flags that we need to explicitly
   // initialize here are those that may need a value other than our parent's.
   mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
     CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
   mFlags.mAssumingHScrollbar = mFlags.mAssumingVScrollbar = false;
   mFlags.mHasClearance = false;
--- a/layout/generic/nsHTMLReflowState.h
+++ b/layout/generic/nsHTMLReflowState.h
@@ -16,20 +16,16 @@
 
 class nsPresContext;
 class nsRenderingContext;
 class nsFloatManager;
 class nsLineLayout;
 class nsIPercentHeightObserver;
 struct nsHypotheticalBox;
 
-namespace mozilla {
-class RubyReflowState;
-}
-
 /**
  * @return aValue clamped to [aMinValue, aMaxValue].
  *
  * @note This function needs to handle aMinValue > aMaxValue. In that case,
  *       aMinValue is returned.
  * @see http://www.w3.org/TR/CSS21/visudet.html#min-max-widths
  * @see http://www.w3.org/TR/CSS21/visudet.html#min-max-heights
  */
@@ -257,19 +253,16 @@ struct nsHTMLReflowState : public nsCSSO
   const nsHTMLReflowState* parentReflowState;
 
   // pointer to the float manager associated with this area
   nsFloatManager* mFloatManager;
 
   // LineLayout object (only for inline reflow; set to nullptr otherwise)
   nsLineLayout*    mLineLayout;
 
-  // RubyReflowState object (only for ruby reflow; set to nullptr otherwise)
-  mozilla::RubyReflowState* mRubyReflowState;
-
   // The appropriate reflow state for the containing block (for
   // percentage widths, etc.) of this reflow state's frame.
   const nsHTMLReflowState *mCBReflowState;
 
   // The type of frame, from css's perspective. This value is
   // initialized by the Init method below.
   nsCSSFrameType   mFrameType;
 
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -53,26 +53,25 @@ using namespace mozilla;
 nsLineLayout::nsLineLayout(nsPresContext* aPresContext,
                            nsFloatManager* aFloatManager,
                            const nsHTMLReflowState* aOuterReflowState,
                            const nsLineList::iterator* aLine,
                            nsLineLayout* aBaseLineLayout)
   : mPresContext(aPresContext),
     mFloatManager(aFloatManager),
     mBlockReflowState(aOuterReflowState),
-    mBaseLineLayout(aBaseLineLayout ? aBaseLineLayout->mBaseLineLayout : this),
+    mBaseLineLayout(aBaseLineLayout),
     mLastOptionalBreakFrame(nullptr),
     mForceBreakFrame(nullptr),
     mBlockRS(nullptr),/* XXX temporary */
     mLastOptionalBreakPriority(gfxBreakPriority::eNoBreak),
     mLastOptionalBreakFrameOffset(-1),
     mForceBreakFrameOffset(-1),
     mMinLineBSize(0),
     mTextIndent(0),
-    mRubyReflowState(nullptr),
     mFirstLetterStyleOK(false),
     mIsTopOfPage(false),
     mImpactedByFloats(false),
     mLastFloatWasLetterFrame(false),
     mLineIsEmpty(false),
     mLineEndsInBR(false),
     mNeedBackup(false),
     mInFirstLine(false),
@@ -82,16 +81,21 @@ nsLineLayout::nsLineLayout(nsPresContext
     mDirtyNextLine(false),
     mLineAtStart(false),
     mHasRuby(false)
 {
   MOZ_ASSERT(aOuterReflowState, "aOuterReflowState must not be null");
   NS_ASSERTION(aFloatManager || aOuterReflowState->frame->GetType() ==
                                   nsGkAtoms::letterFrame,
                "float manager should be present");
+  MOZ_ASSERT((!!mBaseLineLayout) ==
+             (aOuterReflowState->frame->GetType() ==
+              nsGkAtoms::rubyTextContainerFrame),
+             "Only ruby text container frames have "
+             "a different base line layout");
   MOZ_COUNT_CTOR(nsLineLayout);
 
   // Stash away some style data that we need
   nsBlockFrame* blockFrame = do_QueryFrame(aOuterReflowState->frame);
   if (blockFrame)
     mStyleText = blockFrame->StyleTextForLineLayout();
   else
     mStyleText = aOuterReflowState->frame->StyleText();
@@ -177,17 +181,17 @@ nsLineLayout::BeginLineReflow(nscoord aI
 #ifdef DEBUG
   mSpansAllocated = mSpansFreed = mFramesAllocated = mFramesFreed = 0;
 #endif
 
   mFirstLetterStyleOK = false;
   mIsTopOfPage = aIsTopOfPage;
   mImpactedByFloats = aImpactedByFloats;
   mTotalPlacedFrames = 0;
-  if (mBaseLineLayout == this) {
+  if (!mBaseLineLayout) {
     mLineIsEmpty = true;
     mLineAtStart = true;
   } else {
     mLineIsEmpty = false;
     mLineAtStart = false;
   }
   mLineEndsInBR = false;
   mSpanDepth = 0;
@@ -248,27 +252,42 @@ nsLineLayout::BeginLineReflow(nscoord aI
 
     psd->mICoord += indent;
   }
 
   PerFrameData* pfd = NewPerFrameData(mBlockReflowState->frame);
   pfd->mAscent = 0;
   pfd->mSpan = psd;
   psd->mFrame = pfd;
+  nsIFrame* frame = mBlockReflowState->frame;
+  if (frame->GetType() == nsGkAtoms::rubyTextContainerFrame) {
+    // Ruby text container won't be reflowed via ReflowFrame, hence the
+    // relative positioning information should be recorded here.
+    MOZ_ASSERT(mBaseLineLayout != this);
+    pfd->mRelativePos =
+      mBlockReflowState->mStyleDisplay->IsRelativelyPositionedStyle();
+    if (pfd->mRelativePos) {
+      MOZ_ASSERT(
+        mBlockReflowState->GetWritingMode() == frame->GetWritingMode(),
+        "mBlockReflowState->frame == frame, "
+        "hence they should have identical writing mode");
+      pfd->mOffsets = mBlockReflowState->ComputedLogicalOffsets();
+    }
+  }
 }
 
 void
 nsLineLayout::EndLineReflow()
 {
 #ifdef NOISY_REFLOW
   nsFrame::ListTag(stdout, mBlockReflowState->frame);
   printf(": EndLineReflow: width=%d\n", mRootSpan->mICoord - mRootSpan->mIStart);
 #endif
 
-  NS_ASSERTION(mBaseLineLayout == this ||
+  NS_ASSERTION(!mBaseLineLayout ||
                (!mSpansAllocated && !mSpansFreed && !mSpanFreeList &&
                 !mFramesAllocated && !mFramesFreed && !mFrameFreeList),
                "Allocated frames or spans on non-base line layout?");
 
   UnlinkFrame(mRootSpan->mFrame);
   mCurrentSpan = mRootSpan = nullptr;
 
   NS_ASSERTION(mSpansAllocated == mSpansFreed, "leak");
@@ -381,39 +400,40 @@ nsLineLayout::UpdateBand(WritingMode aWM
   mImpactedByFloats = true;
 
   mLastFloatWasLetterFrame = nsGkAtoms::letterFrame == aFloatFrame->GetType();
 }
 
 nsLineLayout::PerSpanData*
 nsLineLayout::NewPerSpanData()
 {
-  PerSpanData* psd = mBaseLineLayout->mSpanFreeList;
+  nsLineLayout* outerLineLayout = GetOutermostLineLayout();
+  PerSpanData* psd = outerLineLayout->mSpanFreeList;
   if (!psd) {
     void *mem;
     size_t sz = sizeof(PerSpanData);
-    PL_ARENA_ALLOCATE(mem, &mBaseLineLayout->mArena, sz);
+    PL_ARENA_ALLOCATE(mem, &outerLineLayout->mArena, sz);
     if (!mem) {
       NS_ABORT_OOM(sz);
     }
     psd = reinterpret_cast<PerSpanData*>(mem);
   }
   else {
-    mBaseLineLayout->mSpanFreeList = psd->mNextFreeSpan;
+    outerLineLayout->mSpanFreeList = psd->mNextFreeSpan;
   }
   psd->mParent = nullptr;
   psd->mFrame = nullptr;
   psd->mFirstFrame = nullptr;
   psd->mLastFrame = nullptr;
   psd->mContainsFloat = false;
   psd->mZeroEffectiveSpanBox = false;
   psd->mHasNonemptyContent = false;
 
 #ifdef DEBUG
-  mBaseLineLayout->mSpansAllocated++;
+  outerLineLayout->mSpansAllocated++;
 #endif
   return psd;
 }
 
 void
 nsLineLayout::BeginSpan(nsIFrame* aFrame,
                         const nsHTMLReflowState* aSpanReflowState,
                         nscoord aIStart, nscoord aIEnd,
@@ -468,23 +488,31 @@ nsLineLayout::EndSpan(nsIFrame* aFrame)
   mCurrentSpan->mReflowState = nullptr;  // no longer valid so null it out!
   mCurrentSpan = mCurrentSpan->mParent;
   return iSizeResult;
 }
 
 void
 nsLineLayout::AttachFrameToBaseLineLayout(PerFrameData* aFrame)
 {
-  NS_PRECONDITION(this != mBaseLineLayout,
+  NS_PRECONDITION(mBaseLineLayout,
                   "This method must not be called in a base line layout.");
 
   PerFrameData* baseFrame = mBaseLineLayout->LastFrame();
   MOZ_ASSERT(aFrame && baseFrame);
   MOZ_ASSERT(!aFrame->mIsLinkedToBase,
              "The frame must not have been linked with the base");
+#ifdef DEBUG
+  nsIAtom* baseType = baseFrame->mFrame->GetType();
+  nsIAtom* annotationType = aFrame->mFrame->GetType();
+  MOZ_ASSERT((baseType == nsGkAtoms::rubyBaseContainerFrame &&
+              annotationType == nsGkAtoms::rubyTextContainerFrame) ||
+             (baseType == nsGkAtoms::rubyBaseFrame &&
+              annotationType == nsGkAtoms::rubyTextFrame));
+#endif
 
   aFrame->mNextAnnotation = baseFrame->mNextAnnotation;
   baseFrame->mNextAnnotation = aFrame;
   aFrame->mIsLinkedToBase = true;
 }
 
 int32_t
 nsLineLayout::GetCurrentSpanCount() const
@@ -598,34 +626,36 @@ nsLineLayout::UnlinkFrame(PerFrameData* 
 }
 
 void
 nsLineLayout::FreeFrame(PerFrameData* pfd)
 {
   if (nullptr != pfd->mSpan) {
     FreeSpan(pfd->mSpan);
   }
-  pfd->mNext = mBaseLineLayout->mFrameFreeList;
-  mBaseLineLayout->mFrameFreeList = pfd;
+  nsLineLayout* outerLineLayout = GetOutermostLineLayout();
+  pfd->mNext = outerLineLayout->mFrameFreeList;
+  outerLineLayout->mFrameFreeList = pfd;
 #ifdef DEBUG
-  mBaseLineLayout->mFramesFreed++;
+  outerLineLayout->mFramesFreed++;
 #endif
 }
 
 void
 nsLineLayout::FreeSpan(PerSpanData* psd)
 {
   // Unlink its frames
   UnlinkFrame(psd->mFirstFrame);
 
+  nsLineLayout* outerLineLayout = GetOutermostLineLayout();
   // Now put the span on the free list since it's free too
-  psd->mNextFreeSpan = mBaseLineLayout->mSpanFreeList;
-  mBaseLineLayout->mSpanFreeList = psd;
+  psd->mNextFreeSpan = outerLineLayout->mSpanFreeList;
+  outerLineLayout->mSpanFreeList = psd;
 #ifdef DEBUG
-  mBaseLineLayout->mSpansFreed++;
+  outerLineLayout->mSpansFreed++;
 #endif
 }
 
 bool
 nsLineLayout::IsZeroBSize()
 {
   PerSpanData* psd = mCurrentSpan;
   PerFrameData* pfd = psd->mFirstFrame;
@@ -636,28 +666,29 @@ nsLineLayout::IsZeroBSize()
     pfd = pfd->mNext;
   }
   return true;
 }
 
 nsLineLayout::PerFrameData*
 nsLineLayout::NewPerFrameData(nsIFrame* aFrame)
 {
-  PerFrameData* pfd = mBaseLineLayout->mFrameFreeList;
+  nsLineLayout* outerLineLayout = GetOutermostLineLayout();
+  PerFrameData* pfd = outerLineLayout->mFrameFreeList;
   if (!pfd) {
     void *mem;
     size_t sz = sizeof(PerFrameData);
-    PL_ARENA_ALLOCATE(mem, &mBaseLineLayout->mArena, sz);
+    PL_ARENA_ALLOCATE(mem, &outerLineLayout->mArena, sz);
     if (!mem) {
       NS_ABORT_OOM(sz);
     }
     pfd = reinterpret_cast<PerFrameData*>(mem);
   }
   else {
-    mBaseLineLayout->mFrameFreeList = pfd->mNext;
+    outerLineLayout->mFrameFreeList = pfd->mNext;
   }
   pfd->mSpan = nullptr;
   pfd->mNext = nullptr;
   pfd->mPrev = nullptr;
   pfd->mNextAnnotation = nullptr;
   pfd->mFrame = aFrame;
 
   // all flags default to false
@@ -670,26 +701,27 @@ nsLineLayout::NewPerFrameData(nsIFrame* 
   pfd->mIsBullet = false;
   pfd->mSkipWhenTrimmingWhitespace = false;
   pfd->mIsEmpty = false;
   pfd->mIsLinkedToBase = false;
 
   WritingMode frameWM = aFrame->GetWritingMode();
   WritingMode lineWM = mRootSpan->mWritingMode;
   pfd->mBounds = LogicalRect(lineWM);
+  pfd->mOverflowAreas.Clear();
   pfd->mMargin = LogicalMargin(lineWM);
   pfd->mBorderPadding = LogicalMargin(lineWM);
   pfd->mOffsets = LogicalMargin(frameWM);
 
   pfd->mJustificationInfo = JustificationInfo();
   pfd->mJustificationAssignment = JustificationAssignment();
 
 #ifdef DEBUG
   pfd->mBlockDirAlign = 0xFF;
-  mBaseLineLayout->mFramesAllocated++;
+  outerLineLayout->mFramesAllocated++;
 #endif
   return pfd;
 }
 
 bool
 nsLineLayout::LineIsBreakable() const
 {
   // XXX mTotalPlacedFrames should go away and we should just use
@@ -865,20 +897,16 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
     // includes room for the side margins.
     // For now, set the available block-size to unconstrained always.
     LogicalSize availSize = mBlockReflowState->ComputedSize(frameWM);
     availSize.BSize(frameWM) = NS_UNCONSTRAINEDSIZE;
     reflowStateHolder.emplace(mPresContext, *psd->mReflowState,
                               aFrame, availSize);
     nsHTMLReflowState& reflowState = *reflowStateHolder;
     reflowState.mLineLayout = this;
-    if (mRubyReflowState) {
-      reflowState.mRubyReflowState = mRubyReflowState;
-      mRubyReflowState = nullptr;
-    }
     reflowState.mFlags.mIsTopOfPage = mIsTopOfPage;
     if (reflowState.ComputedISize() == NS_UNCONSTRAINEDSIZE) {
       reflowState.AvailableISize() = availableSpaceOnLine;
     }
     WritingMode stateWM = reflowState.GetWritingMode();
     pfd->mMargin =
       reflowState.ComputedLogicalMargin().ConvertTo(lineWM, stateWM);
     pfd->mBorderPadding =
@@ -965,17 +993,18 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
           // so we can't know whether the float plus that content will fit
           // on the line. So for now, don't place floats after inline
           // content where there's no break opportunity. This is incorrect
           // but hopefully rare. Fixing it will require significant
           // restructuring of line layout.
           // We might as well allow zero-width floats to be placed, though.
           availableISize = 0;
         }
-        placedFloat = mBaseLineLayout->AddFloat(outOfFlowFrame, availableISize);
+        placedFloat = GetOutermostLineLayout()->
+          AddFloat(outOfFlowFrame, availableISize);
         NS_ASSERTION(!(outOfFlowFrame->GetType() == nsGkAtoms::letterFrame &&
                        GetFirstLetterStyleOK()),
                     "FirstLetterStyle set on line with floating first letter");
       }
     }
     else if (isText) {
       // Note non-empty text-frames for inline frame compatibility hackery
       pfd->mIsTextFrame = true;
@@ -2844,17 +2873,24 @@ nsLineLayout::ExpandRubyBoxWithAnnotatio
     JustificationComputationState computeState;
     ComputeFrameJustification(annotation->mSpan, computeState);
     if (!computeState.mFirstParticipant) {
       continue;
     }
     // Add one gap at each side of this annotation.
     computeState.mFirstParticipant->mJustificationAssignment.mGapsAtStart = 1;
     computeState.mLastParticipant->mJustificationAssignment.mGapsAtEnd = 1;
-    ExpandRubyBox(annotation, reservedISize, aContainerWidth);
+    nsIFrame* parentFrame = annotation->mFrame->GetParent();
+    nscoord containerWidth = parentFrame->GetRect().Width();
+    MOZ_ASSERT(containerWidth == aContainerWidth ||
+               parentFrame->GetType() == nsGkAtoms::rubyTextContainerFrame,
+               "Container width should only be different when the current "
+               "annotation is a ruby text frame, whose parent is not same "
+               "as its base frame.");
+    ExpandRubyBox(annotation, reservedISize, containerWidth);
     ExpandInlineRubyBoxes(annotation->mSpan);
   }
 }
 
 /**
  * This method looks for all expandable ruby box in the given span, and
  * calls ExpandRubyBox to expand them in depth-first preorder.
  */
@@ -3016,16 +3052,55 @@ nsLineLayout::TextAlignLine(nsLineBox* a
 }
 
 void
 nsLineLayout::RelativePositionFrames(nsOverflowAreas& aOverflowAreas)
 {
   RelativePositionFrames(mRootSpan, aOverflowAreas);
 }
 
+// This method applies any relative positioning to the given frame.
+void
+nsLineLayout::ApplyRelativePositioning(PerFrameData* aPFD)
+{
+  if (!aPFD->mRelativePos) {
+    return;
+  }
+
+  nsIFrame* frame = aPFD->mFrame;
+  WritingMode frameWM = frame->GetWritingMode();
+  LogicalPoint origin = frame->GetLogicalPosition(mContainerWidth);
+  // right and bottom are handled by
+  // nsHTMLReflowState::ComputeRelativeOffsets
+  nsHTMLReflowState::ApplyRelativePositioning(frame, frameWM,
+                                              aPFD->mOffsets, &origin,
+                                              mContainerWidth);
+  frame->SetPosition(frameWM, origin, mContainerWidth);
+}
+
+// This method do relative positioning for ruby annotations.
+void
+nsLineLayout::RelativePositionAnnotations(PerSpanData* aRubyPSD,
+                                          nsOverflowAreas& aOverflowAreas)
+{
+  MOZ_ASSERT(aRubyPSD->mFrame->mFrame->GetType() == nsGkAtoms::rubyFrame);
+  for (PerFrameData* pfd = aRubyPSD->mFirstFrame; pfd; pfd = pfd->mNext) {
+    MOZ_ASSERT(pfd->mFrame->GetType() == nsGkAtoms::rubyBaseContainerFrame);
+    for (PerFrameData* rtc = pfd->mNextAnnotation;
+         rtc; rtc = rtc->mNextAnnotation) {
+      nsIFrame* rtcFrame = rtc->mFrame;
+      MOZ_ASSERT(rtcFrame->GetType() == nsGkAtoms::rubyTextContainerFrame);
+      ApplyRelativePositioning(rtc);
+      nsOverflowAreas rtcOverflowAreas;
+      RelativePositionFrames(rtc->mSpan, rtcOverflowAreas);
+      aOverflowAreas.UnionWith(rtcOverflowAreas + rtcFrame->GetPosition());
+    }
+  }
+}
+
 void
 nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsOverflowAreas& aOverflowAreas)
 {
   nsOverflowAreas overflowAreas;
   WritingMode wm = psd->mWritingMode;
   if (psd != mRootSpan) {
     // The span's overflow areas come in three parts:
     // -- this frame's width and height
@@ -3054,26 +3129,17 @@ nsLineLayout::RelativePositionFrames(Per
     overflowAreas.VisualOverflow() = rect.GetPhysicalRect(wm, mContainerWidth);
     overflowAreas.ScrollableOverflow() = overflowAreas.VisualOverflow();
   }
 
   for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
     nsIFrame* frame = pfd->mFrame;
 
     // Adjust the origin of the frame
-    if (pfd->mRelativePos) {
-      WritingMode frameWM = frame->GetWritingMode();
-      LogicalPoint origin = frame->GetLogicalPosition(mContainerWidth);
-      // right and bottom are handled by
-      // nsHTMLReflowState::ComputeRelativeOffsets
-      nsHTMLReflowState::ApplyRelativePositioning(frame, frameWM,
-                                                  pfd->mOffsets, &origin,
-                                                  mContainerWidth);
-      frame->SetPosition(frameWM, origin, mContainerWidth);
-    }
+    ApplyRelativePositioning(pfd);
 
     // We must position the view correctly before positioning its
     // descendants so that widgets are positioned properly (since only
     // some views have widgets).
     if (frame->HasView())
       nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, frame,
         frame->GetView(), pfd->mOverflowAreas.VisualOverflow(),
         NS_FRAME_NO_SIZE_VIEW);
@@ -3119,16 +3185,21 @@ nsLineLayout::RelativePositionFrames(Per
       nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, frame,
                                                  frame->GetView(),
                                                  r.VisualOverflow(),
                                                  NS_FRAME_NO_MOVE_VIEW);
 
     overflowAreas.UnionWith(r + frame->GetPosition());
   }
 
+  // Also compute relative position in the annotations.
+  if (psd->mFrame->mFrame->GetType() == nsGkAtoms::rubyFrame) {
+    RelativePositionAnnotations(psd, overflowAreas);
+  }
+
   // If we just computed a spans combined area, we need to update its
   // overflow rect...
   if (psd != mRootSpan) {
     PerFrameData* spanPFD = psd->mFrame;
     nsIFrame* frame = spanPFD->mFrame;
     frame->FinishAndStoreOverflow(overflowAreas, frame->GetSize());
   }
   aOverflowAreas = overflowAreas;
--- a/layout/generic/nsLineLayout.h
+++ b/layout/generic/nsLineLayout.h
@@ -22,20 +22,16 @@
 #include "plarena.h"
 #include "gfxTypes.h"
 #include "WritingModes.h"
 #include "JustificationUtils.h"
 
 class nsFloatManager;
 struct nsStyleText;
 
-namespace mozilla {
-class RubyReflowState;
-}
-
 class nsLineLayout {
 public:
   /**
    * @param aBaseLineLayout the nsLineLayout for ruby base,
    * nullptr if no separate base nsLineLayout is needed.
    */
   nsLineLayout(nsPresContext* aPresContext,
                nsFloatManager* aFloatManager,
@@ -97,23 +93,16 @@ public:
   }
 
   int32_t GetCurrentSpanCount() const;
 
   void SplitLineTo(int32_t aNewCount);
 
   bool IsZeroBSize();
 
-  // The ruby layout will be passed to the next frame to be reflowed
-  // via the HTML reflow state.
-  void SetRubyReflowState(mozilla::RubyReflowState* aRubyReflowState)
-  {
-    mRubyReflowState = aRubyReflowState;
-  }
-
   // Reflows the frame and returns the reflow status. aPushedFrame is true
   // if the frame is pushed to the next line because it doesn't fit.
   void ReflowFrame(nsIFrame* aFrame,
                    nsReflowStatus& aReflowStatus,
                    nsHTMLReflowMetrics* aMetrics,
                    bool& aPushedFrame);
 
   void AddBulletFrame(nsIFrame* aFrame, const nsHTMLReflowMetrics& aMetrics);
@@ -380,24 +369,33 @@ public:
   nscoord GetCurrentICoord();
 
 protected:
   // This state is constant for a given block frame doing line layout
   nsFloatManager* mFloatManager;
   const nsStyleText* mStyleText; // for the block
   const nsHTMLReflowState* mBlockReflowState;
 
-  // The line layout for the base text. It is usually same as |this|.
-  // It becomes different when the current line layout is for ruby
-  // annotations. All line layouts share the same base line layout
-  // when they are associated. The base line layout is responsible
-  // for managing the life cycle of per-frame data and per-span data,
-  // and handling floats.
+  // The line layout for the base text.  It is usually nullptr.
+  // It becomes not null when the current line layout is for ruby
+  // annotations. When there is nested ruby inside annotation, it
+  // forms a linked list from the inner annotation to the outermost
+  // line layout. The outermost line layout, which has this member
+  // being nullptr, is responsible for managing the life cycle of
+  // per-frame data and per-span data, and handling floats.
   nsLineLayout* const mBaseLineLayout;
 
+  nsLineLayout* GetOutermostLineLayout() {
+    nsLineLayout* lineLayout = this;
+    while (lineLayout->mBaseLineLayout) {
+      lineLayout = lineLayout->mBaseLineLayout;
+    }
+    return lineLayout;
+  }
+
   nsIFrame* mLastOptionalBreakFrame;
   nsIFrame* mForceBreakFrame;
   
   // XXX remove this when landing bug 154892 (splitting absolute positioned frames)
   friend class nsInlineFrame;
 
   nsBlockReflowState* mBlockRS;/* XXX hack! */
 
@@ -560,20 +558,16 @@ protected:
   // max-element-size calculation.
   nscoord mTextIndent;
 
   // This state varies during the reflow of a line but is line
   // "global" state not span "local" state.
   int32_t mLineNumber;
   mozilla::JustificationInfo mJustificationInfo;
 
-  // The ruby layout for the next frame to be reflowed.
-  // It is reset every time it is used.
-  mozilla::RubyReflowState* mRubyReflowState;
-
   int32_t mTotalPlacedFrames;
 
   nscoord mBStartEdge;
   nscoord mMaxStartBoxBSize;
   nscoord mMaxEndBoxBSize;
 
   nscoord mInflationMinFontSize;
 
@@ -660,16 +654,21 @@ protected:
                   nsHTMLReflowMetrics& aMetrics);
 
   void VerticalAlignFrames(PerSpanData* psd);
 
   void PlaceTopBottomFrames(PerSpanData* psd,
                             nscoord aDistanceFromStart,
                             nscoord aLineBSize);
 
+  void ApplyRelativePositioning(PerFrameData* aPFD);
+
+  void RelativePositionAnnotations(PerSpanData* aRubyPSD,
+                                   nsOverflowAreas& aOverflowAreas);
+
   void RelativePositionFrames(PerSpanData* psd, nsOverflowAreas& aOverflowAreas);
 
   bool TrimTrailingWhiteSpaceIn(PerSpanData* psd, nscoord* aDeltaISize);
 
   struct JustificationComputationState;
   int32_t ComputeFrameJustification(PerSpanData* psd,
                                     JustificationComputationState& aState);
 
--- a/layout/generic/nsRubyBaseContainerFrame.cpp
+++ b/layout/generic/nsRubyBaseContainerFrame.cpp
@@ -336,17 +336,16 @@ nsRubyBaseContainerFrame::Reflow(nsPresC
   aStatus = NS_FRAME_COMPLETE;
 
   if (!aReflowState.mLineLayout) {
     NS_ASSERTION(
       aReflowState.mLineLayout,
       "No line layout provided to RubyBaseContainerFrame reflow method.");
     return;
   }
-  MOZ_ASSERT(aReflowState.mRubyReflowState, "No ruby reflow state provided");
 
   AutoTextContainerArray textContainers;
   GetTextContainers(textContainers);
 
   MoveOverflowToChildList();
   // Ask text containers to drain overflows
   const uint32_t rtcCount = textContainers.Length();
   for (uint32_t i = 0; i < rtcCount; i++) {
@@ -388,24 +387,24 @@ nsRubyBaseContainerFrame::Reflow(nsPresC
 
     // Line number is useless for ruby text
     // XXX nullptr here may cause problem, see comments for
     //     nsLineLayout::mBlockRS and nsLineLayout::AddFloat
     lineLayout->Init(nullptr, reflowState->CalcLineHeight(), -1);
     reflowState->mLineLayout = lineLayout;
 
     LogicalMargin borderPadding = reflowState->ComputedLogicalBorderPadding();
-    nscoord containerWidth =
-      reflowState->ComputedWidth() + borderPadding.LeftRight(lineWM);
-
+    // If the writing mode is vertical-rl, the horizontal position of
+    // rt frames will be updated when reflowing this text container,
+    // hence leave container width 0 here for now.
     lineLayout->BeginLineReflow(borderPadding.IStart(lineWM),
                                 borderPadding.BStart(lineWM),
                                 reflowState->ComputedISize(),
                                 NS_UNCONSTRAINEDSIZE,
-                                false, false, lineWM, containerWidth);
+                                false, false, lineWM, 0);
     lineLayout->AttachRootFrameToBaseLineLayout();
   }
 
   WritingMode frameWM = aReflowState.GetWritingMode();
   LogicalMargin borderPadding = aReflowState.ComputedLogicalBorderPadding();
   nscoord startEdge = borderPadding.IStart(frameWM);
   nscoord endEdge = aReflowState.AvailableISize() - borderPadding.IEnd(frameWM);
   aReflowState.mLineLayout->BeginSpan(this, &aReflowState,
@@ -489,17 +488,17 @@ nsRubyBaseContainerFrame::Reflow(nsPresC
     if (!textContainer->IsSpanContainer()) {
       rtcISize = isize;
     } else if (isize > rtcISize) {
       RubyUtils::SetReservedISize(textContainer, isize - rtcISize);
     }
 
     lineLayout->VerticalAlignLine();
     LogicalSize lineSize(lineWM, rtcISize, lineLayout->GetFinalLineBSize());
-    aReflowState.mRubyReflowState->SetTextContainerInfo(i, textContainer, lineSize);
+    textContainer->SetLineSize(lineSize);
     lineLayout->EndLineReflow();
   }
 
   nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, aReflowState,
                                          borderPadding, lineWM, frameWM);
 }
 
 /**
--- a/layout/generic/nsRubyBaseContainerFrame.h
+++ b/layout/generic/nsRubyBaseContainerFrame.h
@@ -8,17 +8,18 @@
 
 #ifndef nsRubyBaseContainerFrame_h___
 #define nsRubyBaseContainerFrame_h___
 
 #include "nsContainerFrame.h"
 #include "nsRubyTextContainerFrame.h"
 #include "nsRubyBaseFrame.h"
 #include "nsRubyTextFrame.h"
-#include "RubyReflowState.h"
+
+#define RTC_ARRAY_SIZE 1
 
 /**
  * Factory function.
  * @return a newly allocated nsRubyBaseContainerFrame (infallible)
  */
 nsContainerFrame* NS_NewRubyBaseContainerFrame(nsIPresShell* aPresShell,
                                                nsStyleContext* aContext);
 
--- a/layout/generic/nsRubyFrame.cpp
+++ b/layout/generic/nsRubyFrame.cpp
@@ -6,17 +6,16 @@
 
 /* rendering object for CSS "display: ruby" */
 #include "nsRubyFrame.h"
 #include "nsLineLayout.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
 #include "WritingModes.h"
 #include "RubyUtils.h"
-#include "RubyReflowState.h"
 #include "nsRubyBaseContainerFrame.h"
 #include "nsRubyTextContainerFrame.h"
 
 using namespace mozilla;
 
 //----------------------------------------------------------------------
 
 // Frame class boilerplate
@@ -236,21 +235,19 @@ nsRubyFrame::ReflowSegment(nsPresContext
   LogicalSize availSize(lineWM, aReflowState.AvailableISize(),
                         aReflowState.AvailableBSize());
 
   nsAutoTArray<nsRubyTextContainerFrame*, RTC_ARRAY_SIZE> textContainers;
   for (RubyTextContainerIterator iter(aBaseContainer); !iter.AtEnd(); iter.Next()) {
     textContainers.AppendElement(iter.GetTextContainer());
   }
   const uint32_t rtcCount = textContainers.Length();
-  RubyReflowState rubyReflowState(lineWM, textContainers);
 
   nsHTMLReflowMetrics baseMetrics(aReflowState);
   bool pushedFrame;
-  aReflowState.mLineLayout->SetRubyReflowState(&rubyReflowState);
   aReflowState.mLineLayout->ReflowFrame(aBaseContainer, aStatus,
                                         &baseMetrics, pushedFrame);
 
   if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) {
     if (aBaseContainer != mFrames.FirstChild()) {
       // Some segments may have been reflowed before, hence it is not
       // a break-before for the ruby container.
       aStatus = NS_INLINE_LINE_BREAK_AFTER(NS_FRAME_NOT_COMPLETE);
@@ -325,23 +322,20 @@ nsRubyFrame::ReflowSegment(nsPresContext
   // lines, so we use 0 instead. (i.e. we assume that the base container
   // is adjacent to the ruby frame's block-start edge.)
   // XXX We may need to add border/padding here. See bug 1055667.
   (lineWM.IsVertical() ? baseRect.x : baseRect.y) = 0;
   // The rect for offsets of text containers.
   nsRect offsetRect = baseRect;
   for (uint32_t i = 0; i < rtcCount; i++) {
     nsRubyTextContainerFrame* textContainer = textContainers[i];
-    rubyReflowState.AdvanceCurrentContainerIndex();
-
     nsReflowStatus textReflowStatus;
     nsHTMLReflowMetrics textMetrics(aReflowState);
     nsHTMLReflowState textReflowState(aPresContext, aReflowState,
                                       textContainer, availSize);
-    textReflowState.mRubyReflowState = &rubyReflowState;
     // FIXME We probably shouldn't be using the same nsLineLayout for
     //       the text containers. But it should be fine now as we are
     //       not actually using this line layout to reflow something,
     //       but just read the writing mode from it.
     textReflowState.mLineLayout = aReflowState.mLineLayout;
     textContainer->Reflow(aPresContext, textMetrics,
                           textReflowState, textReflowStatus);
     // Ruby text containers always return NS_FRAME_COMPLETE even when
--- a/layout/generic/nsRubyTextContainerFrame.cpp
+++ b/layout/generic/nsRubyTextContainerFrame.cpp
@@ -5,17 +5,16 @@
  * http://mozilla.org/MPL/2.0/. */
 
 /* rendering object for CSS "display: ruby-text-container" */
 
 #include "nsRubyTextContainerFrame.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
 #include "WritingModes.h"
-#include "RubyReflowState.h"
 #include "mozilla/UniquePtr.h"
 
 using namespace mozilla;
 
 //----------------------------------------------------------------------
 
 // Frame class boilerplate
 // =======================
@@ -120,24 +119,28 @@ nsRubyTextContainerFrame::UpdateSpanFlag
 nsRubyTextContainerFrame::Reflow(nsPresContext* aPresContext,
                                  nsHTMLReflowMetrics& aDesiredSize,
                                  const nsHTMLReflowState& aReflowState,
                                  nsReflowStatus& aStatus)
 {
   DO_GLOBAL_REFLOW_COUNT("nsRubyTextContainerFrame");
   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
 
-  MOZ_ASSERT(aReflowState.mRubyReflowState, "No ruby reflow state provided");
-
-  // All rt children have already been reflowed. All we need to do is
-  // to report complete and return the desired size provided by the
-  // ruby base container.
-
   // Although a ruby text container may have continuations, returning
   // NS_FRAME_COMPLETE here is still safe, since its parent, ruby frame,
   // ignores the status, and continuations of the ruby base container
   // will take care of our continuations.
   aStatus = NS_FRAME_COMPLETE;
   WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
-  const RubyReflowState::TextContainerInfo& info =
-    aReflowState.mRubyReflowState->GetCurrentTextContainerInfo(this);
-  aDesiredSize.SetSize(lineWM, info.mLineSize);
+  aDesiredSize.SetSize(lineWM, mLineSize);
+
+  if (lineWM.IsVerticalRL()) {
+    nscoord deltaWidth = -mLineSize.Width(lineWM);
+    LogicalPoint translation(lineWM, 0, deltaWidth);
+
+    for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
+      nsIFrame* child = e.get();
+      MOZ_ASSERT(child->GetType() == nsGkAtoms::rubyTextFrame);
+      child->MovePositionBy(lineWM, translation);
+      nsContainerFrame::PlaceFrameView(child);
+    }
+  }
 }
--- a/layout/generic/nsRubyTextContainerFrame.h
+++ b/layout/generic/nsRubyTextContainerFrame.h
@@ -57,17 +57,23 @@ public:
     return GetStateBits() & NS_RUBY_TEXT_CONTAINER_IS_SPAN;
   }
 
 protected:
   friend nsContainerFrame*
     NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell,
                                  nsStyleContext* aContext);
   explicit nsRubyTextContainerFrame(nsStyleContext* aContext)
-    : nsRubyTextContainerFrameSuper(aContext) {}
+    : nsRubyTextContainerFrameSuper(aContext)
+    , mLineSize(mozilla::WritingMode(aContext)) {}
 
   void UpdateSpanFlag();
 
-  // For MoveOverflowToChildList
   friend class nsRubyBaseContainerFrame;
+  void SetLineSize(const mozilla::LogicalSize& aSize) { mLineSize = aSize; }
+
+  // The intended dimensions of the ruby text container. It is set by
+  // the corresponding ruby base container when the segment is reflowed,
+  // and used when the ruby text container is reflowed by its parent.
+  mozilla::LogicalSize mLineSize;
 };
 
 #endif /* nsRubyTextContainerFrame_h___ */
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -195,23 +195,30 @@ static void DestroyGlyphObserverList(voi
 /**
  * This property is set on text frames with TEXT_IN_TEXTRUN_USER_DATA set that
  * have potentially-animated glyphs.
  * The only reason this list is in a property is to automatically destroy the
  * list when the frame is deleted, unregistering the observers.
  */
 NS_DECLARE_FRAME_PROPERTY(TextFrameGlyphObservers, DestroyGlyphObserverList);
 
-#define TEXT_REFLOW_FLAGS    \
-  (TEXT_FIRST_LETTER|TEXT_START_OF_LINE|TEXT_END_OF_LINE|TEXT_HYPHEN_BREAK| \
-   TEXT_TRIMMED_TRAILING_WHITESPACE|TEXT_JUSTIFICATION_ENABLED| \
-   TEXT_HAS_NONCOLLAPSED_CHARACTERS|TEXT_SELECTION_UNDERLINE_OVERFLOWED)
-
-#define TEXT_WHITESPACE_FLAGS      (TEXT_IS_ONLY_WHITESPACE | \
-                                    TEXT_ISNOT_ONLY_WHITESPACE)
+static const nsFrameState TEXT_REFLOW_FLAGS =
+   TEXT_FIRST_LETTER |
+   TEXT_START_OF_LINE |
+   TEXT_END_OF_LINE |
+   TEXT_HYPHEN_BREAK |
+   TEXT_TRIMMED_TRAILING_WHITESPACE |
+   TEXT_JUSTIFICATION_ENABLED |
+   TEXT_HAS_NONCOLLAPSED_CHARACTERS |
+   TEXT_SELECTION_UNDERLINE_OVERFLOWED |
+   TEXT_NO_RENDERED_GLYPHS;
+
+static const nsFrameState TEXT_WHITESPACE_FLAGS =
+    TEXT_IS_ONLY_WHITESPACE |
+    TEXT_ISNOT_ONLY_WHITESPACE;
 
 /*
  * Some general notes
  * 
  * Text frames delegate work to gfxTextRun objects. The gfxTextRun object
  * transforms text to positioned glyphs. It can report the geometry of the
  * glyphs and paint them. Text frames configure gfxTextRuns by providing text,
  * spacing, language, and other information.
@@ -2737,16 +2744,18 @@ static bool IsJustifiableCharacter(const
 }
 
 void
 nsTextFrame::ClearMetrics(nsHTMLReflowMetrics& aMetrics)
 {
   aMetrics.ClearSize();
   aMetrics.SetBlockStartAscent(0);
   mAscent = 0;
+
+  AddStateBits(TEXT_NO_RENDERED_GLYPHS);
 }
 
 static int32_t FindChar(const nsTextFragment* frag,
                         int32_t aOffset, int32_t aLength, char16_t ch)
 {
   int32_t i = 0;
   if (frag->Is2b()) {
     const char16_t* str = frag->Get2b() + aOffset;
@@ -4645,18 +4654,19 @@ nsTextFrame::BuildDisplayList(nsDisplayL
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists)
 {
   if (!IsVisibleForPainting(aBuilder))
     return;
   
   DO_GLOBAL_REFLOW_COUNT_DSP("nsTextFrame");
 
-  if (NS_GET_A(StyleColor()->mColor) == 0 &&
-      !IsSVGText() && !IsSelected() && !StyleText()->HasTextShadow()) {
+  if (((GetStateBits() & TEXT_NO_RENDERED_GLYPHS) ||
+       (NS_GET_A(StyleColor()->mColor) == 0 && !StyleText()->HasTextShadow())) &&
+      aBuilder->IsForPainting() && !IsSVGText() && !IsSelected()) {
     TextDecorations textDecs;
     GetTextDecorations(PresContext(), eResolvedColors, textDecs);
     if (!textDecs.HasDecorationLines()) {
       return;
     }
   }
 
   aLists.Content()->AppendNewToTop(
@@ -5690,46 +5700,32 @@ nsTextFrame::PaintTextWithSelectionColor
     gfxPoint textBaselinePt = vertical ?
       gfxPoint(aTextBaselinePt.x, aFramePt.y + iOffset) :
       gfxPoint(aFramePt.x + iOffset, aTextBaselinePt.y);
 
     // Determine what shadow, if any, to draw - either from textStyle
     // or from the ::-moz-selection pseudo-class if specified there
     nsCSSShadowArray* shadow = textStyle->GetTextShadow();
     GetSelectionTextShadow(this, type, aTextPaintStyle, &shadow);
-
-    // Draw shadows, if any
     if (shadow) {
-      gfxTextRun::Metrics shadowMetrics =
-        mTextRun->MeasureText(offset, length, gfxFont::LOOSE_INK_EXTENTS,
-                              nullptr, &aProvider);
-      if (GetStateBits() & TEXT_HYPHEN_BREAK) {
-        AddHyphenToMetrics(this, mTextRun, &shadowMetrics,
-                           gfxFont::LOOSE_INK_EXTENTS, aCtx);
+      nscoord leftEdge =  iOffset;
+      if (mTextRun->IsRightToLeft()) {
+        leftEdge -= mTextRun->GetAdvanceWidth(offset, length, &aProvider) +
+            hyphenWidth;
       }
-      for (uint32_t i = shadow->Length(); i > 0; --i) {
-        PaintOneShadow(offset, length,
-                       shadow->ShadowAt(i - 1), &aProvider,
-                       dirtyRect, aFramePt, textBaselinePt, aCtx,
-                       foreground, aClipEdges, 
-                       iOffset - (mTextRun->IsRightToLeft() ?
-                                  shadowMetrics.mBoundingBox.width : 0),
-                       shadowMetrics.mBoundingBox);
-      }
+      PaintShadows(shadow, offset, length, dirtyRect, aFramePt, textBaselinePt,
+          leftEdge, aProvider, foreground, aClipEdges, aCtx);
     }
 
     // Draw text segment
     gfxFloat advance;
-
     DrawText(aCtx, aDirtyRect, aFramePt, textBaselinePt,
              offset, length, aProvider, aTextPaintStyle, foreground, aClipEdges,
              advance, hyphenWidth > 0, nullptr, nullptr, aCallbacks);
-    if (hyphenWidth) {
-      advance += hyphenWidth;
-    }
+    advance += hyphenWidth;
     iterator.UpdateWithAdvance(advance);
   }
   return true;
 }
 
 void
 nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
     const gfxPoint& aFramePt,
@@ -6036,16 +6032,54 @@ nsTextFrame::MeasureCharClippedText(Prop
     nscoord* snappedEndEdge = rtl ? aSnappedLeftEdge : aSnappedRightEdge;
     *snappedEndEdge = NSToCoordFloor(gfxFloat(frameWidth) - advanceWidth);
   }
   *aMaxLength = maxLength;
   return maxLength != 0;
 }
 
 void
+nsTextFrame::PaintShadows(nsCSSShadowArray* aShadow,
+                          uint32_t aOffset, uint32_t aLength,
+                          const nsRect& aDirtyRect,
+                          const gfxPoint& aFramePt,
+                          const gfxPoint& aTextBaselinePt,
+                          nscoord aLeftEdgeOffset,
+                          PropertyProvider& aProvider,
+                          nscolor aForegroundColor,
+                          const nsCharClipDisplayItem::ClipEdges& aClipEdges,
+                          gfxContext* aCtx)
+{
+  if (!aShadow) {
+    return;
+  }
+
+  gfxTextRun::Metrics shadowMetrics =
+    mTextRun->MeasureText(aOffset, aLength, gfxFont::LOOSE_INK_EXTENTS,
+                          nullptr, &aProvider);
+  if (GetStateBits() & TEXT_HYPHEN_BREAK) {
+    AddHyphenToMetrics(this, mTextRun, &shadowMetrics,
+                       gfxFont::LOOSE_INK_EXTENTS, aCtx);
+  }
+  // Add bounds of text decorations
+  gfxRect decorationRect(0, -shadowMetrics.mAscent,
+      shadowMetrics.mAdvanceWidth, shadowMetrics.mAscent + shadowMetrics.mDescent);
+  shadowMetrics.mBoundingBox.UnionRect(shadowMetrics.mBoundingBox,
+                                       decorationRect);
+  for (uint32_t i = aShadow->Length(); i > 0; --i) {
+    PaintOneShadow(aOffset, aLength,
+                   aShadow->ShadowAt(i - 1), &aProvider,
+                   aDirtyRect, aFramePt, aTextBaselinePt, aCtx,
+                   aForegroundColor, aClipEdges,
+                   aLeftEdgeOffset,
+                   shadowMetrics.mBoundingBox);
+  }
+}
+
+void
 nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
                        const nsRect& aDirtyRect,
                        const nsCharClipDisplayItem& aItem,
                        gfxTextContextPaint* aContextPaint,
                        nsTextFrame::DrawPathCallbacks* aCallbacks)
 {
   // Don't pass in aRenderingContext here, because we need a *reference*
   // context and aRenderingContext might have some transform in it
@@ -6104,30 +6138,19 @@ nsTextFrame::PaintText(nsRenderingContex
                                aCallbacks)) {
       return;
     }
   }
 
   nscolor foregroundColor = textPaintStyle.GetTextColor();
   if (!aCallbacks) {
     const nsStyleText* textStyle = StyleText();
-    if (textStyle->HasTextShadow()) {
-      // Text shadow happens with the last value being painted at the back,
-      // ie. it is painted first.
-      gfxTextRun::Metrics shadowMetrics = 
-        mTextRun->MeasureText(startOffset, maxLength, gfxFont::LOOSE_INK_EXTENTS,
-                              nullptr, &provider);
-      for (uint32_t i = textStyle->mTextShadow->Length(); i > 0; --i) {
-        PaintOneShadow(startOffset, maxLength,
-                       textStyle->mTextShadow->ShadowAt(i - 1), &provider,
-                       aDirtyRect, framePt, textBaselinePt, ctx,
-                       foregroundColor, clipEdges,
-                       snappedLeftEdge, shadowMetrics.mBoundingBox);
-      }
-    }
+    PaintShadows(textStyle->mTextShadow, startOffset, maxLength,
+        aDirtyRect, framePt, textBaselinePt, snappedLeftEdge, provider,
+        foregroundColor, clipEdges, ctx);
   }
 
   gfxFloat advanceWidth;
   DrawText(ctx, dirtyRect, framePt, textBaselinePt, startOffset, maxLength, provider,
            textPaintStyle, foregroundColor, clipEdges, advanceWidth,
            (GetStateBits() & TEXT_HYPHEN_BREAK) != 0,
            nullptr, aContextPaint, aCallbacks);
 }
@@ -8239,17 +8262,17 @@ nsTextFrame::ReflowText(nsLineLayout& aL
     transformedLength = iter.GetSkippedOffset() - transformedOffset;
   }
   uint32_t transformedLastBreak = 0;
   bool usedHyphenation;
   gfxFloat trimmedWidth = 0;
   gfxFloat availWidth = aAvailableWidth;
   bool canTrimTrailingWhitespace = !textStyle->WhiteSpaceIsSignificant() ||
                                    (GetStateBits() & TEXT_IS_IN_TOKEN_MATHML);
-  int32_t unusedOffset;  
+  int32_t unusedOffset;
   gfxBreakPriority breakPriority;
   aLineLayout.GetLastOptionalBreakPosition(&unusedOffset, &breakPriority);
   gfxTextRun::SuppressBreak suppressBreak = gfxTextRun::eNoSuppressBreak;
   if (StyleContext()->IsInlineDescendantOfRuby()) {
     suppressBreak = gfxTextRun::eSuppressAllBreaks;
   } else if (!aLineLayout.LineIsBreakable()) {
     suppressBreak = gfxTextRun::eSuppressInitialBreak;
   }
@@ -8303,16 +8326,19 @@ nsTextFrame::ReflowText(nsLineLayout& aL
       usedHyphenation = true;
     }
   }
   if (usedHyphenation) {
     // Fix up metrics to include hyphen
     AddHyphenToMetrics(this, mTextRun, &textMetrics, boundingBoxType, ctx);
     AddStateBits(TEXT_HYPHEN_BREAK | TEXT_HAS_NONCOLLAPSED_CHARACTERS);
   }
+  if (textMetrics.mBoundingBox.IsEmpty()) {
+    AddStateBits(TEXT_NO_RENDERED_GLYPHS);
+  }
 
   gfxFloat trimmableWidth = 0;
   bool brokeText = forceBreak >= 0 || transformedCharsFit < transformedLength;
   if (canTrimTrailingWhitespace) {
     // Optimization: if we trimmed trailing whitespace, and we can be sure
     // this frame will be at the end of the line, then leave it trimmed off.
     // Otherwise we have to undo the trimming, in case we're not at the end of
     // the line. (If we actually do end up at the end of the line, we'll have
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -579,16 +579,27 @@ protected:
                       const gfxPoint& aFramePt,
                       const gfxPoint& aTextBaselinePt,
                       gfxContext* aCtx,
                       const nscolor& aForegroundColor,
                       const nsCharClipDisplayItem::ClipEdges& aClipEdges,
                       nscoord aLeftSideOffset,
                       gfxRect& aBoundingBox);
 
+  void PaintShadows(nsCSSShadowArray* aShadow,
+                    uint32_t aOffset, uint32_t aLength,
+                    const nsRect& aDirtyRect,
+                    const gfxPoint& aFramePt,
+                    const gfxPoint& aTextBaselinePt,
+                    nscoord aLeftEdgeOffset,
+                    PropertyProvider& aProvider,
+                    nscolor aForegroundColor,
+                    const nsCharClipDisplayItem::ClipEdges& aClipEdges,
+                    gfxContext* aCtx);
+
   struct LineDecoration {
     nsIFrame* mFrame;
 
     // This is represents the offset from our baseline to mFrame's baseline;
     // positive offsets are *above* the baseline and negative offsets below
     nscoord mBaselineOffset;
 
     nscolor mColor;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ruby/nested-ruby-1.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>Bug 1120313 - Nested ruby inside ruby annotation</title>
+  <link rel="stylesheet" href="common.css">
+</head>
+<body>
+  <ruby>
+    <rb>base1</rb>
+    <rt>
+      <ruby>
+        <rb>base2</rb>
+        <rt>text</rt>
+      </ruby>
+    </rt>
+  </ruby>
+</body>
+</html>
--- a/layout/reftests/css-ruby/reftest.list
+++ b/layout/reftests/css-ruby/reftest.list
@@ -22,17 +22,20 @@ fuzzy-if(winWidget,35,1) == dynamic-remo
 == inlinize-blocks-5.html inlinize-blocks-5-ref.html
 == intra-level-whitespace-1.html intra-level-whitespace-1-ref.html
 == intra-level-whitespace-2.html intra-level-whitespace-2-ref.html
 == intra-level-whitespace-3.html intra-level-whitespace-3-ref.html
 == justification-1.html justification-1-ref.html
 == justification-2.html justification-2-ref.html
 == line-height-1.html line-height-1-ref.html
 == line-height-2.html line-height-2-ref.html
+load nested-ruby-1.html
 == line-height-3.html line-height-3-ref.html
+fails-if(cocoaWidget) == relative-positioning-1.html relative-positioning-1-ref.html # bug 1120280
+== relative-positioning-2.html relative-positioning-2-ref.html
 == ruby-span-1.html ruby-span-1-ref.html
 == ruby-whitespace-1.html ruby-whitespace-1-ref.html
 == ruby-whitespace-2.html ruby-whitespace-2-ref.html
 == ruby-position-horizontal.html ruby-position-horizontal-ref.html
 pref(layout.css.vertical-text.enabled,true) fails == ruby-position-vertical-lr.html ruby-position-vertical-lr-ref.html # bug 1112474
 pref(layout.css.vertical-text.enabled,true) fails == ruby-position-vertical-rl.html ruby-position-vertical-rl-ref.html # bug 1112474
 != ruby-reflow-1-opaqueruby.html ruby-reflow-1-noruby.html
 == ruby-reflow-1-transparentruby.html ruby-reflow-1-noruby.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ruby/relative-positioning-1-ref.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>Bug 1055658 - Relative positioning for ruby</title>
+  <style>
+    .wrapper {
+      width: 50px;
+      text-align: center;
+    }
+    .annotation, .annotation > div {
+      position: absolute;
+      line-height: 1;
+    }
+  </style>
+</head>
+<body>
+  <div style="height: 80px; line-height: 80px;">
+    <div class="wrapper" style="display: inline-block; line-height: normal; position: relative;">
+      <div class="annotation" style="top: 0;">
+        <div class="wrapper" style="top: -100%;">a<span style="position: relative; top: -10px;">b</span>c</div>
+        &nbsp; <!-- to give container a nonzero size for
+                    percent values to resolve against -->
+      </div>
+      base
+    </div>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ruby/relative-positioning-1.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>Bug 1055658 - Relative positioning for ruby</title>
+  <link rel="stylesheet" href="common.css">
+  <style>
+    body {
+      line-height: 80px;
+    }
+    rtc, rt {
+      font-size: 100% !important;
+      line-height: 1 !important;
+    }
+  </style>
+</head>
+<body>
+  <ruby style="position: relative;">
+    <rb>base</rb>
+    <rtc><rt>a<span style="position: relative; top: -10px;">b</span>c</rt></rtc>
+    <rtc><div style="width: 50px; height: 0;"></div></rtc>
+  </ruby>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ruby/relative-positioning-2-ref.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>Bug 1055658 - Relative positioning for ruby</title>
+  <style>
+    body {
+      font-family: monospace;
+    }
+    .annotation, .annotation > div {
+      position: absolute;
+      line-height: 1;
+    }
+  </style>
+</head>
+<body>
+  <div style="height: 80px; line-height: 80px;">
+    before
+    <div style="display: inline-block; line-height: normal; position: relative; top: 20px;">
+      <div class="annotation" style="top: 0; width: 100%;">
+        <div style="top: -100%;">
+          text1
+          <span style="position: relative; top: -20px;">text2</span>
+          <span style="position: relative; right: 10px;">text3</span>
+        </div>
+        &nbsp; <!-- to give container a nonzero size for
+                    percent values to resolve against -->
+      </div>
+      base1
+      <span style="position: relative; left: 10px;">base2</span>
+      <span style="position: relative; bottom: -20px;">base3</span>
+    </div>
+    after
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ruby/relative-positioning-2.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>Bug 1055658 - Relative positioning for ruby</title>
+  <link rel="stylesheet" href="common.css">
+  <style>
+    body {
+      font-family: monospace;
+      line-height: 80px;
+    }
+    rtc, rt {
+      font-size: 100% !important;
+      line-height: 1 !important;
+    }
+  </style>
+</head>
+<body>
+  before
+  <ruby style="position: relative; top: 20px;">
+    <rb>base1</rb>
+    <rtc>text1</rtc>
+    <rb style="position: relative; left: 10px;">base2</rb>
+    <rtc style="position: relative; top: -20px;">text2</rtc>
+    <rbc style="position: relative; bottom: -20px;"><rb>base3</rb></rbc>
+    <rtc><rt style="position: relative; right: 10px;">text3</rt></rtc>
+  </ruby>
+  after
+</body>
+</html>
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -903,16 +903,20 @@ TextRenderedRun::GetRunUserSpaceRect(nsP
   if (length == 0) {
     return r;
   }
 
   // Measure that range.
   gfxTextRun::Metrics metrics =
     textRun->MeasureText(offset, length, gfxFont::LOOSE_INK_EXTENTS,
                          nullptr, nullptr);
+  // Make sure it includes the font-box.
+  gfxRect fontBox(0, -metrics.mAscent,
+      metrics.mAdvanceWidth, metrics.mAscent + metrics.mDescent);
+  metrics.mBoundingBox.UnionRect(metrics.mBoundingBox, fontBox);
 
   // Determine the rectangle that covers the rendered run's fill,
   // taking into account the measured vertical overflow due to
   // decorations.
   nscoord baseline = metrics.mBoundingBox.y + metrics.mAscent;
   gfxFloat x, width;
   if (aFlags & eNoHorizontalOverflow) {
     x = 0.0;
--- a/mfbt/Char16.h
+++ b/mfbt/Char16.h
@@ -12,24 +12,25 @@
 #ifdef __cplusplus
 
 /*
  * C++11 introduces a char16_t type and support for UTF-16 string and character
  * literals. C++11's char16_t is a distinct builtin type. Technically, char16_t
  * is a 16-bit code unit of a Unicode code point, not a "character".
  */
 
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && _MSC_VER < 1900
    /*
     * C++11 says char16_t is a distinct builtin type, but Windows's yvals.h
-    * typedefs char16_t as an unsigned short. We would like to alias char16_t
-    * to Windows's 16-bit wchar_t so we can declare UTF-16 literals as constant
-    * expressions (and pass char16_t pointers to Windows APIs). We #define
-    * _CHAR16T here in order to prevent yvals.h from overriding our char16_t
-    * typedefs, which we set to wchar_t for C++ code.
+    * typedefs char16_t as an unsigned short prior to MSVC 2015, which
+    * implemented C++11's distinct char16_t type). We would like to alias
+    * char16_t to Windows's 16-bit wchar_t so we can declare UTF-16 literals as
+    * constant expressions (and pass char16_t pointers to Windows APIs). We
+    * #define _CHAR16T here in order to prevent yvals.h from overriding our
+    * char16_t typedefs, which we set to wchar_t for C++ code.
     *
     * In addition, #defining _CHAR16T will prevent yvals.h from defining a
     * char32_t type, so we have to undo that damage here and provide our own,
     * which is identical to the yvals.h type.
     */
 #  define MOZ_UTF16_HELPER(s) L##s
 #  define _CHAR16T
 typedef wchar_t char16_t;
@@ -46,23 +47,24 @@ typedef unsigned int char32_t;
 #    define MOZ_USE_CHAR16_WRAPPER
 #  endif
 #endif
 
 #ifdef MOZ_USE_CHAR16_WRAPPER
 # include <string>
   /**
    * Win32 API extensively uses wchar_t, which is represented by a separated
-   * builtin type than char16_t per spec. It's not the case for MSVC, but GCC
-   * follows the spec. We want to mix wchar_t and char16_t on Windows builds.
-   * This class is supposed to make it easier. It stores char16_t const pointer,
-   * but provides implicit casts for wchar_t as well. On other platforms, we
-   * simply use |typedef const char16_t* char16ptr_t|. Here, we want to make
-   * the class as similar to this typedef, including providing some casts that
-   * are allowed by the typedef.
+   * builtin type than char16_t per spec. It's not the case for MSVC prior to
+   * MSVC 2015, but other compilers follow the spec. We want to mix wchar_t and
+   * char16_t on Windows builds. This class is supposed to make it easier. It
+   * stores char16_t const pointer, but provides implicit casts for wchar_t as
+   * well. On other platforms, we simply use
+   * |typedef const char16_t* char16ptr_t|. Here, we want to make the class as
+   * similar to this typedef, including providing some casts that are allowed
+   * by the typedef.
    */
 class char16ptr_t
 {
 private:
   const char16_t* mPtr;
   static_assert(sizeof(char16_t) == sizeof(wchar_t),
                 "char16_t and wchar_t sizes differ");
 
--- a/mfbt/HashFunctions.h
+++ b/mfbt/HashFunctions.h
@@ -182,84 +182,35 @@ AddToHash(uint32_t aHash, A* aA)
 
 template<>
 MOZ_WARN_UNUSED_RESULT inline uint32_t
 AddToHash(uint32_t aHash, uintptr_t aA)
 {
   return detail::AddUintptrToHash<sizeof(uintptr_t)>(aHash, aA);
 }
 
-template<typename A, typename B>
+template<typename A, typename... Args>
 MOZ_WARN_UNUSED_RESULT uint32_t
-AddToHash(uint32_t aHash, A aA, B aB)
-{
-  return AddToHash(AddToHash(aHash, aA), aB);
-}
-
-template<typename A, typename B, typename C>
-MOZ_WARN_UNUSED_RESULT uint32_t
-AddToHash(uint32_t aHash, A aA, B aB, C aC)
+AddToHash(uint32_t aHash, A aArg, Args... aArgs)
 {
-  return AddToHash(AddToHash(aHash, aA, aB), aC);
-}
-
-template<typename A, typename B, typename C, typename D>
-MOZ_WARN_UNUSED_RESULT uint32_t
-AddToHash(uint32_t aHash, A aA, B aB, C aC, D aD)
-{
-  return AddToHash(AddToHash(aHash, aA, aB, aC), aD);
-}
-
-template<typename A, typename B, typename C, typename D, typename E>
-MOZ_WARN_UNUSED_RESULT uint32_t
-AddToHash(uint32_t aHash, A aA, B aB, C aC, D aD, E aE)
-{
-  return AddToHash(AddToHash(aHash, aA, aB, aC, aD), aE);
+  return AddToHash(AddToHash(aHash, aArg), aArgs...);
 }
 
 /**
  * The HashGeneric class of functions let you hash one or more values.
  *
  * If you want to hash together two values x and y, calling HashGeneric(x, y) is
  * much better than calling AddToHash(x, y), because AddToHash(x, y) assumes
  * that x has already been hashed.
  */
-template<typename A>
-MOZ_WARN_UNUSED_RESULT inline uint32_t
-HashGeneric(A aA)
-{
-  return AddToHash(0, aA);
-}
-
-template<typename A, typename B>
-MOZ_WARN_UNUSED_RESULT inline uint32_t
-HashGeneric(A aA, B aB)
-{
-  return AddToHash(0, aA, aB);
-}
-
-template<typename A, typename B, typename C>
+template<typename... Args>
 MOZ_WARN_UNUSED_RESULT inline uint32_t
-HashGeneric(A aA, B aB, C aC)
-{
-  return AddToHash(0, aA, aB, aC);
-}
-
-template<typename A, typename B, typename C, typename D>
-MOZ_WARN_UNUSED_RESULT inline uint32_t
-HashGeneric(A aA, B aB, C aC, D aD)
+HashGeneric(Args... aArgs)
 {
-  return AddToHash(0, aA, aB, aC, aD);
-}
-
-template<typename A, typename B, typename C, typename D, typename E>
-MOZ_WARN_UNUSED_RESULT inline uint32_t
-HashGeneric(A aA, B aB, C aC, D aD, E aE)
-{
-  return AddToHash(0, aA, aB, aC, aD, aE);
+  return AddToHash(0, aArgs...);
 }
 
 namespace detail {
 
 template<typename T>
 uint32_t
 HashUntilZero(const T* aStr)
 {
--- a/mfbt/Maybe.h
+++ b/mfbt/Maybe.h
@@ -322,93 +322,53 @@ public:
   const T& operator*() const
   {
     MOZ_ASSERT(mIsSome);
     return ref();
   }
 
   /* If |isSome()|, runs the provided function or functor on the contents of
    * this Maybe. */
-  template<typename F>
-  void apply(F&& aFunc)
+  template<typename F, typename... Args>
+  void apply(F&& aFunc, Args&&... aArgs)
   {
     if (isSome()) {
-      aFunc(ref());
+      aFunc(ref(), Forward<Args>(aArgs)...);
     }
   }
 
-  template<typename F>
-  void apply(F&& aFunc) const
+  template<typename F, typename... Args>
+  void apply(F&& aFunc, Args&&... aArgs) const
   {
     if (isSome()) {
-      aFunc(ref());
-    }
-  }
-
-  /* Variant of |apply()| that takes an additional argument for the function. */
-  template<typename F, typename A>
-  void apply(F&& aFunc, A&& aArg)
-  {
-    if (isSome()) {
-      aFunc(ref(), Forward<A>(aArg));
-    }
-  }
-
-  template<typename F, typename A>
-  void apply(F&& aFunc, A&& aArg) const
-  {
-    if (isSome()) {
-      aFunc(ref(), Forward<A>(aArg));
+      aFunc(ref(), Forward<Args>(aArgs)...);
     }
   }
 
   /*
    * If |isSome()|, runs the provided function and returns the result wrapped
    * in a Maybe. If |isNothing()|, returns an empty Maybe value.
    */
-  template<typename R>
-  Maybe<R> map(R(*aFunc)(T&))
+  template<typename R, typename... FArgs, typename... Args>
+  Maybe<R> map(R (*aFunc)(T&, FArgs...), Args&&... aArgs)
   {
     if (isSome()) {
       Maybe<R> val;
-      val.emplace(aFunc(ref()));
+      val.emplace(aFunc(ref(), Forward<Args>(aArgs)...));
       return val;
     }
     return Maybe<R>();
   }
 
-  template<typename R>
-  Maybe<R> map(R(*aFunc)(const T&)) const
+  template<typename R, typename... FArgs, typename... Args>
+  Maybe<R> map(R (*aFunc)(const T&, FArgs...), Args&&... aArgs) const
   {
     if (isSome()) {
       Maybe<R> val;
-      val.emplace(aFunc(ref()));
-      return val;
-    }
-    return Maybe<R>();
-  }
-
-  /* Variant of |map()| that takes an additional argument for the function. */
-  template<typename R, typename FA, typename A>
-  Maybe<R> map(R(*aFunc)(T&, FA), A&& aArg)
-  {
-    if (isSome()) {
-      Maybe<R> val;
-      val.emplace(aFunc(ref(), Forward<A>(aArg)));
-      return val;
-    }
-    return Maybe<R>();
-  }
-
-  template<typename R, typename FA, typename A>
-  Maybe<R> map(R(*aFunc)(const T&, FA), A&& aArg) const
-  {
-    if (isSome()) {
-      Maybe<R> val;
-      val.emplace(aFunc(ref(), Forward<A>(aArg)));
+      val.emplace(aFunc(ref(), Forward<Args>(aArgs)...));
       return val;
     }
     return Maybe<R>();
   }
 
   /* If |isSome()|, empties this Maybe and destroys its contents. */
   void reset()
   {
@@ -416,125 +376,22 @@ public:
       ref().~T();
       mIsSome = false;
     }
   }
 
   /*
    * Constructs a T value in-place in this empty Maybe<T>'s storage. The
    * arguments to |emplace()| are the parameters to T's constructor.
-   *
-   * WARNING: You can't pass a literal nullptr to these methods without
-   * hitting GCC 4.4-only (and hence B2G-only) compile errors.
    */
-  void emplace()
-  {
-    MOZ_ASSERT(!mIsSome);
-    ::new (mStorage.addr()) T();
-    mIsSome = true;
-  }
-
-  template<typename T1>
-  void emplace(T1&& t1)
-  {
-    MOZ_ASSERT(!mIsSome);
-    ::new (mStorage.addr()) T(Forward<T1>(t1));
-    mIsSome = true;
-  }
-
-  template<typename T1, typename T2>
-  void emplace(T1&& t1, T2&& t2)
-  {
-    MOZ_ASSERT(!mIsSome);
-    ::new (mStorage.addr()) T(Forward<T1>(t1), Forward<T2>(t2));
-    mIsSome = true;
-  }
-
-  template<typename T1, typename T2, typename T3>
-  void emplace(T1&& t1, T2&& t2, T3&& t3)
-  {
-    MOZ_ASSERT(!mIsSome);
-    ::new (mStorage.addr()) T(Forward<T1>(t1), Forward<T2>(t2), Forward<T3>(t3));
-    mIsSome = true;
-  }
-
-  template<typename T1, typename T2, typename T3, typename T4>
-  void emplace(T1&& t1, T2&& t2, T3&& t3, T4&& t4)
-  {
-    MOZ_ASSERT(!mIsSome);
-    ::new (mStorage.addr()) T(Forward<T1>(t1), Forward<T2>(t2), Forward<T3>(t3),
-                              Forward<T4>(t4));
-    mIsSome = true;
-  }
-
-  template<typename T1, typename T2, typename T3, typename T4, typename T5>
-  void emplace(T1&& t1, T2&& t2, T3&& t3, T4&& t4, T5&& t5)
+  template<typename... Args>
+  void emplace(Args&&... aArgs)
   {
     MOZ_ASSERT(!mIsSome);
-    ::new (mStorage.addr()) T(Forward<T1>(t1), Forward<T2>(t2), Forward<T3>(t3),
-                              Forward<T4>(t4), Forward<T5>(t5));
-    mIsSome = true;
-  }
-
-  template<typename T1, typename T2, typename T3, typename T4, typename T5,
-           typename T6>
-  void emplace(T1&& t1, T2&& t2, T3&& t3, T4&& t4, T5&& t5, T6&& t6)
-  {
-    MOZ_ASSERT(!mIsSome);
-    ::new (mStorage.addr()) T(Forward<T1>(t1), Forward<T2>(t2), Forward<T3>(t3),
-                              Forward<T4>(t4), Forward<T5>(t5), Forward<T6>(t6));
-    mIsSome = true;
-  }
-
-  template<typename T1, typename T2, typename T3, typename T4, typename T5,
-           typename T6, typename T7>
-  void emplace(T1&& t1, T2&& t2, T3&& t3, T4&& t4, T5&& t5, T6&& t6,
-               T7&& t7)
-  {
-    MOZ_ASSERT(!mIsSome);
-    ::new (mStorage.addr()) T(Forward<T1>(t1), Forward<T2>(t2), Forward<T3>(t3),
-                              Forward<T4>(t4), Forward<T5>(t5), Forward<T6>(t6),
-                              Forward<T7>(t7));
-    mIsSome = true;
-  }
-
-  template<typename T1, typename T2, typename T3, typename T4, typename T5,
-           typename T6, typename T7, typename T8>
-  void emplace(T1&& t1, T2&& t2, T3&& t3, T4&& t4, T5&& t5, T6&& t6,
-               T7&& t7, T8&& t8)
-  {
-    MOZ_ASSERT(!mIsSome);
-    ::new (mStorage.addr()) T(Forward<T1>(t1), Forward<T2>(t2), Forward<T3>(t3),
-                              Forward<T4>(t4), Forward<T5>(t5), Forward<T6>(t6),
-                              Forward<T7>(t7), Forward<T8>(t8));
-    mIsSome = true;
-  }
-
-  template<typename T1, typename T2, typename T3, typename T4, typename T5,
-           typename T6, typename T7, typename T8, typename T9>
-  void emplace(T1&& t1, T2&& t2, T3&& t3, T4&& t4, T5&& t5, T6&& t6,
-               T7&& t7, T8&& t8, T9&& t9)
-  {
-    MOZ_ASSERT(!mIsSome);
-    ::new (mStorage.addr()) T(Forward<T1>(t1), Forward<T2>(t2), Forward<T3>(t3),
-                              Forward<T4>(t4), Forward<T5>(t5), Forward<T6>(t6),
-                              Forward<T7>(t7), Forward<T8>(t8), Forward<T9>(t9));
-    mIsSome = true;
-  }
-
-  template<typename T1, typename T2, typename T3, typename T4, typename T5,
-           typename T6, typename T7, typename T8, typename T9, typename T10>
-  void emplace(T1&& t1, T2&& t2, T3&& t3, T4&& t4, T5&& t5, T6&& t6,
-               T7&& t7, T8&& t8, T9&& t9, T10&& t10)
-  {
-    MOZ_ASSERT(!mIsSome);
-    ::new (mStorage.addr()) T(Forward<T1>(t1), Forward<T2>(t2), Forward<T3>(t3),
-                              Forward<T4>(t4), Forward<T5>(t5), Forward<T6>(t6),
-                              Forward<T7>(t7), Forward<T8>(t8), Forward<T9>(t9),
-                              Forward<T1>(t10));
+    ::new (mStorage.addr()) T(Forward<Args>(aArgs)...);
     mIsSome = true;
   }
 };
 
 /*
  * Some() creates a Maybe<T> value containing the provided T value. If T has a
  * move constructor, it's used to make this as efficient as possible.
  *
--- a/mfbt/MaybeOneOf.h
+++ b/mfbt/MaybeOneOf.h
@@ -51,46 +51,22 @@ public:
   MaybeOneOf() : state(None) {}
   ~MaybeOneOf() { destroyIfConstructed(); }
 
   bool empty() const { return state == None; }
 
   template <class T>
   bool constructed() const { return state == Type2State<T>::result; }
 
-  template <class T>
-  void construct()
-  {
-    MOZ_ASSERT(state == None);
-    state = Type2State<T>::result;
-    ::new (storage.addr()) T();
-  }
-
-  template <class T, class U>
-  void construct(U&& aU)
+  template <class T, class... Args>
+  void construct(Args&&... aArgs)
   {
     MOZ_ASSERT(state == None);
     state = Type2State<T>::result;
-    ::new (storage.addr()) T(Move(aU));
-  }
-
-  template <class T, class U1>
-  void construct(const U1& aU1)
-  {
-    MOZ_ASSERT(state == None);
-    state = Type2State<T>::result;
-    ::new (storage.addr()) T(aU1);
-  }
-
-  template <class T, class U1, class U2>
-  void construct(const U1& aU1, const U2& aU2)
-  {
-    MOZ_ASSERT(state == None);
-    state = Type2State<T>::result;
-    ::new (storage.addr()) T(aU1, aU2);
+    ::new (storage.addr()) T(Forward<Args>(aArgs)...);
   }
 
   template <class T>
   T& ref()
   {
     return as<T>();
   }
 
--- a/mfbt/UniquePtr.h
+++ b/mfbt/UniquePtr.h
@@ -664,142 +664,30 @@ struct UniqueSelector<T[N]>
 // We don't have variadic template support everywhere, so just hard-code arities
 // 0-8 for now.  If you need more arguments, feel free to add the extra
 // overloads (and deletions for the T = E[N] case).
 //
 // Beware!  Due to lack of true nullptr support in gcc 4.4 and 4.5, passing
 // literal nullptr to MakeUnique will not work on some platforms.  See Move.h
 // for more details.
 
-template<typename T>
-typename detail::UniqueSelector<T>::SingleObject
-MakeUnique()
-{
-  return UniquePtr<T>(new T());
-}
-
-template<typename T, typename A1>
-typename detail::UniqueSelector<T>::SingleObject
-MakeUnique(A1&& aA1)
-{
-  return UniquePtr<T>(new T(Forward<A1>(aA1)));
-}
-
-template<typename T, typename A1, typename A2>
+template<typename T, typename... Args>
 typename detail::UniqueSelector<T>::SingleObject
-MakeUnique(A1&& aA1, A2&& aA2)
-{
-  return UniquePtr<T>(new T(Forward<A1>(aA1), Forward<A2>(aA2)));
-}
-
-template<typename T, typename A1, typename A2, typename A3>
-typename detail::UniqueSelector<T>::SingleObject
-MakeUnique(A1&& aA1, A2&& aA2, A3&& aA3)
-{
-  return UniquePtr<T>(new T(Forward<A1>(aA1), Forward<A2>(aA2),
-                            Forward<A3>(aA3)));
-}
-
-template<typename T, typename A1, typename A2, typename A3, typename A4>
-typename detail::UniqueSelector<T>::SingleObject
-MakeUnique(A1&& aA1, A2&& aA2, A3&& aA3, A4&& aA4)
+MakeUnique(Args&&... aArgs)
 {
-  return UniquePtr<T>(new T(Forward<A1>(aA1), Forward<A2>(aA2),
-                            Forward<A3>(aA3), Forward<A4>(aA4)));
-}
-
-template<typename T, typename A1, typename A2, typename A3, typename A4,
-         typename A5>
-typename detail::UniqueSelector<T>::SingleObject
-MakeUnique(A1&& aA1, A2&& aA2, A3&& aA3, A4&& aA4, A5&& aA5)
-{
-  return UniquePtr<T>(new T(Forward<A1>(aA1), Forward<A2>(aA2),
-                            Forward<A3>(aA3), Forward<A4>(aA4),
-                            Forward<A5>(aA5)));
-}
-
-template<typename T, typename A1, typename A2, typename A3, typename A4,
-         typename A5, typename A6>
-typename detail::UniqueSelector<T>::SingleObject
-MakeUnique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, A6&& a6)
-{
-  return UniquePtr<T>(new T(Forward<A1>(a1), Forward<A2>(a2),
-                            Forward<A3>(a3), Forward<A4>(a4),
-                            Forward<A5>(a5), Forward<A6>(a6)));
-}
-
-template<typename T, typename A1, typename A2, typename A3, typename A4,
-         typename A5, typename A6, typename A7>
-typename detail::UniqueSelector<T>::SingleObject
-MakeUnique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, A6&& a6, A7&& a7)
-{
-  return UniquePtr<T>(new T(Forward<A1>(a1), Forward<A2>(a2),
-                            Forward<A3>(a3), Forward<A4>(a4),
-                            Forward<A5>(a5), Forward<A6>(a6),
-                            Forward<A7>(a7)));
-}
-
-template<typename T, typename A1, typename A2, typename A3, typename A4,
-         typename A5, typename A6, typename A7, typename A8>
-typename detail::UniqueSelector<T>::SingleObject
-MakeUnique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, A6&& a6, A7&& a7,
-           A8&& a8)
-{
-  return UniquePtr<T>(new T(Forward<A1>(a1), Forward<A2>(a2),
-                            Forward<A3>(a3), Forward<A4>(a4),
-                            Forward<A5>(a5), Forward<A6>(a6),
-                            Forward<A7>(a7), Forward<A8>(a8)));
+  return UniquePtr<T>(new T(Forward<Args>(aArgs)...));
 }
 
 template<typename T>
 typename detail::UniqueSelector<T>::UnknownBound
 MakeUnique(decltype(sizeof(int)) aN)
 {
   typedef typename RemoveExtent<T>::Type ArrayType;
   return UniquePtr<T>(new ArrayType[aN]());
 }
 
-template<typename T>
-typename detail::UniqueSelector<T>::KnownBound
-MakeUnique() = delete;
-
-template<typename T, typename A1>
-typename detail::UniqueSelector<T>::KnownBound
-MakeUnique(A1&& aA1) = delete;
-
-template<typename T, typename A1, typename A2>
-typename detail::UniqueSelector<T>::KnownBound
-MakeUnique(A1&& aA1, A2&& aA2) = delete;
-
-template<typename T, typename A1, typename A2, typename A3>
-typename detail::UniqueSelector<T>::KnownBound
-MakeUnique(A1&& aA1, A2&& aA2, A3&& aA3) = delete;
-
-template<typename T, typename A1, typename A2, typename A3, typename A4>
+template<typename T, typename... Args>
 typename detail::UniqueSelector<T>::KnownBound
-MakeUnique(A1&& aA1, A2&& aA2, A3&& aA3, A4&& aA4) = delete;
-
-template<typename T, typename A1, typename A2, typename A3, typename A4,
-         typename A5>
-typename detail::UniqueSelector<T>::KnownBound
-MakeUnique(A1&& aA1, A2&& aA2, A3&& aA3, A4&& aA4, A5&& aA5) = delete;
-
-template<typename T, typename A1, typename A2, typename A3, typename A4,
-         typename A5, typename A6>
-typename detail::UniqueSelector<T>::KnownBound
-MakeUnique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5,
-           A6&& a6) = delete;
-
-template<typename T, typename A1, typename A2, typename A3, typename A4,
-         typename A5, typename A6, typename A7>
-typename detail::UniqueSelector<T>::KnownBound
-MakeUnique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, A6&& a6,
-           A7&& a7) = delete;
-
-template<typename T, typename A1, typename A2, typename A3, typename A4,
-         typename A5, typename A6, typename A7, typename A8>
-typename detail::UniqueSelector<T>::KnownBound
-MakeUnique(A1&& a1, A2&& a2, A3&& a3, A4&& a4, A5&& a5, A6&& a6,
-           A7&& a7, A8&& a8) = delete;
+MakeUnique(Args&&... aArgs) = delete;
 
 } // namespace mozilla
 
 #endif /* mozilla_UniquePtr_h */
--- a/mobile/android/base/docs/gradle.rst
+++ b/mobile/android/base/docs/gradle.rst
@@ -40,17 +40,17 @@ Caveats
 * There's no support for editing C/C++.
 
 How the Gradle project is laid out
 ----------------------------------
 
 To the greatest extent possible, the Gradle configuration lives in the object
 directory.
 
-At the time of writing, their are three main sub-modules: *app*, *base*, and
+At the time of writing, there are three main sub-modules: *app*, *base*, and
 *thirdparty*, and several smaller sub-modules.
 
 *app* is the Fennec wrapper; it generates the **org.mozilla.fennec.R** resource
 package.  *base* is the Gecko code; it generates the **org.mozilla.gecko.R**
 resource package.  Together, *app* and *base* address the "two package
 namespaces" that has plagued Fennec from day one.
 
 Due to limitations in the Android Gradle plugin, all test code is shoved into
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -166,16 +166,20 @@ pref("dom.keyboardevent.code.enabled", t
 #endif
 
 // Whether the WebCrypto API is enabled
 pref("dom.webcrypto.enabled", true);
 
 // Whether the UndoManager API is enabled
 pref("dom.undo_manager.enabled", false);
 
+// Whether URL,nsLocation,Link::GetHash should be percent encoded
+// in setter and percent decoded in getter (old behaviour = true)
+pref("dom.url.encode_decode_hash", false);
+
 // Whether to run add-on code in different compartments from browser code. This
 // causes a separate compartment for each (addon, global) combination, which may
 // significantly increase the number of compartments in the system.
 #ifdef NIGHTLY_BUILD
 pref("dom.compartment_per_addon", true);
 #else
 pref("dom.compartment_per_addon", false);
 #endif
@@ -705,16 +709,18 @@ pref("canvas.path.enabled", true);
 //
 // This pref is checked only once, and the browser needs a restart to
 // pick up any changes.
 //
 // Values are -1 always on. 1 always off, 0 is auto as some platform perform
 // further checks.
 pref("accessibility.force_disabled", 0);
 
+pref("accessibility.ipc_architecture.enabled", true);
+
 #ifdef XP_WIN
 // Some accessibility tools poke at windows in the plugin process during setup
 // which can cause hangs.  To hack around this set accessibility.delay_plugins
 // to true, you can also try increasing accessibility.delay_plugin_time if your
 // machine is slow and you still experience hangs.
 // See bug 781791.
 pref("accessibility.delay_plugins", false);
 pref("accessibility.delay_plugin_time", 10000);
--- a/netwerk/base/src/nsStandardURL.cpp
+++ b/netwerk/base/src/nsStandardURL.cpp
@@ -19,16 +19,17 @@
 #include "nsAutoPtr.h"
 #include "nsIProgrammingLanguage.h"
 #include "nsIURLParser.h"
 #include "nsNetCID.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ipc/URIUtils.h"
 #include <algorithm>
 #include "mozilla/dom/EncodingUtils.h"
+#include "nsContentUtils.h"
 
 using mozilla::dom::EncodingUtils;
 using namespace mozilla::ipc;
 
 static NS_DEFINE_CID(kThisImplCID, NS_THIS_STANDARDURL_IMPL_CID);
 static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
 
 nsIIDNService *nsStandardURL::gIDN = nullptr;
@@ -548,18 +549,26 @@ nsStandardURL::BuildNormalizedSpec(const
         approxLen += encoder.EncodeSegmentCount(spec, mExtension, esc_FileExtension, encExtension, useEncExtension, 1);
 
         // These next ones *always* add their leading character even if length is 0
         // Handles items like "http://#"
         // ?query
         if (mQuery.mLen >= 0)
             approxLen += 1 + queryEncoder.EncodeSegmentCount(spec, mQuery, esc_Query,        encQuery,     useEncQuery);
         // #ref
-        if (mRef.mLen >= 0)
-            approxLen += 1 + encoder.EncodeSegmentCount(spec, mRef,       esc_Ref,           encRef,       useEncRef);
+
+        if (mRef.mLen >= 0) {
+            if (nsContentUtils::EncodeDecodeURLHash()) {
+                approxLen += 1 + encoder.EncodeSegmentCount(spec, mRef, esc_Ref,
+                                                            encRef, useEncRef);
+            } else {
+                approxLen += 1 + mRef.mLen;
+                useEncRef = false;
+            }
+        }
     }
 
     // do not escape the hostname, if IPv6 address literal, mHost will
     // already point to a [ ] delimited IPv6 address literal.
     // However, perform Unicode normalization on it, as IDN does.
     mHostEncoding = eEncoding_ASCII;
     // Note that we don't disallow URLs without a host - file:, etc
     if (mHost.mLen > 0) {
@@ -2453,25 +2462,27 @@ nsStandardURL::SetRef(const nsACString &
     
     if (mRef.mLen < 0) {
         mSpec.Append('#');
         ++mPath.mLen;  // Include the # in the path.
         mRef.mPos = mSpec.Length();
         mRef.mLen = 0;
     }
 
-    // encode ref if necessary
-    nsAutoCString buf;
-    bool encoded;
-    GET_SEGMENT_ENCODER(encoder);
-    encoder.EncodeSegmentCount(ref, URLSegment(0, refLen), esc_Ref,
-                               buf, encoded);
-    if (encoded) {
-        ref = buf.get();
-        refLen = buf.Length();
+    if (nsContentUtils::EncodeDecodeURLHash()) {
+        // encode ref if necessary
+        nsAutoCString buf;
+        bool encoded;
+        GET_SEGMENT_ENCODER(encoder);
+        encoder.EncodeSegmentCount(ref, URLSegment(0, refLen), esc_Ref,
+                                   buf, encoded);
+        if (encoded) {
+            ref = buf.get();
+            refLen = buf.Length();
+        }
     }
 
     int32_t shift = ReplaceSegment(mRef.mPos, mRef.mLen, ref, refLen);
     mPath.mLen += shift;
     mRef.mLen = refLen;
     return NS_OK;
 }
 
--- a/nsprpub/TAG-INFO
+++ b/nsprpub/TAG-INFO
@@ -1,1 +1,1 @@
-NSPR_4_10_8_BETA2
+NSPR_4_10_8_BETA3
--- a/nsprpub/config/prdepend.h
+++ b/nsprpub/config/prdepend.h
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSPR in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/nsprpub/pr/src/io/prprf.c
+++ b/nsprpub/pr/src/io/prprf.c
@@ -13,17 +13,17 @@
 #include <stdio.h>
 #include <string.h>
 #include "primpl.h"
 #include "prprf.h"
 #include "prlong.h"
 #include "prlog.h"
 #include "prmem.h"
 
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && _MSC_VER < 1900
 #define snprintf _snprintf
 #endif
 
 /*
 ** WARNING: This code may *NOT* call PR_LOG (because PR_LOG calls it)
 */
 
 /*
--- a/nsprpub/pr/src/md/windows/w95io.c
+++ b/nsprpub/pr/src/md/windows/w95io.c
@@ -950,19 +950,20 @@ PRStatus
 {
     PRStatus  rc = PR_SUCCESS;
 	DWORD     rv;
 
 	rv = LockFile( (HANDLE)f,
 		0l, 0l,
 		0x0l, 0xffffffffl ); 
 	if ( rv == 0 ) {
-        DWORD rc = GetLastError();
+        DWORD err = GetLastError();
+        _PR_MD_MAP_DEFAULT_ERROR(err);
         PR_LOG( _pr_io_lm, PR_LOG_ERROR,
-            ("_PR_MD_LOCKFILE() failed. Error: %d", rc ));
+            ("_PR_MD_LOCKFILE() failed. Error: %d", err ));
         rc = PR_FAILURE;
     }
 
     return rc;
 } /* end _PR_MD_LOCKFILE() */
 
 PRStatus
 _PR_MD_TLOCKFILE(PROsfd f)
--- a/nsprpub/pr/src/misc/prsystem.c
+++ b/nsprpub/pr/src/misc/prsystem.c
@@ -19,17 +19,17 @@
 /* define the required constant if it is not already defined in the headers */
 #ifndef QSV_NUMPROCESSORS
 #define QSV_NUMPROCESSORS 26
 #endif
 #endif
 
 /* BSD-derived systems use sysctl() to get the number of processors */
 #if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) \
-    || defined(OPENBSD) || defined(DARWIN)
+    || defined(OPENBSD) || defined(DRAGONFLY) || defined(DARWIN)
 #define _PR_HAVE_SYSCTL
 #include <sys/param.h>
 #include <sys/sysctl.h>
 #endif
 
 #if defined(DARWIN)
 #include <mach/mach_init.h>
 #include <mach/mach_host.h>
@@ -270,25 +270,34 @@ PR_IMPLEMENT(PRUint64) PR_GetPhysicalMem
 
 #if defined(LINUX) || defined(SOLARIS)
 
     long pageSize = sysconf(_SC_PAGESIZE);
     long pageCount = sysconf(_SC_PHYS_PAGES);
     if (pageSize >= 0 && pageCount >= 0)
         bytes = (PRUint64) pageSize * pageCount;
 
-#elif defined(NETBSD) || defined(OPENBSD)
+#elif defined(NETBSD) || defined(OPENBSD) \
+    || defined(FREEBSD) || defined(DRAGONFLY)
 
     int mib[2];
     int rc;
+#ifdef HW_PHYSMEM64
     uint64_t memSize;
+#else
+    unsigned long memSize;
+#endif
     size_t len = sizeof(memSize);
 
     mib[0] = CTL_HW;
+#ifdef HW_PHYSMEM64
     mib[1] = HW_PHYSMEM64;
+#else
+    mib[1] = HW_PHYSMEM;
+#endif
     rc = sysctl(mib, 2, &memSize, &len, NULL, 0);
     if (-1 != rc)  {
         bytes = memSize;
     }
 
 #elif defined(HPUX)
 
     struct pst_static info;
--- a/nsprpub/pr/src/threads/combined/prucpu.c
+++ b/nsprpub/pr/src/threads/combined/prucpu.c
@@ -119,17 +119,17 @@ static _PRCPUQueue *_PR_CreateCPUQueue(v
     PRInt32 index;
     _PRCPUQueue *cpuQueue;
     cpuQueue = PR_NEWZAP(_PRCPUQueue);
  
     _MD_NEW_LOCK( &cpuQueue->runQLock );
     _MD_NEW_LOCK( &cpuQueue->sleepQLock );
     _MD_NEW_LOCK( &cpuQueue->miscQLock );
 
-    for (index = 0; index < PR_PRIORITY_LAST + 1; index++)
+    for (index = 0; index < PR_ARRAY_SIZE(cpuQueue->runQ); index++)
         PR_INIT_CLIST( &(cpuQueue->runQ[index]) );
     PR_INIT_CLIST( &(cpuQueue->sleepQ) );
     PR_INIT_CLIST( &(cpuQueue->pauseQ) );
     PR_INIT_CLIST( &(cpuQueue->suspendQ) );
     PR_INIT_CLIST( &(cpuQueue->waitingToJoinQ) );
 
     cpuQueue->numCPUs = 1;
 
--- a/nsprpub/pr/src/threads/prdump.c
+++ b/nsprpub/pr/src/threads/prdump.c
@@ -82,17 +82,17 @@ void _PR_DumpThreads(PRFileDesc *fd)
     PRThread *t;
     PRIntn i;
 
     _PR_DumpPrintf(fd, "Current Thread:\n");
     t = _PR_MD_CURRENT_THREAD();
     _PR_DumpThread(fd, t);
 
     _PR_DumpPrintf(fd, "Runnable Threads:\n");
-    for (i = 0; i < 32; i++) {
+    for (i = 0; i < PR_ARRAY_SIZE(_PR_RUNQ(t->cpu)); i++) {
         DumpThreadQueue(fd, &_PR_RUNQ(t->cpu)[i]);
     }
 
     _PR_DumpPrintf(fd, "CondVar timed wait Threads:\n");
     DumpThreadQueue(fd, &_PR_SLEEPQ(t->cpu));
 
     _PR_DumpPrintf(fd, "CondVar wait Threads:\n");
     DumpThreadQueue(fd, &_PR_PAUSEQ(t->cpu));
--- a/rdf/base/nsInMemoryDataSource.cpp
+++ b/rdf/base/nsInMemoryDataSource.cpp
@@ -329,33 +329,41 @@ public:
     GetReverseArcs(nsIRDFNode* v) {
         PLDHashEntryHdr* hdr = PL_DHashTableLookup(&mReverseArcs, v);
         return PL_DHASH_ENTRY_IS_BUSY(hdr)
             ? reinterpret_cast<Entry*>(hdr)->mAssertions
             : nullptr; }
 
     void
     SetForwardArcs(nsIRDFResource* u, Assertion* as) {
-        PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mForwardArcs, u,
-                                                    as ? PL_DHASH_ADD : PL_DHASH_REMOVE);
-        if (as && hdr) {
-            Entry* entry = reinterpret_cast<Entry*>(hdr);
-            entry->mNode = u;
-            entry->mAssertions = as;
-        } }
+        if (as) {
+            Entry* entry = reinterpret_cast<Entry*>(PL_DHashTableAdd(&mForwardArcs, u));
+            if (entry) {
+                entry->mNode = u;
+                entry->mAssertions = as;
+            }
+        }
+        else {
+            PL_DHashTableRemove(&mForwardArcs, u);
+        }
+    }
 
     void
     SetReverseArcs(nsIRDFNode* v, Assertion* as) {
-        PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mReverseArcs, v,
-                                                    as ? PL_DHASH_ADD : PL_DHASH_REMOVE);
-        if (as && hdr) {
-            Entry* entry = reinterpret_cast<Entry*>(hdr);
-            entry->mNode = v;
-            entry->mAssertions = as;
-        } }
+        if (as) {
+            Entry* entry = reinterpret_cast<Entry*>(PL_DHashTableAdd(&mReverseArcs, v));
+            if (entry) {
+                entry->mNode = v;
+                entry->mAssertions = as;
+            }
+        }
+        else {
+            PL_DHashTableRemove(&mReverseArcs, v);
+        }
+    }
 
 #ifdef PR_LOGGING
     void
     LogOperation(const char* aOperation,
                  nsIRDFResource* asource,
                  nsIRDFResource* aProperty,
                  nsIRDFNode* aTarget,
                  bool aTruthValue = true);
--- a/security/manager/ssl/src/nsNTLMAuthModule.cpp
+++ b/security/manager/ssl/src/nsNTLMAuthModule.cpp
@@ -585,17 +585,17 @@ GenerateType3Msg(const nsString &domain,
   // get domain name
   //
   if (unicode)
   {
 #ifdef IS_BIG_ENDIAN
     ucsDomainBuf = domain;
     domainPtr = ucsDomainBuf.get();
     domainLen = ucsDomainBuf.Length() * 2;
-    WriteUnicodeLE((void *) domainPtr, reinterpret_cast<const uint16_t*> domainPtr,
+    WriteUnicodeLE((void *) domainPtr, reinterpret_cast<const char16_t*> (domainPtr),
                    ucsDomainBuf.Length());
 #else
     domainPtr = domain.get();
     domainLen = domain.Length() * 2;
 #endif
   }
   else
   {
@@ -608,17 +608,17 @@ GenerateType3Msg(const nsString &domain,
   // get user name
   //
   if (unicode)
   {
 #ifdef IS_BIG_ENDIAN
     ucsUserBuf = username;
     userPtr = ucsUserBuf.get();
     userLen = ucsUserBuf.Length() * 2;
-    WriteUnicodeLE((void *) userPtr, reinterpret_cast<const uint16_t*> userPtr,
+    WriteUnicodeLE((void *) userPtr, reinterpret_cast<const char16_t*> (userPtr),
                    ucsUserBuf.Length());
 #else
     userPtr = username.get();
     userLen = username.Length() * 2;
 #endif
   }
   else
   {
@@ -636,17 +636,17 @@ GenerateType3Msg(const nsString &domain,
   hostLen = strlen(hostBuf);
   if (unicode)
   {
     // hostname is ASCII, so we can do a simple zero-pad expansion:
     CopyASCIItoUTF16(nsDependentCString(hostBuf, hostLen), ucsHostBuf);
     hostPtr = ucsHostBuf.get();
     hostLen = ucsHostBuf.Length() * 2;
 #ifdef IS_BIG_ENDIAN
-    WriteUnicodeLE((void *) hostPtr, reinterpret_cast<const uint16_t*> hostPtr,
+    WriteUnicodeLE((void *) hostPtr, reinterpret_cast<const char16_t*> (hostPtr),
                    ucsHostBuf.Length());
 #endif
   }
   else
     hostPtr = hostBuf;
 
   //
   // now that we have generated all of the strings, we can allocate outBuf.
@@ -679,24 +679,24 @@ GenerateType3Msg(const nsString &domain,
       NS_ERROR("failed to get NTLMv2 target info, can not do NTLMv2");
       return NS_ERROR_UNEXPECTED;
     }
 
     ToUpperCase(username, ucsUserUpperBuf);
     userUpperPtr = ucsUserUpperBuf.get();
     userUpperLen = ucsUserUpperBuf.Length() * 2;
 #ifdef IS_BIG_ENDIAN
-    WriteUnicodeLE((void *) userUpperPtr, reinterpret_cast<const uint16_t*> (userUpperPtr),
+    WriteUnicodeLE((void *) userUpperPtr, reinterpret_cast<const char16_t*> (userUpperPtr),
                    ucsUserUpperBuf.Length());
 #endif
     ToUpperCase(domain, ucsDomainUpperBuf);
     domainUpperPtr = ucsDomainUpperBuf.get();
     domainUpperLen = ucsDomainUpperBuf.Length() * 2;
 #ifdef IS_BIG_ENDIAN
-    WriteUnicodeLE((void *) domainUpperPtr, reinterpret_cast<const uint16_t*> (domainUpperPtr),
+    WriteUnicodeLE((void *) domainUpperPtr, reinterpret_cast<const char16_t*> (domainUpperPtr),
                    ucsDomainUpperBuf.Length());
 #endif
 
     NTLM_Hash(password, ntlmHash);
     ntlmHashStr = nsAutoCString(reinterpret_cast<const char *>(ntlmHash), NTLM_HASH_LEN);
 
     nsCOMPtr<nsIKeyObjectFactory> keyFactory =
         do_CreateInstance(NS_KEYMODULEOBJECTFACTORY_CONTRACTID, &rv);
--- a/security/manager/ssl/tests/unit/xpcshell.ini
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -50,18 +50,16 @@ run-sequentially = hardcoded ports
 [test_ocsp_stapling_with_intermediate.js]
 run-sequentially = hardcoded ports
 [test_ocsp_caching.js]
 run-sequentially = hardcoded ports
 [test_ocsp_required.js]
 run-sequentially = hardcoded ports
 [test_ocsp_timeout.js]
 run-sequentially = hardcoded ports
-# Bug 1005266: intermittent failures on Windows
-skip-if = os == "win"
 [test_cert_signatures.js]
 [test_ev_certs.js]
 run-sequentially = hardcoded ports
 [test_getchain.js]
 [test_cert_overrides.js]
 run-sequentially = hardcoded ports
 [test_intermediate_basic_usage_constraints.js]
 [test_name_constraints.js]
--- a/security/pkix/include/pkix/Input.h
+++ b/security/pkix/include/pkix/Input.h
@@ -119,17 +119,17 @@ public:
   // Don't use this. It is here because we have some "friend" functions that we
   // don't want to declare in this header file.
   const uint8_t* UnsafeGetData() const { return data; }
 
 private:
   const uint8_t* data;
   size_t len;
 
-  void operator=(const Input&) /* = delete */; // Use Init instead.
+  void operator=(const Input&) = delete; // Use Init instead.
 };
 
 inline bool
 InputsAreEqual(const Input& a, const Input& b)
 {
   return a.GetLength() == b.GetLength() &&
          !std::memcmp(a.UnsafeGetData(), b.UnsafeGetData(), a.GetLength());
 }
@@ -286,17 +286,17 @@ public:
 
   class Mark
   {
   private:
     friend class Reader;
     Mark(const Reader& input, const uint8_t* mark) : input(input), mark(mark) { }
     const Reader& input;
     const uint8_t* const mark;
-    void operator=(const Mark&) /* = delete */;
+    void operator=(const Mark&) = delete;
   };
 
   Mark GetMark() const { return Mark(*this, input); }
 
   Result GetInput(const Mark& mark, /*out*/ Input& item)
   {
     if (&mark.input != this || mark.mark > input) {
       return NotReached("invalid mark", Result::FATAL_ERROR_INVALID_ARGS);
@@ -315,18 +315,18 @@ private:
     input = data;
     end = data + len;
     return Success;
   }
 
   const uint8_t* input;
   const uint8_t* end;
 
-  Reader(const Reader&) /* = delete */;
-  void operator=(const Reader&) /* = delete */;
+  Reader(const Reader&) = delete;
+  void operator=(const Reader&) = delete;
 };
 
 inline bool
 InputContains(const Input& input, uint8_t toFind)
 {
   Reader reader(input);
   for (;;) {
     uint8_t b;
--- a/security/pkix/include/pkix/ScopedPtr.h
+++ b/security/pkix/include/pkix/ScopedPtr.h
@@ -64,18 +64,18 @@ public:
     return result;
   }
 
   void reset() { *this = nullptr; }
 
 protected:
   T* mValue;
 
-  ScopedPtr(const ScopedPtr&) /* = delete */;
-  void operator=(const ScopedPtr&) /* = delete */;
+  ScopedPtr(const ScopedPtr&) = delete;
+  void operator=(const ScopedPtr&) = delete;
 };
 
 template <typename T, void(&Destroyer)(T*)>
 inline bool
 operator==(T* a, const ScopedPtr<T, Destroyer>& b)
 {
   return a == b.get();
 }
--- a/security/pkix/include/pkix/bind.h
+++ b/security/pkix/include/pkix/bind.h
@@ -75,47 +75,47 @@ class Bind1
 {
 public:
   typedef R (&F)(P1&, B1&);
   Bind1(F f, B1& b1) : f(f), b1(b1) { }
   R operator()(P1& p1) const { return f(p1, b1); }
 private:
   F f;
   B1& b1;
-  void operator=(const Bind1&) /*= delete*/;
+  void operator=(const Bind1&) = delete;
 };
 
 template <typename R, typename P1, typename B1, typename B2>
 class Bind2
 {
 public:
   typedef R (&F)(P1&, B1&, B2&);
   Bind2(F f, B1& b1, B2& b2) : f(f), b1(b1), b2(b2) { }
   R operator()(P1& p1) const { return f(p1, b1, b2); }
 private:
   F f;
   B1& b1;
   B2& b2;
-  void operator=(const Bind2&) /*= delete*/;
+  void operator=(const Bind2&) = delete;
 };
 
 template <typename R, typename P1, typename B1, typename B2, typename B3>
 class Bind3
 {
 public:
   typedef R (&F)(P1&, B1, B2, B3&);
   Bind3(F f, B1& b1, B2& b2, B3& b3)
     : f(f), b1(b1), b2(b2), b3(b3) { }
   R operator()(P1& p1) const { return f(p1, b1, b2, b3); }
 private:
   F f;
   B1& b1;
   B2& b2;
   B3& b3;
-  void operator=(const Bind3&) /*= delete*/;
+  void operator=(const Bind3&) = delete;
 };
 
 template <typename R, typename P1, typename B1, typename B2, typename B3,
           typename B4>
 class Bind4
 {
 public:
   typedef R (&F)(P1&, B1, B2, B3&, B4&);
@@ -123,17 +123,17 @@ public:
     : f(f), b1(b1), b2(b2), b3(b3), b4(b4) { }
   R operator()(P1& p1) const { return f(p1, b1, b2, b3, b4); }
 private:
   F f;
   B1& b1;
   B2& b2;
   B3& b3;
   B4& b4;
-  void operator=(const Bind4&) /*= delete*/;
+  void operator=(const Bind4&) = delete;
 };
 
 template <typename R, typename C1, typename P1, typename P2, typename P3,
           typename P4>
 class BindToMemberFunction4
 {
 public:
   // XXX: C++ doesn't have reference-to-member function, only
@@ -143,17 +143,17 @@ public:
   BindToMemberFunction4(F f, C1& that) : f(f), that(that) { }
   R operator()(P1& p1, P2& p2, P3 p3, P4& p4) const
   {
     return (that.*f)(p1, p2, p3, p4);
   }
 private:
   const F f;
   C1& that;
-  void operator=(const BindToMemberFunction4&) /*= delete*/;
+  void operator=(const BindToMemberFunction4&) = delete;
 };
 
 template <typename R, typename P1, typename B1, typename B2, typename B3,
           typename B4, typename B5>
 class Bind5
 {
 public:
   typedef R (&F)(P1&, B1, B2, B3, B4, B5);
@@ -162,17 +162,17 @@ public:
   R operator()(P1& p1) const { return f(p1, b1, b2, b3, b4, b5); }
 private:
   F f;
   B1 b1;
   B2 b2;
   B3 b3;
   B4 b4;
   B5 b5;
-  void operator=(const Bind5&) /*= delete*/;
+  void operator=(const Bind5&) = delete;
 };
 
 } // namespace internal
 
 template <typename R, typename P1, typename B1>
 inline internal::Bind1<R, P1, B1>
 bind(R (&f)(P1&, B1&), Placeholder1&, B1& b1)
 {
--- a/security/pkix/include/pkix/pkixtypes.h
+++ b/security/pkix/include/pkix/pkixtypes.h
@@ -75,18 +75,17 @@ enum class SignatureAlgorithm
 
 struct SignedDataWithSignature
 {
 public:
   Input data;
   SignatureAlgorithm algorithm;
   Input signature;
 
-private:
-  void operator=(const SignedDataWithSignature&) /*= delete*/;
+  void operator=(const SignedDataWithSignature&) = delete;
 };
 
 enum class EndEntityOrCA { MustBeEndEntity = 0, MustBeCA = 1 };
 
 enum class KeyUsage : uint8_t {
   digitalSignature = 0,
   nonRepudiation   = 1,
   keyEncipherment  = 2,
@@ -143,18 +142,18 @@ public:
     : issuer(issuer)
     , issuerSubjectPublicKeyInfo(issuerSubjectPublicKeyInfo)
     , serialNumber(serialNumber)
   {
   }
   const Input issuer;
   const Input issuerSubjectPublicKeyInfo;
   const Input serialNumber;
-private:
-  void operator=(const CertID&) /*= delete*/;
+
+  void operator=(const CertID&) = delete;
 };
 
 class DERArray
 {
 public:
   // Returns the number of DER-encoded items in the array.
   virtual size_t GetLength() const = 0;
 
@@ -204,19 +203,19 @@ public:
     // constraints will be checked in addition to any any name constraints
     // contained in potentialIssuerDER.
     virtual Result Check(Input potentialIssuerDER,
             /*optional*/ const Input* additionalNameConstraints,
                  /*out*/ bool& keepGoing) = 0;
   protected:
     IssuerChecker();
     virtual ~IssuerChecker();
-  private:
-    IssuerChecker(const IssuerChecker&) /*= delete*/;
-    void operator=(const IssuerChecker&) /*= delete*/;
+
+    IssuerChecker(const IssuerChecker&) = delete;
+    void operator=(const IssuerChecker&) = delete;
   };
 
   // Search for a CA certificate with the given name. The implementation must
   // call checker.Check with the DER encoding of the potential issuer
   // certificate. The implementation must follow these rules:
   //
   // * The implementation must be reentrant and must limit the amount of stack
   //   space it uses; see the note on reentrancy and stack usage below.
@@ -320,16 +319,15 @@ public:
   // other, extensive, memory safety efforts in mozilla::pkix, and we should
   // find a way to provide a more-obviously-safe interface.
   static const size_t DIGEST_LENGTH = 20; // length of SHA-1 digest
   virtual Result DigestBuf(Input item, /*out*/ uint8_t* digestBuf,
                            size_t digestBufLen) = 0;
 protected:
   TrustDomain() { }
 
-private:
-  TrustDomain(const TrustDomain&) /* = delete */;
-  void operator=(const TrustDomain&) /* = delete */;
+  TrustDomain(const TrustDomain&) = delete;
+  void operator=(const TrustDomain&) = delete;
 };
 
 } } // namespace mozilla::pkix
 
 #endif // mozilla_pkix__pkixtypes_h
--- a/security/pkix/lib/pkixbuild.cpp
+++ b/security/pkix/lib/pkixbuild.cpp
@@ -79,18 +79,18 @@ private:
   /*optional*/ Input const* const stapledOCSPResponse;
   const unsigned int subCACount;
   const Result deferredSubjectError;
 
   Result RecordResult(Result currentResult, /*out*/ bool& keepGoing);
   Result result;
   bool resultWasSet;
 
-  PathBuildingStep(const PathBuildingStep&) /*= delete*/;
-  void operator=(const PathBuildingStep&) /*= delete*/;
+  PathBuildingStep(const PathBuildingStep&) = delete;
+  void operator=(const PathBuildingStep&) = delete;
 };
 
 Result
 PathBuildingStep::RecordResult(Result newResult, /*out*/ bool& keepGoing)
 {
   if (newResult == Result::ERROR_UNTRUSTED_CERT) {
     newResult = Result::ERROR_UNTRUSTED_ISSUER;
   } else if (newResult == Result::ERROR_EXPIRED_CERTIFICATE) {
--- a/security/pkix/lib/pkixocsp.cpp
+++ b/security/pkix/lib/pkixocsp.cpp
@@ -66,19 +66,18 @@ public:
   const CertID& certID;
   const Time time;
   const uint16_t maxLifetimeInDays;
   CertStatus certStatus;
   Time* thisUpdate;
   Time* validThrough;
   bool expired;
 
-private:
-  Context(const Context&); // delete
-  void operator=(const Context&); // delete
+  Context(const Context&) = delete;
+  void operator=(const Context&) = delete;
 };
 
 // Verify that potentialSigner is a valid delegated OCSP response signing cert
 // according to RFC 6960 section 4.2.2.2.
 static Result
 CheckOCSPResponseSignerCert(TrustDomain& trustDomain,
                             BackCert& potentialSigner,
                             Input issuerSubject,
--- a/security/pkix/lib/pkixutil.h
+++ b/security/pkix/lib/pkixutil.h
@@ -138,18 +138,18 @@ private:
   Input keyUsage;
   Input nameConstraints;
   Input subjectAltName;
   Input criticalNetscapeCertificateType;
 
   Result RememberExtension(Reader& extnID, const Input& extnValue,
                            bool critical, /*out*/ bool& understood);
 
-  BackCert(const BackCert&) /* = delete */;
-  void operator=(const BackCert&); /* = delete */;
+  BackCert(const BackCert&) = delete;
+  void operator=(const BackCert&) = delete;
 };
 
 class NonOwningDERArray : public DERArray
 {
 public:
   NonOwningDERArray()
     : numItems(0)
   {
@@ -178,18 +178,18 @@ public:
   }
 
   // Public so we can static_assert on this. Keep in sync with MAX_SUBCA_COUNT.
   static const size_t MAX_LENGTH = 8;
 private:
   Input items[MAX_LENGTH]; // avoids any heap allocations
   size_t numItems;
 
-  NonOwningDERArray(const NonOwningDERArray&) /* = delete*/;
-  void operator=(const NonOwningDERArray&) /* = delete*/;
+  NonOwningDERArray(const NonOwningDERArray&) = delete;
+  void operator=(const NonOwningDERArray&) = delete;
 };
 
 inline unsigned int
 DaysBeforeYear(unsigned int year)
 {
   assert(year <= 9999);
   return ((year - 1u) * 365u)
        + ((year - 1u) / 4u)    // leap years are every 4 years,
--- a/security/pkix/test/gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp
+++ b/security/pkix/test/gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp
@@ -81,19 +81,18 @@ public:
     return TestDigestBuf(item, digestBuf, digestBufLen);
   }
 
   virtual Result CheckPublicKey(Input subjectPublicKeyInfo)
   {
     return TestCheckPublicKey(subjectPublicKeyInfo);
   }
 
-private:
-  OCSPTestTrustDomain(const OCSPTestTrustDomain&) /*delete*/;
-  void operator=(const OCSPTestTrustDomain&) /*delete*/;
+  OCSPTestTrustDomain(const OCSPTestTrustDomain&) = delete;
+  void operator=(const OCSPTestTrustDomain&) = delete;
 };
 
 namespace {
 char const* const rootName = "Test CA 1";
 void deleteCertID(CertID* certID) { delete certID; }
 } // unnamed namespace
 
 class pkixocsp_VerifyEncodedResponse : public ::testing::Test
--- a/security/pkix/test/lib/pkixtestutil.h
+++ b/security/pkix/test/lib/pkixtestutil.h
@@ -241,18 +241,18 @@ public:
   virtual TestKeyPair* Clone() const = 0;
 protected:
   TestKeyPair(const ByteString& spki, const ByteString& spk)
     : subjectPublicKeyInfo(spki)
     , subjectPublicKey(spk)
   {
   }
 
-  TestKeyPair(const TestKeyPair&) /*= delete*/;
-  void operator=(const TestKeyPair&) /*= delete*/;
+  TestKeyPair(const TestKeyPair&) = delete;
+  void operator=(const TestKeyPair&) = delete;
 };
 
 TestKeyPair* CloneReusedKeyPair();
 TestKeyPair* GenerateKeyPair();
 TestKeyPair* GenerateDSSKeyPair();
 inline void DeleteTestKeyPair(TestKeyPair* keyPair) { delete keyPair; }
 typedef ScopedPtr<TestKeyPair, DeleteTestKeyPair> ScopedTestKeyPair;
 
--- a/storage/test/test_async_callbacks_with_spun_event_loops.cpp
+++ b/storage/test/test_async_callbacks_with_spun_event_loops.cpp
@@ -53,37 +53,37 @@ public:
 private:
   ~UnownedCallback()
   {
     sAlive = false;
     blocking_async_close(mDBConn);
   }
 
 public:
-  NS_IMETHOD HandleResult(mozIStorageResultSet* aResultSet)
+  NS_IMETHOD HandleResult(mozIStorageResultSet* aResultSet) MOZ_OVERRIDE
   {
     sResult = true;
     spin_events_loop_until_true(&mCompleted);
     if (!sAlive) {
       NS_RUNTIMEABORT("The statement callback was destroyed prematurely.");
     }
     return NS_OK;
   }
 
-  NS_IMETHOD HandleError(mozIStorageError* aError)
+  NS_IMETHOD HandleError(mozIStorageError* aError) MOZ_OVERRIDE
   {
     sError = true;
     spin_events_loop_until_true(&mCompleted);
     if (!sAlive) {
       NS_RUNTIMEABORT("The statement callback was destroyed prematurely.");
     }
     return NS_OK;
   }
 
-  NS_IMETHOD HandleCompletion(uint16_t aReason)
+  NS_IMETHOD HandleCompletion(uint16_t aReason) MOZ_OVERRIDE
   {
     mCompleted = true;
     return NS_OK;
   }
 
 protected:
   nsCOMPtr<mozIStorageConnection> mDBConn;
   bool mCompleted;
deleted file mode 100644
--- a/testing/web-platform/meta/XMLHttpRequest/open-method-responsetype-set-sync.htm.ini
+++ /dev/null
@@ -1,17 +0,0 @@
-[open-method-responsetype-set-sync.htm]
-  type: testharness
-  [XMLHttpRequest: open() sync request not allowed if responseType is set (arraybuffer)]
-    expected: FAIL
-
-  [XMLHttpRequest: open() sync request not allowed if responseType is set (blob)]
-    expected: FAIL
-
-  [XMLHttpRequest: open() sync request not allowed if responseType is set (json)]
-    expected: FAIL
-
-  [XMLHttpRequest: open() sync request not allowed if responseType is set (text)]
-    expected: FAIL
-
-  [XMLHttpRequest: open() sync request not allowed if responseType is set (document)]
-    expected: FAIL
-
--- a/testing/web-platform/meta/XMLHttpRequest/responsetext-decoding.htm.ini
+++ b/testing/web-platform/meta/XMLHttpRequest/responsetext-decoding.htm.ini
@@ -7,14 +7,8 @@
     expected: FAIL
 
   [XMLHttpRequest: responseText decoding (text/plain %FE%FF%FE%FF)]
     expected: FAIL
 
   [XMLHttpRequest: responseText decoding (text/plain %C2)]
     expected: FAIL
 
-  [XMLHttpRequest: responseText decoding (text/plain %E3%81%B2)]
-    expected: FAIL
-
-  [XMLHttpRequest: responseText decoding (text/xml %3C%3Fxml%20version%3D\'1.0\'%20encoding%3D\'windows-1252\'%3F%3E%3Cx%3E%E3%81%B2%3C%2Fx%3E)]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/XMLHttpRequest/responsetype.html.ini
+++ /dev/null
@@ -1,20 +0,0 @@
-[responsetype.html]
-  type: testharness
-  [Set responseType to "" when readyState is UNSENT.]
-    expected: FAIL
-
-  [Set responseType to "json" when readyState is UNSENT.]
-    expected: FAIL
-
-  [Set responseType to "document" when readyState is UNSENT.]
-    expected: FAIL
-
-  [Set responseType to "arraybuffer" when readyState is UNSENT.]
-    expected: FAIL
-
-  [Set responseType to "blob" when readyState is UNSENT.]
-    expected: FAIL
-
-  [Set responseType to "text" when readyState is UNSENT.]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/XMLHttpRequest/responsexml-non-document-types.htm.ini
+++ /dev/null
@@ -1,17 +0,0 @@
-[responsexml-non-document-types.htm]
-  type: testharness
-  [XMLHttpRequest: responseXML/responseText on other responseType (arraybuffer)]
-    expected: FAIL
-
-  [XMLHttpRequest: responseXML/responseText on other responseType (blob)]
-    expected: FAIL
-
-  [XMLHttpRequest: responseXML/responseText on other responseType (json)]
-    expected: FAIL
-
-  [XMLHttpRequest: responseXML/responseText on other responseType (text)]
-    expected: FAIL
-
-  [XMLHttpRequest: responseXML/responseText on other responseType (document)]
-    expected: FAIL
-
--- a/testing/web-platform/meta/url/a-element.html.ini
+++ b/testing/web-platform/meta/url/a-element.html.ini
@@ -1,16 +1,13 @@
 [a-element.html]
   type: testharness
   [Parsing: <a:\t foo.com> against <http://example.org/foo/bar>]
     expected: FAIL
 
-  [Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar>]
-    expected: FAIL
-
   [Parsing: <http://f:b/c> against <http://example.org/foo/bar>]
     expected: FAIL
 
   [Parsing: <http://f: /c> against <http://example.org/foo/bar>]
     expected: FAIL
 
   [Parsing: <http://f:fifty-two/c> against <http://example.org/foo/bar>]
     expected: FAIL
@@ -160,19 +157,16 @@
     expected: FAIL
 
   [Parsing: <http://example.com/foo/%2e> against <about:blank>]
     expected: FAIL
 
   [Parsing: <http://example.com\\\\foo\\\\bar> against <about:blank>]
     expected: FAIL
 
-  [Parsing: <http://www.google.com/foo?bar=baz# \xc2\xbb> against <about:blank>]
-    expected: FAIL
-
   [Parsing: <http://[www.google.com\]/> against <about:blank>]
     expected: FAIL
 
   [Parsing: <http://user:pass@/> against <about:blank>]
     expected: FAIL
 
   [Parsing: <http:\\\\www.google.com\\foo> against <about:blank>]
     expected: FAIL
@@ -328,19 +322,16 @@
     expected: FAIL
 
   [Parsing: <http://192.168.0.1 hello> against <http://other.com/>]
     expected: FAIL
 
   [Parsing: <http://[google.com\]> against <http://other.com/>]
     expected: FAIL
 
-  [Parsing: <#\xce\xb2> against <http://example.org/foo/bar>]
-    expected: FAIL
-
   [Parsing: <http://192.0x00A80001> against <about:blank>]
     expected: FAIL
 
   [Parsing: <http://192.168.0.257> against <http://other.com/>]
     expected: FAIL
 
   [Parsing: <http://\xef\xbc\x90\xef\xbc\xb8\xef\xbd\x83\xef\xbc\x90\xef\xbc\x8e\xef\xbc\x90\xef\xbc\x92\xef\xbc\x95\xef\xbc\x90\xef\xbc\x8e\xef\xbc\x90\xef\xbc\x91> against <http://other.com/>]
     expected: FAIL
--- a/testing/web-platform/meta/url/a-element.xhtml.ini
+++ b/testing/web-platform/meta/url/a-element.xhtml.ini
@@ -1,16 +1,13 @@
 [a-element.xhtml]
   type: testharness
   [Parsing: <a:\t foo.com> against <http://example.org/foo/bar>]
     expected: FAIL
 
-  [Parsing: <http://f:21/ b ? d # e > against <http://example.org/foo/bar>]
-    expected: FAIL
-
   [Parsing: <http://f:b/c> against <http://example.org/foo/bar>]
     expected: FAIL
 
   [Parsing: <http://f: /c> against <http://example.org/foo/bar>]
     expected: FAIL
 
   [Parsing: <http://f:fifty-two/c> against <http://example.org/foo/bar>]
     expected: FAIL
@@ -184,19 +181,16 @@
     expected: FAIL
 
   [Parsing: <http://example.com/foo/%2e> against <about:blank>]
     expected: FAIL
 
   [Parsing: <http://example.com\\\\foo\\\\bar> against <about:blank>]
     expected: FAIL
 
-  [Parsing: <http://www.google.com/foo?bar=baz# \xc2\xbb> against <about:blank>]
-    expected: FAIL
-
   [Parsing: <http://[www.google.com\]/> against <about:blank>]
     expected: FAIL
 
   [Parsing: <http://user:pass@/> against <about:blank>]
     expected: FAIL
 
   [Parsing: <http:\\\\www.google.com\\foo> against <about:blank>]
     expected: FAIL
@@ -352,19 +346,16 @@
     expected: FAIL
 
   [Parsing: <http://192.168.0.1 hello> against <http://other.com/>]
     expected: FAIL
 
   [Parsing: <http://[google.com\]> against <http://other.com/>]
     expected: FAIL
 
-  [Parsing: <#\xce\xb2> against <http://example.org/foo/bar>]
-    expected: FAIL
-
   [Parsing: <http://192.0x00A80001> against <about:blank>]
     expected: FAIL
 
   [Parsing: <http://192.168.0.257> against <http://other.com/>]
     expected: FAIL
 
   [Parsing: <http://\xef\xbc\x90\xef\xbc\xb8\xef\xbd\x83\xef\xbc\x90\xef\xbc\x8e\xef\xbc\x90\xef\xbc\x92\xef\xbc\x95\xef\xbc\x90\xef\xbc\x8e\xef\xbc\x90\xef\xbc\x91> against <http://other.com/>]
     expected: FAIL
--- a/toolkit/content/aboutSupport.js
+++ b/toolkit/content/aboutSupport.js
@@ -1,12 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+"use strict";
+
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Troubleshoot.jsm");
 Cu.import("resource://gre/modules/ResetProfile.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
@@ -342,29 +344,29 @@ let $ = document.getElementById.bind(doc
   if (Array.isArray(textContentOrChildren))
     this.append(elt, textContentOrChildren);
   else
     elt.textContent = String(textContentOrChildren);
   return elt;
 };
 
 $.append = function $_append(parent, children) {
-  children.forEach(function (c) parent.appendChild(c));
+  children.forEach(c => parent.appendChild(c));
 };
 
 function stringBundle() {
   return Services.strings.createBundle(
            "chrome://global/locale/aboutSupport.properties");
 }
 
 function sortedArrayFromObject(obj) {
   let tuples = [];
   for (let prop in obj)
     tuples.push([prop, obj[prop]]);
-  tuples.sort(function ([prop1, v1], [prop2, v2]) prop1.localeCompare(prop2));
+  tuples.sort(([prop1, v1], [prop2, v2]) => prop1.localeCompare(prop2));
   return tuples;
 }
 
 function copyRawDataToClipboard(button) {
   if (button)
     button.disabled = true;
   try {
     Troubleshoot.snapshot(function (snapshot) {
--- a/toolkit/content/aboutTelemetry.js
+++ b/toolkit/content/aboutTelemetry.js
@@ -562,17 +562,17 @@ let Histogram = {
   /**
    * Unpacks histogram values
    *
    * @param aHgram Packed histogram
    *
    * @return Unpacked histogram representation
    */
   unpack: function Histogram_unpack(aHgram) {
-    let sample_count = aHgram.counts.reduceRight(function (a, b) a + b);
+    let sample_count = aHgram.counts.reduceRight((a, b) => a + b);
     let buckets = [0, 1];
     if (aHgram.histogram_type != Telemetry.HISTOGRAM_BOOLEAN) {
       buckets = aHgram.ranges;
     }
 
     let average =  Math.round(aHgram.sum * 10 / sample_count) / 10;
     let max_value = Math.max.apply(Math, aHgram.counts);
 
@@ -959,31 +959,29 @@ function setupListeners() {
   }, false);
 
   document.getElementById("late-writes-hide-symbols").addEventListener("click",
     function () {
       let ping = TelemetryPing.getPayload();
       LateWritesSingleton.renderLateWrites(ping.lateWrites);
   }, false);
 
-
   // Clicking on the section name will toggle its state
   let sectionHeaders = document.getElementsByClassName("section-name");
   for (let sectionHeader of sectionHeaders) {
     sectionHeader.addEventListener("click", toggleSection, false);
   }
 
   // Clicking on the "toggle" text will also toggle section's state
   let toggleLinks = document.getElementsByClassName("toggle-caption");
   for (let toggleLink of toggleLinks) {
     toggleLink.addEventListener("click", toggleSection, false);
   }
 }
 
-
 function onLoad() {
   window.removeEventListener("load", onLoad);
 
   // Set the text in the page header
   setupPageHeader();
 
   // Set up event listeners
   setupListeners();
--- a/toolkit/crashreporter/client/crashreporter_win.cpp
+++ b/toolkit/crashreporter/client/crashreporter_win.cpp
@@ -1434,29 +1434,23 @@ bool UIDeleteFile(const string& oldfile)
 {
   return DeleteFile(UTF8ToWide(oldfile).c_str()) == TRUE;
 }
 
 ifstream* UIOpenRead(const string& filename)
 {
   // adapted from breakpad's src/common/windows/http_upload.cc
 
-  // The "open" method on pre-MSVC8 ifstream implementations doesn't accept a
-  // wchar_t* filename, so use _wfopen directly in that case.  For VC8 and
-  // later, _wfopen has been deprecated in favor of _wfopen_s, which does
-  // not exist in earlier versions, so let the ifstream open the file itself.
-#if _MSC_VER >= 1400  // MSVC 2005/8
+#if defined(_MSC_VER)
   ifstream* file = new ifstream();
   file->open(UTF8ToWide(filename).c_str(), ios::in);
-#elif defined(_MSC_VER)
-  ifstream* file = new ifstream(_wfopen(UTF8ToWide(filename).c_str(), L"r"));
 #else   // GCC
   ifstream* file = new ifstream(WideToMBCP(UTF8ToWide(filename), CP_ACP).c_str(),
                                 ios::in);
-#endif  // _MSC_VER >= 1400
+#endif  // _MSC_VER
 
   return file;
 }
 
 ofstream* UIOpenWrite(const string& filename,
                       bool append, // append=false
                       bool binary) // binary=false
 {
@@ -1464,28 +1458,23 @@ ofstream* UIOpenWrite(const string& file
   std::ios_base::openmode mode = ios::out;
   if (append) {
     mode = mode | ios::app;
   }
   if (binary) {
     mode = mode | ios::binary;
   }
 
-  // For VC8 and later, _wfopen has been deprecated in favor of _wfopen_s,
-  // which does not exist in earlier versions, so let the ifstream open the
-  // file itself.
-#if _MSC_VER >= 1400  // MSVC 2005/8
+#if defined(_MSC_VER)
   ofstream* file = new ofstream();
   file->open(UTF8ToWide(filename).c_str(), mode);
-#elif defined(_MSC_VER)
-#error "Compiling with your version of MSVC is no longer supported."
 #else   // GCC
   ofstream* file = new ofstream(WideToMBCP(UTF8ToWide(filename), CP_ACP).c_str(),
                                 mode);
-#endif  // _MSC_VER >= 1400
+#endif  // _MSC_VER
 
   return file;
 }
 
 struct FileData
 {
   FILETIME timestamp;
   wstring path;
--- a/toolkit/devtools/server/protocol.js
+++ b/toolkit/devtools/server/protocol.js
@@ -992,17 +992,17 @@ let actorProto = function(actorProto) {
   actorProto.requestTypes = Object.create(null);
   protoSpec.methods.forEach(spec => {
     let handler = function(packet, conn) {
       try {
         let args;
         try {
           args = spec.request.read(packet, this);
         } catch(ex) {
-          console.error("Error writing request: " + packet.type);
+          console.error("Error reading request: " + packet.type);
           throw ex;
         }
 
         let ret = this[spec.name].apply(this, args);
 
         let sendReturn = (ret) => {
           if (spec.oneway) {
             // No need to send a response.
--- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm
+++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm
@@ -76,20 +76,19 @@ this.ForgetAboutSite = {
              getService(Ci.nsICookieManager2);
     let enumerator = cm.getCookiesFromHost(aDomain);
     while (enumerator.hasMoreElements()) {
       let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
       cm.remove(cookie.host, cookie.name, cookie.path, false);
     }
 
     // EME
-    let (mps = Cc["@mozilla.org/gecko-media-plugin-service;1"].
-               getService(Ci.mozIGeckoMediaPluginService)) {
-      mps.forgetThisSite(aDomain);
-    }
+    let mps = Cc["@mozilla.org/gecko-media-plugin-service;1"].
+               getService(Ci.mozIGeckoMediaPluginService);
+    mps.forgetThisSite(aDomain);
 
     // Plugin data
     const phInterface = Ci.nsIPluginHost;
     const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
     let ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface);
     let tags = ph.getPluginTags();
     for (let i = 0; i < tags.length; i++) {
       try {
@@ -104,17 +103,17 @@ this.ForgetAboutSite = {
     try {
       // This method throws an exception if the old Download Manager is disabled.
       Services.downloads.activeDownloadCount;
     } catch (ex) {
       useJSTransfer = true;
     }
 
     if (useJSTransfer) {
-      Task.spawn(function() {
+      Task.spawn(function*() {
         let list = yield Downloads.getList(Downloads.ALL);
         list.removeFinished(download => hasRootDomain(
              NetUtil.newURI(download.source.url).host, aDomain));
       }).then(null, Cu.reportError);
     }
     else {
       let dm = Cc["@mozilla.org/download-manager;1"].
                getService(Ci.nsIDownloadManager);
--- a/toolkit/mozapps/installer/upload-files.mk
+++ b/toolkit/mozapps/installer/upload-files.mk
@@ -61,24 +61,16 @@ endif
 
 # JavaScript Shell packaging
 ifndef LIBXUL_SDK
 JSSHELL_BINS  = \
   $(DIST)/bin/js$(BIN_SUFFIX) \
   $(DIST)/bin/$(DLL_PREFIX)mozglue$(DLL_SUFFIX) \
   $(NULL)
 ifndef MOZ_NATIVE_NSPR
-ifeq ($(_MSC_VER),1600)
-JSSHELL_BINS += $(DIST)/bin/msvcr100.dll
-JSSHELL_BINS += $(DIST)/bin/msvcp100.dll
-endif
-ifeq ($(_MSC_VER),1700)
-JSSHELL_BINS += $(DIST)/bin/msvcr110.dll
-JSSHELL_BINS += $(DIST)/bin/msvcp110.dll
-endif
 ifeq ($(_MSC_VER),1800)
 JSSHELL_BINS += $(DIST)/bin/msvcr120.dll
 JSSHELL_BINS += $(DIST)/bin/msvcp120.dll
 endif
 ifdef MOZ_FOLD_LIBS
 JSSHELL_BINS += $(DIST)/bin/$(DLL_PREFIX)nss3$(DLL_SUFFIX)
 else
 JSSHELL_BINS += \
--- a/toolkit/xre/WindowsCrtPatch.h
+++ b/toolkit/xre/WindowsCrtPatch.h
@@ -122,21 +122,17 @@ Init()
   // catch breakage faster.
   //
   // If these assertions fail, see the comment at the top of this file for
   // possible causes. Any changes to the lines below MUST be tested on XP SP2!
   MOZ_ASSERT(!GetModuleHandleA("mozglue.dll"));
   MOZ_ASSERT(!GetModuleHandleA("msvcr120.dll"));
   MOZ_ASSERT(!GetModuleHandleA("msvcr120d.dll"));
 
-  // Temporary until we fully switch over to VS 2013:
-  MOZ_ASSERT(!GetModuleHandleA("msvcr100.dll"));
-  MOZ_ASSERT(!GetModuleHandleA("msvcr100d.dll"));
-
-#if defined(_M_IX86) && defined(_MSC_VER) && _MSC_VER >= 1800
+#if defined(_M_IX86) && defined(_MSC_VER)
   if (!mozilla::IsXPSP3OrLater()) {
     NtdllIntercept.Init("ntdll.dll");
     NtdllIntercept.AddHook("RtlImageNtHeader",
                            reinterpret_cast<intptr_t>(patched_RtlImageNtHeader),
                            reinterpret_cast<void**>(&stub_RtlImageNtHeader));
   }
 #endif
 }
--- a/tools/profiler/platform-win32.cc
+++ b/tools/profiler/platform-win32.cc
@@ -184,17 +184,23 @@ class SamplerThread : public Thread {
 
     // Unique Set Size is not supported on Windows.
     sample->ussMemory = 0;
 
     static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
     if (SuspendThread(profiled_thread) == kSuspendFailed)
       return;
 
+    // CONTEXT_CONTROL is faster but we can't use it on 64-bit because it
+    // causes crashes in RtlVirtualUnwind (see bug 1120126).
+#if V8_HOST_ARCH_X64
+    context.ContextFlags = CONTEXT_FULL;
+#else
     context.ContextFlags = CONTEXT_CONTROL;
+#endif
     if (GetThreadContext(profiled_thread, &context) != 0) {
 #if V8_HOST_ARCH_X64
       sample->pc = reinterpret_cast<Address>(context.Rip);
       sample->sp = reinterpret_cast<Address>(context.Rsp);
       sample->fp = reinterpret_cast<Address>(context.Rbp);
 #else
       sample->pc = reinterpret_cast<Address>(context.Eip);
       sample->sp = reinterpret_cast<Address>(context.Esp);
--- a/uriloader/exthandler/tests/unit_ipc/test_encoding.js
+++ b/uriloader/exthandler/tests/unit_ipc/test_encoding.js
@@ -103,16 +103,18 @@ registerTemporaryComponent(DownloadMgrUI
 registerTemporaryComponent(AlertsSVC);
 
 function initChildTestEnv()
 {
   sendCommand('                                                                \
     const Cc = Components.classes;                                             \
     const Ci = Components.interfaces;                                          \
     const Cr = Components.results;                                             \
+    const Cu = Components.utils;                                               \
+    Cu.import("resource://gre/modules/Services.jsm");                          \
     function WindowContext() { }                                               \
                                                                                \
     WindowContext.prototype = {                                                \
       getInterface: function (iid) {                                           \
         if (iid.equals(Ci.nsIInterfaceRequestor) ||                            \
             iid.equals(Ci.nsIURIContentListener) ||                            \
             iid.equals(Ci.nsILoadGroup) ||                                     \
             iid.equals(Ci.nsIDocumentLoader) ||                                \
--- a/widget/VsyncDispatcher.h
+++ b/widget/VsyncDispatcher.h
@@ -35,21 +35,16 @@ protected:
 class CompositorVsyncDispatcher MOZ_FINAL
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorVsyncDispatcher)
 
 public:
   CompositorVsyncDispatcher();
 
   // Called on the vsync thread when a hardware vsync occurs
-  // The aVsyncTimestamp can mean different things depending on the platform:
-  // b2g - The vsync timestamp of the previous frame that was just displayed
-  // OSX - The vsync timestamp of the upcoming frame
-  // TODO: Windows / Linux. DOCUMENT THIS WHEN IMPLEMENTING ON THOSE PLATFORMS
-  // Android: TODO
   void NotifyVsync(TimeStamp aVsyncTimestamp);
 
   // Compositor vsync observers must be added/removed on the compositor thread
   void SetCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
   void Shutdown();
 
 private:
   virtual ~CompositorVsyncDispatcher();
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -118,16 +118,18 @@ extern "C" {
   
 #include "nsShmImage.h"
 
 #include "nsIDOMWheelEvent.h"
 
 #include "NativeKeyBindings.h"
 #include "nsWindow.h"
 
+#include "mozilla/layers/APZCTreeManager.h"
+
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::widget;
 using namespace mozilla::layers;
 using mozilla::gl::GLContext;
 
 // Don't put more than this many rects in the dirty region, just fluff
 // out to the bounding-box if there are more
@@ -3151,18 +3153,29 @@ nsWindow::OnScrollEvent(GdkEventScroll *
         wheelEvent.refPoint = point -
             LayoutDeviceIntPoint::FromUntyped(WidgetToScreenOffset());
     }
 
     KeymapWrapper::InitInputEvent(wheelEvent, aEvent->state);
 
     wheelEvent.time = aEvent->time;
 
-    nsEventStatus status;
-    DispatchEvent(&wheelEvent, status);
+    if (mAPZC) {
+        uint64_t inputBlockId = 0;
+        ScrollableLayerGuid guid;
+
+        nsEventStatus result = mAPZC->ReceiveInputEvent(*wheelEvent.AsWheelEvent(), &guid, &inputBlockId);
+        if (result == nsEventStatus_eConsumeNoDefault) {
+            return;
+        }
+        DispatchEventForAPZ(&wheelEvent, guid, inputBlockId);
+    } else {
+        nsEventStatus status;
+        DispatchEvent(&wheelEvent, status);
+    }
 }
 
 void
 nsWindow::OnVisibilityNotifyEvent(GdkEventVisibility *aEvent)
 {
     LOGDRAW(("Visibility event %i on [%p] %p\n",
              aEvent->state, this, aEvent->window));
 
--- a/xpcom/threads/BackgroundHangMonitor.cpp
+++ b/xpcom/threads/BackgroundHangMonitor.cpp
@@ -508,30 +508,36 @@ void
 BackgroundHangMonitor::NotifyActivity()
 {
 #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
   if (mThread == nullptr) {
     MOZ_ASSERT(BackgroundHangManager::sProhibited,
                "This thread is not initialized for hang monitoring");
     return;
   }
-  mThread->NotifyActivity();
+
+  if (Telemetry::CanRecord()) {
+    mThread->NotifyActivity();
+  }
 #endif
 }
 
 void
 BackgroundHangMonitor::NotifyWait()
 {
 #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
   if (mThread == nullptr) {
     MOZ_ASSERT(BackgroundHangManager::sProhibited,
                "This thread is not initialized for hang monitoring");
     return;
   }
-  mThread->NotifyWait();
+
+  if (Telemetry::CanRecord()) {
+    mThread->NotifyWait();
+  }
 #endif
 }
 
 void
 BackgroundHangMonitor::Prohibit()
 {
 #ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR
   MOZ_ASSERT(BackgroundHangManager::sInstance == nullptr,