merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 25 Feb 2015 12:05:55 +0100
changeset 230638 6608e0605dfcaf9666011a22a9ecf4e76f743e49
parent 230584 07c04d7a483a287ca02ef0c048d7c887716d62b4 (current diff)
parent 230637 9d4ffa427cf81879df56459a0c5194857b32097f (diff)
child 230659 9c8c249134b56a5269447bb9a335384197f563a9
child 230724 900075e013be8999585cbb6362d77502b9343a42
child 230800 8edbdb8ca8925797da80e71bd1da55e628922ef3
push id28332
push usercbook@mozilla.com
push dateWed, 25 Feb 2015 11:06:35 +0000
treeherdermozilla-central@6608e0605dfc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone39.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
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -143,16 +143,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource:///modules/FormValidationHandler.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "WebChannel",
                                   "resource://gre/modules/WebChannel.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ReaderParent",
                                   "resource:///modules/ReaderParent.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "AddonWatcher",
+                                  "resource://gre/modules/AddonWatcher.jsm");
+
 const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
 const PREF_PLUGINS_UPDATEURL  = "plugins.update.url";
 
 // Seconds of idle before trying to create a bookmarks backup.
 const BOOKMARKS_BACKUP_IDLE_TIME_SEC = 8 * 60;
 // Minimum interval between backups.  We try to not create more than one backup
 // per interval.
 const BOOKMARKS_BACKUP_MIN_INTERVAL_DAYS = 1;
@@ -582,16 +585,86 @@ BrowserGlue.prototype = {
   },
 
   _onAppDefaults: function BG__onAppDefaults() {
     // apply distribution customizations (prefs)
     // other customizations are applied in _finalUIStartup()
     this._distributionCustomizer.applyPrefDefaults();
   },
 
+  _notifySlowAddon: function BG_notifySlowAddon(addonId) {
+    let addonCallback = function(addon) {
+      if (!addon) {
+        Cu.reportError("couldn't look up addon: " + addonId);
+        return;
+      }
+      let win = RecentWindow.getMostRecentBrowserWindow();
+
+      if (!win) {
+        return;
+      }
+
+      let brandBundle = win.document.getElementById("bundle_brand");
+      let brandShortName = brandBundle.getString("brandShortName");
+      let message = win.gNavigatorBundle.getFormattedString("addonwatch.slow", [addon.name, brandShortName]);
+      let notificationBox = win.document.getElementById("global-notificationbox");
+      let notificationId = 'addon-slow:' + addonId;
+      let notification = notificationBox.getNotificationWithValue(notificationId);
+      if(notification) {
+        notification.label = message;
+      } else {
+        let buttons = [
+          {
+            label: win.gNavigatorBundle.getFormattedString("addonwatch.disable.label", [addon.name]),
+            accessKey: win.gNavigatorBundle.getString("addonwatch.disable.accesskey"),
+            callback: function() {
+              addon.userDisabled = true;
+              if (addon.pendingOperations != addon.PENDING_NONE) {
+                let restartMessage = win.gNavigatorBundle.getFormattedString("addonwatch.restart.message", [addon.name, brandShortName]);
+                let restartButton = [
+                  {
+                    label: win.gNavigatorBundle.getFormattedString("addonwatch.restart.label", [brandShortName]),
+                    accessKey: win.gNavigatorBundle.getString("addonwatch.restart.accesskey"),
+                    callback: function() {
+                      let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
+                        .getService(Ci.nsIAppStartup);
+                      appStartup.quit(appStartup.eForceQuit | appStartup.eRestart);
+                    }
+                  }
+                ];
+                const priority = notificationBox.PRIORITY_WARNING_MEDIUM;
+                notificationBox.appendNotification(restartMessage, "restart-" + addonId, "",
+                                                   priority, restartButton);
+              }
+            }
+          },
+          {
+            label: win.gNavigatorBundle.getString("addonwatch.ignoreSession.label"),
+            accessKey: win.gNavigatorBundle.getString("addonwatch.ignoreSession.accesskey"),
+            callback: function() {
+              AddonWatcher.ignoreAddonForSession(addonId);
+            }
+          },
+          {
+            label: win.gNavigatorBundle.getString("addonwatch.ignorePerm.label"),
+            accessKey: win.gNavigatorBundle.getString("addonwatch.ignorePerm.accesskey"),
+            callback: function() {
+              AddonWatcher.ignoreAddonPermanently(addonId);
+            }
+          },
+        ];
+
+        const priority = notificationBox.PRIORITY_WARNING_MEDIUM;
+        notificationBox.appendNotification(message, notificationId, "",
+                                             priority, buttons);
+      }
+    };
+    AddonManager.getAddonByID(addonId, addonCallback);
+  },
+
   // runs on startup, before the first command line handler is invoked
   // (i.e. before the first window is opened)
   _finalUIStartup: function BG__finalUIStartup() {
     this._sanitizer.onStartup();
     // check if we're in safe mode
     if (Services.appinfo.inSafeMode) {
       Services.ww.openWindow(null, "chrome://browser/content/safeMode.xul", 
                              "_blank", "chrome,centerscreen,modal,resizable=no", null);
@@ -637,16 +710,18 @@ BrowserGlue.prototype = {
 #endif
 
 #ifdef MOZ_DEBUG_UA
     UserAgentOverrides.init();
     DebugUserAgent.init();
 #endif
 
     Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
+
+    AddonWatcher.init(this._notifySlowAddon);
   },
 
   _checkForOldBuildUpdates: function () {
     // check for update if our build is old
     if (Services.prefs.getBoolPref("app.update.enabled") &&
         Services.prefs.getBoolPref("app.update.checkInstallTime")) {
 
       let buildID = Services.appinfo.appBuildID;
@@ -902,16 +977,17 @@ BrowserGlue.prototype = {
       SignInToWebsiteUX.uninit();
     }
 #endif
 #ifdef MOZ_DEBUG_UA
     UserAgentOverrides.uninit();
 #endif
     webrtcUI.uninit();
     FormValidationHandler.uninit();
+    AddonWatcher.uninit();
   },
 
   _initServiceDiscovery: function () {
     var rokuDevice = {
       id: "roku:ecp",
       target: "roku:ecp",
       factory: function(aService) {
         Cu.import("resource://gre/modules/RokuApp.jsm");
--- a/browser/devtools/debugger/test/browser.ini
+++ b/browser/devtools/debugger/test/browser.ini
@@ -98,81 +98,55 @@ support-files =
   doc_with-frame.html
   head.js
   sjs_random-javascript.sjs
   testactors.js
 
 [browser_dbg_aaa_run_first_leaktest.js]
 skip-if = e10s && debug
 [browser_dbg_addonactor.js]
-skip-if = e10s && debug
 [browser_dbg_addon-sources.js]
-skip-if = e10s && debug
 [browser_dbg_addon-modules.js]
 skip-if = e10s # TODO
 [browser_dbg_addon-modules-unpacked.js]
 skip-if = e10s # TODO
 [browser_dbg_addon-panels.js]
-skip-if = e10s && debug
 [browser_dbg_addon-console.js]
 skip-if = e10s && debug || os == 'win' # bug 1005274
 [browser_dbg_auto-pretty-print-01.js]
-skip-if = e10s && debug
 [browser_dbg_auto-pretty-print-02.js]
-skip-if = e10s && debug
 [browser_dbg_bfcache.js]
 skip-if = e10s || true # bug 1113935
 [browser_dbg_blackboxing-01.js]
-skip-if = e10s && debug
 [browser_dbg_blackboxing-02.js]
-skip-if = e10s && debug
 [browser_dbg_blackboxing-03.js]
-skip-if = e10s && debug
 [browser_dbg_blackboxing-04.js]
-skip-if = e10s && debug
 [browser_dbg_blackboxing-05.js]
-skip-if = e10s && debug
 [browser_dbg_blackboxing-06.js]
-skip-if = e10s && debug
 [browser_dbg_breadcrumbs-access.js]
-skip-if = e10s && debug
 [browser_dbg_break-on-dom-01.js]
-skip-if = e10s && debug
 [browser_dbg_break-on-dom-02.js]
-skip-if = e10s && debug
 [browser_dbg_break-on-dom-03.js]
-skip-if = e10s && debug
 [browser_dbg_break-on-dom-04.js]
-skip-if = e10s && debug
 [browser_dbg_break-on-dom-05.js]
-skip-if = e10s && debug
 [browser_dbg_break-on-dom-06.js]
-skip-if = e10s && debug
 [browser_dbg_break-on-dom-07.js]
-skip-if = e10s && debug
 [browser_dbg_break-on-dom-08.js]
-skip-if = e10s && debug
 [browser_dbg_break-on-dom-event-01.js]
 skip-if = e10s || os == "mac" || e10s # Bug 895426
 [browser_dbg_break-on-dom-event-02.js]
 skip-if = e10s # TODO
 [browser_dbg_breakpoints-actual-location.js]
-skip-if = e10s && debug
 [browser_dbg_breakpoints-actual-location2.js]
-skip-if = e10s && debug
 [browser_dbg_breakpoints-break-on-last-line-of-script-on-reload.js]
 skip-if = e10s # Bug 1093535
 [browser_dbg_breakpoints-button-01.js]
-skip-if = e10s && debug
 [browser_dbg_breakpoints-button-02.js]
-skip-if = e10s && debug
 [browser_dbg_breakpoints-contextmenu-add.js]
-skip-if = e10s && debug
 [browser_dbg_breakpoints-contextmenu.js]
-skip-if = e10s && debug
 [browser_dbg_breakpoints-disabled-reload.js]
 skip-if = e10s # Bug 1093535
 [browser_dbg_breakpoints-editor.js]
 skip-if = e10s && debug
 [browser_dbg_breakpoints-eval.js]
 skip-if = e10s && debug
 [browser_dbg_breakpoints-highlight.js]
 skip-if = e10s && debug
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -35,16 +35,27 @@ xpinstallDisabledButton.accesskey=n
 # http://developer.mozilla.org/en/docs/Localization_and_Plurals
 # Also see https://bugzilla.mozilla.org/show_bug.cgi?id=570012 for mockups
 addonDownloading=Add-on downloading;Add-ons downloading
 addonDownloadCancelled=Add-on download cancelled.;Add-on downloads cancelled.
 addonDownloadRestart=Restart Download;Restart Downloads
 addonDownloadRestart.accessKey=R
 addonDownloadCancelTooltip=Cancel
 
+addonwatch.slow=%1$S might be making %2$S run slowly
+addonwatch.disable.label=Disable %S
+addonwatch.disable.accesskey=D
+addonwatch.ignoreSession.label=Ignore for now
+addonwatch.ignoreSession.accesskey=I
+addonwatch.ignorePerm.label=Ignore permanently
+addonwatch.ignorePerm.accesskey=p
+addonwatch.restart.message=To disable %1$S you must restart %2$S
+addonwatch.restart.label=Restart %S
+addonwatch.restart.accesskey=R
+
 # LOCALIZATION NOTE (addonsInstalled, addonsInstalledNeedsRestart):
 # Semicolon-separated list of plural forms. See:
 # http://developer.mozilla.org/en/docs/Localization_and_Plurals
 # #1 first add-on's name, #2 number of add-ons, #3 application name
 addonsInstalled=#1 has been installed successfully.;#2 add-ons have been installed successfully.
 addonsInstalledNeedsRestart=#1 will be installed after you restart #3.;#2 add-ons will be installed after you restart #3.
 addonInstallRestartButton=Restart Now
 addonInstallRestartButton.accesskey=R
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -37,55 +37,56 @@ ifdef MOZ_INCLUDE_SOURCE_INFO
 source_repo ?= $(call getSourceRepo,$(topsrcdir)/$(MOZ_BUILD_APP)/..)
 ifneq (,$(source_repo))
   DEFINES += -DMOZ_SOURCE_REPO='$(source_repo)'
 endif
 endif
 
 endif
 
-# Put a useful .gdbinit in the bin directory, to be picked up automatically
-# by GDB when we debug executables there.
 # NOTE: Keep .gdbinit in the topsrcdir for people who run gdb from the topsrcdir.
-GDBINIT_FILES := $(topsrcdir)/.gdbinit
+# needs to be absolute to be distinct from $(topsrcdir)/.gdbinit
 GDBINIT_OBJDIR_FILES = $(topsrcdir)/.gdbinit
-GDBINIT_DEST = $(FINAL_TARGET)
-
-# needs to be absolute to be distinct from $(topsrcdir)/.gdbinit
 GDBINIT_OBJDIR_DEST = $(abspath $(DEPTH))
-INSTALL_TARGETS += GDBINIT GDBINIT_OBJDIR
+INSTALL_TARGETS += GDBINIT_OBJDIR
 
 # Put a .lldbinit in the bin directory and the objdir, to be picked up
 # automatically by LLDB when we debug executables using either of those two
 # directories as the current working directory.  The .lldbinit file will
 # load $(topsrcdir)/.lldbinit, which is where the actual debugging commands are.
 LLDBINIT_OBJDIR := .lldbinit.in
 LLDBINIT_OBJDIR_PATH = $(DEPTH)
 LLDBINIT_OBJDIR_FLAGS += -Dtopsrcdir=$(abspath $(topsrcdir))
 PP_TARGETS += LLDBINIT_OBJDIR
 
 LLDBINIT_FINAL_TARGET_FILES := $(DEPTH)/.lldbinit
 LLDBINIT_FINAL_TARGET_DEST = $(FINAL_TARGET)
 INSTALL_TARGETS += LLDBINIT_FINAL_TARGET
 
-ifeq (1_1,$(MOZ_ASAN)_$(CLANG_CL))
-# Install the clang-cl runtime library for ASAN next to the binaries we produce.
-CLANG_RT_ASAN_FILES := $(MOZ_CLANG_RT_ASAN_LIB_PATH)
-CLANG_RT_ASAN_DEST = $(FINAL_TARGET)
-INSTALL_TARGETS += CLANG_RT_ASAN
-endif
-
 ifdef MOZTTDIR
 # Install the Firefox OS fonts.
 include $(MOZTTDIR)/fonts.mk
 MOZTT_DEST = $(FINAL_TARGET)/fonts
 MOZTT_FILES = $(patsubst external/moztt/%,$(MOZTTDIR)/%,$(filter external/moztt/%,$(subst :, ,$(PRODUCT_COPY_FILES))))
 INSTALL_TARGETS += MOZTT
 endif
 
+ifdef MOZ_VALGRIND
+_VALGRIND_DIR = $(DEPTH)/_valgrind
+GARBAGE_DIRS += $(_VALGRIND_DIR)
+
+_VALGRIND_FILES = \
+		$(topsrcdir)/build/valgrind/cross-architecture.sup \
+		$(topsrcdir)/build/valgrind/i386-redhat-linux-gnu.sup \
+		$(topsrcdir)/build/valgrind/x86_64-redhat-linux-gnu.sup \
+		$(NULL)
+_VALGRIND_DEST = $(_VALGRIND_DIR)
+INSTALL_TARGETS += _VALGRIND
+endif
+
 include $(topsrcdir)/config/rules.mk
 
 TARGET_DEPTH = ..
 include $(srcdir)/automation-build.mk
 
 ifdef MOZ_APP_BASENAME
 $(FINAL_TARGET)/application.ini: $(APP_INI_DEPS)
 
@@ -94,46 +95,11 @@ application.ini.h: appini_header.py $(FI
 	$(PYTHON) $^ > $@
 export:: application.ini.h
 GARBAGE += application.ini.h
 endif
 endif
 
 libs:: automation.py
 
-ifdef MOZ_VALGRIND
-_VALGRIND_DIR = $(DEPTH)/_valgrind
-GARBAGE_DIRS += $(_VALGRIND_DIR)
-
-_VALGRIND_FILES = \
-		$(topsrcdir)/build/valgrind/cross-architecture.sup \
-		$(topsrcdir)/build/valgrind/i386-redhat-linux-gnu.sup \
-		$(topsrcdir)/build/valgrind/x86_64-redhat-linux-gnu.sup \
-		$(NULL)
-
-libs:: $(_VALGRIND_FILES)
-	$(INSTALL) $^ $(_VALGRIND_DIR)
-endif
-
-ifneq (,$(ENABLE_TESTS)$(MOZ_DMD))
-libs:: $(topsrcdir)/tools/rb/fix_stack_using_bpsyms.py
-	$(INSTALL) $< $(DIST)/bin
-
-ifeq ($(OS_ARCH),Darwin)
-libs:: $(topsrcdir)/tools/rb/fix_macosx_stack.py
-	$(INSTALL) $< $(DIST)/bin
-endif
-
-ifeq ($(OS_ARCH),Linux)
-libs:: $(topsrcdir)/tools/rb/fix_linux_stack.py
-	$(INSTALL) $< $(DIST)/bin
-endif
-endif # ENABLE_TESTS or MOZ_DMD
-
 ifdef ENABLE_TESTS
 GARBAGE += $(srcdir)/automationutils.pyc
 endif # ENABLE_TESTS
-
-ifdef MOZ_DMD
-libs:: $(topsrcdir)/memory/replace/dmd/dmd.py
-	$(INSTALL) $< $(DIST)/bin
-endif
-
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -440,27 +440,28 @@ class ShutdownLeaks(object):
   """
 
   def __init__(self, logger):
     self.logger = logger
     self.tests = []
     self.leakedWindows = {}
     self.leakedDocShells = set()
     self.currentTest = None
-    self.seenShutdown = False
+    self.seenShutdown = set()
 
   def log(self, message):
     if message['action'] == 'log':
         line = message['message']
         if line[2:11] == "DOMWINDOW":
           self._logWindow(line)
         elif line[2:10] == "DOCSHELL":
           self._logDocShell(line)
-        elif line.startswith("TEST-START | Shutdown"):
-          self.seenShutdown = True
+        elif line.startswith("Completed ShutdownLeaks collections in process"):
+          pid = int(line.split()[-1])
+          self.seenShutdown.add(pid)
     elif message['action'] == 'test_start':
       fileName = message['test'].replace("chrome://mochitests/content/browser/", "")
       self.currentTest = {"fileName": fileName, "windows": set(), "docShells": set()}
     elif message['action'] == 'test_end':
       # don't track a test if no windows or docShells leaked
       if self.currentTest and (self.currentTest["windows"] or self.currentTest["docShells"]):
         self.tests.append(self.currentTest)
       self.currentTest = None
@@ -494,17 +495,17 @@ class ShutdownLeaks(object):
     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:
+    elif int(pid) in self.seenShutdown and not created:
       self.leakedWindows[key] = self._parseValue(line, "url")
 
   def _logDocShell(self, line):
     created = line[:2] == "++"
     pid = self._parseValue(line, "pid")
     id = self._parseValue(line, "id")
 
     # log line has invalid format
@@ -515,17 +516,17 @@ class ShutdownLeaks(object):
     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:
+    elif int(pid) in self.seenShutdown and not created:
       self.leakedDocShells.add(key)
 
   def _parseValue(self, line, name):
     match = re.search("\[%s = (.+?)\]" % name, line)
     if match:
       return match.group(1)
     return None
 
--- a/build/moz.build
+++ b/build/moz.build
@@ -43,8 +43,27 @@ for var in ('MOZ_CRASHREPORTER', 'MOZ_PR
             'MOZ_APP_STATIC_INI'):
     if CONFIG[var]:
         DEFINES[var] = True
 
 if CONFIG['MOZ_BUILD_APP'] == 'browser':
     PYTHON_UNIT_TESTS += [
         'compare-mozconfig/compare-mozconfigs-wrapper.py',
     ]
+
+if CONFIG['ENABLE_TESTS'] or CONFIG['MOZ_DMD']:
+    tools_dir = TOPSRCDIR + '/tools/rb/'
+    FINAL_TARGET_FILES += [tools_dir + 'fix_stack_using_bpsyms.py']
+    if CONFIG['OS_ARCH'] == 'Darwin':
+        FINAL_TARGET_FILES += [tools_dir + 'fix_macosx_stack.py']
+    if CONFIG['OS_ARCH'] == 'Linux':
+        FINAL_TARGET_FILES += [tools_dir + 'fix_linux_stack.py']
+
+if CONFIG['MOZ_DMD']:
+    FINAL_TARGET_FILES += [TOPSRCDIR + '/memory/replace/dmd/dmd.py']
+
+# Put a useful .gdbinit in the bin directory, to be picked up automatically
+# by GDB when we debug executables there.
+FINAL_TARGET_FILES += [TOPSRCDIR + '/.gdbinit']
+
+# Install the clang-cl runtime library for ASAN next to the binaries we produce.
+if CONFIG['MOZ_ASAN'] and CONFIG['CLANG_CL']:
+    FINAL_TARGET_FILES += [CONFIG['MOZ_CLANG_RT_ASAN_LIB_PATH']]
--- a/caps/moz.build
+++ b/caps/moz.build
@@ -12,16 +12,17 @@ XPIDL_SOURCES += [
     'nsIScriptSecurityManager.idl',
 ]
 
 XPIDL_MODULE = 'caps'
 
 EXPORTS += [
     'nsJSPrincipals.h',
     'nsNullPrincipal.h',
+    'nsNullPrincipalURI.h',
 ]
 
 UNIFIED_SOURCES += [
     'DomainPolicy.cpp',
     'nsJSPrincipals.cpp',
     'nsNullPrincipal.cpp',
     'nsNullPrincipalURI.cpp',
     'nsPrincipal.cpp',
@@ -31,11 +32,13 @@ UNIFIED_SOURCES += [
 
 MSVC_ENABLE_PGO = True
 
 LOCAL_INCLUDES += [
     '/dom/base',
     '/js/xpconnect/src',
 ]
 
+include('/ipc/chromium/chromium-config.mozbuild')
+
 FINAL_LIBRARY = 'xul'
 
 FAIL_ON_WARNINGS = True
--- a/caps/nsNullPrincipal.cpp
+++ b/caps/nsNullPrincipal.cpp
@@ -1,9 +1,10 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 sts=2 ts=2 et 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/. */
 
 /**
  * This is the principal that has no rights and can't be accessed by
  * anything other than itself and chrome; null principals are not
  * same-origin with anything but themselves.
@@ -81,16 +82,34 @@ nsNullPrincipal::CreateWithInheritedAttr
 
 nsresult
 nsNullPrincipal::Init(uint32_t aAppId, bool aInMozBrowser)
 {
   MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
   mAppId = aAppId;
   mInMozBrowser = aInMozBrowser;
 
+  nsCString str;
+  nsresult rv = GenerateNullPrincipalURI(str);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  mURI = new nsNullPrincipalURI(str);
+
+  return NS_OK;
+}
+
+void
+nsNullPrincipal::GetScriptLocation(nsACString &aStr)
+{
+  mURI->GetSpec(aStr);
+}
+
+nsresult
+nsNullPrincipal::GenerateNullPrincipalURI(nsACString &aStr)
+{
   // FIXME: bug 327161 -- make sure the uuid generator is reseeding-resistant.
   nsresult rv;
   nsCOMPtr<nsIUUIDGenerator> uuidgen =
     do_GetService("@mozilla.org/uuid-generator;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsID id;
   rv = uuidgen->GenerateUUIDInPlace(&id);
@@ -99,38 +118,29 @@ nsNullPrincipal::Init(uint32_t aAppId, b
   char chars[NSID_LENGTH];
   id.ToProvidedString(chars);
 
   uint32_t suffixLen = NSID_LENGTH - 1;
   uint32_t prefixLen = ArrayLength(NS_NULLPRINCIPAL_PREFIX) - 1;
 
   // Use an nsCString so we only do the allocation once here and then share
   // with nsJSPrincipals
-  nsCString str;
-  str.SetCapacity(prefixLen + suffixLen);
+  aStr.SetCapacity(prefixLen + suffixLen);
 
-  str.Append(NS_NULLPRINCIPAL_PREFIX);
-  str.Append(chars);
+  aStr.Append(NS_NULLPRINCIPAL_PREFIX);
+  aStr.Append(chars);
 
-  if (str.Length() != prefixLen + suffixLen) {
+  if (aStr.Length() != prefixLen + suffixLen) {
     NS_WARNING("Out of memory allocating null-principal URI");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  mURI = new nsNullPrincipalURI(str);
-
   return NS_OK;
 }
 
-void
-nsNullPrincipal::GetScriptLocation(nsACString &aStr)
-{
-  mURI->GetSpec(aStr);
-}
-
 #ifdef DEBUG
 void nsNullPrincipal::dumpImpl()
 {
   nsAutoCString str;
   mURI->GetSpec(str);
   fprintf(stderr, "nsNullPrincipal (%p) = %s\n", this, str.get());
 }
 #endif 
--- a/caps/nsNullPrincipal.h
+++ b/caps/nsNullPrincipal.h
@@ -26,17 +26,17 @@ class nsIURI;
 #define NS_NULLPRINCIPAL_CONTRACTID "@mozilla.org/nullprincipal;1"
 
 #define NS_NULLPRINCIPAL_SCHEME "moz-nullprincipal"
 
 class nsNullPrincipal MOZ_FINAL : public nsJSPrincipals
 {
 public:
   nsNullPrincipal();
-  
+
   // Our refcount is managed by nsJSPrincipals.  Use this macro to avoid an
   // extra refcount member.
 
   // FIXME: bug 327245 -- I sorta wish there were a clean way to share the
   // nsJSPrincipals munging code between the various principal classes without
   // giving up the NS_DECL_NSIPRINCIPAL goodness.
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIPRINCIPAL
@@ -44,16 +44,18 @@ public:
 
   static already_AddRefed<nsNullPrincipal> CreateWithInheritedAttributes(nsIPrincipal *aInheritFrom);
 
   nsresult Init(uint32_t aAppId = nsIScriptSecurityManager::NO_APP_ID,
                 bool aInMozBrowser = false);
 
   virtual void GetScriptLocation(nsACString &aStr) MOZ_OVERRIDE;
 
+  static nsresult GenerateNullPrincipalURI(nsACString &aStr);
+
 #ifdef DEBUG
   virtual void dumpImpl() MOZ_OVERRIDE;
 #endif 
 
  protected:
   virtual ~nsNullPrincipal();
 
   nsCOMPtr<nsIURI> mURI;
--- a/caps/nsNullPrincipalURI.cpp
+++ b/caps/nsNullPrincipalURI.cpp
@@ -4,25 +4,33 @@
  * 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 "nsNullPrincipalURI.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/MemoryReporting.h"
 
+#include "mozilla/ipc/URIParams.h"
+
 #include "nsNetUtil.h"
 #include "nsEscape.h"
 #include "nsCRT.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 //// nsNullPrincipalURI
 
 nsNullPrincipalURI::nsNullPrincipalURI(const nsCString &aSpec)
 {
+  InitializeFromSpec(aSpec);
+}
+
+void
+nsNullPrincipalURI::InitializeFromSpec(const nsCString &aSpec)
+{
   int32_t dividerPosition = aSpec.FindChar(':');
   NS_ASSERTION(dividerPosition != -1, "Malformed URI!");
 
   mozilla::DebugOnly<int32_t> n = aSpec.Left(mScheme, dividerPosition);
   NS_ASSERTION(n == dividerPosition, "Storing the scheme failed!");
 
   int32_t count = aSpec.Length() - dividerPosition - 1;
   n = aSpec.Mid(mPath, dividerPosition + 1, count);
@@ -39,16 +47,17 @@ NS_IMPL_RELEASE(nsNullPrincipalURI)
 
 NS_INTERFACE_MAP_BEGIN(nsNullPrincipalURI)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIURI)
   if (aIID.Equals(kNullPrincipalURIImplementationCID))
     foundInterface = static_cast<nsIURI *>(this);
   else
   NS_INTERFACE_MAP_ENTRY(nsIURI)
   NS_INTERFACE_MAP_ENTRY(nsISizeOf)
+  NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableURI)
 NS_INTERFACE_MAP_END
 
 ////////////////////////////////////////////////////////////////////////////////
 //// nsIURI
 
 NS_IMETHODIMP
 nsNullPrincipalURI::GetAsciiHost(nsACString &_host)
 {
@@ -268,16 +277,41 @@ nsNullPrincipalURI::Resolve(const nsACSt
 NS_IMETHODIMP
 nsNullPrincipalURI::SchemeIs(const char *aScheme, bool *_schemeIs)
 {
   *_schemeIs = (0 == nsCRT::strcasecmp(mScheme.get(), aScheme));
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+//// nsIIPCSerializableURI
+
+void
+nsNullPrincipalURI::Serialize(mozilla::ipc::URIParams &aParams)
+{
+  aParams = mozilla::ipc::NullPrincipalURIParams();
+}
+
+bool
+nsNullPrincipalURI::Deserialize(const mozilla::ipc::URIParams &aParams)
+{
+  if (aParams.type() != mozilla::ipc::URIParams::TNullPrincipalURIParams) {
+    MOZ_ASSERT_UNREACHABLE("unexpected URIParams type");
+    return false;
+  }
+
+  nsCString str;
+  nsresult rv = nsNullPrincipal::GenerateNullPrincipalURI(str);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  InitializeFromSpec(str);
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
 //// nsISizeOf
 
 size_t
 nsNullPrincipalURI::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   return mScheme.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
          mPath.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
 }
--- a/caps/nsNullPrincipalURI.h
+++ b/caps/nsNullPrincipalURI.h
@@ -11,36 +11,44 @@
 #ifndef __nsNullPrincipalURI_h__
 #define __nsNullPrincipalURI_h__
 
 #include "nsIURI.h"
 #include "nsISizeOf.h"
 #include "nsAutoPtr.h"
 #include "nsString.h"
 #include "mozilla/Attributes.h"
+#include "nsIIPCSerializableURI.h"
 #include "mozilla/MemoryReporting.h"
 
 // {51fcd543-3b52-41f7-b91b-6b54102236e6}
 #define NS_NULLPRINCIPALURI_IMPLEMENTATION_CID \
   {0x51fcd543, 0x3b52, 0x41f7, \
     {0xb9, 0x1b, 0x6b, 0x54, 0x10, 0x22, 0x36, 0xe6} }
 
 class nsNullPrincipalURI MOZ_FINAL : public nsIURI
                                    , public nsISizeOf
+                                   , public nsIIPCSerializableURI
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIURI
+  NS_DECL_NSIIPCSERIALIZABLEURI
 
   // nsISizeOf
   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);
 
+  // NB: This constructor exists only for deserialization.
+  nsNullPrincipalURI() { }
+
 private:
   ~nsNullPrincipalURI() {}
 
+  void InitializeFromSpec(const nsCString &aSpec);
+
   nsCString mScheme;
   nsCString mPath;
 };
 
 #endif // __nsNullPrincipalURI_h__
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -8,34 +8,33 @@
 #
 # The WebIDL interfaces are defined in dom/webidl. For each such interface, there
 # is a corresponding entry in the configuration table below. The configuration
 # table maps each interface name to a |descriptor| or list of |descriptor|s.
 #
 # Valid fields for all descriptors:
 #   * nativeType - The native type (concrete class or XPCOM interface) that
 #                  instances of this interface will unwrap to.  If not
-#                  specified, defaults to 'mozilla::dom::InterfaceName' for
-#                  non-worker non-external-or-callback interfaces, to
+#                  specified, defaults to 'nsIDOM' followed by the interface
+#                  name for external interfaces,
 #                  'mozilla::dom::workers::InterfaceName' for worker
-#                  non-external interfaces, to 'nsIDOM' followed by the
-#                  interface name for non-worker external-or-callback
-#                  interfaces, and to 'JSObject' for worker external-or-callback
-#                  interfaces.
+#                  non-callback interfaces, and 'mozilla::dom::InterfaceName'
+#                  for everything else.
 #   * headerFile - The file in which the nativeType is declared (defaults
 #                  to an educated guess).
 #   * concrete - Indicates whether there exist JS objects with this interface as
 #                their primary interface (and hence whose prototype is this
 #                interface's prototype object).  Always False for callback
 #                interfaces.  Defaults to True otherwise.
 #   * workers - Indicates whether the descriptor is intended to be used solely
 #               for worker threads (defaults to false). If true the interface
 #               will not be made available on the main thread.
 #   * notflattened - The native type does not have nsIClassInfo, so when
 #                    wrapping it the right IID needs to be passed in.
+#                    Only relevant for callback interfaces.
 #   * register - True if this binding should be registered.  Defaults to true.
 #   * binaryNames - Dict for mapping method and attribute names to different
 #                   names when calling the native methods (defaults to an empty
 #                   dict). The keys are the property names as they appear in the
 #                   .webidl file and the values are the names as they should be
 #                   in the WebIDL.
 #   * wrapperCache: True if this object is a wrapper cache.  Objects that are
 #                   not can only be returned from a limited set of methods,
@@ -601,41 +600,33 @@ DOMInterfaces = {
     'nativeType': 'mozilla::dom::indexedDB::IDBTransaction',
 },
 
 'IDBVersionChangeEvent': {
     'nativeType': 'mozilla::dom::indexedDB::IDBVersionChangeEvent',
     'headerFile': 'IDBEvents.h',
 },
 
-'IID': [
-{
+'IID': {
     'nativeType': 'nsIJSID',
     'headerFile': 'xpcjsid.h',
 },
-{
-    'workers': True,
-}],
 
 'ImageCapture': {
     'binaryNames': { 'videoStreamTrack': 'GetVideoStreamTrack' }
 },
 
 'ImageData': {
     'wrapperCache': False,
 },
 
-'InputStream': [
-{
+'InputStream': {
     'nativeType': 'nsIInputStream',
     'notflattened': True
 },
-{
-    'workers': True,
-}],
 
 'InstallEvent': {
     'headerFile': 'ServiceWorkerEvents.h',
     'nativeType': 'mozilla::dom::workers::InstallEvent',
 },
 
 'KeyEvent': {
     'concrete': False
@@ -1479,26 +1470,20 @@ DOMInterfaces = {
 
 'Window': {
     'nativeType': 'nsGlobalWindow',
     'binaryNames': {
         'postMessage': 'postMessageMoz',
     },
 },
 
-'WindowProxy': [
-{
+'WindowProxy': {
     'nativeType': 'nsIDOMWindow',
     'concrete': False
 },
-{
-    # We need a worker descriptor for WindowProxy because EventTarget exists in
-    # workers.  But it's an external interface, so it'll just map to JSObject*.
-    'workers': True
-}],
 
 'WindowRoot': {
     'nativeType': 'nsWindowRoot'
 },
 
 'Worker': {
     'headerFile': 'mozilla/dom/WorkerPrivate.h',
     'nativeType': 'mozilla::dom::workers::WorkerPrivate',
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -376,17 +376,17 @@ class CGDOMJSClass(CGThing):
             },
             JS_NULL_OBJECT_OPS
             """,
             objectMoved=objectMovedHook)
         if self.descriptor.isGlobal():
             classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS) | JSCLASS_IMPLEMENTS_BARRIERS"
             traceHook = "JS_GlobalObjectTraceHook"
             reservedSlots = "JSCLASS_GLOBAL_APPLICATION_SLOTS"
-            if not self.descriptor.workers:
+            if self.descriptor.interface.identifier.name == "Window":
                 classExtensionAndObjectOps = fill(
                     """
                     {
                       nsGlobalWindow::OuterObject, /* outerObject */
                       nullptr, /* innerObject */
                       false,   /* isWrappedNative */
                       nullptr, /* weakmapKeyDelegateOp */
                       ${objectMoved} /* objectMovedOp */
@@ -4630,20 +4630,17 @@ def getJSToNativeConversionInfo(type, de
                                         dealWithOptional=isOptional and (not nullable or isOwningUnion))
 
     if type.isGeckoInterface():
         assert not isEnforceRange and not isClamp
 
         descriptor = descriptorProvider.getDescriptor(
             type.unroll().inner.identifier.name)
 
-        if descriptor.nativeType == 'JSObject':
-            # XXXbz Workers code does this sometimes
-            assert descriptor.workers
-            return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
+        assert descriptor.nativeType != 'JSObject'
 
         if descriptor.interface.isCallback():
             name = descriptor.interface.identifier.name
             if type.nullable() or isCallbackReturnValue:
                 declType = CGGeneric("nsRefPtr<%s>" % name)
             else:
                 declType = CGGeneric("OwningNonNull<%s>" % name)
             conversion = indent(CGCallbackTempRoot(name).define())
@@ -4710,19 +4707,20 @@ def getJSToNativeConversionInfo(type, de
             else:
                 templateBody += str(FailureFatalCastableObjectUnwrapper(
                     descriptor,
                     "&${val}.toObject()",
                     "${declName}",
                     exceptionCode,
                     isCallbackReturnValue,
                     firstCap(sourceDescription)))
-        elif descriptor.workers:
-            return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
-        else:
+        else:
+            # Worker descriptors can't end up here, because all of our
+            # "external" stuff is not exposed in workers.
+            assert not descriptor.workers
             # Either external, or new-binding non-castable.  We always have a
             # holder for these, because we don't actually know whether we have
             # to addref when unwrapping or not.  So we just pass an
             # getter_AddRefs(nsRefPtr) to XPConnect and if we'll need a release
             # it'll put a non-null pointer in there.
             if forceOwningType:
                 # Don't return a holderType in this case; our declName
                 # will just own stuff.
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -300,20 +300,18 @@ class Descriptor(DescriptorProvider):
     """
     def __init__(self, config, interface, desc):
         DescriptorProvider.__init__(self, config, desc.get('workers', False))
         self.interface = interface
 
         # Read the desc, and fill in the relevant defaults.
         ifaceName = self.interface.identifier.name
         if self.interface.isExternal():
-            if self.workers:
-                nativeTypeDefault = "JSObject"
-            else:
-                nativeTypeDefault = "nsIDOM" + ifaceName
+            assert not self.workers
+            nativeTypeDefault = "nsIDOM" + ifaceName
         elif self.interface.isCallback():
             nativeTypeDefault = "mozilla::dom::" + ifaceName
         else:
             if self.workers:
                 nativeTypeDefault = "mozilla::dom::workers::" + ifaceName
             else:
                 nativeTypeDefault = "mozilla::dom::" + ifaceName
 
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1847,16 +1847,22 @@ WebGLContext::TexImageFromVideoElement(c
         tex->Bind(TexImageTargetToTexTarget(texImageTarget));
     }
 
     srcImage = nullptr;
     container->UnlockCurrentImage();
     return ok;
 }
 
+size_t mozilla::RoundUpToMultipleOf(size_t value, size_t multiple)
+{
+    size_t overshoot = value + multiple - 1;
+    return overshoot - (overshoot % multiple);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 WebGLContext::ScopedMaskWorkaround::ScopedMaskWorkaround(WebGLContext& webgl)
     : mWebGL(webgl)
     , mNeedsChange(NeedsChange(webgl))
 {
     if (mNeedsChange) {
         mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
@@ -1870,16 +1876,17 @@ WebGLContext::ScopedMaskWorkaround::~Sco
 {
     if (mNeedsChange) {
         mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
                               mWebGL.mColorWriteMask[1],
                               mWebGL.mColorWriteMask[2],
                               mWebGL.mColorWriteMask[3]);
     }
 }
+
 ////////////////////////////////////////////////////////////////////////////////
 // XPCOM goop
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
   mCanvasElement,
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1087,19 +1087,17 @@ protected:
     static CheckedUint32 GetImageSize(GLsizei height, GLsizei width,
                                       GLsizei depth, uint32_t pixelSize,
                                       uint32_t alignment);
 
     virtual JS::Value GetTexParameterInternal(const TexTarget& target,
                                               GLenum pname);
 
     // Returns x rounded to the next highest multiple of y.
-    static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x,
-                                                 CheckedUint32 y)
-    {
+    static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y) {
         return ((x + y - 1) / y) * y;
     }
 
     inline void InvalidateBufferFetching()
     {
         mBufferFetchingIsVerified = false;
         mBufferFetchingHasPerVertex = false;
         mMaxFetchedVertices = 0;
@@ -1688,11 +1686,13 @@ public:
     void UnregisterMemoryPressureEvent();
 
 private:
     ~WebGLObserver();
 
     WebGLContext* mWebGL;
 };
 
+size_t RoundUpToMultipleOf(size_t value, size_t multiple);
+
 } // namespace mozilla
 
 #endif
--- a/dom/canvas/WebGLContextFramebufferOperations.cpp
+++ b/dom/canvas/WebGLContextFramebufferOperations.cpp
@@ -44,41 +44,51 @@ WebGLContext::Clear(GLbitfield mask)
         ScopedMaskWorkaround autoMask(*this);
         gl->fClear(mask);
     }
 
     Invalidate();
     mShouldPresent = true;
 }
 
-static GLclampf
-GLClampFloat(GLclampf val)
+static GLfloat
+GLClampFloat(GLfloat val)
 {
     if (val < 0.0)
         return 0.0;
 
     if (val > 1.0)
         return 1.0;
 
     return val;
 }
 
 void
-WebGLContext::ClearColor(GLclampf r, GLclampf g,
-                             GLclampf b, GLclampf a)
+WebGLContext::ClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
 {
     if (IsContextLost())
         return;
 
     MakeContextCurrent();
-    mColorClearValue[0] = GLClampFloat(r);
-    mColorClearValue[1] = GLClampFloat(g);
-    mColorClearValue[2] = GLClampFloat(b);
-    mColorClearValue[3] = GLClampFloat(a);
+
+    const bool supportsFloatColorBuffers = (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) ||
+                                            IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float));
+    if (!supportsFloatColorBuffers) {
+        r = GLClampFloat(r);
+        g = GLClampFloat(g);
+        b = GLClampFloat(b);
+        a = GLClampFloat(a);
+    }
+
     gl->fClearColor(r, g, b, a);
+
+    mColorClearValue[0] = r;
+    mColorClearValue[1] = g;
+    mColorClearValue[2] = b;
+    mColorClearValue[3] = a;
 }
 
 void
 WebGLContext::ClearDepth(GLclampf v)
 {
     if (IsContextLost())
         return;
 
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -1858,16 +1858,94 @@ SetFullAlpha(void* data, GLenum format, 
 
         return true;
     }
 
     MOZ_ASSERT(false, "Unhandled case, how'd we get here?");
     return false;
 }
 
+static void
+ReadPixelsAndConvert(gl::GLContext* gl, GLint x, GLint y, GLsizei width, GLsizei height,
+                     GLenum readFormat, GLenum readType, size_t pixelStorePackAlignment,
+                     GLenum destFormat, GLenum destType, void* destBytes)
+{
+    if (readFormat == destFormat && readType == destType) {
+        gl->fReadPixels(x, y, width, height, destFormat, destType, destBytes);
+        return;
+    }
+
+    if (readFormat == LOCAL_GL_RGBA &&
+        readType == LOCAL_GL_HALF_FLOAT &&
+        destFormat == LOCAL_GL_RGBA &&
+        destType == LOCAL_GL_FLOAT)
+    {
+        size_t readBytesPerPixel = sizeof(uint16_t) * 4;
+        size_t destBytesPerPixel = sizeof(float) * 4;
+
+        size_t readBytesPerRow = readBytesPerPixel * width;
+
+        size_t readStride = RoundUpToMultipleOf(readBytesPerRow, pixelStorePackAlignment);
+        size_t destStride = RoundUpToMultipleOf(destBytesPerPixel * width,
+                                                pixelStorePackAlignment);
+
+        size_t bytesNeeded = ((height - 1) * readStride) + readBytesPerRow;
+        UniquePtr<uint8_t[]> readBuffer(new uint8_t[bytesNeeded]);
+
+        gl->fReadPixels(x, y, width, height, readFormat, readType, readBuffer.get());
+
+        size_t channelsPerRow = width * 4;
+        for (size_t j = 0; j < (size_t)height; j++) {
+            uint16_t* src = (uint16_t*)(readBuffer.get()) + j*readStride;
+            float* dst = (float*)(destBytes) + j*destStride;
+
+            uint16_t* srcEnd = src + channelsPerRow;
+            while (src != srcEnd) {
+                *dst = unpackFromFloat16(*src);
+
+                ++src;
+                ++dst;
+            }
+        }
+
+        return;
+    }
+
+    MOZ_CRASH("bad format/type");
+}
+
+static bool
+IsFormatAndTypeUnpackable(GLenum format, GLenum type)
+{
+    switch (type) {
+    case LOCAL_GL_UNSIGNED_BYTE:
+    case LOCAL_GL_FLOAT:
+    case LOCAL_GL_HALF_FLOAT:
+    case LOCAL_GL_HALF_FLOAT_OES:
+        switch (format) {
+        case LOCAL_GL_ALPHA:
+        case LOCAL_GL_RGB:
+        case LOCAL_GL_RGBA:
+            return true;
+        default:
+            return false;
+        }
+
+    case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
+    case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
+        return format == LOCAL_GL_RGBA;
+
+    case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
+        return format == LOCAL_GL_RGB;
+
+    default:
+        return false;
+    }
+}
+
 void
 WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
                          GLsizei height, GLenum format,
                          GLenum type, const Nullable<ArrayBufferView> &pixels,
                          ErrorResult& rv)
 {
     if (IsContextLost())
         return;
@@ -1878,69 +1956,71 @@ 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");
 
+    if (!IsFormatAndTypeUnpackable(format, type))
+        return ErrorInvalidEnum("readPixels: Bad format or type.");
+
     const WebGLRectangleObject* framebufferRect = CurValidReadFBRectObject();
     GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
     GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
 
-    uint32_t channels = 0;
+    int channels = 0;
 
     // Check the format param
     switch (format) {
-        case LOCAL_GL_ALPHA:
-            channels = 1;
-            break;
-        case LOCAL_GL_RGB:
-            channels = 3;
-            break;
-        case LOCAL_GL_RGBA:
-            channels = 4;
-            break;
-        default:
-            return ErrorInvalidEnum("readPixels: Bad format");
+    case LOCAL_GL_ALPHA:
+        channels = 1;
+        break;
+    case LOCAL_GL_RGB:
+        channels = 3;
+        break;
+    case LOCAL_GL_RGBA:
+        channels = 4;
+        break;
+    default:
+        MOZ_CRASH("bad `format`");
     }
 
-    uint32_t bytesPerPixel = 0;
-    int requiredDataType = 0;
 
     // Check the type param
-    bool isReadTypeValid = false;
-    bool isReadTypeFloat = false;
+    int bytesPerPixel;
+    int requiredDataType;
     switch (type) {
-        case LOCAL_GL_UNSIGNED_BYTE:
-            isReadTypeValid = true;
-            bytesPerPixel = 1*channels;
-            requiredDataType = js::Scalar::Uint8;
-            break;
-        case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
-        case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
-        case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
-            isReadTypeValid = true;
-            bytesPerPixel = 2;
-            requiredDataType = js::Scalar::Uint16;
-            break;
-        case LOCAL_GL_FLOAT:
-            if (IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float) ||
-                IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float))
-            {
-                isReadTypeValid = true;
-                isReadTypeFloat = true;
-                bytesPerPixel = 4*channels;
-                requiredDataType = js::Scalar::Float32;
-            }
-            break;
+    case LOCAL_GL_UNSIGNED_BYTE:
+        bytesPerPixel = 1*channels;
+        requiredDataType = js::Scalar::Uint8;
+        break;
+
+    case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
+    case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
+    case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
+        bytesPerPixel = 2;
+        requiredDataType = js::Scalar::Uint16;
+        break;
+
+    case LOCAL_GL_FLOAT:
+        bytesPerPixel = 4*channels;
+        requiredDataType = js::Scalar::Float32;
+        break;
+
+    case LOCAL_GL_HALF_FLOAT:
+    case LOCAL_GL_HALF_FLOAT_OES:
+        bytesPerPixel = 2*channels;
+        requiredDataType = js::Scalar::Uint16;
+        break;
+
+    default:
+        MOZ_CRASH("bad `type`");
     }
-    if (!isReadTypeValid)
-        return ErrorInvalidEnum("readPixels: Bad type", type);
 
     const ArrayBufferView& pixbuf = pixels.Value();
     int dataType = JS_GetArrayBufferViewType(pixbuf.Obj());
 
     // Check the pixels param type
     if (dataType != requiredDataType)
         return ErrorInvalidOperation("readPixels: Mismatched type/pixels types");
 
@@ -1983,64 +2063,62 @@ WebGLContext::ReadPixels(GLint x, GLint 
         isSourceTypeFloat = (type == LOCAL_GL_FLOAT ||
                              type == LOCAL_GL_HALF_FLOAT);
     } else {
         ClearBackbufferIfNeeded();
 
         isSourceTypeFloat = false;
     }
 
-    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)
 
-    bool isFormatAndTypeValid = false;
+    const GLenum mainReadFormat = LOCAL_GL_RGBA;
+    const GLenum mainReadType = isSourceTypeFloat ? LOCAL_GL_FLOAT
+                                                  : LOCAL_GL_UNSIGNED_BYTE;
+
+    GLenum auxReadFormat = mainReadFormat;
+    GLenum auxReadType = mainReadType;
 
     // OpenGL ES 2.0 $4.3.1 - IMPLEMENTATION_COLOR_READ_{TYPE/FORMAT} is a valid
     // combination for glReadPixels().
     if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
-        GLenum implType = 0;
-        GLenum implFormat = 0;
-
+        gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT,
+                         reinterpret_cast<GLint*>(&auxReadFormat));
         gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE,
-                         reinterpret_cast<GLint*>(&implType));
-        gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT,
-                         reinterpret_cast<GLint*>(&implFormat));
-
-        if (type == implType && format == implFormat) {
-            isFormatAndTypeValid = true;
-        }
+                         reinterpret_cast<GLint*>(&auxReadType));
     }
 
-    switch (format) {
-        case LOCAL_GL_RGBA: {
-            switch (type) {
-                case LOCAL_GL_UNSIGNED_BYTE:
-                case LOCAL_GL_FLOAT:
-                    isFormatAndTypeValid = true;
-                    break;
-            }
-            break;
+    const bool mainMatches = (format == mainReadFormat && type == mainReadType);
+    const bool auxMatches = (format == auxReadFormat && type == auxReadType);
+    const bool isValid = mainMatches || auxMatches;
+    if (!isValid)
+        return ErrorInvalidOperation("readPixels: Invalid format/type pair");
+
+    GLenum readType = type;
+    if (gl->WorkAroundDriverBugs() && gl->IsANGLE()) {
+        if (type == LOCAL_GL_FLOAT &&
+            auxReadFormat == format &&
+            auxReadType == LOCAL_GL_HALF_FLOAT)
+        {
+            readType = auxReadType;
         }
     }
 
-    if (!isFormatAndTypeValid) {
-        return ErrorInvalidOperation("readPixels: Invalid format/type pair");
-    }
-
     // Now that the errors are out of the way, on to actually reading
 
     // If we won't be reading any pixels anyways, just skip the actual reading
     if (width == 0 || height == 0)
         return DummyFramebufferOperation("readPixels");
 
     if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
         // the easy case: we're not reading out-of-range pixels
-        gl->fReadPixels(x, y, width, height, format, type, data);
+
+        // Effectively: gl->fReadPixels(x, y, width, height, format, type, dest);
+        ReadPixelsAndConvert(gl, x, y, width, height, format, readType,
+                             mPixelStorePackAlignment, format, type, data);
     } else {
         // the rectangle doesn't fit entirely in the bound buffer. We then have to set to zero the part
         // of the buffer that correspond to out-of-range pixels. We don't want to rely on system OpenGL
         // to do that for us, because passing out of range parameters to a buggy OpenGL implementation
         // could conceivably allow to read memory we shouldn't be allowed to read. So we manually initialize
         // the buffer to zero and compute the parameters to pass to OpenGL. We have to use an intermediate buffer
         // to accomodate the potentially different strides (widths).
 
@@ -2079,18 +2157,21 @@ WebGLContext::ReadPixels(GLint x, GLint 
             RoundedToNextMultipleOf(subrect_plainRowSize, mPixelStorePackAlignment).value();
         uint32_t subrect_byteLength = (subrect_height-1)*subrect_alignedRowSize + subrect_plainRowSize;
 
         // create subrect buffer, call glReadPixels, copy pixels into destination buffer, delete subrect buffer
         UniquePtr<GLubyte> subrect_data(new (fallible) GLubyte[subrect_byteLength]);
         if (!subrect_data)
             return ErrorOutOfMemory("readPixels: subrect_data");
 
-        gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height,
-                        format, type, subrect_data.get());
+        // Effectively: gl->fReadPixels(subrect_x, subrect_y, subrect_width,
+        //                              subrect_height, format, type, subrect_data.get());
+        ReadPixelsAndConvert(gl, subrect_x, subrect_y, subrect_width, subrect_height,
+                             format, readType, mPixelStorePackAlignment, format, type,
+                             subrect_data.get());
 
         // notice that this for loop terminates because we already checked that subrect_height is at most height
         for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) {
             GLint subrect_x_in_dest_buffer = subrect_x - x;
             GLint subrect_y_in_dest_buffer = subrect_y - y;
             memcpy(static_cast<GLubyte*>(data)
                      + checked_alignedRowSize.value() * (subrect_y_in_dest_buffer + y_inside_subrect)
                      + bytesPerPixel * subrect_x_in_dest_buffer, // destination
@@ -3592,17 +3673,17 @@ mozilla::GetWebGLTexelFormat(TexInternal
         case LOCAL_GL_RGB5_A1:                return WebGLTexelFormat::RGBA5551;
         case LOCAL_GL_RGB565:                 return WebGLTexelFormat::RGB565;
         default:
             return WebGLTexelFormat::FormatNotSupportingAnyConversion;
     }
 }
 
 void
-WebGLContext::BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) {
+WebGLContext::BlendColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
     if (IsContextLost())
         return;
     MakeContextCurrent();
     gl->fBlendColor(r, g, b, a);
 }
 
 void
 WebGLContext::Flush() {
--- a/dom/canvas/WebGLContextState.cpp
+++ b/dom/canvas/WebGLContextState.cpp
@@ -261,25 +261,45 @@ WebGLContext::GetParameter(JSContext* cx
         case LOCAL_GL_BLEND_EQUATION_RGB:
         case LOCAL_GL_BLEND_EQUATION_ALPHA:
         case LOCAL_GL_GENERATE_MIPMAP_HINT: {
             GLint i = 0;
             gl->fGetIntegerv(pname, &i);
             return JS::NumberValue(uint32_t(i));
         }
         case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: {
+            if (mBoundReadFramebuffer) {
+                FBStatus status = mBoundReadFramebuffer->CheckFramebufferStatus();
+                if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
+                    ErrorInvalidOperation("getParameter: Read framebuffer must be"
+                                          " complete before querying"
+                                          " IMPLEMENTATION_COLOR_READ_TYPE.");
+                    return JS::NullValue();
+                }
+            }
+
             GLint i = 0;
             if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
                 gl->fGetIntegerv(pname, &i);
             } else {
                 i = LOCAL_GL_UNSIGNED_BYTE;
             }
             return JS::NumberValue(uint32_t(i));
         }
         case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT: {
+            if (mBoundReadFramebuffer) {
+                FBStatus status = mBoundReadFramebuffer->CheckFramebufferStatus();
+                if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
+                    ErrorInvalidOperation("getParameter: Read framebuffer must be"
+                                          " complete before querying"
+                                          " IMPLEMENTATION_COLOR_READ_FORMAT.");
+                    return JS::NullValue();
+                }
+            }
+
             GLint i = 0;
             if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
                 gl->fGetIntegerv(pname, &i);
             } else {
                 i = LOCAL_GL_RGBA;
             }
             return JS::NumberValue(uint32_t(i));
         }
--- a/dom/canvas/WebGLExtensionColorBufferHalfFloat.cpp
+++ b/dom/canvas/WebGLExtensionColorBufferHalfFloat.cpp
@@ -21,14 +21,15 @@ WebGLExtensionColorBufferHalfFloat::~Web
 }
 
 bool
 WebGLExtensionColorBufferHalfFloat::IsSupported(const WebGLContext* webgl)
 {
     gl::GLContext* gl = webgl->GL();
 
     // ANGLE doesn't support ReadPixels from a RGBA16F with RGBA/FLOAT.
-    return gl->IsSupported(gl::GLFeature::renderbuffer_color_half_float);
+    return gl->IsSupported(gl::GLFeature::renderbuffer_color_half_float) ||
+           gl->IsANGLE();
 }
 
 IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionColorBufferHalfFloat)
 
 } // namespace mozilla
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -124,16 +124,17 @@ WebGLFramebuffer::Attachment::EffectiveI
 
 bool
 WebGLFramebuffer::Attachment::IsReadableFloat() const
 {
     TexInternalFormat internalformat = EffectiveInternalFormat();
     MOZ_ASSERT(internalformat != LOCAL_GL_NONE);
     TexType type = TypeFromInternalFormat(internalformat);
     return type == LOCAL_GL_FLOAT ||
+           type == LOCAL_GL_HALF_FLOAT_OES ||
            type == LOCAL_GL_HALF_FLOAT;
 }
 
 void
 WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex,
                                           TexImageTarget target, GLint level)
 {
     mTexturePtr = tex;
@@ -798,16 +799,17 @@ WebGLFramebuffer::CheckFramebufferStatus
         return mStatus;
 
     // Looks good on our end. Let's ask the driver.
     mContext->MakeContextCurrent();
 
     // Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}.
     FinalizeAttachments();
 
+    // TODO: This should not be unconditionally GL_FRAMEBUFFER.
     mStatus = mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
     return mStatus;
 }
 
 bool
 WebGLFramebuffer::HasCompletePlanes(GLbitfield mask)
 {
     if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
--- a/dom/canvas/WebGLTexelConversions.h
+++ b/dom/canvas/WebGLTexelConversions.h
@@ -100,17 +100,17 @@ unpackFromFloat16(uint16_t v)
         uint32_t f32Bits;
     };
 
     // grab sign bit
     f32Bits = uint32_t(v & 0x8000) << 16;
     uint16_t exp = (v >> 10) & 0x001F;
     uint16_t mantissa = v & 0x03FF;
 
-    if (exp) {
+    if (!exp) {
         // Handle denormalized numbers
         // Adapted from: OpenGL ES 2.0 Programming Guide Appx.
         // Converting Float to Half-Float
         if (mantissa) {
             exp = 112; // See packToFloat16
             mantissa <<= 1;
             // For every leading zero, decrement the exponent
             // and shift the mantissa to the left
--- a/dom/canvas/test/webgl-mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest.ini
@@ -17,16 +17,18 @@ skip-if = (os == 'b2g') || buildapp == '
 [webgl-mochitest/test_highp_fs.html]
 [webgl-mochitest/test_no_arr_points.html]
 skip-if = android_version == '10' #Android 2.3 aws only; bug 1030942
 [webgl-mochitest/test_noprog_draw.html]
 [webgl-mochitest/test_privileged_exts.html]
 [webgl-mochitest/test_texsubimage_float.html]
 [webgl-mochitest/test_webgl_available.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
+#[webgl-mochitest/test_webgl_color_buffer_float.html]
+# We haven't cleaned up the Try results yet, but let's get this on the books first.
 [webgl-mochitest/test_webgl_conformance.html]
 skip-if = buildapp == 'mulet' || toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [webgl-mochitest/test_webgl_request_context.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [webgl-mochitest/test_webgl_request_mismatch.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [webgl-mochitest/test_webgl2_not_exposed.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-mochitest/test_webgl_color_buffer_float.html
@@ -0,0 +1,486 @@
+<html>
+  <head>
+    <meta charset='UTF-8'>
+    <script src='/tests/SimpleTest/SimpleTest.js'></script>
+    <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
+  </head>
+  <body>
+<script id='vs' type='x-shader/x-vertex'>
+
+attribute vec2 aVertCoord;
+
+void main(void) {
+  gl_Position = vec4(aVertCoord, 0.0, 1.0);
+}
+
+</script>
+<script id='fs' type='x-shader/x-fragment'>
+
+precision mediump float; // 💩
+
+uniform vec4 uFragColor;
+
+void main(void) {
+  gl_FragColor = uFragColor;
+}
+
+</script>
+
+<canvas id='c' width='200' height='200'></canvas>
+
+<script>
+
+function GetGLSLByElemId(elemId) {
+  var elem = document.getElementById(elemId);
+  if (!elem)
+    throw 'Bad `elemId`: ' + elemId;
+
+  return elem.innerHTML.trim();
+}
+
+function ProgramByElemIds(gl, vsId, fsId) {
+  var vs = gl.createShader(gl.VERTEX_SHADER);
+  gl.shaderSource(vs, GetGLSLByElemId(vsId));
+  gl.compileShader(vs);
+
+  var fs = gl.createShader(gl.FRAGMENT_SHADER);
+  gl.shaderSource(fs, GetGLSLByElemId(fsId));
+  gl.compileShader(fs);
+
+  var prog = gl.createProgram();
+  gl.attachShader(prog, vs);
+  gl.attachShader(prog, fs);
+
+  gl.linkProgram(prog);
+
+  var success = gl.getProgramParameter(prog, gl.LINK_STATUS);
+  if (success)
+      return prog;
+
+  console.log('Error linking program for \'' + vsId + '\' and \'' + fsId + '\'.');
+  console.log('\nLink log: ' + gl.getProgramInfoLog(prog));
+  console.log('\nVert shader log: ' + gl.getShaderInfoLog(vs));
+  console.log('\nFrag shader log: ' + gl.getShaderInfoLog(fs));
+  return null;
+}
+
+var RGBA = 0x1908;
+var UNSIGNED_BYTE = 0x1401;
+var FLOAT = 0x1406;
+var HALF_FLOAT_OES = 0x8D61;
+var HALF_FLOAT = 0x140B;
+var RGBA4 = 0x8056;
+var RGBA8 = 0x8058;
+var RGBA32F = 0x8814;
+var RGBA16F = 0x881A;
+
+function EnumName(val) {
+  switch (val) {
+    case RGBA:
+      return 'RGBA';
+    case UNSIGNED_BYTE:
+      return 'UNSIGNED_BYTE';
+    case FLOAT:
+      return 'FLOAT';
+    case HALF_FLOAT_OES:
+      return 'HALF_FLOAT_OES';
+    case HALF_FLOAT:
+      return 'HALF_FLOAT';
+    case RGBA4:
+      return 'RGBA4';
+    case RGBA32F:
+      return 'RGBA32F';
+    default:
+      throw 'Unknown enum: 0x' + val.toString(16);
+  }
+}
+
+var gl;
+
+function RGBAToString(arr) {
+  return '[' + arr[0].toPrecision(4) + ', ' +
+               arr[1].toPrecision(4) + ', ' +
+               arr[2].toPrecision(4) + ', ' +
+               arr[3].toPrecision(4) + ']';
+}
+
+function TestScreenColor(gl, isFBFloat, r, g, b, a) {
+  var readType = isFBFloat ? FLOAT : UNSIGNED_BYTE;
+
+  var arr;
+  switch (readType) {
+    case gl.UNSIGNED_BYTE:
+      arr = new Uint8Array(4);
+      break;
+
+    case gl.FLOAT:
+      arr = new Float32Array(4);
+      break;
+
+    default:
+      throw 'Bad `readType`.';
+  }
+
+  gl.readPixels(0, 0, 1, 1, gl.RGBA, readType, arr);
+
+  var err = gl.getError();
+  ok(err == 0, 'Should be no errors.');
+  if (err)
+    return;
+
+  var floatArr;
+  switch (readType) {
+    case gl.UNSIGNED_BYTE:
+      floatArr = new Float32Array(4);
+      floatArr[0] = arr[0] / 255.0;
+      floatArr[1] = arr[1] / 255.0;
+      floatArr[2] = arr[2] / 255.0;
+      floatArr[3] = arr[3] / 255.0;
+      break;
+
+    case gl.FLOAT:
+      floatArr = arr;
+      break;
+
+    default:
+      throw 'Bad `readType`.';
+  }
+
+  var testText = RGBAToString(floatArr);
+  var refText = RGBAToString([r, g, b, a]);
+
+  var eps = 1.0 / 255.0;
+  var isSame = (Math.abs(floatArr[0] - r) < eps &&
+                Math.abs(floatArr[1] - g) < eps &&
+                Math.abs(floatArr[2] - b) < eps &&
+                Math.abs(floatArr[3] - a) < eps);
+
+  ok(isSame, 'Should be ' + refText + ', was ' + testText + ',');
+}
+
+function TestReadFormat(gl, isFBFloat, format, type) {
+  var err = gl.getError();
+  if (err) {
+    ok(false, 'Should be no error at start of TestReadFormat(). (0x' + err.toString(16) + ')');
+    return;
+  }
+  var implFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
+  var implType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
+
+  var err = gl.getError();
+  if (err) {
+    ok(false, 'Should be no error at start2 of TestReadFormat(). (0x' + err.toString(16) + ')');
+    return;
+  }
+
+  var defaultReadType = isFBFloat ? FLOAT : UNSIGNED_BYTE;
+
+  var formatOk = (format == gl.RGBA &&
+                  type == defaultReadType);
+
+  if (format == implFormat &&
+      type == implType)
+  {
+    formatOk = true;
+  }
+
+  var w = 1;
+  var h = 1;
+  var channels = 4;
+  var arrSize = w * h * channels;
+
+  var arr;
+  switch (type) {
+    case UNSIGNED_BYTE:
+      arr = new Uint8Array(arrSize);
+      break;
+
+    case FLOAT:
+      arr = new Float32Array(arrSize);
+      break;
+
+    case HALF_FLOAT_OES:
+    case HALF_FLOAT:
+      arr = new Uint16Array(arrSize);
+      break;
+
+    default:
+      throw 'Bad `type`: 0x' + type.toString(16);
+  }
+
+  gl.readPixels(0, 0, 1, 1, format, type, arr);
+  var wasOk = gl.getError() == 0;
+
+  var text = 'Should ' + (formatOk ? '' : 'not ') + 'allow reading with ' +
+             EnumName(format) + '/' + EnumName(type) + '.'
+  ok(wasOk == formatOk, text);
+}
+
+function TestError(gl, expectedErr, descText) {
+  var err = gl.getError();
+
+  while (gl.getError()) {}
+
+  ok(err == expectedErr,
+     descText + ': Error should be 0x' + expectedErr.toString(16) + ', was 0x' +
+     err.toString(16) + '.');
+
+  return err;
+}
+
+function AttachRBToCurFB(gl, sizedFormat) {
+  var isSupported;
+  switch (sizedFormat) {
+  case RGBA4:
+    isSupported = true;
+    break;
+
+  case RGBA16F:
+    isSupported = !!gl.getExtension('EXT_color_buffer_half_float');
+    break;
+
+  case RGBA32F:
+    isSupported = !!gl.getExtension('WEBGL_color_buffer_float');
+    break;
+
+  default:
+    throw 'Bad `sizedFormat`.';
+  }
+
+  var rb = gl.createRenderbuffer();
+  gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
+  gl.renderbufferStorage(gl.RENDERBUFFER, sizedFormat, 1, 1);
+
+  var correctError = isSupported ? 0 : gl.INVALID_ENUM;
+  var err = TestError(gl, correctError, 'RB specification with supported format');
+  if (err)
+    return false;
+
+  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb);
+
+  var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+  var isComplete = (status == gl.FRAMEBUFFER_COMPLETE);
+  ok(isComplete, 'Framebuffer should be complete after RB attachment.');
+  return isComplete;
+}
+
+function AttachTexToCurFB(gl, sizedFormat) {
+  var canCreate;
+  var isAttachGuaranteed;
+  var format;
+  var type;
+
+  switch (sizedFormat) {
+  case RGBA8:
+    canCreate = true;
+    isAttachGuaranteed = true;
+    format = RGBA;
+    type = UNSIGNED_BYTE;
+    break;
+
+  case RGBA16F:
+    canCreate = !!gl.getExtension('OES_texture_half_float');
+    isAttachGuaranteed = !!gl.getExtension('EXT_color_buffer_half_float');
+    format = RGBA;
+    type = HALF_FLOAT_OES;
+    break;
+
+  case RGBA32F:
+    canCreate = !!gl.getExtension('OES_texture_float');
+    isAttachGuaranteed = !!gl.getExtension('WEBGL_color_buffer_float');
+    format = RGBA;
+    type = FLOAT;
+    break;
+
+  default:
+    throw 'Bad `sizedFormat`.';
+  }
+
+  var tex = gl.createTexture();
+  gl.bindTexture(gl.TEXTURE_2D, tex);
+  gl.texImage2D(gl.TEXTURE_2D, 0, format, 1, 1, 0, format, type, null);
+
+  var correctError = canCreate ? 0 : gl.INVALID_ENUM;
+  var err = TestError(gl, correctError, 'Tex specification with supported format');
+  if (err)
+    return false;
+
+  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+
+  var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+  var isComplete = (status == gl.FRAMEBUFFER_COMPLETE);
+
+  if (!isAttachGuaranteed && !isComplete)
+    todo(false, 'Framebuffer needn\'t be complete after tex attachment.');
+  else
+    ok(isComplete, 'Framebuffer should be complete after tex attachment.');
+
+  return isComplete;
+}
+
+function IsFormatFloat(sizedFormat) {
+  switch (sizedFormat) {
+  case RGBA4:
+  case RGBA8:
+    return false;
+
+  case RGBA16F:
+  case RGBA32F:
+    return true;
+
+  default:
+    throw 'Bad `sizedFormat`.';
+  }
+}
+
+function TestType(gl, prog, isTex, sizedFormat) {
+  TestError(gl, 0, 'At start of TestRB()');
+
+  var isAttached = isTex ? AttachTexToCurFB(gl, sizedFormat)
+                         : AttachRBToCurFB(gl, sizedFormat);
+  if (!isAttached)
+    return;
+
+  var isFormatFloat = IsFormatFloat(sizedFormat);
+
+  TestReadFormat(gl, isFormatFloat, gl.RGBA, gl.UNSIGNED_BYTE);
+  TestReadFormat(gl, isFormatFloat, gl.RGBA, gl.FLOAT);
+  TestReadFormat(gl, isFormatFloat, gl.RGBA, HALF_FLOAT);
+  TestReadFormat(gl, isFormatFloat, gl.RGBA, HALF_FLOAT_OES);
+
+  //////////////////////////////////////
+
+  ok(true, 'Drawing:');
+
+  gl.clearColor(0.0, 1.5, 0.5, 1.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+
+  if (isFormatFloat)
+    TestScreenColor(gl, isFormatFloat, 0, 1.5, 0.5, 1);
+  else
+    TestScreenColor(gl, isFormatFloat, 0, 1, 0.5, 1);
+
+  ////////
+
+  ok(true, 'Clearing:');
+
+  gl.uniform4f(prog.uFragColor, 0, 0.5, 1.5, 1);
+  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+
+  if (isFormatFloat)
+    TestScreenColor(gl, isFormatFloat, 0, 0.5, 1.5, 1);
+  else
+    TestScreenColor(gl, isFormatFloat, 0, 0.5, 1.0, 1);
+
+  ////////
+
+  ok(true, 'Blending:');
+
+  gl.enable(gl.BLEND);
+  gl.blendFunc(gl.CONSTANT_COLOR, gl.ZERO);
+  gl.blendColor(0, 10, 0.1, 1);
+
+  gl.uniform4f(prog.uFragColor, 0, 0.5, 15.0, 1);
+  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+
+  if (isFormatFloat)
+    TestScreenColor(gl, isFormatFloat, 0, 5.0, 1.5, 1);
+  else
+    TestScreenColor(gl, isFormatFloat, 0, 0.5, 0.1, 1);
+
+  gl.disable(gl.BLEND);
+
+  //////////////////////////////////////
+}
+
+// Give ourselves a scope to return early from:
+(function() {
+  var canvas = document.getElementById('c');
+  var attribs = {
+    antialias: false,
+    depth: false,
+  };
+  gl = canvas.getContext('experimental-webgl', attribs);
+  if (!gl) {
+    todo(false, 'WebGL is unavailable.');
+    return;
+  }
+
+  var cbf = gl.getExtension('WEBGL_color_buffer_float');
+  var cbhf = gl.getExtension('EXT_color_buffer_half_float');
+
+  //////////////////////////////////////
+
+  gl.viewport(0, 0, 1, 1);
+
+  var prog = ProgramByElemIds(gl, 'vs', 'fs');
+  ok(prog, 'Program should link.');
+  if (!prog)
+    return;
+
+  prog.aVertCoord = gl.getAttribLocation(prog, 'aVertCoord');
+  prog.uFragColor = gl.getUniformLocation(prog, 'uFragColor');
+
+  gl.useProgram(prog);
+
+  var arr = new Float32Array([
+    -1, -1,
+     1, -1,
+    -1,  1,
+     1,  1,
+  ]);
+  var vb = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, vb);
+  gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW);
+
+  gl.enableVertexAttribArray(0);
+  gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+
+  //////////////////////////////////////
+
+  var fb = gl.createFramebuffer();
+  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+
+  error = gl.getError();
+  ok(error == 0, 'Should be no errors after setup. (0x' + error.toString(16) + ')');
+
+  //////////////////////////////////////
+  ok(true, '---------------------------------------------------------------------------');
+  ok(true, 'RGBA8 texture');
+  TestType(gl, prog, true, RGBA8);
+
+  ok(true, '---------------------------------------------------------------------------');
+  ok(true, 'RGBA16F texture');
+  TestType(gl, prog, true, RGBA16F);
+
+  ok(true, '---------------------------------------------------------------------------');
+  ok(true, 'RGBA32F texture');
+  TestType(gl, prog, true, RGBA32F);
+
+  ////////
+
+  ok(true, '---------------------------------------------------------------------------');
+  ok(true, 'RGBA4 renderbuffer');
+  TestType(gl, prog, false, RGBA4);
+
+  ok(true, '---------------------------------------------------------------------------');
+  ok(true, 'RGBA16F renderbuffer');
+  TestType(gl, prog, false, RGBA16F);
+
+  ok(true, '---------------------------------------------------------------------------');
+  ok(true, 'RGBA32F renderbuffer');
+  TestType(gl, prog, false, RGBA32F);
+
+  ok(true, '---------------------------------------------------------------------------');
+  //////////////////////////////////////
+
+  error = gl.getError();
+  ok(error == 0, 'Should be no errors after test.');
+
+  ok(true, 'TEST COMPLETE');
+})();
+
+</script>
+
+  </body>
+</html>
--- a/dom/ipc/tests/mochitest.ini
+++ b/dom/ipc/tests/mochitest.ini
@@ -1,14 +1,16 @@
 [test_blob_sliced_from_child_process.html]
 # This test is only supposed to run in the main process.
 skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s
 [test_blob_sliced_from_parent_process.html]
 # This test is only supposed to run in the main process.
 skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s
+[test_cpow_cookies.html]
+skip-if = buildapp == 'b2g' || buildapp == 'mulet'
 [test_NuwaProcessCreation.html]
 skip-if = toolkit != 'gonk'
 [test_NuwaProcessDeadlock.html]
 run-if = toolkit == 'gonk'
 [test_child_docshell.html]
 run-if = toolkit != 'cocoa' # disabled due to hangs, see changeset 6852e7c47edf
 [test_CrashService_crash.html]
 run-if = crashreporter && !e10s && (toolkit == 'gtk2' || toolkit == 'gtk3' || toolkit == 'cocoa' || toolkit == 'windows') && (buildapp != 'b2g' || toolkit == 'gonk')
new file mode 100644
--- /dev/null
+++ b/dom/ipc/tests/test_cpow_cookies.html
@@ -0,0 +1,89 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for recursive CPOW-getting-cookie bug</title>
+  <script type="application/javascript"
+          src="/tests/SimpleTest/SimpleTest.js">
+  </script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+  <script type="application/javascript;version=1.8">
+    "use strict";
+
+    SimpleTest.waitForExplicitFinish();
+
+    const childFrameURL =
+      "data:text/html,<!DOCTYPE HTML><html><body></body></html>";
+
+    function childFrameScript() {
+      "use strict";
+
+      const Ci = Components.interfaces;
+
+      function test1(message) {
+        // NB: This is a no-op because we're a data: document with a null
+        // principal.
+        content.document.cookie = "a=b";
+        message.target.sendAsyncMessage("testCPOWCookies:test1Finished", { pass: true });
+      }
+
+      addMessageListener("testCPOWCookies:test1", function(message) {
+        test1(message);
+      });
+    }
+
+    let test;
+    function* testStructure(mm) {
+      let lastResult;
+
+      function testDone(msg) {
+        test.next(msg.data);
+      }
+
+      mm.addMessageListener("testCPOWCookies:test1Finished", testDone);
+
+      mm.sendAsyncMessage("testCPOWCookies:test1", {});
+      lastResult = yield;
+      ok(lastResult.pass, "got the right answer and didn't crash");
+
+      SimpleTest.finish();
+    }
+
+    function runTests() {
+      info("Browser prefs set.");
+
+      let iframe = document.createElement("iframe");
+      SpecialPowers.wrap(iframe).mozbrowser = true;
+      iframe.id = "iframe";
+      iframe.src = childFrameURL;
+
+      iframe.addEventListener("mozbrowserloadend", function() {
+        info("Got iframe load event.");
+        let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+        mm.loadFrameScript("data:,(" + encodeURI(childFrameScript.toString()) + ")();",
+                           false);
+
+        test = testStructure(mm);
+        test.next();
+      });
+
+      document.body.appendChild(iframe);
+    }
+
+    addEventListener("load", function() {
+      info("Got load event.");
+
+      SpecialPowers.addPermission("browser", true, document);
+      SpecialPowers.pushPrefEnv({
+        "set": [
+          ["dom.ipc.browser_frames.oop_by_default", true],
+          ["dom.mozBrowserFramesEnabled", true],
+          ["browser.pagethumbnails.capturing_disabled", true]
+        ]
+      }, runTests);
+    });
+  </script>
+</body>
+</html>
--- a/dom/webidl/EventTarget.webidl
+++ b/dom/webidl/EventTarget.webidl
@@ -38,11 +38,11 @@ partial interface EventTarget {
   [ChromeOnly]
   EventHandler getEventHandler(DOMString type);
 };
 
 // Mozilla extension to make firing events on event targets from
 // chrome easier.  This returns the window which can be used to create
 // events to fire at this EventTarget, or null if there isn't one.
 partial interface EventTarget {
-  [ChromeOnly]
+  [ChromeOnly, Exposed=Window]
   readonly attribute WindowProxy? ownerGlobal;
 };
--- a/dom/webidl/WebGLRenderingContext.webidl
+++ b/dom/webidl/WebGLRenderingContext.webidl
@@ -515,32 +515,32 @@ interface WebGLRenderingContext {
 
     void activeTexture(GLenum texture);
     void attachShader(WebGLProgram? program, WebGLShader? shader);
     void bindAttribLocation(WebGLProgram? program, GLuint index, DOMString name);
     void bindBuffer(GLenum target, WebGLBuffer? buffer);
     void bindFramebuffer(GLenum target, WebGLFramebuffer? framebuffer);
     void bindRenderbuffer(GLenum target, WebGLRenderbuffer? renderbuffer);
     void bindTexture(GLenum target, WebGLTexture? texture);
-    void blendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+    void blendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
     void blendEquation(GLenum mode);
     void blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
     void blendFunc(GLenum sfactor, GLenum dfactor);
     void blendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
                            GLenum srcAlpha, GLenum dstAlpha);
 
     void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
     void bufferData(GLenum target, ArrayBufferView data, GLenum usage);
     void bufferData(GLenum target, ArrayBuffer? data, GLenum usage);
     void bufferSubData(GLenum target, GLintptr offset, ArrayBufferView data);
     void bufferSubData(GLenum target, GLintptr offset, ArrayBuffer? data);
 
     [WebGLHandlesContextLoss] GLenum checkFramebufferStatus(GLenum target);
     void clear(GLbitfield mask);
-    void clearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+    void clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
     void clearDepth(GLclampf depth);
     void clearStencil(GLint s);
     void colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
     void compileShader(WebGLShader? shader);
 
     void compressedTexImage2D(GLenum target, GLint level, GLenum internalformat,
                               GLsizei width, GLsizei height, GLint border,
                               ArrayBufferView data);
--- a/embedding/components/printingui/mac/nsPrintProgress.cpp
+++ b/embedding/components/printingui/mac/nsPrintProgress.cpp
@@ -37,65 +37,31 @@ nsPrintProgress::~nsPrintProgress()
 
 /* void openProgressDialog (in nsIDOMWindow parent, in string dialogURL, in nsISupports parameters); */
 NS_IMETHODIMP nsPrintProgress::OpenProgressDialog(nsIDOMWindow *parent,
                                                   const char *dialogURL,
                                                   nsISupports *parameters, 
                                                   nsIObserver *openDialogObserver,
                                                   bool *notifyOnOpen)
 {
-  m_observer = openDialogObserver;
-
-  nsresult rv = NS_ERROR_FAILURE;
-  
-  if (m_dialog)
-    return NS_ERROR_ALREADY_INITIALIZED;
-  
-  if (!dialogURL || !*dialogURL)
-    return NS_ERROR_INVALID_ARG;
-
-  if (parent)
-  {
-    // Set up window.arguments[0]...
-    nsCOMPtr<nsISupportsArray> array;
-    rv = NS_NewISupportsArray(getter_AddRefs(array));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsCOMPtr<nsISupportsInterfacePointer> ifptr =
-      do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-    
-    ifptr->SetData(static_cast<nsIPrintProgress*>(this));
-    ifptr->SetDataIID(&NS_GET_IID(nsIPrintProgress));
-
-    array->AppendElement(ifptr);
-
-    array->AppendElement(parameters);
-
-    // Open the dialog.
-    nsCOMPtr<nsIDOMWindow> newWindow;
-    rv = parent->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL),
-                            NS_LITERAL_STRING("_blank"),
-                            NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"),
-                            array, getter_AddRefs(newWindow));
-    if (NS_SUCCEEDED(rv)) {
-      *notifyOnOpen = true;
-    }
-  }
-
-  return rv;
+  MOZ_ASSERT_UNREACHABLE("The nsPrintingPromptService::ShowProgress "
+                         "implementation for OS X returns "
+                         "NS_ERROR_NOT_IMPLEMENTED, so we should never get "
+                         "here.");
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* void closeProgressDialog (in boolean forceClose); */
 NS_IMETHODIMP nsPrintProgress::CloseProgressDialog(bool forceClose)
 {
-  m_closeProgress = true;
-  // XXX Casting bool to nsresult
-  return OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_STOP,
-                       static_cast<nsresult>(forceClose));
+  MOZ_ASSERT_UNREACHABLE("The nsPrintingPromptService::ShowProgress "
+                         "implementation for OS X returns "
+                         "NS_ERROR_NOT_IMPLEMENTED, so we should never get "
+                         "here.");
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 /* nsIPrompt GetPrompter (); */
 NS_IMETHODIMP nsPrintProgress::GetPrompter(nsIPrompt **_retval)
 {
   NS_ENSURE_ARG_POINTER(_retval);
   *_retval = nullptr;
 
--- a/embedding/components/printingui/unixshared/nsPrintProgress.cpp
+++ b/embedding/components/printingui/unixshared/nsPrintProgress.cpp
@@ -1,20 +1,26 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsPrintProgress.h"
 
 #include "nsIBaseWindow.h"
+#include "nsIDocShell.h"
+#include "nsIDocShellTreeOwner.h"
+#include "nsIInterfaceRequestorUtils.h"
 #include "nsISupportsArray.h"
+#include "nsIXULWindow.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIComponentManager.h"
+#include "nsPIDOMWindow.h"
+
 
 NS_IMPL_ADDREF(nsPrintProgress)
 NS_IMPL_RELEASE(nsPrintProgress)
 
 NS_INTERFACE_MAP_BEGIN(nsPrintProgress)
    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrintStatusFeedback)
    NS_INTERFACE_MAP_ENTRY(nsIPrintProgress)
    NS_INTERFACE_MAP_ENTRY(nsIPrintStatusFeedback)
@@ -66,22 +72,39 @@ NS_IMETHODIMP nsPrintProgress::OpenProgr
     
     ifptr->SetData(static_cast<nsIPrintProgress*>(this));
     ifptr->SetDataIID(&NS_GET_IID(nsIPrintProgress));
 
     array->AppendElement(ifptr);
 
     array->AppendElement(parameters);
 
+    // We will set the opener of the dialog to be the nsIDOMWindow for the
+    // browser XUL window itself, as opposed to the content. That way, the
+    // progress window has access to the opener.
+    nsCOMPtr<nsPIDOMWindow> pParentWindow = do_QueryInterface(parent);
+    NS_ENSURE_STATE(pParentWindow);
+
+    nsCOMPtr<nsIDocShell> docShell = pParentWindow->GetDocShell();
+    NS_ENSURE_STATE(docShell);
+
+    nsCOMPtr<nsIDocShellTreeOwner> owner;
+    docShell->GetTreeOwner(getter_AddRefs(owner));
+
+    nsCOMPtr<nsIXULWindow> ownerXULWindow = do_GetInterface(owner);
+    nsCOMPtr<nsIDOMWindow> ownerWindow = do_GetInterface(ownerXULWindow);
+    NS_ENSURE_STATE(ownerWindow);
+
     // Open the dialog.
     nsCOMPtr<nsIDOMWindow> newWindow;
-    rv = parent->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL),
-                            NS_LITERAL_STRING("_blank"),
-                            NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"),
-                            array, getter_AddRefs(newWindow));
+
+    rv = ownerWindow->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL),
+                                 NS_LITERAL_STRING("_blank"),
+                                 NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"),
+                                 array, getter_AddRefs(newWindow));
   }
 
   return rv;
 }
 
 /* void closeProgressDialog (in boolean forceClose); */
 NS_IMETHODIMP nsPrintProgress::CloseProgressDialog(bool forceClose)
 {
--- a/embedding/components/printingui/win/nsPrintProgress.cpp
+++ b/embedding/components/printingui/win/nsPrintProgress.cpp
@@ -1,21 +1,26 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsPrintProgress.h"
 
 #include "nsIBaseWindow.h"
+#include "nsIDocShell.h"
+#include "nsIDocShellTreeOwner.h"
+#include "nsIInterfaceRequestorUtils.h"
 #include "nsISupportsArray.h"
+#include "nsIXULWindow.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIComponentManager.h"
 #include "nsIServiceManager.h"
+#include "nsPIDOMWindow.h"
 
 #if 0
 NS_IMPL_ADDREF(nsPrintProgress)
 NS_IMPL_RELEASE(nsPrintProgress)
 #else
 NS_IMETHODIMP_(MozExternalRefCountType) nsPrintProgress::AddRef(void)
 {
   NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt");
@@ -95,22 +100,38 @@ NS_IMETHODIMP nsPrintProgress::OpenProgr
     
     ifptr->SetData(static_cast<nsIPrintProgress*>(this));
     ifptr->SetDataIID(&NS_GET_IID(nsIPrintProgress));
 
     array->AppendElement(ifptr);
 
     array->AppendElement(parameters);
 
+    // We will set the opener of the dialog to be the nsIDOMWindow for the
+    // browser XUL window itself, as opposed to the content. That way, the
+    // progress window has access to the opener.
+    nsCOMPtr<nsPIDOMWindow> pParentWindow = do_QueryInterface(parent);
+    NS_ENSURE_STATE(pParentWindow);
+
+    nsCOMPtr<nsIDocShell> docShell = pParentWindow->GetDocShell();
+    NS_ENSURE_STATE(docShell);
+
+    nsCOMPtr<nsIDocShellTreeOwner> owner;
+    docShell->GetTreeOwner(getter_AddRefs(owner));
+
+    nsCOMPtr<nsIXULWindow> ownerXULWindow = do_GetInterface(owner);
+    nsCOMPtr<nsIDOMWindow> ownerWindow = do_GetInterface(ownerXULWindow);
+    NS_ENSURE_STATE(ownerWindow);
+
     // Open the dialog.
     nsCOMPtr<nsIDOMWindow> newWindow;
-    rv = parent->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL),
-                            NS_LITERAL_STRING("_blank"),
-                            NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"),
-                            array, getter_AddRefs(newWindow));
+    rv = ownerWindow->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL),
+                                 NS_LITERAL_STRING("_blank"),
+                                 NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"),
+                                 array, getter_AddRefs(newWindow));
   }
 
   return rv;
 }
 
 /* void closeProgressDialog (in boolean forceClose); */
 NS_IMETHODIMP nsPrintProgress::CloseProgressDialog(bool forceClose)
 {
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -1161,16 +1161,18 @@ public:
   static TemporaryRef<DrawEventRecorder>
     CreateEventRecorderForFile(const char *aFilename);
 
   static void SetGlobalEventRecorder(DrawEventRecorder *aRecorder);
 
   // This is a little hacky at the moment, but we want to have this data. Bug 1068613.
   static void SetLogForwarder(LogForwarder* aLogFwd);
 
+  static uint32_t GetMaxSurfaceSize(BackendType aType);
+
   static LogForwarder* GetLogForwarder() { return mLogForwarder; }
 
 private:
   static LogForwarder* mLogForwarder;
 public:
 
 #ifdef USE_SKIA_GPU
   static TemporaryRef<DrawTarget>
--- a/gfx/2d/BaseRect.h
+++ b/gfx/2d/BaseRect.h
@@ -106,18 +106,18 @@ struct BaseRect {
   // (including edges) of *this and aRect. If there are no points in that
   // intersection, returns an empty rectangle with x/y set to the std::max of the x/y
   // of *this and aRect.
   Sub Intersect(const Sub& aRect) const
   {
     Sub result;
     result.x = std::max<T>(x, aRect.x);
     result.y = std::max<T>(y, aRect.y);
-    result.width = std::min<T>(XMost(), aRect.XMost()) - result.x;
-    result.height = std::min<T>(YMost(), aRect.YMost()) - result.y;
+    result.width = std::min<T>(x - result.x + width, aRect.x - result.x + aRect.width);
+    result.height = std::min<T>(y - result.y + height, aRect.y - result.y + aRect.height);
     if (result.width < 0 || result.height < 0) {
       result.SizeTo(0, 0);
     }
     return result;
   }
   // Sets *this to be the rectangle containing the intersection of the points
   // (including edges) of *this and aRect. If there are no points in that
   // intersection, sets *this to be an empty rectangle with x/y set to the std::max
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -1688,20 +1688,21 @@ bool
 DrawTargetCG::Init(BackendType aType,
                    unsigned char* aData,
                    const IntSize &aSize,
                    int32_t aStride,
                    SurfaceFormat aFormat)
 {
   // XXX: we should come up with some consistent semantics for dealing
   // with zero area drawtargets
-  if (aSize.width <= 0 || aSize.height <= 0 ||
-      // 32767 is the maximum size supported by cairo
-      // we clamp to that to make it easier to interoperate
-      aSize.width > 32767 || aSize.height > 32767) {
+  if (aSize.width <= 0 ||
+      aSize.height <= 0 ||
+      size_t(aSize.width) > GetMaxSurfaceSize() ||
+      size_t(aSize.height) > GetMaxSurfaceSize())
+  {
     gfxWarning() << "Failed to Init() DrawTargetCG because of bad size.";
     mColorSpace = nullptr;
     mCg = nullptr;
     return false;
   }
 
   //XXX: handle SurfaceFormat
 
--- a/gfx/2d/DrawTargetCG.h
+++ b/gfx/2d/DrawTargetCG.h
@@ -178,16 +178,23 @@ public:
   virtual TemporaryRef<SourceSurface> CreateSourceSurfaceFromData(unsigned char *aData,
                                                             const IntSize &aSize,
                                                             int32_t aStride,
                                                             SurfaceFormat aFormat) const MOZ_OVERRIDE;
   virtual TemporaryRef<SourceSurface> OptimizeSourceSurface(SourceSurface *aSurface) const MOZ_OVERRIDE;
   CGContextRef GetCGContext() {
       return mCg;
   }
+
+  // 32767 is the maximum size supported by cairo. We clamp to that to make it
+  // easier to interoperate.
+  static size_t GetMaxSurfaceSize() {
+    return 32767;
+  }
+
 private:
   void MarkChanged();
 
   IntSize mSize;
   CGColorSpaceRef mColorSpace;
   CGContextRef mCg;
 
   /**
--- a/gfx/2d/DrawTargetCairo.h
+++ b/gfx/2d/DrawTargetCairo.h
@@ -165,16 +165,21 @@ public:
 
   // Call to set up aContext for drawing (with the current transform, etc).
   // Pass the path you're going to be using if you have one.
   // Implicitly calls WillChange(aPath).
   void PrepareForDrawing(cairo_t* aContext, const Path* aPath = nullptr);
 
   static cairo_surface_t *GetDummySurface();
 
+  // Cairo hardcodes this as its maximum surface size.
+  static size_t GetMaxSurfaceSize() {
+    return 32767;
+  }
+
 private: // methods
   // Init cairo surface without doing a cairo_surface_reference() call.
   bool InitAlreadyReferenced(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat = nullptr);
   enum DrawPatternType { DRAW_FILL, DRAW_STROKE };
   void DrawPattern(const Pattern& aPattern,
                    const StrokeOptions& aStrokeOptions,
                    const DrawOptions& aOptions,
                    DrawPatternType aDrawType,
--- a/gfx/2d/DrawTargetD2D.h
+++ b/gfx/2d/DrawTargetD2D.h
@@ -140,16 +140,20 @@ public:
 
   TemporaryRef<ID2D1Image> GetImageForSurface(SourceSurface *aSurface);
 
   static ID2D1Factory *factory();
   static void CleanupD2D();
   static IDWriteFactory *GetDWriteFactory();
   ID2D1RenderTarget *GetRT() { return mRT; }
 
+  static uint32_t GetMaxSurfaceSize() {
+    return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+  }
+
   operator std::string() const {
     std::stringstream stream;
     stream << "DrawTargetD2D(" << this << ")";
     return stream.str();
   }
 
   static uint64_t mVRAMUsageDT;
   static uint64_t mVRAMUsageSS;
--- a/gfx/2d/DrawTargetD2D1.h
+++ b/gfx/2d/DrawTargetD2D1.h
@@ -139,16 +139,20 @@ public:
   static IDWriteFactory *GetDWriteFactory();
 
   operator std::string() const {
     std::stringstream stream;
     stream << "DrawTargetD2D 1.1 (" << this << ")";
     return stream.str();
   }
 
+  static uint32_t GetMaxSurfaceSize() {
+    return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+  }
+
   static uint64_t mVRAMUsageDT;
   static uint64_t mVRAMUsageSS;
 
 private:
   friend class SourceSurfaceD2D1;
 
   typedef std::unordered_set<DrawTargetD2D1*> TargetSet;
 
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -444,16 +444,40 @@ Factory::DoesBackendSupportDataDrawtarge
   case BackendType::COREGRAPHICS:
   case BackendType::SKIA:
     return true;
   }
 
   return false;
 }
 
+uint32_t
+Factory::GetMaxSurfaceSize(BackendType aType)
+{
+  switch (aType) {
+  case BackendType::CAIRO:
+  case BackendType::COREGRAPHICS:
+    return DrawTargetCairo::GetMaxSurfaceSize();
+#ifdef XP_MACOSX
+  case BackendType::COREGRAPHICS_ACCELERATED:
+    return DrawTargetCG::GetMaxSurfaceSize();
+#endif
+  case BackendType::SKIA:
+    return INT_MAX;
+#ifdef WIN32
+  case BackendType::DIRECT2D:
+    return DrawTargetD2D::GetMaxSurfaceSize();
+  case BackendType::DIRECT2D1_1:
+    return DrawTargetD2D1::GetMaxSurfaceSize();
+#endif
+  default:
+    return 0;
+  }
+}
+
 TemporaryRef<ScaledFont>
 Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize)
 {
   switch (aNativeFont.mType) {
 #ifdef WIN32
   case NativeFontType::DWRITE_FONT_FACE:
     {
       return new ScaledFontDWrite(static_cast<IDWriteFontFace*>(aNativeFont.mFont), aSize);
--- a/gfx/angle/src/libGLESv2/libGLESv2.cpp
+++ b/gfx/angle/src/libGLESv2/libGLESv2.cpp
@@ -290,17 +290,17 @@ void GL_APIENTRY glBlendColor(GLclampf r
 {
     EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",
           red, green, blue, alpha);
 
     gl::Context* context = gl::getNonLostContext();
 
     if (context)
     {
-        context->getState().setBlendColor(gl::clamp01(red), gl::clamp01(green), gl::clamp01(blue), gl::clamp01(alpha));
+        context->getState().setBlendColor(red, green, blue, alpha);
     }
 }
 
 void GL_APIENTRY glBlendEquation(GLenum mode)
 {
     glBlendEquationSeparate(mode, mode);
 }
 
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -881,17 +881,17 @@ public:
     }
 
     void fBindTexture(GLenum target, GLuint texture) {
         BEFORE_GL_CALL;
         mSymbols.fBindTexture(target, texture);
         AFTER_GL_CALL;
     }
 
-    void fBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+    void fBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
         BEFORE_GL_CALL;
         mSymbols.fBlendColor(red, green, blue, alpha);
         AFTER_GL_CALL;
     }
 
     void fBlendEquation(GLenum mode) {
         BEFORE_GL_CALL;
         mSymbols.fBlendEquation(mode);
@@ -981,17 +981,17 @@ public:
     }
 
     void fClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {
         BEFORE_GL_CALL;
         mSymbols.fClearBufferuiv(buffer, drawbuffer, value);
         AFTER_GL_CALL;
     }
 
-    void fClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) {
+    void fClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
         BEFORE_GL_CALL;
         mSymbols.fClearColor(r, g, b, a);
         AFTER_GL_CALL;
     }
 
     void fClearStencil(GLint s) {
         BEFORE_GL_CALL;
         mSymbols.fClearStencil(s);
--- a/gfx/gl/GLContextSymbols.h
+++ b/gfx/gl/GLContextSymbols.h
@@ -44,17 +44,17 @@ struct GLContextSymbols
     typedef void (GLAPIENTRY * PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar* name);
     PFNGLBINDATTRIBLOCATIONPROC fBindAttribLocation;
     typedef void (GLAPIENTRY * PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
     PFNGLBINDBUFFERPROC fBindBuffer;
     typedef void (GLAPIENTRY * PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
     PFNGLBINDTEXTUREPROC fBindTexture;
     typedef void (GLAPIENTRY * PFNGLBINDVERTEXARRAYPROC) (GLuint array);
     PFNGLBINDVERTEXARRAYPROC fBindVertexArray;
-    typedef void (GLAPIENTRY * PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+    typedef void (GLAPIENTRY * PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
     PFNGLBLENDCOLORPROC fBlendColor;
     typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONPROC) (GLenum mode);
     PFNGLBLENDEQUATIONPROC fBlendEquation;
     typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum, GLenum);
     PFNGLBLENDEQUATIONSEPARATEPROC fBlendEquationSeparate;
     typedef void (GLAPIENTRY * PFNGLBLENDFUNCPROC) (GLenum, GLenum);
     PFNGLBLENDFUNCPROC fBlendFunc;
     typedef void (GLAPIENTRY * PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
@@ -68,17 +68,17 @@ struct GLContextSymbols
     typedef void (GLAPIENTRY * PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
     PFNGLCLEARBUFFERFIPROC fClearBufferfi;
     typedef void (GLAPIENTRY * PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat* value);
     PFNGLCLEARBUFFERFVPROC fClearBufferfv;
     typedef void (GLAPIENTRY * PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint* value);
     PFNGLCLEARBUFFERIVPROC fClearBufferiv;
     typedef void (GLAPIENTRY * PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint* value);
     PFNGLCLEARBUFFERUIVPROC fClearBufferuiv;
-    typedef void (GLAPIENTRY * PFNGLCLEARCOLORPROC) (GLclampf, GLclampf, GLclampf, GLclampf);
+    typedef void (GLAPIENTRY * PFNGLCLEARCOLORPROC) (GLfloat, GLfloat, GLfloat, GLfloat);
     PFNGLCLEARCOLORPROC fClearColor;
     typedef void (GLAPIENTRY * PFNGLCLEARSTENCILPROC) (GLint);
     PFNGLCLEARSTENCILPROC fClearStencil;
     typedef void (GLAPIENTRY * PFNGLCOLORMASKPROC) (realGLboolean red, realGLboolean green, realGLboolean blue, realGLboolean alpha);
     PFNGLCOLORMASKPROC fColorMask;
     typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE2D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *pixels);
     PFNGLCOMPRESSEDTEXIMAGE2D fCompressedTexImage2D;
     typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *pixels);
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -62,23 +62,32 @@ public:
   RefPtr<gfx::DataSourceSurface> mSurface;
 };
 
 BasicCompositor::BasicCompositor(nsIWidget *aWidget)
   : mWidget(aWidget)
 {
   MOZ_COUNT_CTOR(BasicCompositor);
   SetBackend(LayersBackend::LAYERS_BASIC);
+
+  mMaxTextureSize =
+    Factory::GetMaxSurfaceSize(gfxPlatform::GetPlatform()->GetContentBackend());
 }
 
 BasicCompositor::~BasicCompositor()
 {
   MOZ_COUNT_DTOR(BasicCompositor);
 }
 
+int32_t
+BasicCompositor::GetMaxTextureSize() const
+{
+  return mMaxTextureSize;
+}
+
 void
 BasicCompositingRenderTarget::BindRenderTarget()
 {
   if (mClearOnBind) {
     mDrawTarget->ClearRect(Rect(0, 0, mSize.width, mSize.height));
     mClearOnBind = false;
   }
 }
--- a/gfx/layers/basic/BasicCompositor.h
+++ b/gfx/layers/basic/BasicCompositor.h
@@ -98,17 +98,17 @@ public:
   virtual void EndFrame() MOZ_OVERRIDE;
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) MOZ_OVERRIDE
   {
     NS_RUNTIMEABORT("We shouldn't ever hit this");
   }
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE { return true; }
   virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) MOZ_OVERRIDE { return true; }
-  virtual int32_t GetMaxTextureSize() const MOZ_OVERRIDE { return INT32_MAX; }
+  virtual int32_t GetMaxTextureSize() const MOZ_OVERRIDE;
   virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) MOZ_OVERRIDE { }
   
   virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) MOZ_OVERRIDE {
   }
 
   virtual void MakeCurrent(MakeCurrentFlags aFlags = 0) MOZ_OVERRIDE { }
 
   virtual void PrepareViewport(const gfx::IntSize& aSize) MOZ_OVERRIDE { }
@@ -135,14 +135,16 @@ private:
 
   // The final destination surface
   RefPtr<gfx::DrawTarget> mDrawTarget;
   // The current render target for drawing
   RefPtr<BasicCompositingRenderTarget> mRenderTarget;
 
   gfx::IntRect mInvalidRect;
   nsIntRegion mInvalidRegion;
+
+  uint32_t mMaxTextureSize;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_BASICCOMPOSITOR_H */
--- a/gfx/layers/client/ClientTiledPaintedLayer.cpp
+++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp
@@ -214,52 +214,75 @@ ClientTiledPaintedLayer::IsScrollingOnCo
          !FuzzyEqualsAdditive(compositorMetrics.GetScrollOffset().y,
                               aParentMetrics.GetScrollOffset().y,
                               COORDINATE_EPSILON);
 }
 
 bool
 ClientTiledPaintedLayer::UseFastPath()
 {
+  // The fast path doesn't allow rendering at low resolution. It will draw the low-res
+  // area at full resolution and cause OOM.
+  if (gfxPrefs::UseLowPrecisionBuffer()) {
+    return false;
+  }
+
   LayerMetricsWrapper scrollAncestor;
   GetAncestorLayers(&scrollAncestor, nullptr);
   if (!scrollAncestor) {
     return true;
   }
   const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
 
   bool multipleTransactionsNeeded = gfxPlatform::GetPlatform()->UseProgressivePaint()
-                                 || gfxPrefs::UseLowPrecisionBuffer()
                                  || !parentMetrics.GetCriticalDisplayPort().IsEmpty();
   bool isFixed = GetIsFixedPosition() || GetParent()->GetIsFixedPosition();
   bool isScrollable = parentMetrics.IsScrollable();
 
-  return !multipleTransactionsNeeded || isFixed || !isScrollable
-#if !defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ)
-         || !IsScrollingOnCompositor(parentMetrics)
+  return !multipleTransactionsNeeded || isFixed || !isScrollable;
+}
+
+bool
+ClientTiledPaintedLayer::UseProgressiveDraw() {
+  // Don't draw progressively in a reftest scenario (that's what the HasShadowTarget() check is for).
+  if (!gfxPlatform::GetPlatform()->UseProgressivePaint() || ClientManager()->HasShadowTarget()) {
+    return false;
+  }
+
+  // XXX We probably want to disable progressive drawing for non active APZ layers in the future
+  //     but we should wait for a proper test case before making this change.
+
+#if 0 //!defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ)
+  LayerMetricsWrapper scrollAncestor;
+  GetAncestorLayers(&scrollAncestor, nullptr);
+  if (!scrollAncestor) {
+    return true;
+  }
+  const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
+
+  return !IsScrollingOnCompositor(parentMetrics);
+#else
+  return true;
 #endif
-         ;
 }
 
 bool
 ClientTiledPaintedLayer::RenderHighPrecision(nsIntRegion& aInvalidRegion,
                                             const nsIntRegion& aVisibleRegion,
                                             LayerManager::DrawPaintedLayerCallback aCallback,
                                             void* aCallbackData)
 {
   // If we have no high-precision stuff to draw, or we have started drawing low-precision
   // already, then we shouldn't do anything there.
   if (aInvalidRegion.IsEmpty() || mPaintData.mLowPrecisionPaintCount != 0) {
     return false;
   }
 
-  // Only draw progressively when the resolution is unchanged, and we're not
-  // in a reftest scenario (that's what the HasShadowManager() check is for).
-  if (gfxPlatform::GetPlatform()->UseProgressivePaint() &&
-      !ClientManager()->HasShadowTarget() &&
+  // Only draw progressively when the resolution is unchanged
+  if (UseProgressiveDraw() &&
       mContentClient->mTiledBuffer.GetFrameResolution() == mPaintData.mResolution) {
     // Store the old valid region, then clear it before painting.
     // We clip the old valid region to the visible region, as it only gets
     // used to decide stale content (currently valid and previously visible)
     nsIntRegion oldValidRegion = mContentClient->mTiledBuffer.GetValidRegion();
     oldValidRegion.And(oldValidRegion, aVisibleRegion);
     if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
       oldValidRegion.And(oldValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
@@ -413,46 +436,30 @@ ClientTiledPaintedLayer::RenderLayer()
   }
 
   if (!ClientManager()->IsRepeatTransaction()) {
     // Only paint the mask layer on the first transaction.
     if (GetMaskLayer()) {
       ToClientLayer(GetMaskLayer())->RenderLayer();
     }
 
-    // For more complex cases we need to calculate a bunch of metrics before we
-    // can do the paint.
-    BeginPaint();
-    if (mPaintData.mPaintFinished) {
-      return;
-    }
-
     // In some cases we can take a fast path and just be done with it.
     if (UseFastPath()) {
       TILING_LOG("TILING %p: Taking fast-path\n", this);
       mValidRegion = neededRegion;
-
-      // Make sure that tiles that fall outside of the visible region or outside of the
-      // critical displayport are discarded on the first update. Also make sure that we
-      // only draw stuff inside the critical displayport on the first update.
-      if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
-        mValidRegion.And(mValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
-        invalidRegion.And(invalidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
-      }
-
-      if (invalidRegion.IsEmpty()) {
-        EndPaint();
-        return;
-      }
-
-      mContentClient->mTiledBuffer.SetFrameResolution(mPaintData.mResolution);
       mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion, callback, data);
       ClientManager()->Hold(this);
       mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER);
-      EndPaint();
+      return;
+    }
+
+    // For more complex cases we need to calculate a bunch of metrics before we
+    // can do the paint.
+    BeginPaint();
+    if (mPaintData.mPaintFinished) {
       return;
     }
 
     // Make sure that tiles that fall outside of the visible region or outside of the
     // critical displayport are discarded on the first update. Also make sure that we
     // only draw stuff inside the critical displayport on the first update.
     mValidRegion.And(mValidRegion, neededRegion);
     if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
--- a/gfx/layers/client/ClientTiledPaintedLayer.h
+++ b/gfx/layers/client/ClientTiledPaintedLayer.h
@@ -102,16 +102,23 @@ private:
   bool UseFastPath();
 
   /**
    * Check if the layer is being scrolled by APZ on the compositor.
    */
   bool IsScrollingOnCompositor(const FrameMetrics& aParentMetrics);
 
   /**
+   * Check if we should use progressive draw on this layer. We will
+   * disable progressive draw based on a preference or if the layer
+   * is not being scrolled.
+   */
+  bool UseProgressiveDraw();
+
+  /**
    * Helper function to do the high-precision paint.
    * This function returns true if it updated the paint buffer.
    */
   bool RenderHighPrecision(nsIntRegion& aInvalidRegion,
                            const nsIntRegion& aVisibleRegion,
                            LayerManager::DrawPaintedLayerCallback aCallback,
                            void* aCallbackData);
 
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -740,17 +740,17 @@ BufferTextureClient::AllocateForSurface(
   MOZ_ASSERT(aSize.width > 0 && aSize.height > 0);
 
   if (aSize.width <= 0 || aSize.height <= 0) {
     gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x" << aSize.height;
     return false;
   }
 
   uint32_t bufSize = ImageDataSerializer::ComputeMinBufferSize(aSize, mFormat);
-  if (!Allocate(bufSize)) {
+  if (!bufSize || !Allocate(bufSize)) {
     return false;
   }
 
   if (aFlags & ALLOC_CLEAR_BUFFER) {
     memset(GetBuffer(), 0, bufSize);
   }
   if (aFlags & ALLOC_CLEAR_BUFFER_WHITE) {
     memset(GetBuffer(), 0xFF, bufSize);
--- a/gfx/qcms/iccread.c
+++ b/gfx/qcms/iccread.c
@@ -542,17 +542,17 @@ static struct lutmABType *read_tag_lutmA
 	struct lutmABType *lut;
 	uint32_t i;
 
 	if (type != LUT_MAB_TYPE && type != LUT_MBA_TYPE) {
 		return NULL;
 	}
 
 	num_in_channels = read_u8(src, offset + 8);
-	num_out_channels = read_u8(src, offset + 8);
+	num_out_channels = read_u8(src, offset + 9);
 	if (num_in_channels > MAX_CHANNELS || num_out_channels > MAX_CHANNELS)
 		return NULL;
 
 	// We require 3in/out channels since we only support RGB->XYZ (or RGB->LAB)
 	// XXX: If we remove this restriction make sure that the number of channels
 	//      is less or equal to the maximum number of mAB curves in qcmsint.h
 	//      also check for clut_size overflow.
 	if (num_in_channels != 3 || num_out_channels != 3)
--- a/gfx/tests/gtest/TestRect.cpp
+++ b/gfx/tests/gtest/TestRect.cpp
@@ -395,35 +395,57 @@ TestFiniteGfx()
 
     // Reset to a finite value...
     values[i] = 5.0*i;
   }
 
   return true;
 }
 
+// We want to test nsRect values that are still in range but where
+// the implementation is at risk of overflowing
+template <class RectType>
+static bool
+TestBug1135677()
+{
+  RectType  rect1(1073741344, 1073741344, 1073756696, 1073819936);
+  RectType  rect2(1073741820, 1073741820, 14400, 77640);
+  RectType  dest;
+
+  dest = rect1.Intersect(rect2);
+
+  EXPECT_TRUE(dest.x == 1073741820 && dest.y == 1073741820 &&
+              dest.width == 14400 && dest.height == 77640) <<
+              "[1] Operation should not overflow internally.";
+
+  return true;
+}
+
 TEST(Gfx, nsRect) {
   TestConstructors<nsRect>();
   TestEqualityOperator<nsRect>();
   TestContainment<nsRect>();
   TestIntersects<nsRect>();
   TestIntersection<nsRect>();
   TestUnion<nsRect>();
+  TestBug1135677<nsRect>();
 }
 
 TEST(Gfx, nsIntRect) {
   TestConstructors<nsIntRect>();
   TestEqualityOperator<nsIntRect>();
   TestContainment<nsIntRect>();
   TestIntersects<nsIntRect>();
   TestIntersection<nsIntRect>();
   TestUnion<nsIntRect>();
+  TestBug1135677<nsIntRect>();
 }
 
 TEST(Gfx, gfxRect) {
   TestConstructors<gfxRect>();
   // Skip TestEqualityOperator<gfxRect>(); as gfxRect::operator== is private
   TestContainment<gfxRect>();
   TestIntersects<gfxRect>();
   TestIntersection<gfxRect>();
   TestUnion<gfxRect>();
+  TestBug1135677<gfxRect>();
   TestFiniteGfx();
 }
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -307,17 +307,17 @@ private:
   DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.force-enabled", LayersOffMainThreadCompositionForceEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.testing.enabled", LayersOffMainThreadCompositionTestingEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.use-image-offscreen-surfaces",   UseImageOffscreenSurfaces, bool, false);
   DECL_GFX_PREF(Live, "layers.orientation.sync.timeout",       OrientationSyncMillis, uint32_t, (uint32_t)0);
   DECL_GFX_PREF(Once, "layers.d3d11.disable-warp",             LayersD3D11DisableWARP, bool, false);
   DECL_GFX_PREF(Once, "layers.d3d11.force-warp",               LayersD3D11ForceWARP, bool, false);
   DECL_GFX_PREF(Once, "layers.prefer-d3d9",                    LayersPreferD3D9, bool, false);
   DECL_GFX_PREF(Once, "layers.prefer-opengl",                  LayersPreferOpenGL, bool, false);
-  DECL_GFX_PREF(Once, "layers.progressive-paint",              ProgressivePaintDoNotUseDirectly, bool, false);
+  DECL_GFX_PREF(Live, "layers.progressive-paint",              ProgressivePaintDoNotUseDirectly, bool, false);
   DECL_GFX_PREF(Once, "layers.uniformity-info",                UniformityInfo, bool, false);
   DECL_GFX_PREF(Once, "layers.gralloc.disable",                DisableGralloc, bool, false);
 
   DECL_GFX_PREF(Live, "layout.css.scroll-behavior.damping-ratio", ScrollBehaviorDampingRatio, float, 1.0f);
   DECL_GFX_PREF(Live, "layout.css.scroll-behavior.enabled",    ScrollBehaviorEnabled, bool, false);
   DECL_GFX_PREF(Live, "layout.css.scroll-behavior.spring-constant", ScrollBehaviorSpringConstant, float, 250.0f);
   DECL_GFX_PREF(Once, "layout.css.touch_action.enabled",       TouchActionEnabled, bool, false);
   DECL_GFX_PREF(Once, "layout.frame_rate",                     LayoutFrameRate, int32_t, -1);
--- a/ipc/glue/URIParams.ipdlh
+++ b/ipc/glue/URIParams.ipdlh
@@ -59,22 +59,28 @@ struct IconURIParams
   uint32_t size;
   nsCString contentType;
   nsCString fileName;
   nsCString stockIcon;
   int32_t iconSize;
   int32_t iconState;
 };
 
+struct NullPrincipalURIParams
+{
+  // Purposefully empty. Null principal URIs do not round-trip.
+};
+
 union URIParams
 {
   SimpleURIParams;
   StandardURLParams;
   JARURIParams;
   IconURIParams;
+  NullPrincipalURIParams;
 };
 
 union OptionalURIParams
 {
   void_t;
   URIParams;
 };
 
--- a/ipc/glue/URIUtils.cpp
+++ b/ipc/glue/URIUtils.cpp
@@ -8,16 +8,17 @@
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDebug.h"
 #include "nsID.h"
 #include "nsJARURI.h"
 #include "nsIIconURI.h"
+#include "nsNullPrincipalURI.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsThreadUtils.h"
 
 using namespace mozilla::ipc;
 using mozilla::ArrayLength;
 
 namespace {
@@ -36,17 +37,17 @@ void
 SerializeURI(nsIURI* aURI,
              URIParams& aParams)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aURI);
 
   nsCOMPtr<nsIIPCSerializableURI> serializable = do_QueryInterface(aURI);
   if (!serializable) {
-    MOZ_CRASH("All IPDL URIs must be serializable scheme!");
+    MOZ_CRASH("All IPDL URIs must be serializable!");
   }
 
   serializable->Serialize(aParams);
   if (aParams.type() == URIParams::T__None) {
     MOZ_CRASH("Serialize failed!");
   }
 }
 
@@ -85,16 +86,20 @@ DeserializeURI(const URIParams& aParams)
     case URIParams::TJARURIParams:
       serializable = do_CreateInstance(kJARURICID);
       break;
 
     case URIParams::TIconURIParams:
       serializable = do_CreateInstance(kIconURICID);
       break;
 
+    case URIParams::TNullPrincipalURIParams:
+      serializable = new nsNullPrincipalURI();
+      break;
+
     default:
       MOZ_CRASH("Unknown params!");
   }
 
   MOZ_ASSERT(serializable);
 
   if (!serializable->Deserialize(aParams)) {
     MOZ_ASSERT(false, "Deserialize failed!");
--- a/js/public/Proxy.h
+++ b/js/public/Proxy.h
@@ -350,17 +350,17 @@ class JS_FRIEND_API(BaseProxyHandler)
  * reimplemented such that they forward their behavior to the target. This
  * allows consumers of this class to forward to another object as transparently
  * and efficiently as possible.
  *
  * Important: If you add a method implementation here, you probably also need
  * to add an override in CrossCompartmentWrapper. If you don't, you risk
  * compartment mismatches. See bug 945826 comment 0.
  */
-class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler
+class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler
 {
   public:
     explicit MOZ_CONSTEXPR DirectProxyHandler(const void *aFamily, bool aHasPrototype = false,
                                               bool aHasSecurityPolicy = false)
       : BaseProxyHandler(aFamily, aHasPrototype, aHasSecurityPolicy)
     { }
 
     /* Standard internal methods. */
--- a/js/src/builtin/SymbolObject.cpp
+++ b/js/src/builtin/SymbolObject.cpp
@@ -24,17 +24,17 @@ const Class SymbolObject::class_ = {
     nullptr, /* getProperty */
     nullptr, /* setProperty */
     nullptr, /* enumerate */
     nullptr, /* resolve */
     convert
 };
 
 SymbolObject *
-SymbolObject::create(JSContext *cx, JS::Symbol *symbol)
+SymbolObject::create(JSContext *cx, JS::HandleSymbol symbol)
 {
     JSObject *obj = NewBuiltinClassInstance(cx, &class_);
     if (!obj)
         return nullptr;
     SymbolObject &symobj = obj->as<SymbolObject>();
     symobj.setPrimitiveValue(symbol);
     return &symobj;
 }
--- a/js/src/builtin/SymbolObject.h
+++ b/js/src/builtin/SymbolObject.h
@@ -23,17 +23,17 @@ class SymbolObject : public NativeObject
     static const Class class_;
 
     static JSObject *initClass(JSContext *cx, js::HandleObject obj);
 
     /*
      * Creates a new Symbol object boxing the given primitive Symbol.  The
      * object's [[Prototype]] is determined from context.
      */
-    static SymbolObject *create(JSContext *cx, JS::Symbol *symbol);
+    static SymbolObject *create(JSContext *cx, JS::HandleSymbol symbol);
 
     JS::Symbol *unbox() const {
         return getFixedSlot(PRIMITIVE_VALUE_SLOT).toSymbol();
     }
 
   private:
     inline void setPrimitiveValue(JS::Symbol *symbol) {
         setFixedSlot(PRIMITIVE_VALUE_SLOT, SymbolValue(symbol));
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -178,16 +178,28 @@ GetBuildConfiguration(JSContext *cx, uns
 #ifdef EXPOSE_INTL_API
     value = BooleanValue(true);
 #else
     value = BooleanValue(false);
 #endif
     if (!JS_SetProperty(cx, info, "intl-api", value))
         return false;
 
+#if defined(XP_WIN)
+    value = BooleanValue(false);
+#elif defined(SOLARIS)
+    value = BooleanValue(false);
+#elif defined(XP_UNIX)
+    value = BooleanValue(true);
+#else
+    value = BooleanValue(false);
+#endif
+    if (!JS_SetProperty(cx, info, "mapped-array-buffer", value))
+        return false;
+
     args.rval().setObject(*info);
     return true;
 }
 
 static bool
 GC(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2563,17 +2563,17 @@ Parser<ParseHandler>::functionArgsAndBod
         if (!tokenStream.matchToken(&matched, TOK_RC))
             return false;
         if (!matched) {
             report(ParseError, false, null(), JSMSG_CURLY_AFTER_BODY);
             return false;
         }
         funbox->bufEnd = pos().begin + 1;
     } else {
-#if not JS_HAS_EXPR_CLOSURES
+#if !JS_HAS_EXPR_CLOSURES
         MOZ_ASSERT(kind == Arrow);
 #endif
         if (tokenStream.hadError())
             return false;
         funbox->bufEnd = pos().end;
         if (kind == Statement && !MatchOrInsertSemicolon(tokenStream))
             return false;
     }
--- a/js/src/irregexp/RegExpEngine.cpp
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -1607,18 +1607,18 @@ RegExpCompiler::Assemble(JSContext *cx,
     while (!work_list_.empty())
         work_list_.popCopy()->Emit(this, &new_trace);
 
     RegExpCode code = macro_assembler_->GenerateCode(cx, match_only_);
     if (code.empty())
         return RegExpCode();
 
     if (reg_exp_too_big_) {
+        code.destroy();
         JS_ReportError(cx, "regexp too big");
-        code.destroy();
         return RegExpCode();
     }
 
     return code;
 }
 
 template <typename CharT>
 static void
--- a/js/src/jit/ExecutableAllocator.h
+++ b/js/src/jit/ExecutableAllocator.h
@@ -28,16 +28,17 @@
 
 #include <limits>
 #include <stddef.h> // for ptrdiff_t
 
 #include "jsalloc.h"
 
 #include "jit/arm/Simulator-arm.h"
 #include "jit/mips/Simulator-mips.h"
+#include "js/GCAPI.h"
 #include "js/HashTable.h"
 #include "js/Vector.h"
 
 #ifdef JS_CPU_SPARC
 #ifdef __linux__  // bugzilla 502369
 static void sync_instruction_memory(caddr_t v, u_int len)
 {
     caddr_t end = v + len;
@@ -245,18 +246,21 @@ class ExecutableAllocator {
         // (found, or created if necessary) a pool that had enough space.
         void *result = (*poolp)->alloc(n, type);
         MOZ_ASSERT(result);
         return result;
     }
 
     void releasePoolPages(ExecutablePool *pool) {
         MOZ_ASSERT(pool->m_allocation.pages);
-        if (destroyCallback)
+        if (destroyCallback) {
+            // Do not allow GC during the page release callback.
+            JS::AutoSuppressGCAnalysis nogc;
             destroyCallback(pool->m_allocation.pages, pool->m_allocation.size);
+        }
         systemRelease(pool->m_allocation);
         MOZ_ASSERT(m_pools.initialized());
         m_pools.remove(m_pools.lookup(pool));   // this asserts if |pool| is not in m_pools
     }
 
     void addSizeOfCode(JS::CodeSizes *sizes) const;
 
     void setDestroyCallback(DestroyCallback destroyCallback) {
--- a/js/src/jit/IonOptimizationLevels.cpp
+++ b/js/src/jit/IonOptimizationLevels.cpp
@@ -29,17 +29,17 @@ OptimizationInfo::initNormalOptimization
     inlineInterpreted_ = true;
     inlineNative_ = true;
     gvn_ = true;
     licm_ = true;
     rangeAnalysis_ = true;
     loopUnrolling_ = true;
     autoTruncate_ = true;
     sink_ = true;
-    registerAllocator_ = RegisterAllocator_LSRA;
+    registerAllocator_ = RegisterAllocator_Backtracking;
 
     inlineMaxTotalBytecodeLength_ = 1000;
     inliningMaxCallerBytecodeLength_ = 10000;
     maxInlineDepth_ = 3;
     scalarReplacement_ = true;
     smallFunctionMaxInlineDepth_ = 10;
     compilerWarmUpThreshold_ = CompilerWarmupThreshold;
     inliningWarmUpThresholdFactor_ = 0.125;
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -140,16 +140,24 @@ JS_NewObjectWithUniqueType(JSContext *cx
                                                  parent, SingletonObject));
     if (!obj)
         return nullptr;
     if (!JS_SplicePrototype(cx, obj, proto))
         return nullptr;
     return obj;
 }
 
+JS_FRIEND_API(JSObject *)
+JS_NewObjectWithoutMetadata(JSContext *cx, const JSClass *clasp, JS::Handle<JSObject*> proto)
+{
+    // Use an AutoEnterAnalysis to suppress invocation of the metadata callback.
+    AutoEnterAnalysis enter(cx);
+    return JS_NewObjectWithGivenProto(cx, clasp, proto);
+}
+
 JS_FRIEND_API(JSPrincipals *)
 JS_GetCompartmentPrincipals(JSCompartment *compartment)
 {
     return compartment->principals;
 }
 
 JS_FRIEND_API(void)
 JS_SetCompartmentPrincipals(JSCompartment *compartment, JSPrincipals *principals)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -55,16 +55,23 @@ JS_GetObjectFunction(JSObject *obj);
 
 extern JS_FRIEND_API(bool)
 JS_SplicePrototype(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto);
 
 extern JS_FRIEND_API(JSObject *)
 JS_NewObjectWithUniqueType(JSContext *cx, const JSClass *clasp, JS::HandleObject proto,
                            JS::HandleObject parent);
 
+// Allocate an object in exactly the same way as JS_NewObjectWithGivenProto, but
+// without invoking the metadata callback on it.  This allows creation of
+// internal bookkeeping objects that are guaranteed to not have metadata
+// attached to them.
+extern JS_FRIEND_API(JSObject *)
+JS_NewObjectWithoutMetadata(JSContext *cx, const JSClass *clasp, JS::Handle<JSObject*> proto);
+
 extern JS_FRIEND_API(uint32_t)
 JS_ObjectCountDynamicSlots(JS::HandleObject obj);
 
 extern JS_FRIEND_API(size_t)
 JS_SetProtoCalled(JSContext *cx);
 
 extern JS_FRIEND_API(size_t)
 JS_GetCustomIteratorCount(JSContext *cx);
@@ -139,16 +146,34 @@ JS_ObjectToInnerObject(JSContext *cx, JS
 /* Requires obj != nullptr. */
 extern JS_FRIEND_API(JSObject *)
 JS_ObjectToOuterObject(JSContext *cx, JS::HandleObject obj);
 
 extern JS_FRIEND_API(JSObject *)
 JS_CloneObject(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto,
                JS::HandleObject parent);
 
+/*
+ * Copy the own properties of src to dst in a fast way.  src and dst must both
+ * be native and must be in the compartment of cx.  They must have the same
+ * class, the same parent, and the same prototype.  Class reserved slots will
+ * NOT be copied.
+ *
+ * dst must not have any properties on it before this function is called.
+ *
+ * src must have been allocated via JS_NewObjectWithoutMetadata so that we can
+ * be sure it has no metadata that needs copying to dst.  This also means that
+ * dst needs to have the compartment global as its parent.  This function will
+ * preserve the existing metadata on dst, if any.
+ */
+extern JS_FRIEND_API(bool)
+JS_InitializePropertiesFromCompatibleNativeObject(JSContext *cx,
+                                                  JS::HandleObject dst,
+                                                  JS::HandleObject src);
+
 extern JS_FRIEND_API(JSString *)
 JS_BasicObjectToString(JSContext *cx, JS::HandleObject obj);
 
 JS_FRIEND_API(void)
 js_ReportOverRecursed(JSContext *maybecx);
 
 JS_FRIEND_API(bool)
 js_ObjectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1262,21 +1262,26 @@ js::NewObjectWithGivenTaggedProto(Exclus
     }
 
     RootedObjectGroup group(cxArg, ObjectGroup::defaultNewGroup(cxArg, clasp, proto, nullptr));
     if (!group)
         return nullptr;
 
     /*
      * Default parent to the parent of the prototype, which was set from
-     * the parent of the prototype's constructor.
+     * the parent of the prototype's constructor.  If there is no
+     * prototype, use the global.
      */
     RootedObject parent(cxArg, parentArg);
-    if (!parent && proto.isObject())
-        parent = proto.toObject()->getParent();
+    if (!parent) {
+        if (proto.isObject())
+            parent = proto.toObject()->getParent();
+        else
+            parent = cxArg->global();
+    }
 
     RootedObject obj(cxArg, NewObject(cxArg, group, parent, allocKind, newKind));
     if (!obj)
         return nullptr;
 
     if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
         NewObjectCache &cache = cxArg->asJSContext()->runtime()->newObjectCache;
         NewObjectCache::EntryIndex entry = -1;
@@ -1859,17 +1864,18 @@ js::DeepCloneObjectLiteral(JSContext *cx
         clone->setDenseInitializedLength(i + 1);
         clone->initDenseElement(i, v);
     }
 
     MOZ_ASSERT(obj->compartment() == clone->compartment());
     MOZ_ASSERT(!obj->hasPrivate());
     RootedShape shape(cx, obj->lastProperty());
     size_t span = shape->slotSpan();
-    clone->setLastProperty(cx, shape);
+    if (!clone->setLastProperty(cx, shape))
+        return nullptr;
     for (size_t i = 0; i < span; i++) {
         v = obj->getSlot(i);
         if (v.isObject()) {
             deepObj = &v.toObject().as<NativeObject>();
             deepObj = js::DeepCloneObjectLiteral(cx, deepObj, newKind);
             if (!deepObj)
                 return nullptr;
             v.setObject(*deepObj);
@@ -1889,16 +1895,68 @@ js::DeepCloneObjectLiteral(JSContext *cx
     if (obj->is<ArrayObject>() && obj->denseElementsAreCopyOnWrite()) {
         if (!ObjectElements::MakeElementsCopyOnWrite(cx, clone))
             return nullptr;
     }
 
     return clone;
 }
 
+static bool
+InitializePropertiesFromCompatibleNativeObject(JSContext *cx,
+                                               HandleNativeObject dst,
+                                               HandleNativeObject src)
+{
+    assertSameCompartment(cx, src, dst);
+    MOZ_ASSERT(src->getClass() == dst->getClass());
+    MOZ_ASSERT(src->getParent() == dst->getParent());
+    MOZ_ASSERT(dst->getParent() == cx->global());
+    MOZ_ASSERT(src->getProto() == dst->getProto());
+    MOZ_ASSERT(dst->lastProperty()->getObjectFlags() == 0);
+    MOZ_ASSERT(!src->getMetadata());
+    MOZ_ASSERT(!src->isSingleton());
+
+    // Save the dst metadata, if any, before we start messing with its shape.
+    RootedObject dstMetadata(cx, dst->getMetadata());
+
+    if (!dst->ensureElements(cx, src->getDenseInitializedLength()))
+        return false;
+
+    uint32_t initialized = src->getDenseInitializedLength();
+    for (uint32_t i = 0; i < initialized; ++i) {
+        dst->setDenseInitializedLength(i + 1);
+        dst->initDenseElement(i, src->getDenseElement(i));
+    }
+
+    MOZ_ASSERT(!src->hasPrivate());
+    RootedShape shape(cx, src->lastProperty());
+    size_t span = shape->slotSpan();
+    if (!dst->setLastProperty(cx, shape))
+        return false;
+    for (size_t i = JSCLASS_RESERVED_SLOTS(src->getClass()); i < span; i++)
+        dst->setSlot(i, src->getSlot(i));
+
+    if (dstMetadata) {
+        if (!js::SetObjectMetadata(cx, dst, dstMetadata))
+            return false;
+    }
+
+    return true;
+}
+
+JS_FRIEND_API(bool)
+JS_InitializePropertiesFromCompatibleNativeObject(JSContext *cx,
+                                                  HandleObject dst,
+                                                  HandleObject src)
+{
+    return InitializePropertiesFromCompatibleNativeObject(cx,
+                                                          dst.as<NativeObject>(),
+                                                          src.as<NativeObject>());
+}
+
 template<XDRMode mode>
 bool
 js::XDRObjectLiteral(XDRState<mode> *xdr, MutableHandleNativeObject obj)
 {
     /* NB: Keep this in sync with DeepCloneObjectLiteral. */
 
     JSContext *cx = xdr->cx();
     MOZ_ASSERT_IF(mode == XDR_ENCODE && obj->isSingleton(),
@@ -3551,17 +3609,18 @@ js::PrimitiveToObject(JSContext *cx, con
         Rooted<JSString*> str(cx, v.toString());
         return StringObject::create(cx, str);
     }
     if (v.isNumber())
         return NumberObject::create(cx, v.toNumber());
     if (v.isBoolean())
         return BooleanObject::create(cx, v.toBoolean());
     MOZ_ASSERT(v.isSymbol());
-    return SymbolObject::create(cx, v.toSymbol());
+    RootedSymbol symbol(cx, v.toSymbol());
+    return SymbolObject::create(cx, symbol);
 }
 
 /*
  * Invokes the ES5 ToObject algorithm on vp, returning the result. If vp might
  * already be an object, use ToObject. reportCantConvert controls how null and
  * undefined errors are reported.
  *
  * Callers must handle the already-object case.
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -489,16 +489,21 @@ if CONFIG['MOZ_LINKER']:
 if CONFIG['_MSC_VER']:
     if CONFIG['CPU_ARCH'] == 'x86':
         SOURCES['builtin/RegExp.cpp'].no_pgo = True # Bug 772303
     elif CONFIG['CPU_ARCH'] == 'x86_64' and CONFIG['JS_HAS_CTYPES']:
         SOURCES['ctypes/CTypes.cpp'].no_pgo = True # Bug 810661
     # Prevent floating point errors caused by VC++ optimizations
     # XXX We should add this to CXXFLAGS, too?
     CFLAGS += ['-fp:precise']
+    # C4805 warns mixing bool with other integral types in computation.
+    # But given the conversion from bool is specified, and this is a
+    # pattern widely used in code in js/src, suppress this warning here.
+    CXXFLAGS += ['-wd4805']
+    CXXFLAGS += ['-we4067', '-we4258', '-we4275']
 
 if CONFIG['OS_ARCH'] not in ('WINNT', 'HP-UX'):
     OS_LIBS += [
         'm',
     ]
 
 if CONFIG['OS_ARCH'] == 'FreeBSD':
     OS_LIBS += [
--- a/js/src/tests/js1_8_5/extensions/file-mapped-arraybuffers.js
+++ b/js/src/tests/js1_8_5/extensions/file-mapped-arraybuffers.js
@@ -31,10 +31,11 @@ function test() {
     view = new Uint8Array(buffer3);
     assertEq(viewToString(view), "01234567");
 
     // Check that invalid sizes and offsets are caught
     assertThrows(() => createMappedArrayBuffer("empty.txt", 8), RangeError);
     assertThrows(() => createMappedArrayBuffer("empty.txt", 0, 8), Error);
 }
 
-test();
+if (getBuildConfiguration()["mapped-array-buffer"])
+    test();
 reportCompare(0, 0, 'ok');
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -247,17 +247,17 @@ class ObjectGroup : public gc::TenuredCe
 
     UnboxedLayout *maybeUnboxedLayoutDontCheckGeneration() const {
         if (addendumKind() == Addendum_UnboxedLayout)
             return reinterpret_cast<UnboxedLayout *>(addendum_);
         return nullptr;
     }
 
     TypeNewScript *anyNewScript();
-    void detachNewScript(bool writeBarrier);
+    void detachNewScript(bool writeBarrier, ObjectGroup *replacement);
 
     ObjectGroupFlags flagsDontCheckGeneration() {
         return flags_;
     }
 
   public:
 
     ObjectGroupFlags flags() {
@@ -475,17 +475,17 @@ class ObjectGroup : public gc::TenuredCe
     bool addDefiniteProperties(ExclusiveContext *cx, Shape *shape);
     bool matchDefiniteProperties(HandleObject obj);
     void markPropertyNonData(ExclusiveContext *cx, jsid id);
     void markPropertyNonWritable(ExclusiveContext *cx, jsid id);
     void markStateChange(ExclusiveContext *cx);
     void setFlags(ExclusiveContext *cx, ObjectGroupFlags flags);
     void markUnknown(ExclusiveContext *cx);
     void maybeClearNewScriptOnOOM();
-    void clearNewScript(ExclusiveContext *cx);
+    void clearNewScript(ExclusiveContext *cx, ObjectGroup *replacement = nullptr);
     bool isPropertyNonData(jsid id);
     bool isPropertyNonWritable(jsid id);
 
     void print();
 
     inline void clearProperties();
     void maybeSweep(AutoClearTypeInferenceStateOnOOM *oom);
 
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -2760,28 +2760,36 @@ ObjectGroup::anyNewScript()
     if (newScript())
         return newScript();
     if (maybeUnboxedLayout())
         return unboxedLayout().newScript();
     return nullptr;
 }
 
 void
-ObjectGroup::detachNewScript(bool writeBarrier)
+ObjectGroup::detachNewScript(bool writeBarrier, ObjectGroup *replacement)
 {
     // Clear the TypeNewScript from this ObjectGroup and, if it has been
     // analyzed, remove it from the newObjectGroups table so that it will not be
     // produced by calling 'new' on the associated function anymore.
     // The TypeNewScript is not actually destroyed.
     TypeNewScript *newScript = anyNewScript();
     MOZ_ASSERT(newScript);
 
     if (newScript->analyzed()) {
-        newScript->function()->compartment()->objectGroups.removeDefaultNewGroup(nullptr, proto(),
-                                                                                 newScript->function());
+        ObjectGroupCompartment &objectGroups = newScript->function()->compartment()->objectGroups;
+        if (replacement) {
+            MOZ_ASSERT(replacement->newScript()->function() == newScript->function());
+            objectGroups.replaceDefaultNewGroup(nullptr, proto(), newScript->function(),
+                                                replacement);
+        } else {
+            objectGroups.removeDefaultNewGroup(nullptr, proto(), newScript->function());
+        }
+    } else {
+        MOZ_ASSERT(!replacement);
     }
 
     if (this->newScript())
         setAddendum(Addendum_None, nullptr, writeBarrier);
     else
         unboxedLayout().setNewScript(nullptr, writeBarrier);
 }
 
@@ -2795,39 +2803,41 @@ ObjectGroup::maybeClearNewScriptOnOOM()
 
     TypeNewScript *newScript = anyNewScript();
     if (!newScript)
         return;
 
     addFlags(OBJECT_FLAG_NEW_SCRIPT_CLEARED);
 
     // This method is called during GC sweeping, so don't trigger pre barriers.
-    detachNewScript(/* writeBarrier = */ false);
+    detachNewScript(/* writeBarrier = */ false, nullptr);
 
     js_delete(newScript);
 }
 
 void
-ObjectGroup::clearNewScript(ExclusiveContext *cx)
+ObjectGroup::clearNewScript(ExclusiveContext *cx, ObjectGroup *replacement /* = nullptr*/)
 {
     TypeNewScript *newScript = anyNewScript();
     if (!newScript)
         return;
 
     AutoEnterAnalysis enter(cx);
 
-    // Invalidate any Ion code constructing objects of this type.
-    setFlags(cx, OBJECT_FLAG_NEW_SCRIPT_CLEARED);
-
-    // Mark the constructing function as having its 'new' script cleared, so we
-    // will not try to construct another one later.
-    if (!newScript->function()->setNewScriptCleared(cx))
-        cx->recoverFromOutOfMemory();
-
-    detachNewScript(/* writeBarrier = */ true);
+    if (!replacement) {
+        // Invalidate any Ion code constructing objects of this type.
+        setFlags(cx, OBJECT_FLAG_NEW_SCRIPT_CLEARED);
+
+        // Mark the constructing function as having its 'new' script cleared, so we
+        // will not try to construct another one later.
+        if (!newScript->function()->setNewScriptCleared(cx))
+            cx->recoverFromOutOfMemory();
+    }
+
+    detachNewScript(/* writeBarrier = */ true, replacement);
 
     if (cx->isJSContext()) {
         bool found = newScript->rollbackPartiallyInitializedObjects(cx->asJSContext(), this);
 
         // If we managed to rollback any partially initialized objects, then
         // any definite properties we added due to analysis of the new script
         // are now invalid, so remove them. If there weren't any partially
         // initialized objects then we don't need to change type information,
@@ -3263,16 +3273,43 @@ TypeNewScript::make(JSContext *cx, Objec
     if (!newScript->preliminaryObjects)
         return;
 
     group->setNewScript(newScript.forget());
 
     gc::TraceTypeNewScript(group);
 }
 
+// Make a TypeNewScript with the same initializer list as |newScript| but with
+// a new template object.
+/* static */ TypeNewScript *
+TypeNewScript::makeNativeVersion(JSContext *cx, TypeNewScript *newScript,
+                                 PlainObject *templateObject)
+{
+    MOZ_ASSERT(cx->zone()->types.activeAnalysis);
+
+    ScopedJSDeletePtr<TypeNewScript> nativeNewScript(cx->new_<TypeNewScript>());
+    if (!nativeNewScript)
+        return nullptr;
+
+    nativeNewScript->function_ = newScript->function();
+    nativeNewScript->templateObject_ = templateObject;
+
+    Initializer *cursor = newScript->initializerList;
+    while (cursor->kind != Initializer::DONE) { cursor++; }
+    size_t initializerLength = cursor - newScript->initializerList + 1;
+
+    nativeNewScript->initializerList = cx->zone()->pod_calloc<Initializer>(initializerLength);
+    if (!nativeNewScript->initializerList)
+        return nullptr;
+    PodCopy(nativeNewScript->initializerList, newScript->initializerList, initializerLength);
+
+    return nativeNewScript.forget();
+}
+
 size_t
 TypeNewScript::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
 {
     size_t n = mallocSizeOf(this);
     n += mallocSizeOf(preliminaryObjects);
     n += mallocSizeOf(initializerList);
     return n;
 }
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -822,18 +822,16 @@ class TypeNewScript
         uint32_t offset;
         Initializer(Kind kind, uint32_t offset)
           : kind(kind), offset(offset)
         {}
     };
 
   private:
     // Scripted function which this information was computed for.
-    // If instances of the associated group are created without calling
-    // 'new' on this function, the new script information is cleared.
     HeapPtrFunction function_;
 
     // Any preliminary objects with the type. The analyses are not performed
     // until this array is cleared.
     PreliminaryObjectArray *preliminaryObjects;
 
     // After the new script properties analyses have been performed, a template
     // object to use for newly constructed objects. The shape of this object
@@ -897,16 +895,18 @@ class TypeNewScript
     void sweep();
 
     void registerNewObject(PlainObject *res);
     bool maybeAnalyze(JSContext *cx, ObjectGroup *group, bool *regenerate, bool force = false);
 
     bool rollbackPartiallyInitializedObjects(JSContext *cx, ObjectGroup *group);
 
     static void make(JSContext *cx, ObjectGroup *group, JSFunction *fun);
+    static TypeNewScript *makeNativeVersion(JSContext *cx, TypeNewScript *newScript,
+                                            PlainObject *templateObject);
 
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 };
 
 /* Is this a reasonable PC to be doing inlining on? */
 inline bool isInlinableCall(jsbytecode *pc);
 
 bool
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -30,16 +30,19 @@ UnboxedLayout::trace(JSTracer *trc)
     if (newScript())
         newScript()->trace(trc);
 
     if (nativeGroup_)
         MarkObjectGroup(trc, &nativeGroup_, "unboxed_layout_nativeGroup");
 
     if (nativeShape_)
         MarkShape(trc, &nativeShape_, "unboxed_layout_nativeShape");
+
+    if (replacementNewGroup_)
+        MarkObjectGroup(trc, &replacementNewGroup_, "unboxed_layout_replacementNewGroup");
 }
 
 size_t
 UnboxedLayout::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     return mallocSizeOf(this)
          + properties_.sizeOfExcludingThis(mallocSizeOf)
          + (newScript() ? newScript()->sizeOfIncludingThis(mallocSizeOf) : 0)
@@ -167,28 +170,59 @@ UnboxedPlainObject::trace(JSTracer *trc,
 
     // Unboxed objects don't have Values to trace.
     MOZ_ASSERT(*(list + 1) == -1);
 }
 
 /* static */ bool
 UnboxedLayout::makeNativeGroup(JSContext *cx, ObjectGroup *group)
 {
+    AutoEnterAnalysis enter(cx);
+
     UnboxedLayout &layout = group->unboxedLayout();
+    Rooted<TaggedProto> proto(cx, group->proto());
 
     MOZ_ASSERT(!layout.nativeGroup());
 
-    // Immediately clear any new script on the group, as
-    // rollbackPartiallyInitializedObjects() will be confused by the type
-    // changes we make later on.
-    group->clearNewScript(cx);
+    // Immediately clear any new script on the group. This is done by replacing
+    // the existing new script with one for a replacement default new group.
+    // This is done so that the size of the replacment group's objects is the
+    // same as that for the unboxed group, so that we do not see polymorphic
+    // slot accesses later on for sites that see converted objects from this
+    // group and objects that were allocated using the replacement new group.
+    RootedObjectGroup replacementNewGroup(cx);
+    if (layout.newScript()) {
+        replacementNewGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto);
+        if (!replacementNewGroup)
+            return false;
+
+        PlainObject *templateObject = NewObjectWithGroup<PlainObject>(cx, replacementNewGroup,
+                                                                      cx->global(), layout.getAllocKind(),
+                                                                      MaybeSingletonObject);
+        if (!templateObject)
+            return false;
 
-    AutoEnterAnalysis enter(cx);
+        for (size_t i = 0; i < layout.properties().length(); i++) {
+            const UnboxedLayout::Property &property = layout.properties()[i];
+            if (!templateObject->addDataProperty(cx, NameToId(property.name), i, JSPROP_ENUMERATE))
+                return false;
+            MOZ_ASSERT(templateObject->slotSpan() == i + 1);
+            MOZ_ASSERT(!templateObject->inDictionaryMode());
+        }
 
-    Rooted<TaggedProto> proto(cx, group->proto());
+        TypeNewScript *replacementNewScript =
+            TypeNewScript::makeNativeVersion(cx, layout.newScript(), templateObject);
+        if (!replacementNewScript)
+            return false;
+
+        replacementNewGroup->setNewScript(replacementNewScript);
+        gc::TraceTypeNewScript(replacementNewGroup);
+
+        group->clearNewScript(cx, replacementNewGroup);
+    }
 
     size_t nfixed = gc::GetGCKindSlots(layout.getAllocKind());
     RootedShape shape(cx, EmptyShape::getInitialShape(cx, &PlainObject::class_, proto,
                                                       cx->global(), nullptr, nfixed, 0));
     if (!shape)
         return false;
 
     for (size_t i = 0; i < layout.properties().length(); i++) {
@@ -209,26 +243,27 @@ UnboxedLayout::makeNativeGroup(JSContext
         return false;
 
     // Propagate all property types from the old group to the new group.
     for (size_t i = 0; i < group->getPropertyCount(); i++) {
         if (ObjectGroup::Property *property = group->getProperty(i)) {
             TypeSet::TypeList types;
             if (!property->types.enumerateTypes(&types))
                 return false;
-            for (size_t i = 0; i < types.length(); i++)
-                AddTypePropertyId(cx, nativeGroup, property->id, types[i]);
+            for (size_t j = 0; j < types.length(); j++)
+                AddTypePropertyId(cx, nativeGroup, property->id, types[j]);
             HeapTypeSet *nativeProperty = nativeGroup->maybeGetProperty(property->id);
             if (nativeProperty->canSetDefinite(i))
                 nativeProperty->setDefinite(i);
         }
     }
 
     layout.nativeGroup_ = nativeGroup;
     layout.nativeShape_ = shape;
+    layout.replacementNewGroup_ = replacementNewGroup;
 
     nativeGroup->setOriginalUnboxedGroup(group);
 
     return true;
 }
 
 /* static */ bool
 UnboxedPlainObject::convertToNative(JSContext *cx, JSObject *obj)
--- a/js/src/vm/UnboxedObject.h
+++ b/js/src/vm/UnboxedObject.h
@@ -66,20 +66,28 @@ class UnboxedLayout : public mozilla::Li
     int32_t *traceList_;
 
     // If objects in this group have ever been converted to native objects,
     // these store the corresponding native group and initial shape for such
     // objects. Type information for this object is reflected in nativeGroup.
     HeapPtrObjectGroup nativeGroup_;
     HeapPtrShape nativeShape_;
 
+    // If nativeGroup is set and this object originally had a TypeNewScript,
+    // this points to the default 'new' group which replaced this one (and
+    // which might itself have been cleared since). This link is only needed to
+    // keep the replacement group from being GC'ed. If it were GC'ed and a new
+    // one regenerated later, that new group might have a different allocation
+    // kind from this group.
+    HeapPtrObjectGroup replacementNewGroup_;
+
   public:
     UnboxedLayout(const PropertyVector &properties, size_t size)
       : size_(size), newScript_(nullptr), traceList_(nullptr),
-        nativeGroup_(nullptr), nativeShape_(nullptr)
+        nativeGroup_(nullptr), nativeShape_(nullptr), replacementNewGroup_(nullptr)
     {
         properties_.appendAll(properties);
     }
 
     ~UnboxedLayout() {
         js_delete(newScript_);
         js_free(traceList_);
     }
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -4314,19 +4314,18 @@ FrameLayerBuilder::PaintItems(nsTArray<C
                               gfxContext *aContext,
                               nsRenderingContext *aRC,
                               nsDisplayListBuilder* aBuilder,
                               nsPresContext* aPresContext,
                               const nsIntPoint& aOffset,
                               float aXScale, float aYScale,
                               int32_t aCommonClipCount)
 {
-#ifdef MOZ_DUMP_PAINTING
   DrawTarget& aDrawTarget = *aRC->GetDrawTarget();
-#endif
+
   int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
   nsRect boundRect = aRect.ToAppUnits(appUnitsPerDevPixel);
   boundRect.MoveBy(NSIntPixelsToAppUnits(aOffset.x, appUnitsPerDevPixel),
                  NSIntPixelsToAppUnits(aOffset.y, appUnitsPerDevPixel));
   boundRect.ScaleInverseRoundOut(aXScale, aYScale);
 
   DisplayItemClip currentClip;
   bool currentClipIsSetInContext = false;
@@ -4366,17 +4365,19 @@ FrameLayerBuilder::PaintItems(nsTArray<C
         NS_ASSERTION(aCommonClipCount < 100,
           "Maybe you really do have more than a hundred clipping rounded rects, or maybe something has gone wrong.");
         currentClip.ApplyTo(aContext, aPresContext, aCommonClipCount);
         aContext->NewPath();
       }
     }
 
     if (cdi->mInactiveLayerManager) {
+      bool saved = aDrawTarget.GetPermitSubpixelAA();
       PaintInactiveLayer(aBuilder, cdi->mInactiveLayerManager, cdi->mItem, aContext, aRC);
+      aDrawTarget.SetPermitSubpixelAA(saved);
     } else {
       nsIFrame* frame = cdi->mItem->Frame();
       frame->AddStateBits(NS_FRAME_PAINTED_THEBES);
 #ifdef MOZ_DUMP_PAINTING
       if (gfxUtils::sDumpPainting) {
         DebugPaintItem(aDrawTarget, aPresContext, cdi->mItem, aBuilder);
       } else {
 #else
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -428,17 +428,17 @@ load 818454.html
 asserts-if(gtk2Widget,0-1) load 822865.html # bug 540078
 load 824862.html
 load 826163.html
 load 833604-1.html
 load 835056.html
 load 836990-1.html
 load 840480.html
 load 847242.html
-load 852293.html
+pref(layers.progressive-paint,false) pref(layers.low-precision-buffer,false) load 852293.html
 load 860579-1.html
 pref(layers.force-active,true) load 859526-1.html
 pref(layers.force-active,true) load 859630-1.html
 load 866588.html
 load 876092.html
 load 876221.html
 load 897852.html
 asserts-if(Android,2) asserts-if(!Android,4-6) load 898913.html # bug 847368
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -2768,22 +2768,50 @@ nsTreeBodyFrame::HandleEvent(nsPresConte
                   CloseCallback, nsITimer::TYPE_ONE_SHOT,
                   getter_AddRefs(mSlots->mTimer));
     }
   }
 
   return NS_OK;
 }
 
-static void
-PaintTreeBody(nsIFrame* aFrame, nsRenderingContext* aCtx,
-              const nsRect& aDirtyRect, nsPoint aPt)
-{
-  static_cast<nsTreeBodyFrame*>(aFrame)->PaintTreeBody(*aCtx, aDirtyRect, aPt);
-}
+class nsDisplayTreeBody MOZ_FINAL : public nsDisplayItem {
+public:
+  nsDisplayTreeBody(nsDisplayListBuilder* aBuilder, nsFrame* aFrame) :
+    nsDisplayItem(aBuilder, aFrame),
+    mDisableSubpixelAA(false) {
+    MOZ_COUNT_CTOR(nsDisplayTreeBody);
+  }
+#ifdef NS_BUILD_REFCNT_LOGGING
+  virtual ~nsDisplayTreeBody() {
+    MOZ_COUNT_DTOR(nsDisplayTreeBody);
+  }
+#endif
+
+  virtual void Paint(nsDisplayListBuilder* aBuilder,
+                     nsRenderingContext* aCtx) MOZ_OVERRIDE
+  {
+    gfxContext* ctx = aCtx->ThebesContext();
+    gfxContextAutoDisableSubpixelAntialiasing disable(ctx, mDisableSubpixelAA);
+    static_cast<nsTreeBodyFrame*>(mFrame)->
+      PaintTreeBody(*aCtx, mVisibleRect, ToReferenceFrame());
+  }
+  NS_DISPLAY_DECL_NAME("XULTreeBody", TYPE_XUL_TREE_BODY)
+
+  virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
+  {
+    bool snap;
+    return GetBounds(aBuilder, &snap);
+  }
+  virtual void DisableComponentAlpha() MOZ_OVERRIDE {
+    mDisableSubpixelAA = true;
+  }
+
+  bool mDisableSubpixelAA;
+};
 
 // Painting routines
 void
 nsTreeBodyFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                   const nsRect&           aDirtyRect,
                                   const nsDisplayListSet& aLists)
 {
   // REVIEW: why did we paint if we were collapsed? that makes no sense!
@@ -2794,18 +2822,17 @@ nsTreeBodyFrame::BuildDisplayList(nsDisp
   nsLeafBoxFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
 
   // Bail out now if there's no view or we can't run script because the
   // document is a zombie
   if (!mView || !GetContent ()->GetComposedDoc()->GetWindow())
     return;
 
   aLists.Content()->AppendNewToTop(new (aBuilder)
-    nsDisplayGeneric(aBuilder, this, ::PaintTreeBody, "XULTreeBody",
-                     nsDisplayItem::TYPE_XUL_TREE_BODY));
+    nsDisplayTreeBody(aBuilder, this));
 }
 
 void
 nsTreeBodyFrame::PaintTreeBody(nsRenderingContext& aRenderingContext,
                                const nsRect& aDirtyRect, nsPoint aPt)
 {
   // Update our available height and our page count.
   CalcInnerBox();
--- a/media/libsoundtouch/src/soundtouch_config.h
+++ b/media/libsoundtouch/src/soundtouch_config.h
@@ -1,19 +1,7 @@
 #include "mozilla/SSE.h"
 
 #ifdef MOZ_SAMPLE_TYPE_FLOAT32
 #define SOUNDTOUCH_FLOAT_SAMPLES 1
 #else
 #define SOUNDTOUCH_INTEGER_SAMPLES 1
 #endif
-
-#ifndef MOZILLA_PRESUME_SSE
-#ifdef MOZ_SAMPLE_TYPE_FLOAT32
-#define SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS 1
-#endif
-#endif
-
-#ifndef MOZILLA_PRESUME_MMX
-#ifdef MOZ_SAMPLE_TYPE_S16
-#define SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS 1
-#endif
-#endif
--- a/media/webrtc/signaling/test/FakeMediaStreams.h
+++ b/media/webrtc/signaling/test/FakeMediaStreams.h
@@ -260,17 +260,23 @@ protected:
     // Note: memory leak
     mMediaStream->Stop();
   }
 
 public:
   explicit Fake_DOMMediaStream(Fake_MediaStream *stream = nullptr)
     : mMediaStream(stream ? stream : new Fake_MediaStream())
     , mVideoTrack(new Fake_MediaStreamTrack(true, this))
-    , mAudioTrack(new Fake_MediaStreamTrack(false, this)) {}
+    , mAudioTrack(new Fake_MediaStreamTrack(false, this))
+    {
+      static size_t counter = 0;
+      std::ostringstream os;
+      os << counter++;
+      mID = os.str();
+    }
 
   NS_DECL_THREADSAFE_ISUPPORTS
 
   static already_AddRefed<Fake_DOMMediaStream>
   CreateSourceStream(nsIDOMWindow* aWindow, uint32_t aHintContents) {
     Fake_SourceMediaStream *source = new Fake_SourceMediaStream();
 
     nsRefPtr<Fake_DOMMediaStream> ds = new Fake_DOMMediaStream(source);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4472,16 +4472,26 @@ pref("dom.mozSettings.SettingsManager.ve
 pref("dom.mozSettings.SettingsRequestManager.verbose.enabled", false);
 pref("dom.mozSettings.SettingsService.verbose.enabled", false);
 
 // Controlling whether we want to allow forcing some Settings
 // IndexedDB transactions to be opened as readonly or keep everything as
 // readwrite.
 pref("dom.mozSettings.allowForceReadOnly", false);
 
+// The interval at which to check for slow running addons
+#ifdef NIGHTLY_BUILD
+pref("browser.addon-watch.interval", 15000);
+#else
+pref("browser.addon-watch.interval", -1);
+#endif
+pref("browser.addon-watch.ignore", "[\"mochikit@mozilla.org\",\"special-powers@mozilla.org\"]");
+// the percentage of time addons are allowed to use without being labeled slow
+pref("browser.addon-watch.percentage-limit", 5);
+
 // RequestSync API is disabled by default.
 pref("dom.requestSync.enabled", false);
 
 // Search service settings
 pref("browser.search.log", false);
 pref("browser.search.update", true);
 pref("browser.search.update.log", false);
 pref("browser.search.update.interval", 21600);
--- a/netwerk/cookie/CookieServiceChild.cpp
+++ b/netwerk/cookie/CookieServiceChild.cpp
@@ -104,16 +104,23 @@ CookieServiceChild::GetCookieStringInter
                                             char **aCookieString,
                                             bool aFromHttp)
 {
   NS_ENSURE_ARG(aHostURI);
   NS_ENSURE_ARG_POINTER(aCookieString);
 
   *aCookieString = nullptr;
 
+  // Fast past: don't bother sending IPC messages about nullprincipal'd
+  // documents.
+  nsAutoCString scheme;
+  aHostURI->GetScheme(scheme);
+  if (scheme.EqualsLiteral("moz-nullprincipal"))
+    return NS_OK;
+
   // Determine whether the request is foreign. Failure is acceptable.
   bool isForeign = true;
   if (RequireThirdPartyCheck())
     mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
 
   URIParams uriParams;
   SerializeURI(aHostURI, uriParams);
 
@@ -132,16 +139,23 @@ CookieServiceChild::SetCookieStringInter
                                             nsIChannel *aChannel,
                                             const char *aCookieString,
                                             const char *aServerTime,
                                             bool aFromHttp)
 {
   NS_ENSURE_ARG(aHostURI);
   NS_ENSURE_ARG_POINTER(aCookieString);
 
+  // Fast past: don't bother sending IPC messages about nullprincipal'd
+  // documents.
+  nsAutoCString scheme;
+  aHostURI->GetScheme(scheme);
+  if (scheme.EqualsLiteral("moz-nullprincipal"))
+    return NS_OK;
+
   // Determine whether the request is foreign. Failure is acceptable.
   bool isForeign = true;
   if (RequireThirdPartyCheck())
     mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
 
   nsDependentCString cookieString(aCookieString);
   nsDependentCString serverTime;
   if (aServerTime)
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -55,21 +55,21 @@ class Context(KeyedDefaultDict):
     When reading a value for a given key, we first try to read the existing
     value. If a value is not found and it is defined in the allowed variables
     set, we return a new instance of the class for that variable. We don't
     assign default instances until they are accessed because this makes
     debugging the end-result much simpler. Instead of a data structure with
     lots of empty/default values, you have a data structure with only the
     values that were read or touched.
 
-    Instances of variables classes are created by invoking class_name(),
-    except when class_name derives from ContextDerivedValue, in which
-    case class_name(instance_of_the_context) is invoked.
-    A value is added to those calls when instances are created during
-    assignment (setitem).
+    Instances of variables classes are created by invoking ``class_name()``,
+    except when class_name derives from ``ContextDerivedValue`` or
+    ``SubContext``, in which case ``class_name(instance_of_the_context)`` or
+    ``class_name(self)`` is invoked. A value is added to those calls when
+    instances are created during assignment (setitem).
 
     allowed_variables is a dict of the variables that can be set and read in
     this context instance. Keys in this dict are the strings representing keys
     in this context which are valid. Values are tuples of stored type,
     assigned type, default value, a docstring describing the purpose of the
     variable, and a tier indicator (see comment above the VARIABLES declaration
     in this module).
 
@@ -79,16 +79,17 @@ class Context(KeyedDefaultDict):
         self._allowed_variables = allowed_variables
         self.main_path = None
         self.current_path = None
         # There aren't going to be enough paths for the performance of scanning
         # a list to be a problem.
         self._all_paths = []
         self.config = config
         self.execution_time = 0
+        self._sandbox = None
         KeyedDefaultDict.__init__(self, self._factory)
 
     def push_source(self, path):
         """Adds the given path as source of the data from this context and make
         it the current path for the context."""
         assert os.path.isabs(path)
         if not self.main_path:
             self.main_path = path
@@ -267,16 +268,45 @@ class Context(KeyedDefaultDict):
         return set(tier for tier in tiers if tier)
 
 
 class TemplateContext(Context):
     def _validate(self, key, value):
         return Context._validate(self, key, value, True)
 
 
+class SubContext(Context, ContextDerivedValue):
+    """A Context derived from another Context.
+
+    Sub-contexts are intended to be used as context managers.
+
+    Sub-contexts inherit paths and other relevant state from the parent
+    context.
+    """
+    def __init__(self, parent):
+        assert isinstance(parent, Context)
+
+        Context.__init__(self, allowed_variables=self.VARIABLES,
+                         config=parent.config)
+
+        # Copy state from parent.
+        for p in parent.source_stack:
+            self.push_source(p)
+        self._sandbox = parent._sandbox
+
+    def __enter__(self):
+        if not self._sandbox or self._sandbox() is None:
+            raise Exception('a sandbox is required')
+
+        self._sandbox().push_subcontext(self)
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        self._sandbox().pop_subcontext(self)
+
+
 class FinalTargetValue(ContextDerivedValue, unicode):
     def __new__(cls, context, value=""):
         if not value:
             value = 'dist/'
             if context['XPI_NAME']:
                 value += 'xpi-stage/' + context['XPI_NAME']
             else:
                 value += 'bin'
@@ -361,16 +391,37 @@ def ContextDerivedTypedList(type, base_c
                 def __new__(cls, obj):
                     return type(context, obj)
             self.TYPE = _Type
             super(_TypedList, self).__init__(iterable)
 
     return _TypedList
 
 
+# This defines functions that create sub-contexts.
+#
+# Values are classes that are SubContexts. The class name will be turned into
+# a function that when called emits an instance of that class.
+#
+# Arbitrary arguments can be passed to the class constructor. The first
+# argument is always the parent context. It is up to each class to perform
+# argument validation.
+SUBCONTEXTS = [
+]
+
+for cls in SUBCONTEXTS:
+    if not issubclass(cls, SubContext):
+        raise ValueError('SUBCONTEXTS entry not a SubContext class: %s' % cls)
+
+    if not hasattr(cls, 'VARIABLES'):
+        raise ValueError('SUBCONTEXTS entry does not have VARIABLES: %s' % cls)
+
+SUBCONTEXTS = {cls.__name__: cls for cls in SUBCONTEXTS}
+
+
 # This defines the set of mutable global variables.
 #
 # Each variable is a tuple of:
 #
 #   (storage_type, input_types, docs, tier)
 #
 # Tier says for which specific tier the variable has an effect.
 # Valid tiers are:
--- a/python/mozbuild/mozbuild/frontend/reader.py
+++ b/python/mozbuild/mozbuild/frontend/reader.py
@@ -57,16 +57,17 @@ from .sandbox import (
 
 from .context import (
     Context,
     ContextDerivedValue,
     FUNCTIONS,
     VARIABLES,
     DEPRECATION_HINTS,
     SPECIAL_VARIABLES,
+    SUBCONTEXTS,
     TemplateContext,
 )
 
 if sys.version_info.major == 2:
     text_type = unicode
     type_type = types.TypeType
 else:
     text_type = str
@@ -135,22 +136,24 @@ class MozbuildSandbox(Sandbox):
         context.update(exports)
         self.templates = self.metadata.setdefault('templates', {})
 
     def __getitem__(self, key):
         if key in SPECIAL_VARIABLES:
             return SPECIAL_VARIABLES[key][0](self._context)
         if key in FUNCTIONS:
             return self._create_function(FUNCTIONS[key])
+        if key in SUBCONTEXTS:
+            return self._create_subcontext(SUBCONTEXTS[key])
         if key in self.templates:
             return self._create_template_function(self.templates[key])
         return Sandbox.__getitem__(self, key)
 
     def __setitem__(self, key, value):
-        if key in SPECIAL_VARIABLES or key in FUNCTIONS:
+        if key in SPECIAL_VARIABLES or key in FUNCTIONS or key in SUBCONTEXTS:
             raise KeyError()
         if key in self.exports:
             self._context[key] = value
             self.exports.remove(key)
             return
         Sandbox.__setitem__(self, key, value)
 
     def exec_file(self, path):
@@ -306,16 +309,24 @@ class MozbuildSandbox(Sandbox):
         # So we need to prepend with n - 1 newlines so that line numbers
         # are unchanged.
         code = '\n' * (firstlineno + begin[0] - 3) + 'if True:\n'
         code += ''.join(lines[begin[0] - 1:])
 
         self.templates[name] = func, code, self._context.current_path
 
     @memoize
+    def _create_subcontext(self, cls):
+        """Return a function object that creates SubContext instances."""
+        def fn(*args, **kwargs):
+            return cls(self._context, *args, **kwargs)
+
+        return fn
+
+    @memoize
     def _create_function(self, function_def):
         """Returns a function object for use within the sandbox for the given
         function definition.
 
         The wrapper function does type coercion on the function arguments
         """
         func, args_def, doc = function_def
         def function(*args):
@@ -731,17 +742,17 @@ class BuildReader(object):
 
         This starts with the tree's top-most moz.build file and descends into
         all linked moz.build files until all relevant files have been evaluated.
 
         This is a generator of Context instances. As each moz.build file is
         read, a new Context is created and emitted.
         """
         path = mozpath.join(self.config.topsrcdir, 'moz.build')
-        return self.read_mozbuild(path, self.config, read_tiers=True)
+        return self.read_mozbuild(path, self.config)
 
     def all_mozbuild_paths(self):
         """Iterator over all available moz.build files.
 
         This method has little to do with the reader. It should arguably belong
         elsewhere.
         """
         # In the future, we may traverse moz.build files by looking
@@ -867,46 +878,41 @@ class BuildReader(object):
                 source = fh.read()
 
             tree = ast.parse(source, full)
             Visitor().visit(tree)
 
             for name, key, value in assignments:
                 yield p, name, key, value
 
-    def read_mozbuild(self, path, config, read_tiers=False, descend=True,
-            metadata={}):
+    def read_mozbuild(self, path, config, descend=True, metadata={}):
         """Read and process a mozbuild file, descending into children.
 
         This starts with a single mozbuild file, executes it, and descends into
         other referenced files per our traversal logic.
 
         The traversal logic is to iterate over the *DIRS variables, treating
         each element as a relative directory path. For each encountered
         directory, we will open the moz.build file located in that
         directory in a new Sandbox and process it.
 
-        If read_tiers is True (it should only be True for the top-level
-        mozbuild file in a project), the TIERS variable will be used for
-        traversal as well.
-
         If descend is True (the default), we will descend into child
         directories and files per variable values.
 
         Arbitrary metadata in the form of a dict can be passed into this
         function. This feature is intended to facilitate the build reader
         injecting state and annotations into moz.build files that is
         independent of the sandbox's execution context.
 
         Traversal is performed depth first (for no particular reason).
         """
         self._execution_stack.append(path)
         try:
-            for s in self._read_mozbuild(path, config, read_tiers=read_tiers,
-                descend=descend, metadata=metadata):
+            for s in self._read_mozbuild(path, config, descend=descend,
+                                         metadata=metadata):
                 yield s
 
         except BuildReaderError as bre:
             raise bre
 
         except SandboxCalledError as sce:
             raise BuildReaderError(list(self._execution_stack),
                 sys.exc_info()[2], sandbox_called_error=sce)
@@ -922,17 +928,17 @@ class BuildReader(object):
         except SandboxValidationError as ve:
             raise BuildReaderError(list(self._execution_stack),
                 sys.exc_info()[2], validation_error=ve)
 
         except Exception as e:
             raise BuildReaderError(list(self._execution_stack),
                 sys.exc_info()[2], other_error=e)
 
-    def _read_mozbuild(self, path, config, read_tiers, descend, metadata):
+    def _read_mozbuild(self, path, config, descend, metadata):
         path = mozpath.normpath(path)
         log(self._log, logging.DEBUG, 'read_mozbuild', {'path': path},
             'Reading file: {path}')
 
         if path in self._read_files:
             log(self._log, logging.WARNING, 'read_already', {'path': path},
                 'File already read. Skipping: {path}')
             return
@@ -1003,21 +1009,22 @@ class BuildReader(object):
                                                           target_dir),
                                              gyp_dir.variables,
                                              non_unified_sources = non_unified_sources):
                 gyp_context.update(gyp_dir.sandbox_vars)
                 gyp_contexts.append(gyp_context)
 
         for gyp_context in gyp_contexts:
             context['DIRS'].append(mozpath.relpath(gyp_context.objdir, context.objdir))
+            sandbox.subcontexts.append(gyp_context)
 
         yield context
 
-        for gyp_context in gyp_contexts:
-            yield gyp_context
+        for subcontext in sandbox.subcontexts:
+            yield subcontext
 
         # Traverse into referenced files.
 
         # It's very tempting to use a set here. Unfortunately, the recursive
         # make backend needs order preserved. Once we autogenerate all backend
         # files, we should be able to convert this to a set.
         recurse_info = OrderedDict()
         for var, var_dirs in dirs:
@@ -1046,12 +1053,12 @@ class BuildReader(object):
                 raise SandboxValidationError(
                     'Attempting to process file outside of allowed paths: %s' %
                         child_path, context)
 
             if not descend:
                 continue
 
             for res in self.read_mozbuild(child_path, context.config,
-                read_tiers=False, metadata=child_metadata):
+                                          metadata=child_metadata):
                 yield res
 
         self._execution_stack.pop()
--- a/python/mozbuild/mozbuild/frontend/sandbox.py
+++ b/python/mozbuild/mozbuild/frontend/sandbox.py
@@ -17,16 +17,17 @@ KeyError are machine parseable. This mac
 user-friendly error messages in the case of errors.
 """
 
 from __future__ import unicode_literals
 
 import copy
 import os
 import sys
+import weakref
 
 from contextlib import contextmanager
 
 from mozbuild.util import ReadOnlyDict
 from context import Context
 
 
 def alphabetical_sorted(iterable, cmp=None, key=lambda x: x.lower(),
@@ -111,22 +112,32 @@ class Sandbox(dict):
         """Initialize a Sandbox ready for execution.
         """
         self._builtins = builtins or self.BUILTINS
         dict.__setitem__(self, '__builtins__', self._builtins)
 
         assert isinstance(self._builtins, ReadOnlyDict)
         assert isinstance(context, Context)
 
-        self._context = context
+        # Contexts are modeled as a stack because multiple context managers
+        # may be active.
+        self._active_contexts = [context]
+
+        # Seen sub-contexts. Will be populated with other Context instances
+        # that were related to execution of this instance.
+        self.subcontexts = []
 
         # We need to record this because it gets swallowed as part of
         # evaluation.
         self._last_name_error = None
 
+    @property
+    def _context(self):
+        return self._active_contexts[-1]
+
     def exec_file(self, path):
         """Execute code at a path in the sandbox.
 
         The path must be absolute.
         """
         assert os.path.isabs(path)
 
         source = None
@@ -148,16 +159,19 @@ class Sandbox(dict):
 
         You should almost always go through exec_file() because exec_source()
         does not perform extra path normalization. This can cause relative
         paths to behave weirdly.
         """
         if path:
             self._context.push_source(path)
 
+        old_sandbox = self._context._sandbox
+        self._context._sandbox = weakref.ref(self)
+
         # We don't have to worry about bytecode generation here because we are
         # too low-level for that. However, we could add bytecode generation via
         # the marshall module if parsing performance were ever an issue.
 
         try:
             # compile() inherits the __future__ from the module by default. We
             # do want Unicode literals.
             code = compile(source, path, 'exec')
@@ -185,19 +199,41 @@ class Sandbox(dict):
 
         except Exception as e:
             # Need to copy the stack otherwise we get a reference and that is
             # mutated during the finally.
             exc = sys.exc_info()
             raise SandboxExecutionError(self._context.source_stack, exc[0],
                 exc[1], exc[2])
         finally:
+            self._context._sandbox = old_sandbox
             if path:
                 self._context.pop_source()
 
+    def push_subcontext(self, context):
+        """Push a SubContext onto the execution stack.
+
+        When called, the active context will be set to the specified context,
+        meaning all variable accesses will go through it. We also record this
+        SubContext as having been executed as part of this sandbox.
+        """
+        self._active_contexts.append(context)
+        if context not in self.subcontexts:
+            self.subcontexts.append(context)
+
+    def pop_subcontext(self, context):
+        """Pop a SubContext off the execution stack.
+
+        SubContexts must be pushed and popped in opposite order. This is
+        validated as part of the function call to ensure proper consumer API
+        use.
+        """
+        popped = self._active_contexts.pop()
+        assert popped == context
+
     def __getitem__(self, key):
         if key.isupper():
             try:
                 return self._context[key]
             except Exception as e:
                 self._last_name_error = e
                 raise
 
--- a/python/mozbuild/mozbuild/sphinx.py
+++ b/python/mozbuild/mozbuild/sphinx.py
@@ -96,16 +96,31 @@ def special_reference(v, func, typ, doc)
     lines.extend(docstring[1:])
     lines.append('')
 
     return lines
 
 
 def format_module(m):
     lines = []
+
+    for subcontext, cls in sorted(m.SUBCONTEXTS.items()):
+        lines.extend([
+            '.. _mozbuild_subcontext_%s:' % subcontext,
+            '',
+            'Sub-Context: %s' % subcontext,
+            '=============' + '=' * len(subcontext),
+            '',
+            prepare_docstring(cls.__doc__)[0],
+            '',
+        ])
+
+        for k, v in sorted(cls.VARIABLES.items()):
+            lines.extend(variable_reference(k, *v))
+
     lines.extend([
         'Variables',
         '=========',
         '',
     ])
 
     for v in sorted(m.VARIABLES):
         lines.extend(variable_reference(v, *m.VARIABLES[v]))
--- a/python/mozbuild/mozbuild/test/frontend/test_context.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_context.py
@@ -6,16 +6,17 @@ import os
 import unittest
 
 from mozunit import main
 
 from mozbuild.frontend.context import (
     Context,
     FUNCTIONS,
     SPECIAL_VARIABLES,
+    SUBCONTEXTS,
     VARIABLES,
 )
 
 from mozpack import path as mozpath
 
 
 class TestContext(unittest.TestCase):
     def test_defaults(self):
@@ -251,11 +252,17 @@ class TestSymbols(unittest.TestCase):
             self._verify_doc(doc)
 
         for attr, args, doc in FUNCTIONS.values():
             self._verify_doc(doc)
 
         for func, typ, doc in SPECIAL_VARIABLES.values():
             self._verify_doc(doc)
 
+        for name, cls in SUBCONTEXTS.items():
+            self._verify_doc(cls.__doc__)
+
+            for name, v in cls.VARIABLES.items():
+                self._verify_doc(v[2])
+
 
 if __name__ == '__main__':
     main()
--- a/python/mozbuild/mozpack/path.py
+++ b/python/mozbuild/mozpack/path.py
@@ -94,22 +94,22 @@ def match(path, pattern):
     patch is considered matching:
         'foo/bar' matches 'foo'
     Two adjacent asterisks can be used to match files and zero or more
     directories and subdirectories.
         'foo/bar' matches 'foo/**/bar', or '**/bar'
     '''
     if not pattern:
         return True
-    if not pattern in re_cache:
-        pattern = re.escape(pattern)
-        pattern = re.sub(r'(^|\\\/)\\\*\\\*\\\/', r'\1(?:.+/)?', pattern)
-        pattern = re.sub(r'(^|\\\/)\\\*\\\*$', r'(?:\1.+)?', pattern)
-        pattern = pattern.replace(r'\*', '[^/]*') + '(?:/.*)?$'
-        re_cache[pattern] = re.compile(pattern)
+    if pattern not in re_cache:
+        p = re.escape(pattern)
+        p = re.sub(r'(^|\\\/)\\\*\\\*\\\/', r'\1(?:.+/)?', p)
+        p = re.sub(r'(^|\\\/)\\\*\\\*$', r'(?:\1.+)?', p)
+        p = p.replace(r'\*', '[^/]*') + '(?:/.*)?$'
+        re_cache[pattern] = re.compile(p)
     return re_cache[pattern].match(path) is not None
 
 
 def rebase(oldbase, base, relativepath):
     '''
     Return relativepath relative to base instead of oldbase.
     '''
     if base == oldbase:
--- a/testing/marionette/marionette-server.js
+++ b/testing/marionette/marionette-server.js
@@ -1442,26 +1442,21 @@ MarionetteServerConnection.prototype = {
     if (browser === null) {
       return null;
     }
     let permKey = browser.permanentKey;
     if (this._browserIds.has(permKey)) {
       return this._browserIds.get(permKey);
     }
 
-    let contentWindow = browser.contentWindowAsCPOW;
-    if (contentWindow !== null && !Cu.isDeadWrapper(contentWindow)) {
-      let winId = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                               .getInterface(Ci.nsIDOMWindowUtils)
-                               .outerWindowID;
-      if (winId) {
-        winId += "";
-        this._browserIds.set(permKey, winId);
-        return winId;
-      }
+    let winId = browser.outerWindowID;
+    if (winId) {
+      winId += "";
+      this._browserIds.set(permKey, winId);
+      return winId;
     }
     return null;
   },
 
   /**
    * Get a list of top-level browsing contexts. On desktop this typically
    * corresponds to the set of open tabs.
    *
new file mode 100644
--- /dev/null
+++ b/testing/mochitest/ShutdownLeaksCollector.jsm
@@ -0,0 +1,48 @@
+/* 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/. */
+
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+var Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+this.EXPORTED_SYMBOLS = ["ContentCollector"];
+
+// This listens for the message "browser-test:collect-request". When it gets it,
+// it runs some GCs and CCs, then prints out a message indicating the collections
+// are complete. Mochitest uses this information to determine when windows and
+// docshells should be destroyed.
+
+var ContentCollector = {
+  init: function() {
+    let cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
+                 .getService(Ci.nsISyncMessageSender);
+    cpmm.addMessageListener("browser-test:collect-request", this);
+  },
+
+  receiveMessage: function(aMessage) {
+    switch (aMessage.name) {
+      case "browser-test:collect-request":
+        Services.obs.notifyObservers(null, "memory-pressure", "heap-minimize");
+
+        Cu.forceGC();
+        Cu.forceCC();
+
+        Cu.schedulePreciseShrinkingGC(() => {
+          Cu.forceCC();
+
+          let pid = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).processID;
+          dump("Completed ShutdownLeaks collections in process " + pid + "\n")});
+
+          let cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
+                       .getService(Ci.nsISyncMessageSender);
+          cpmm.removeMessageListener("browser-test:collect-request", this);
+
+        break;
+    }
+  }
+
+};
+ContentCollector.init();
--- a/testing/mochitest/browser-test.js
+++ b/testing/mochitest/browser-test.js
@@ -83,16 +83,22 @@ function testInit() {
     };
 
     var listener = 'data:,function doLoad(e) { var data=e.detail&&e.detail.data;removeEventListener("contentEvent", function (e) { doLoad(e); }, false, true);sendAsyncMessage("chromeEvent", {"data":data}); };addEventListener("contentEvent", function (e) { doLoad(e); }, false, true);';
     messageManager.loadFrameScript(listener, true);
     messageManager.addMessageListener("chromeEvent", messageHandler);
   }
   if (gConfig.e10s) {
     e10s_init();
+    let globalMM = Cc["@mozilla.org/globalmessagemanager;1"]
+                     .getService(Ci.nsIMessageListenerManager);
+    globalMM.loadFrameScript("chrome://mochikit/content/shutdown-leaks-collector.js", true);
+  } else {
+    // In non-e10s, only run the ShutdownLeaksCollector in the parent process.
+    Components.utils.import("chrome://mochikit/content/ShutdownLeaksCollector.jsm");
   }
 }
 
 function Tester(aTests, aDumper, aCallback) {
   this.dumper = aDumper;
   this.tests = aTests;
   this.callback = aCallback;
   this.openedWindows = {};
@@ -570,16 +576,20 @@ Tester.prototype = {
         Services.obs.notifyObservers({wrappedJSObject: barrier},
           "shutdown-leaks-before-check", null);
 
         barrier.wait().then(() => {
           // Simulate memory pressure so that we're forced to free more resources
           // and thus get rid of more false leaks like already terminated workers.
           Services.obs.notifyObservers(null, "memory-pressure", "heap-minimize");
 
+          let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
+                       .getService(Ci.nsIMessageBroadcaster);
+          ppmm.broadcastAsyncMessage("browser-test:collect-request");
+
           checkForLeakedGlobalWindows(aResults => {
             if (aResults.length == 0) {
               this.finish();
               return;
             }
             // After the first check, if there are reported leaked windows, sleep
             // for a while, to allow off-main-thread work to complete and free up
             // main-thread objects.  Then check again.
--- a/testing/mochitest/jar.mn
+++ b/testing/mochitest/jar.mn
@@ -5,16 +5,18 @@ mochikit.jar:
   content/browser-test-overlay.xul (browser-test-overlay.xul)
   content/jetpack-package-harness.js (jetpack-package-harness.js)
   content/jetpack-package-overlay.xul (jetpack-package-overlay.xul)
   content/jetpack-addon-harness.js (jetpack-addon-harness.js)
   content/jetpack-addon-overlay.xul (jetpack-addon-overlay.xul)
   content/cc-analyzer.js (cc-analyzer.js)
   content/chrome-harness.js (chrome-harness.js)
   content/mochitest-e10s-utils.js (mochitest-e10s-utils.js)
+  content/shutdown-leaks-collector.js (shutdown-leaks-collector.js)
+  content/ShutdownLeaksCollector.jsm (ShutdownLeaksCollector.jsm)
   content/harness.xul (harness.xul)
   content/redirect.html (redirect.html)
   content/server.js (server.js)
   content/chunkifyTests.js (chunkifyTests.js)
   content/manifestLibrary.js (manifestLibrary.js)
   content/nested_setup.js (nested_setup.js)
   content/dynamic/getMyDirectory.sjs (dynamic/getMyDirectory.sjs)
   content/static/harness.css (static/harness.css)
new file mode 100644
--- /dev/null
+++ b/testing/mochitest/shutdown-leaks-collector.js
@@ -0,0 +1,7 @@
+/* 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/. */
+
+// We run this code in a .jsm rather than here to avoid keeping the current
+// compartment alive.
+Components.utils.import("chrome://mochikit/content/ShutdownLeaksCollector.jsm");
--- a/testing/web-platform/harness/wptrunner/executors/executormarionette.py
+++ b/testing/web-platform/harness/wptrunner/executors/executormarionette.py
@@ -25,20 +25,22 @@ from ..testrunner import Stop
 extra_timeout = 5 # seconds
 
 required_files = [("testharness_runner.html", "", False),
                   ("testharnessreport.js", "resources/", True)]
 
 
 def do_delayed_imports():
     global marionette
+    global errors
     try:
         import marionette
+        from marionette import errors
     except ImportError:
-        import marionette_driver.marionette as marionette
+        from marionette_driver import marionette, errors
 
 
 class MarionetteTestExecutor(TestExecutor):
     def __init__(self,
                  browser,
                  http_server_url,
                  timeout_multiplier=1,
                  debug_args=None,
@@ -148,23 +150,23 @@ class MarionetteTestExecutor(TestExecuto
                     self.runner.send_message("test_ended", test, result)
 
         if self.debug_args is None:
             self.timer = threading.Timer(timeout + 2 * extra_timeout, timeout_func)
             self.timer.start()
 
         try:
             self.marionette.set_script_timeout((timeout + extra_timeout) * 1000)
-        except IOError, marionette.errors.InvalidResponseException:
+        except IOError, errors.InvalidResponseException:
             self.logger.error("Lost marionette connection before starting test")
             return Stop
 
         try:
             result = self.convert_result(test, self.do_test(test, timeout))
-        except marionette.errors.ScriptTimeoutException:
+        except errors.ScriptTimeoutException:
             with result_lock:
                 if not result_flag.is_set():
                     result_flag.set()
                     result = (test.result_cls("EXTERNAL-TIMEOUT", None), [])
             # Clean up any unclosed windows
             # This doesn't account for the possibility the browser window
             # is totally hung. That seems less likely since we are still
             # getting data from marionette, but it might be just as well
@@ -174,17 +176,17 @@ class MarionetteTestExecutor(TestExecuto
             # while True:
             #     handles = self.marionette.window_handles
             #     self.marionette.switch_to_window(handles[-1])
             #     if len(handles) > 1:
             #         self.marionette.close()
             #     else:
             #         break
             # Now need to check if the browser is still responsive and restart it if not
-        except (socket.timeout, marionette.errors.InvalidResponseException, IOError):
+        except (socket.timeout, errors.InvalidResponseException, IOError):
             # This can happen on a crash
             # Also, should check after the test if the firefox process is still running
             # and otherwise ignore any other result and set it to crash
             with result_lock:
                 if not result_flag.is_set():
                     result_flag.set()
                     result = (test.result_cls("CRASH", None), [])
         finally:
@@ -245,17 +247,17 @@ class MarionetteReftestExecutor(Marionet
         self.marionette.switch_to_window(self.marionette.window_handles[-1])
         for url_type, url in [("test", test_url), ("ref", ref_url)]:
             if hashes[url_type] is None:
                 # Would like to do this in a new tab each time, but that isn't
                 # easy with the current state of marionette
                 full_url = urlparse.urljoin(self.http_server_url, url)
                 try:
                     self.marionette.navigate(full_url)
-                except marionette.errors.MarionetteException:
+                except errors.MarionetteException:
                     return {"status": "ERROR",
                             "message": "Failed to load url %s" % (full_url,)}
                 if url_type == "test":
                     self.wait()
                 screenshot = self.marionette.screenshot()
                 # strip off the data:img/png, part of the url
                 if screenshot.startswith("data:image/png;base64,"):
                     screenshot = screenshot.split(",", 1)[1]
--- a/testing/web-platform/harness/wptrunner/update/tree.py
+++ b/testing/web-platform/harness/wptrunner/update/tree.py
@@ -119,16 +119,23 @@ class HgTree(object):
             args = ()
 
         self.hg("qrefresh", *args)
         return True
 
     def commit_patch(self):
         self.hg("qfinish")
 
+    def contains_commit(self, commit):
+        try:
+            self.hg("identify", "-r", commit.sha1)
+            return True
+        except subprocess.CalledProcessError:
+            return False
+
 
 class GitTree(object):
     name = "git"
 
     def __init__(self, root=None):
         if root is None:
             root = git("rev-parse", "--show-toplevel").strip()
         self.root = root
new file mode 100644
--- /dev/null
+++ b/toolkit/modules/AddonWatcher.jsm
@@ -0,0 +1,96 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["AddonWatcher"];
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
+                                  "resource://gre/modules/Preferences.jsm");
+
+let AddonWatcher = {
+  _lastAddonTime: {},
+  _timer: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer),
+  _callback: null,
+  _interval: 1500,
+  _ignoreList: null,
+  init: function(callback) {
+    if (!callback) {
+      return;
+    }
+
+    if (this._callback) {
+      return;
+    }
+
+    this._interval = Preferences.get("browser.addon-watch.interval", 15000);
+    if (this._interval == -1) {
+      return;
+    }
+
+    this._callback = callback;
+    try {
+      this._ignoreList = new Set(JSON.parse(Preferences.get("browser.addon-watch.ignore", null)));
+    } catch (ex) {
+      // probably some malformed JSON, ignore and carry on
+      this._ignoreList = new Set();
+    }
+    this._timer.initWithCallback(this._checkAddons.bind(this), this._interval, Ci.nsITimer.TYPE_REPEATING_SLACK);
+  },
+  uninit: function() {
+    if (this._timer) {
+      this._timer.cancel();
+      this._timer = null;
+    }
+  },
+  _checkAddons: function() {
+    let compartmentInfo = Cc["@mozilla.org/compartment-info;1"]
+      .getService(Ci.nsICompartmentInfo);
+    let compartments = compartmentInfo.getCompartments();
+    let count = compartments.length;
+    let addons = {};
+    for (let i = 0; i < count; i++) {
+      let compartment = compartments.queryElementAt(i, Ci.nsICompartment);
+      if (compartment.addonId) {
+        if (addons[compartment.addonId]) {
+          addons[compartment.addonId] += compartment.time;
+        } else {
+          addons[compartment.addonId] = compartment.time;
+        }
+      }
+    }
+    let limit = this._interval * Preferences.get("browser.addon-watch.percentage-limit", 75) * 10;
+    for (let addonId in addons) {
+      if (!this._ignoreList.has(addonId)) {
+        if (!this._lastAddonTime[addonId]) {
+          this._lastAddonTime[addonId] = 0;
+        }
+        if ((addons[addonId] - this._lastAddonTime[addonId]) > limit) {
+          this._callback(addonId);
+        }
+        this._lastAddonTime[addonId] = addons[addonId];
+      }
+    }
+  },
+  ignoreAddonForSession: function(addonid) {
+    this._ignoreList.add(addonid);
+  },
+  ignoreAddonPermanently: function(addonid) {
+    this._ignoreList.add(addonid);
+    try {
+      let ignoreList = JSON.parse(Preferences.get("browser.addon-watch.ignore", "[]"))
+      if (!ignoreList.includes(addonid)) {
+        ignoreList.push(addonid);
+        Preferences.set("browser.addon-watch.ignore", JSON.stringify(ignoreList));
+      }
+    } catch (ex) {
+      Preferences.set("browser.addon-watch.ignore", JSON.stringify([addonid]));
+    }
+  }
+};
--- a/toolkit/modules/moz.build
+++ b/toolkit/modules/moz.build
@@ -7,16 +7,17 @@
 XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
 BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
 MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini']
 MOCHITEST_CHROME_MANIFESTS += ['tests/chrome/chrome.ini']
 
 SPHINX_TREES['toolkit_modules'] = 'docs'
 
 EXTRA_JS_MODULES += [
+    'AddonWatcher.jsm',
     'Battery.jsm',
     'BinarySearch.jsm',
     'BrowserUtils.jsm',
     'CharsetMenu.jsm',
     'debug.js',
     'DeferredTask.jsm',
     'Deprecated.jsm',
     'Dict.jsm',
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -78,19 +78,30 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "@mozilla.org/security/certblocklist;1",
                                    "nsICertBlocklist");
 
 XPCOMUtils.defineLazyGetter(this, "gPref", function bls_gPref() {
   return Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).
          QueryInterface(Ci.nsIPrefBranch);
 });
 
+// From appinfo in Services.jsm. It is not possible to use the one in
+// Services.jsm since it will not successfully QueryInterface nsIXULAppInfo in
+// xpcshell tests due to other code calling Services.appinfo before the
+// nsIXULAppInfo is created by the tests.
 XPCOMUtils.defineLazyGetter(this, "gApp", function bls_gApp() {
-  return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).
-         QueryInterface(Ci.nsIXULRuntime);
+  let appinfo = Cc["@mozilla.org/xre/app-info;1"]
+                  .getService(Ci.nsIXULRuntime);
+  try {
+    appinfo.QueryInterface(Ci.nsIXULAppInfo);
+  } catch (ex if ex instanceof Components.Exception &&
+                 ex.result == Cr.NS_NOINTERFACE) {
+    // Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't).
+  }
+  return appinfo;
 });
 
 XPCOMUtils.defineLazyGetter(this, "gABI", function bls_gABI() {
   let abi = null;
   try {
     abi = gApp.XPCOMABI;
   }
   catch (e) {
@@ -391,16 +402,20 @@ Blocklist.prototype = {
    * @returns The blocklist state for the item, one of the STATE constants as
    *          defined in nsIBlocklistService.
    */
   _getAddonBlocklistState: function Blocklist_getAddonBlocklistStateCall(addon,
                            addonEntries, appVersion, toolkitVersion) {
     if (!gBlocklistEnabled)
       return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
 
+    // Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't).
+    if (!appVersion && !gApp.version)
+      return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
+
     if (!appVersion)
       appVersion = gApp.version;
     if (!toolkitVersion)
       toolkitVersion = gApp.platformVersion;
 
     var blItem = this._findMatchingAddonEntry(addonEntries, addon);
     if (!blItem)
       return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
@@ -524,19 +539,23 @@ Blocklist.prototype = {
     }
 
     if (pingCountVersion < 1)
       pingCountVersion = 1;
     if (pingCountTotal < 1)
       pingCountTotal = 1;
 
     dsURI = dsURI.replace(/%APP_ID%/g, gApp.ID);
-    dsURI = dsURI.replace(/%APP_VERSION%/g, gApp.version);
+    // Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't).
+    if (gApp.version)
+      dsURI = dsURI.replace(/%APP_VERSION%/g, gApp.version);
     dsURI = dsURI.replace(/%PRODUCT%/g, gApp.name);
-    dsURI = dsURI.replace(/%VERSION%/g, gApp.version);
+    // Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't).
+    if (gApp.version)
+      dsURI = dsURI.replace(/%VERSION%/g, gApp.version);
     dsURI = dsURI.replace(/%BUILD_ID%/g, gApp.appBuildID);
     dsURI = dsURI.replace(/%BUILD_TARGET%/g, gApp.OS + "_" + gABI);
     dsURI = dsURI.replace(/%OS_VERSION%/g, gOSVersion);
     dsURI = dsURI.replace(/%LOCALE%/g, getLocale());
     dsURI = dsURI.replace(/%CHANNEL%/g, UpdateChannel.get());
     dsURI = dsURI.replace(/%PLATFORM_VERSION%/g, gApp.platformVersion);
     dsURI = dsURI.replace(/%DISTRIBUTION%/g,
                       getDistributionPrefValue(PREF_APP_DISTRIBUTION));
@@ -1043,16 +1062,20 @@ Blocklist.prototype = {
    * @returns The blocklist state for the item, one of the STATE constants as
    *          defined in nsIBlocklistService.
    */
   _getPluginBlocklistState: function Blocklist_getPluginBlocklistState(plugin,
                             pluginEntries, appVersion, toolkitVersion) {
     if (!gBlocklistEnabled)
       return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
 
+    // Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't).
+    if (!appVersion && !gApp.version)
+      return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
+
     if (!appVersion)
       appVersion = gApp.version;
     if (!toolkitVersion)
       toolkitVersion = gApp.platformVersion;
 
     for each (var blockEntry in pluginEntries) {
       var matchFailed = false;
       for (var name in blockEntry.matches) {