Merge m-c to fx-team, a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 27 May 2016 14:44:06 -0700
changeset 338311 b094e88c2184607005c0ce50b6eca797bc50de0a
parent 338310 3e1d7c5d1a58cb1763a2a78de02f96c6bcd2f06d (current diff)
parent 338301 ea15028498ed95677844fb7f30be5efcaf8b2621 (diff)
child 338312 1bd815acf6d3d51ded73a0ffbe05bd8a2c515784
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone49.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 m-c to fx-team, a=merge
testing/web-platform/meta/html/semantics/forms/form-control-infrastructure/form.html.ini
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -702,23 +702,25 @@ extensions.registerSchemaAPI("tabs", nul
 
         let browser = tab.linkedBrowser;
         let recipient = {innerWindowID: browser.innerWindowID};
 
         return context.sendMessage(browser.messageManager, "Extension:DetectLanguage",
                                    {}, {recipient});
       },
 
+      // Used to executeScript, insertCSS and removeCSS.
       _execute: function(tabId, details, kind, method) {
         let tab = tabId !== null ? TabManager.getTab(tabId) : TabManager.activeTab;
         let mm = tab.linkedBrowser.messageManager;
 
         let options = {
           js: [],
           css: [],
+          remove_css: method == "removeCSS",
         };
 
         // We require a `code` or a `file` property, but we can't accept both.
         if ((details.code === null) == (details.file === null)) {
           return Promise.reject({message: `${method} requires either a 'code' or a 'file' property, but not both`});
         }
 
         if (details.frameId !== null && details.allFrames) {
@@ -768,16 +770,20 @@ extensions.registerSchemaAPI("tabs", nul
       executeScript: function(tabId, details) {
         return self.tabs._execute(tabId, details, "js", "executeScript");
       },
 
       insertCSS: function(tabId, details) {
         return self.tabs._execute(tabId, details, "css", "insertCSS");
       },
 
+      removeCSS: function(tabId, details) {
+        return self.tabs._execute(tabId, details, "css", "removeCSS");
+      },
+
       connect: function(tabId, connectInfo) {
         let tab = TabManager.getTab(tabId);
         let mm = tab.linkedBrowser.messageManager;
 
         let name = "";
         if (connectInfo && connectInfo.name !== null) {
           name = connectInfo.name;
         }
--- a/browser/components/extensions/schemas/tabs.json
+++ b/browser/components/extensions/schemas/tabs.json
@@ -862,16 +862,43 @@
             "name": "callback",
             "optional": true,
             "description": "Called when all the CSS has been inserted.",
             "parameters": []
           }
         ]
       },
       {
+        "name": "removeCSS",
+        "type": "function",
+        "description": "Removes injected CSS from a page. For details, see the $(topic:content_scripts)[programmatic injection] section of the content scripts doc.",
+        "async": "callback",
+        "parameters": [
+          {
+            "type": "integer",
+            "name": "tabId",
+            "minimum": 0,
+            "optional": true,
+            "description": "The ID of the tab from which to remove the injected CSS; defaults to the active tab of the current window."
+          },
+          {
+            "$ref": "extensionTypes.InjectDetails",
+            "name": "details",
+            "description": "Details of the CSS text to remove."
+          },
+          {
+            "type": "function",
+            "name": "callback",
+            "optional": true,
+            "description": "Called when all the CSS has been removed.",
+            "parameters": []
+          }
+        ]
+      },
+      {
         "name": "setZoom",
         "type": "function",
         "description": "Zooms a specified tab.",
         "async": "callback",
         "parameters": [
           {
             "type": "integer",
             "name": "tabId",
--- a/browser/components/extensions/test/browser/browser.ini
+++ b/browser/components/extensions/test/browser/browser.ini
@@ -48,16 +48,17 @@ support-files =
 [browser_ext_tabs_duplicate.js]
 [browser_ext_tabs_events.js]
 [browser_ext_tabs_executeScript.js]
 [browser_ext_tabs_executeScript_good.js]
 [browser_ext_tabs_executeScript_bad.js]
 [browser_ext_tabs_executeScript_runAt.js]
 [browser_ext_tabs_getCurrent.js]
 [browser_ext_tabs_insertCSS.js]
+[browser_ext_tabs_removeCSS.js]
 [browser_ext_tabs_move.js]
 [browser_ext_tabs_move_window.js]
 [browser_ext_tabs_move_window_multiple.js]
 [browser_ext_tabs_move_window_pinned.js]
 [browser_ext_tabs_onHighlighted.js]
 [browser_ext_tabs_onUpdated.js]
 [browser_ext_tabs_query.js]
 [browser_ext_tabs_reload.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_removeCSS.js
@@ -0,0 +1,103 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+add_task(function* testExecuteScript() {
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/", true);
+
+  function background() {
+    let promises = [
+      // Insert CSS file.
+      {
+        background: "transparent",
+        foreground: "rgb(0, 113, 4)",
+        promise: () => {
+          return browser.tabs.insertCSS({
+            file: "file2.css",
+          });
+        },
+      },
+      // Insert CSS code.
+      {
+        background: "rgb(42, 42, 42)",
+        foreground: "rgb(0, 113, 4)",
+        promise: () => {
+          return browser.tabs.insertCSS({
+            code: "* { background: rgb(42, 42, 42) }",
+          });
+        },
+      },
+      // Remove CSS code again.
+      {
+        background: "transparent",
+        foreground: "rgb(0, 113, 4)",
+        promise: () => {
+          return browser.tabs.removeCSS({
+            code: "* { background: rgb(42, 42, 42) }",
+          });
+        },
+      },
+      // Remove CSS file again.
+      {
+        background: "transparent",
+        foreground: "rgb(0, 0, 0)",
+        promise: () => {
+          return browser.tabs.removeCSS({
+            file: "file2.css",
+          });
+        },
+      },
+    ];
+
+    function checkCSS() {
+      let computedStyle = window.getComputedStyle(document.body);
+      return [computedStyle.backgroundColor, computedStyle.color];
+    }
+
+    function next() {
+      if (!promises.length) {
+        return;
+      }
+
+      let {promise, background, foreground} = promises.shift();
+      return promise().then(result => {
+        browser.test.assertEq(undefined, result, "Expected callback result");
+
+        return browser.tabs.executeScript({
+          code: `(${checkCSS})()`,
+        });
+      }).then(result => {
+        browser.test.assertEq(background, result[0], "Expected background color");
+        browser.test.assertEq(foreground, result[1], "Expected foreground color");
+        return next();
+      });
+    }
+
+    next().then(() => {
+      browser.test.notifyPass("removeCSS");
+    }).catch(e => {
+      browser.test.fail(`Error: ${e} :: ${e.stack}`);
+      browser.test.notifyFailure("removeCSS");
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "permissions": ["http://mochi.test/"],
+    },
+
+    background,
+
+    files: {
+      "file2.css": "* { color: rgb(0, 113, 4) }",
+    },
+  });
+
+  yield extension.startup();
+
+  yield extension.awaitFinish("removeCSS");
+
+  yield extension.unload();
+
+  yield BrowserTestUtils.removeTab(tab);
+});
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -154,17 +154,16 @@ def old_configure_options(*options):
 
 
 @old_configure_options(
     '--cache-file',
     '--enable-accessibility',
     '--enable-address-sanitizer',
     '--enable-alsa',
     '--enable-android-omx',
-    '--enable-android-resource-constrained',
     '--enable-approximate-location',
     '--enable-b2g-bt',
     '--enable-b2g-camera',
     '--enable-b2g-ril',
     '--enable-bundled-fonts',
     '--enable-clang-plugin',
     '--enable-content-sandbox',
     '--enable-cookies',
--- a/config/external/nss/Makefile.in
+++ b/config/external/nss/Makefile.in
@@ -240,17 +240,17 @@ DEFAULT_GMAKE_FLAGS += \
 endif
 
 DEFAULT_GMAKE_FLAGS += FREEBL_NO_DEPEND=0 $(FREEBL_LOWHASH_FLAG)
 
 ifdef MOZ_NO_WLZDEFS
 DEFAULT_GMAKE_FLAGS += ZDEFS_FLAG=
 endif
 ifdef MOZ_CFLAGS_NSS
-XCFLAGS += $(filter-out -W%,$(CFLAGS))
+NSS_XCFLAGS += $(filter-out -W%,$(CFLAGS))
 DEFAULT_GMAKE_FLAGS += DARWIN_DYLIB_VERSIONS='-compatibility_version 1 -current_version 1 $(LDFLAGS)'
 endif
 ifeq (1_1,$(CLANG_CL)_$(MOZ_ASAN))
 XLDFLAGS := $(OS_LDFLAGS)
 DEFAULT_GMAKE_FLAGS += XLDFLAGS='$(XLDFLAGS)'
 endif
 
 DEFAULT_GMAKE_FLAGS += NSS_NO_PKCS11_BYPASS=1
@@ -263,28 +263,28 @@ DEFAULT_GMAKE_FLAGS += MODULE_INCLUDES='
 # Work around NSS's MAKE_OBJDIR being racy. See bug #836220
 DEFAULT_GMAKE_FLAGS += MAKE_OBJDIR='$$(INSTALL) -D $$(OBJDIR)'
 
 # Work around NSS adding IMPORT_LIBRARY to TARGETS with no rule for
 # it, creating race conditions. See bug #836220
 DEFAULT_GMAKE_FLAGS += TARGETS='$$(LIBRARY) $$(SHARED_LIBRARY) $$(PROGRAM)'
 
 ifdef MOZ_FOLD_LIBS_FLAGS
-XCFLAGS += $(MOZ_FOLD_LIBS_FLAGS)
+NSS_XCFLAGS += $(MOZ_FOLD_LIBS_FLAGS)
 endif
 
 # Pass on the MSVC target arch from the main build system.
 # Note this is case- and switch-character sensitive, while
 # the MSVC option is not.
 ifeq (WINNT,$(OS_TARGET))
-XCFLAGS += $(filter -arch:%,$(CFLAGS))
+NSS_XCFLAGS += $(filter -arch:%,$(CFLAGS))
 endif
 
 # Export accumulated XCFLAGS to modify nss defaults.
-DEFAULT_GMAKE_FLAGS += XCFLAGS='$(XCFLAGS)'
+DEFAULT_GMAKE_FLAGS += XCFLAGS='$(NSS_XCFLAGS)'
 
 NSS_SRCDIR = $(topsrcdir)
 
 NSS_DIRS =
 ifndef MOZ_FOLD_LIBS
 NSS_DIRS += nss/lib
 else
 ifndef NSS_DISABLE_DBM
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -1,16 +1,17 @@
 [DEFAULT]
 tags = devtools
 subsuite = devtools
 support-files =
   dropmarker.svg
   head.js
   html_content-type-test-page.html
   html_content-type-without-cache-test-page.html
+  html_cors-test-page.html
   html_custom-get-page.html
   html_single-get-page.html
   html_cyrillic-test-page.html
   html_filter-test-page.html
   html_infinite-get-page.html
   html_json-custom-mime-test-page.html
   html_json-long-test-page.html
   html_json-malformed-test-page.html
@@ -68,16 +69,17 @@ subsuite = clipboard
 subsuite = clipboard
 [browser_net_copy_response.js]
 subsuite = clipboard
 [browser_net_copy_headers.js]
 subsuite = clipboard
 [browser_net_copy_as_curl.js]
 subsuite = clipboard
 skip-if = e10s # Bug 1091596
+[browser_net_cors_requests.js]
 [browser_net_cyrillic-01.js]
 [browser_net_cyrillic-02.js]
 [browser_net_details-no-duplicated-content.js]
 skip-if = (os == 'linux' && e10s && debug) # Bug 1242204
 [browser_net_filter-01.js]
 [browser_net_filter-02.js]
 [browser_net_filter-03.js]
 [browser_net_filter-04.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/browser_net_cors_requests.js
@@ -0,0 +1,29 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+/**
+ * Test that CORS preflight requests are displayed by network monitor
+ */
+
+add_task(function* () {
+  let [, debuggee, monitor] = yield initNetMonitor(CORS_URL);
+  let { RequestsMenu } = monitor.panelWin.NetMonitorView;
+  RequestsMenu.lazyUpdate = false;
+
+  info("Performing a CORS request");
+  let url = "http://test1.example.com" + CORS_SJS_PATH;
+  debuggee.performRequests(url, "triggering/preflight", "post-data");
+
+  info("Waiting until the requests appear in netmonitor");
+  yield waitForNetworkEvents(monitor, 1, 1);
+
+  info("Checking the preflight and flight methods");
+  ["OPTIONS", "POST"].forEach((method, i) => {
+    verifyRequestItemTarget(RequestsMenu.getItemAtIndex(i), method, url);
+  });
+
+  yield teardown(monitor);
+  finish();
+});
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -37,16 +37,17 @@ const SORTING_URL = EXAMPLE_URL + "html_
 const FILTERING_URL = EXAMPLE_URL + "html_filter-test-page.html";
 const INFINITE_GET_URL = EXAMPLE_URL + "html_infinite-get-page.html";
 const CUSTOM_GET_URL = EXAMPLE_URL + "html_custom-get-page.html";
 const SINGLE_GET_URL = EXAMPLE_URL + "html_single-get-page.html";
 const STATISTICS_URL = EXAMPLE_URL + "html_statistics-test-page.html";
 const CURL_URL = EXAMPLE_URL + "html_copy-as-curl.html";
 const CURL_UTILS_URL = EXAMPLE_URL + "html_curl-utils.html";
 const SEND_BEACON_URL = EXAMPLE_URL + "html_send-beacon.html";
+const CORS_URL = EXAMPLE_URL + "html_cors-test-page.html";
 
 const SIMPLE_SJS = EXAMPLE_URL + "sjs_simple-test-server.sjs";
 const CONTENT_TYPE_SJS = EXAMPLE_URL + "sjs_content-type-test-server.sjs";
 const STATUS_CODES_SJS = EXAMPLE_URL + "sjs_status-codes-test-server.sjs";
 const SORTING_SJS = EXAMPLE_URL + "sjs_sorting-test-server.sjs";
 const HTTPS_REDIRECT_SJS = EXAMPLE_URL + "sjs_https-redirect-test-server.sjs";
 const CORS_SJS_PATH = "/browser/devtools/client/netmonitor/test/sjs_cors-test-server.sjs";
 
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/html_cors-test-page.html
@@ -0,0 +1,31 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
+    <meta http-equiv="Pragma" content="no-cache" />
+    <meta http-equiv="Expires" content="0" />
+    <title>Network Monitor test page</title>
+  </head>
+
+  <body>
+    <p>POST with CORS test page</p>
+
+    <script type="text/javascript">
+      function post(url, contentType, postData) {
+        var xhr = new XMLHttpRequest();
+        xhr.open("POST", url, true);
+        xhr.setRequestHeader("Content-Type", contentType);
+        xhr.send(postData);
+      }
+
+      function performRequests(url, contentType, postData) {
+        post(url, contentType, postData);
+      }
+    </script>
+  </body>
+
+</html>
--- a/devtools/client/netmonitor/test/sjs_cors-test-server.sjs
+++ b/devtools/client/netmonitor/test/sjs_cors-test-server.sjs
@@ -4,13 +4,14 @@
 function handleRequest(request, response) {
   response.setStatusLine(request.httpVersion, 200, "Och Aye");
 
   response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
   response.setHeader("Pragma", "no-cache");
   response.setHeader("Expires", "0");
 
   response.setHeader("Access-Control-Allow-Origin", "*", false);
+  response.setHeader("Access-Control-Allow-Headers", "content-type", false);
 
   response.setHeader("Content-Type", "text/plain; charset=utf-8", false);
 
   response.write("Access-Control-Allow-Origin: *");
 }
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -5591,17 +5591,17 @@ nsDocShell::GetCurrentDescriptor(nsISupp
 //*****************************************************************************
 
 NS_IMETHODIMP
 nsDocShell::InitWindow(nativeWindow aParentNativeWindow,
                        nsIWidget* aParentWidget, int32_t aX, int32_t aY,
                        int32_t aWidth, int32_t aHeight)
 {
   SetParentWidget(aParentWidget);
-  SetPositionAndSize(aX, aY, aWidth, aHeight, false);
+  SetPositionAndSize(aX, aY, aWidth, aHeight, 0);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::Create()
 {
   if (mCreated) {
@@ -5837,53 +5837,57 @@ nsDocShell::GetPosition(int32_t* aX, int
   return GetPositionAndSize(aX, aY, nullptr, nullptr);
 }
 
 NS_IMETHODIMP
 nsDocShell::SetSize(int32_t aWidth, int32_t aHeight, bool aRepaint)
 {
   int32_t x = 0, y = 0;
   GetPosition(&x, &y);
-  return SetPositionAndSize(x, y, aWidth, aHeight, aRepaint);
+  return SetPositionAndSize(x, y, aWidth, aHeight,
+                            aRepaint ? nsIBaseWindow::eRepaint : 0);
 }
 
 NS_IMETHODIMP
 nsDocShell::GetSize(int32_t* aWidth, int32_t* aHeight)
 {
   return GetPositionAndSize(nullptr, nullptr, aWidth, aHeight);
 }
 
 NS_IMETHODIMP
 nsDocShell::SetPositionAndSize(int32_t aX, int32_t aY, int32_t aWidth,
-                               int32_t aHeight, bool aFRepaint)
+                               int32_t aHeight, uint32_t aFlags)
 {
   mBounds.x = aX;
   mBounds.y = aY;
   mBounds.width = aWidth;
   mBounds.height = aHeight;
 
   // Hold strong ref, since SetBounds can make us null out mContentViewer
   nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
   if (viewer) {
+    uint32_t cvflags = (aFlags & nsIBaseWindow::eDelayResize) ?
+                           nsIContentViewer::eDelayResize : 0;
     // XXX Border figured in here or is that handled elsewhere?
-    NS_ENSURE_SUCCESS(viewer->SetBounds(mBounds), NS_ERROR_FAILURE);
+    nsresult rv = viewer->SetBoundsWithFlags(mBounds, cvflags);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aWidth,
                                int32_t* aHeight)
 {
   if (mParentWidget) {
     // ensure size is up-to-date if window has changed resolution
     LayoutDeviceIntRect r;
     mParentWidget->GetClientBounds(r);
-    SetPositionAndSize(mBounds.x, mBounds.y, r.width, r.height, false);
+    SetPositionAndSize(mBounds.x, mBounds.y, r.width, r.height, 0);
   }
 
   // We should really consider just getting this information from
   // our window instead of duplicating the storage and code...
   if (aWidth || aHeight) {
     // Caller wants to know our size; make sure to give them up to
     // date information.
     nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(mParent)));
--- a/docshell/base/nsIContentViewer.idl
+++ b/docshell/base/nsIContentViewer.idl
@@ -99,16 +99,22 @@ interface nsIContentViewer : nsISupports
 
   /**
    * Returns DOMDocument as nsIDocument and without addrefing.
    */
   [noscript,notxpcom] nsIDocument getDocument();
 
   [noscript] void getBounds(in nsIntRectRef aBounds);
   [noscript] void setBounds([const] in nsIntRectRef aBounds);
+  /**
+   * The 'aFlags' argument to setBoundsWithFlags is a set of these bits.
+   */
+  const unsigned long eDelayResize = 1;
+  [noscript] void setBoundsWithFlags([const] in nsIntRectRef aBounds,
+                                     in unsigned long aFlags);
 
   /**
    * The previous content viewer, which has been |close|d but not
    * |destroy|ed.
    */
   [noscript] attribute nsIContentViewer previousViewer;
 
   void move(in long aX, in long aY);
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -2333,17 +2333,18 @@ nsFrameLoader::UpdateBaseWindowPositionA
 
     if (!weakFrame.IsAlive()) {
       // GetPosition() killed us
       return;
     }
 
     ScreenIntSize size = aIFrame->GetSubdocumentSize();
 
-    baseWindow->SetPositionAndSize(x, y, size.width, size.height, false);
+    baseWindow->SetPositionAndSize(x, y, size.width, size.height,
+                                   nsIBaseWindow::eDelayResize);
   }
 }
 
 NS_IMETHODIMP
 nsFrameLoader::GetEventMode(uint32_t* aEventMode)
 {
   *aEventMode = mEventMode;
   return NS_OK;
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2379,23 +2379,16 @@ mozilla::dom::StartupJSEnvironment()
   sShuttingDown = false;
   sContextCount = 0;
   sSecurityManager = nullptr;
   gCCStats.Init();
   sExpensiveCollectorPokes = 0;
 }
 
 static void
-ReportAllJSExceptionsPrefChangedCallback(const char* aPrefName, void* aClosure)
-{
-  bool reportAll = Preferences::GetBool(aPrefName, false);
-  nsContentUtils::XPConnect()->SetReportAllJSExceptions(reportAll);
-}
-
-static void
 SetMemoryHighWaterMarkPrefChangedCallback(const char* aPrefName, void* aClosure)
 {
   int32_t highwatermark = Preferences::GetInt(aPrefName, 128);
 
   JS_SetGCParameter(sRuntime, JSGC_MAX_MALLOC_BYTES,
                     highwatermark * 1024L * 1024L);
 }
 
@@ -2538,19 +2531,16 @@ nsJSContext::EnsureStatics()
     AsmJSCacheOpenEntryForRead,
     asmjscache::CloseEntryForRead,
     AsmJSCacheOpenEntryForWrite,
     asmjscache::CloseEntryForWrite
   };
   JS::SetAsmJSCacheOps(sRuntime, &asmJSCacheOps);
 
   // Set these global xpconnect options...
-  Preferences::RegisterCallbackAndCall(ReportAllJSExceptionsPrefChangedCallback,
-                                       "dom.report_all_js_exceptions");
-
   Preferences::RegisterCallbackAndCall(SetMemoryHighWaterMarkPrefChangedCallback,
                                        "javascript.options.mem.high_water_mark");
 
   Preferences::RegisterCallbackAndCall(SetMemoryMaxPrefChangedCallback,
                                        "javascript.options.mem.max");
 
   Preferences::RegisterCallbackAndCall(SetMemoryGCModePrefChangedCallback,
                                        "javascript.options.mem.gc_per_compartment");
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -420,17 +420,16 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
 
   *aResult = nullptr;
 
   // First deal with aNode and walk its attributes (and their children). Then,
   // if aDeep is true, deal with aNode's children (and recurse into their
   // attributes and children).
 
   nsAutoScriptBlocker scriptBlocker;
-  AutoJSContext cx;
   nsresult rv;
 
   nsNodeInfoManager *nodeInfoManager = aNewNodeInfoManager;
 
   // aNode.
   NodeInfo *nodeInfo = aNode->mNodeInfo;
   RefPtr<NodeInfo> newNodeInfo;
   if (nodeInfoManager) {
@@ -559,16 +558,17 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
       newDoc->SetMayHaveAnimationObservers();
     }
 
     if (elem) {
       elem->RecompileScriptEventListeners();
     }
 
     if (aReparentScope) {
+      AutoJSContext cx;
       JS::Rooted<JSObject*> wrapper(cx);
       if ((wrapper = aNode->GetWrapper())) {
         MOZ_ASSERT(IsDOMObject(wrapper));
         JSAutoCompartment ac(cx, wrapper);
         rv = ReparentWrapper(cx, wrapper);
         if (NS_FAILED(rv)) {
           aNode->mNodeInfo.swap(nodeInfo);
 
--- a/dom/canvas/WebGLContextExtensions.cpp
+++ b/dom/canvas/WebGLContextExtensions.cpp
@@ -107,28 +107,24 @@ WebGLContext::IsExtensionSupported(WebGL
 {
     if (mDisableExtensions)
         return false;
 
     // Extensions for both WebGL 1 and 2.
     switch (ext) {
     // In alphabetical order
     // EXT_
-    case WebGLExtensionID::EXT_color_buffer_half_float:
-        return WebGLExtensionColorBufferHalfFloat::IsSupported(this);
     case WebGLExtensionID::EXT_texture_filter_anisotropic:
         return gl->IsExtensionSupported(gl::GLContext::EXT_texture_filter_anisotropic);
 
     // OES_
     case WebGLExtensionID::OES_texture_float_linear:
         return gl->IsSupported(gl::GLFeature::texture_float_linear);
 
     // WEBGL_
-    case WebGLExtensionID::WEBGL_color_buffer_float:
-        return WebGLExtensionColorBufferFloat::IsSupported(this);
     case WebGLExtensionID::WEBGL_compressed_texture_atc:
         return gl->IsExtensionSupported(gl::GLContext::AMD_compressed_ATC_texture);
     case WebGLExtensionID::WEBGL_compressed_texture_etc1:
         return gl->IsExtensionSupported(gl::GLContext::OES_compressed_ETC1_RGB8_texture);
     case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
         return gl->IsExtensionSupported(gl::GLContext::IMG_texture_compression_pvrtc);
     case WebGLExtensionID::WEBGL_compressed_texture_s3tc:
         if (gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_s3tc))
@@ -166,16 +162,18 @@ WebGLContext::IsExtensionSupported(WebGL
         switch (ext) {
         // ANGLE_
         case WebGLExtensionID::ANGLE_instanced_arrays:
             return WebGLExtensionInstancedArrays::IsSupported(this);
 
         // EXT_
         case WebGLExtensionID::EXT_blend_minmax:
             return WebGLExtensionBlendMinMax::IsSupported(this);
+        case WebGLExtensionID::EXT_color_buffer_half_float:
+            return WebGLExtensionColorBufferHalfFloat::IsSupported(this);
         case WebGLExtensionID::EXT_frag_depth:
             return WebGLExtensionFragDepth::IsSupported(this);
         case WebGLExtensionID::EXT_shader_texture_lod:
             return gl->IsExtensionSupported(gl::GLContext::EXT_shader_texture_lod);
         case WebGLExtensionID::EXT_sRGB:
             return WebGLExtensionSRGB::IsSupported(this);
 
         // OES_
@@ -189,16 +187,18 @@ WebGLContext::IsExtensionSupported(WebGL
             return WebGLExtensionTextureHalfFloat::IsSupported(this);
         case WebGLExtensionID::OES_texture_half_float_linear:
             return gl->IsSupported(gl::GLFeature::texture_half_float_linear);
 
         case WebGLExtensionID::OES_vertex_array_object:
             return true;
 
         // WEBGL_
+        case WebGLExtensionID::WEBGL_color_buffer_float:
+            return WebGLExtensionColorBufferFloat::IsSupported(this);
         case WebGLExtensionID::WEBGL_depth_texture:
             // WEBGL_depth_texture supports DEPTH_STENCIL textures
             if (!gl->IsSupported(gl::GLFeature::packed_depth_stencil))
                 return false;
 
             return gl->IsSupported(gl::GLFeature::depth_texture) ||
                    gl->IsExtensionSupported(gl::GLContext::ANGLE_depth_texture);
         case WebGLExtensionID::WEBGL_draw_buffers:
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/ensure-ext.js
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/ensure-ext.js
@@ -1,26 +1,38 @@
 'use strict';
 
-function EnsureExt(name, shouldBe = true) {
+function EnsureExt(extName, shouldHave=true) {
+    EnsureExtFor('webgl', extName, shouldHave);
+    EnsureExtFor('webgl2', extName, shouldHave);
+}
+
+function EnsureExtFor(contextType, extName, shouldHave=true) {
     var c = document.createElement('canvas');
-    var gl = c.getContext('experimental-webgl');
+    var gl = c.getContext(contextType);
 
-    if (shouldBe) {
-        ok(gl.getExtension(name), 'Should have extension ' + name + '.');
+    if (!gl) {
+        todo(false, 'Failed to create context: ' + contextType);
+        return;
+    }
+
+    var ext = gl.getExtension(extName);
+    var haveText = ' have ' + contextType + ' extension ' + extName + '.';
+    if (shouldHave) {
+        ok(ext, 'Should' + haveText);
     } else {
-        ok(!gl.getExtension(name), 'Should not have extension ' + name + '.');
+        ok(!ext, 'Should not' + haveText);
     }
 }
 
-function EnsureDraftExt(name, shouldBe = true) {
+function Lastly_WithDraftExtsEnabled(func) {
     SimpleTest.waitForExplicitFinish();
 
     var fnEnsure = function() {
-        EnsureExt(name, shouldBe);
+        func();
         SimpleTest.finish();
     };
 
     if ('SpecialPowers' in window) {
         var prefStateList = [
             ['webgl.enable-draft-extensions', true],
         ];
         var prefEnv = {'set': prefStateList};
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_ANGLE_instanced_arrays.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_ANGLE_instanced_arrays.html
@@ -5,13 +5,13 @@
     <script src='/tests/SimpleTest/SimpleTest.js'></script>
     <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
     <script src='ensure-ext.js'></script>
   </head>
   <body>
     <script>
 
 'use strict';
-EnsureExt('ANGLE_instanced_arrays');
+EnsureExtFor('webgl', 'ANGLE_instanced_arrays');
 
     </script>
   </body>
 </html>
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_blend_minmax.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_blend_minmax.html
@@ -5,13 +5,13 @@
     <script src='/tests/SimpleTest/SimpleTest.js'></script>
     <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
     <script src='ensure-ext.js'></script>
   </head>
   <body>
     <script>
 
 'use strict';
-EnsureExt('EXT_blend_minmax');
+EnsureExtFor('webgl', 'EXT_blend_minmax');
 
     </script>
   </body>
 </html>
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_color_buffer_half_float.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_color_buffer_half_float.html
@@ -5,13 +5,13 @@
     <script src='/tests/SimpleTest/SimpleTest.js'></script>
     <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
     <script src='ensure-ext.js'></script>
   </head>
   <body>
     <script>
 
 'use strict';
-EnsureExt('EXT_color_buffer_half_float');
+EnsureExtFor('webgl', 'EXT_color_buffer_half_float');
 
     </script>
   </body>
 </html>
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_disjoint_timer_query.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_disjoint_timer_query.html
@@ -5,13 +5,15 @@
     <script src='/tests/SimpleTest/SimpleTest.js'></script>
     <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
     <script src='ensure-ext.js'></script>
   </head>
   <body>
     <script>
 
 'use strict';
-EnsureDraftExt('EXT_disjoint_timer_query');
+Lastly_WithDraftExtsEnabled(function() {
+    EnsureExt('EXT_disjoint_timer_query');
+});
 
     </script>
   </body>
 </html>
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_frag_depth.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_frag_depth.html
@@ -5,13 +5,13 @@
     <script src='/tests/SimpleTest/SimpleTest.js'></script>
     <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
     <script src='ensure-ext.js'></script>
   </head>
   <body>
     <script>
 
 'use strict';
-EnsureExt('EXT_frag_depth');
+EnsureExtFor('webgl', 'EXT_frag_depth');
 
     </script>
   </body>
 </html>
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_sRGB.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_sRGB.html
@@ -5,13 +5,13 @@
     <script src='/tests/SimpleTest/SimpleTest.js'></script>
     <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
     <script src='ensure-ext.js'></script>
   </head>
   <body>
     <script>
 
 'use strict';
-EnsureExt('EXT_sRGB');
+EnsureExtFor('webgl', 'EXT_sRGB');
 
     </script>
   </body>
 </html>
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_shader_texture_lod.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_EXT_shader_texture_lod.html
@@ -5,13 +5,13 @@
     <script src='/tests/SimpleTest/SimpleTest.js'></script>
     <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
     <script src='ensure-ext.js'></script>
   </head>
   <body>
     <script>
 
 'use strict';
-EnsureExt('EXT_shader_texture_lod');
+EnsureExtFor('webgl', 'EXT_shader_texture_lod');
 
     </script>
   </body>
 </html>
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_OES_standard_derivatives.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_OES_standard_derivatives.html
@@ -5,13 +5,13 @@
     <script src='/tests/SimpleTest/SimpleTest.js'></script>
     <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
     <script src='ensure-ext.js'></script>
   </head>
   <body>
     <script>
 
 'use strict';
-EnsureExt('OES_standard_derivatives');
+EnsureExtFor('webgl', 'OES_standard_derivatives');
 
     </script>
   </body>
 </html>
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_WEBGL_color_buffer_float.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_WEBGL_color_buffer_float.html
@@ -5,13 +5,13 @@
     <script src='/tests/SimpleTest/SimpleTest.js'></script>
     <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
     <script src='ensure-ext.js'></script>
   </head>
   <body>
     <script>
 
 'use strict';
-EnsureExt('WEBGL_color_buffer_float');
+EnsureExtFor('webgl', 'WEBGL_color_buffer_float');
 
     </script>
   </body>
 </html>
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_WEBGL_compressed_texture_es3.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_WEBGL_compressed_texture_es3.html
@@ -5,13 +5,15 @@
     <script src='/tests/SimpleTest/SimpleTest.js'></script>
     <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
     <script src='ensure-ext.js'></script>
   </head>
   <body>
     <script>
 
 'use strict';
-EnsureDraftExt('WEBGL_compressed_texture_es3');
+Lastly_WithDraftExtsEnabled(function() {
+    EnsureExt('WEBGL_compressed_texture_es3');
+});
 
     </script>
   </body>
 </html>
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_WEBGL_depth_texture.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_WEBGL_depth_texture.html
@@ -5,13 +5,13 @@
     <script src='/tests/SimpleTest/SimpleTest.js'></script>
     <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
     <script src='ensure-ext.js'></script>
   </head>
   <body>
     <script>
 
 'use strict';
-EnsureExt('WEBGL_depth_texture');
+EnsureExtFor('webgl', 'WEBGL_depth_texture');
 
     </script>
   </body>
 </html>
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_WEBGL_draw_buffers.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_WEBGL_draw_buffers.html
@@ -5,13 +5,13 @@
     <script src='/tests/SimpleTest/SimpleTest.js'></script>
     <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
     <script src='ensure-ext.js'></script>
   </head>
   <body>
     <script>
 
 'use strict';
-EnsureExt('WEBGL_draw_buffers');
+EnsureExtFor('webgl', 'WEBGL_draw_buffers');
 
     </script>
   </body>
 </html>
--- a/dom/canvas/test/webgl-mochitest/ensure-exts/test_common.html
+++ b/dom/canvas/test/webgl-mochitest/ensure-exts/test_common.html
@@ -1,75 +1,110 @@
 <!DOCTYPE HTML>
 <html>
   <head>
     <meta charset='utf-8'/>
     <script src='/tests/SimpleTest/SimpleTest.js'></script>
     <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
+    <script src='ensure-ext.js'></script>
   </head>
   <body>
     <script>
 
 'use strict';
 
-var c = document.createElement('canvas');
-var gl = c.getContext('experimental-webgl');
+var ENSURE = 'ENSURE'; // Works on all test machines.
+var FORBID = 'FORBID'; // Should not work on any test machine.
+var MACHINE_SPECIFIC = 'MACHINE_SPECIFIC';
+
+var defaultExts = [
+    // Ratified
+    ['ANGLE_instanced_arrays'        , [MACHINE_SPECIFIC, FORBID          ]],
+    ['EXT_blend_minmax'              , [MACHINE_SPECIFIC, FORBID          ]],
+    ['EXT_frag_depth'                , [MACHINE_SPECIFIC, FORBID          ]],
+    ['EXT_shader_texture_lod'        , [MACHINE_SPECIFIC, FORBID          ]],
+    ['EXT_texture_filter_anisotropic', [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
+    ['OES_element_index_uint'        , [ENSURE          , FORBID          ]],
+    ['OES_standard_derivatives'      , [MACHINE_SPECIFIC, FORBID          ]],
+    ['OES_texture_float'             , [ENSURE          , FORBID          ]],
+    ['OES_texture_float_linear'      , [ENSURE          , ENSURE          ]],
+    ['OES_texture_half_float'        , [ENSURE          , FORBID          ]],
+    ['OES_texture_half_float_linear' , [ENSURE          , FORBID          ]],
+    ['OES_vertex_array_object'       , [ENSURE          , FORBID          ]],
+    ['WEBGL_compressed_texture_s3tc' , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
+//  ['WEBGL_debug_renderer_info'     , [FORBID          , FORBID          ]], // Complicated!
+    ['WEBGL_debug_shaders'           , [FORBID          , FORBID          ]],
+    ['WEBGL_depth_texture'           , [MACHINE_SPECIFIC, FORBID          ]],
+    ['WEBGL_draw_buffers'            , [MACHINE_SPECIFIC, FORBID          ]],
+    ['WEBGL_lose_context'            , [ENSURE          , ENSURE          ]],
 
-function ensureExt(name) {
-  ok(gl.getExtension(name), 'Should have extension ' + name + '.');
-}
+    // Community Approved
+    ['EXT_color_buffer_float'        , [FORBID          , ENSURE          ]],
+    ['EXT_color_buffer_half_float'   , [MACHINE_SPECIFIC, FORBID          ]],
+    ['EXT_sRGB'                      , [MACHINE_SPECIFIC, FORBID          ]],
+    ['WEBGL_color_buffer_float'      , [MACHINE_SPECIFIC, FORBID          ]],
+    ['WEBGL_compressed_texture_atc'  , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
+    ['WEBGL_compressed_texture_etc1' , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
+    ['WEBGL_compressed_texture_pvrtc', [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
+];
+
+var draftExts = [
+    ['EXT_disjoint_timer_query'    , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]], // TODO: Actually Community Approved now.
+    ['WEBGL_compressed_texture_es3', [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
+];
 
-function ensureNoExt(name) {
-  ok(!gl.getExtension(name), 'Should not have extension ' + name + '.');
+var nonImplementedExts = [
+    'OES_fbo_render_mipmap',
+    'WEBGL_compressed_texture_astc',
+    'WEBGL_security_sensitive_resources',
+    'WEBGL_shared_resources',
+];
+
+////////////////////
+
+function TestExtFor(contextType, extName, status) {
+    switch (status) {
+    case ENSURE:
+        EnsureExtFor(contextType, extName);
+        break;
+
+    case FORBID:
+        EnsureExtFor(contextType, extName, false);
+        break;
+
+    case MACHINE_SPECIFIC:
+        break;
+    }
 }
 
-do {
-  if (!gl)
-    break;
+function TestExt(extName, statusArr) {
+    TestExtFor('webgl', extName, statusArr[0]);
+    TestExtFor('webgl2', extName, statusArr[1]);
+}
 
-  // These aren't all guaranteed, but they're common to all our test slaves.
-  // If you're adding a slave config that is missing one of these, comment the line out
-  // and split it into its own test.
+////////////////////
+
+defaultExts.forEach(function(x) {
+    var extName = x[0];
+    var statusArr = x[1];
+    TestExt(extName, statusArr);
+});
 
-  // Implemented. (commented out if not test-slave-universal)
-  //ensureExt('ANGLE_instanced_arrays');
-  //ensureExt('EXT_blend_minmax');
-  //ensureExt('EXT_color_buffer_half_float');
-  //ensureExt('EXT_frag_depth');
-  //ensureExt('EXT_shader_texture_lod');
-  //ensureExt('EXT_sRGB');
-  //ensureExt('EXT_texture_filter_anisotropic');
-  ensureExt('OES_element_index_uint');
-  //ensureExt('OES_standard_derivatives');
-  ensureExt('OES_texture_float');
-  ensureExt('OES_texture_float_linear');
-  ensureExt('OES_texture_half_float');
-  ensureExt('OES_texture_half_float_linear');
-  ensureExt('OES_vertex_array_object');
-  //ensureExt('WEBGL_color_buffer_float');
-  //ensureExt('WEBGL_compressed_texture_atc');
-  //ensureExt('WEBGL_compressed_texture_es3');
-  //ensureExt('WEBGL_compressed_texture_etc1');
-  //ensureExt('WEBGL_compressed_texture_pvrtc');
-  //ensureExt('WEBGL_compressed_texture_s3tc');
-  //ensureExt('WEBGL_depth_texture');
-  //ensureExt('WEBGL_draw_buffers');
-  ensureExt('WEBGL_lose_context');
+nonImplementedExts.forEach(function(extName) {
+    EnsureExt(extName, false);
+});
 
-  // Draft extensions, which should not be exposed by default.
-  ensureNoExt('EXT_disjoint_timer_query');
-  ensureNoExt('WEBGL_compressed_texture_es3');
+draftExts.forEach(function(x) {
+    var extName = x[0];
+    EnsureExt(extName, false);
+});
 
-  // Not implemented.
-  ensureNoExt('EXT_color_buffer_float');
-  ensureNoExt('OES_fbo_render_mipmap');
-  ensureNoExt('WEBGL_compressed_texture_astc');
-  ensureNoExt('WEBGL_security_sensitive_resources');
-  ensureNoExt('WEBGL_shared_resources');
-
-  // Privileged
-  //ensureExt('WEBGL_debug_renderer_info');
-  //ensureExt('WEBGL_debug_shaders');
-} while (false);
+Lastly_WithDraftExtsEnabled(function() {
+    draftExts.forEach(function(x) {
+        var extName = x[0];
+        var statusArr = x[1];
+        TestExt(extName, statusArr);
+    });
+});
 
     </script>
   </body>
 </html>
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -1532,17 +1532,18 @@ EventStateManager::FireContextClick()
       nsCOMPtr<nsIFormControl> formCtrl(do_QueryInterface(mGestureDownContent));
 
       if (formCtrl) {
         allowedToDispatch = formCtrl->IsTextOrNumberControl(/*aExcludePassword*/ false) ||
                             formCtrl->GetType() == NS_FORM_INPUT_FILE;
       }
       else if (mGestureDownContent->IsAnyOfHTMLElements(nsGkAtoms::applet,
                                                         nsGkAtoms::embed,
-                                                        nsGkAtoms::object)) {
+                                                        nsGkAtoms::object,
+                                                        nsGkAtoms::label)) {
         allowedToDispatch = false;
       }
     }
 
     if (allowedToDispatch) {
       // init the event while mCurrentTarget is still good
       WidgetMouseEvent event(true, eContextMenu, targetWidget,
                              WidgetMouseEvent::eReal);
@@ -4395,16 +4396,19 @@ EventStateManager::SetPointerLock(nsIWid
       dragService->Suppress();
     }
   } else {
     // Unlocking, so return pointer to the original position by firing a
     // synthetic mouse event. We first reset sLastRefPoint to its
     // pre-pointerlock position, so that the synthetic mouse event reports
     // no movement.
     sLastRefPoint = mPreLockPoint;
+    // Reset SynthCenteringPoint to invalid so that next time we start
+    // locking pointer, it has its initial value.
+    sSynthCenteringPoint = kInvalidRefPoint;
     if (aWidget) {
       aWidget->SynthesizeNativeMouseMove(
         mPreLockPoint + aWidget->WidgetToScreenOffset(), nullptr);
     }
 
     // Don't retarget events to this element any more.
     nsIPresShell::SetCapturingContent(nullptr, CAPTURE_POINTERLOCK);
 
--- a/dom/events/test/test_bug602962.xul
+++ b/dom/events/test/test_bug602962.xul
@@ -32,18 +32,20 @@ function doTest() {
   scrollbox = win.document.getElementById("page-scrollbox");
   sbo = scrollbox.boxObject;
   content = win.document.getElementById("page-box");
   content.style.width = 400 + "px";
   
   win.addEventListener("resize", function() {
     win.removeEventListener("resize", arguments.callee, false);
 
-    sbo.scrollBy(200, 0);
-    setTimeout(function() { resize(); }, 0);
+    setTimeout(function(){
+      sbo.scrollBy(200, 0);
+      resize();
+    },0);
   }, false);
 
   oldWidth = win.outerWidth;
   oldHeight = win.outerHeight;
   win.resizeTo(200, 400);
 }
 
 function resize() {
--- a/dom/html/HTMLFieldSetElement.cpp
+++ b/dom/html/HTMLFieldSetElement.cpp
@@ -119,17 +119,17 @@ HTMLFieldSetElement::GetType(nsAString& 
 }
 
 /* static */
 bool
 HTMLFieldSetElement::MatchListedElements(nsIContent* aContent, int32_t aNamespaceID,
                                          nsIAtom* aAtom, void* aData)
 {
   nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aContent);
-  return formControl && formControl->GetType() != NS_FORM_LABEL;
+  return formControl;
 }
 
 NS_IMETHODIMP
 HTMLFieldSetElement::GetElements(nsIDOMHTMLCollection** aElements)
 {
   NS_ADDREF(*aElements = Elements());
   return NS_OK;
 }
--- a/dom/html/HTMLFormControlsCollection.cpp
+++ b/dom/html/HTMLFormControlsCollection.cpp
@@ -58,17 +58,19 @@ HTMLFormControlsCollection::ShouldBeInEl
   case NS_FORM_OUTPUT :
     return true;
   }
 
   // These form control types are not supposed to end up in the
   // form.elements array
   //
   // NS_FORM_INPUT_IMAGE
-  // NS_FORM_LABEL
+  //
+  // XXXbz maybe we should just check for that type here instead of the big
+  // switch?
 
   return false;
 }
 
 HTMLFormControlsCollection::HTMLFormControlsCollection(HTMLFormElement* aForm)
   : mForm(aForm)
   // Initialize the elements list to have an initial capacity
   // of 8 to reduce allocations on small forms.
--- a/dom/html/HTMLLabelElement.cpp
+++ b/dom/html/HTMLLabelElement.cpp
@@ -29,27 +29,29 @@ HTMLLabelElement::~HTMLLabelElement()
 JSObject*
 HTMLLabelElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return HTMLLabelElementBinding::Wrap(aCx, this, aGivenProto);
 }
 
 // nsISupports
 
-NS_IMPL_ISUPPORTS_INHERITED(HTMLLabelElement, nsGenericHTMLFormElement,
+NS_IMPL_ISUPPORTS_INHERITED(HTMLLabelElement, nsGenericHTMLElement,
                             nsIDOMHTMLLabelElement)
 
 // nsIDOMHTMLLabelElement
 
 NS_IMPL_ELEMENT_CLONE(HTMLLabelElement)
 
 NS_IMETHODIMP
 HTMLLabelElement::GetForm(nsIDOMHTMLFormElement** aForm)
 {
-  return nsGenericHTMLFormElement::GetForm(aForm);
+  RefPtr<nsIDOMHTMLFormElement> form = GetForm();
+  form.forget(aForm);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLLabelElement::GetControl(nsIDOMHTMLElement** aElement)
 {
   nsCOMPtr<nsIDOMHTMLElement> element = do_QueryObject(GetLabeledElement());
   element.forget(aElement);
   return NS_OK;
@@ -67,16 +69,33 @@ NS_IMETHODIMP
 HTMLLabelElement::GetHtmlFor(nsAString& aHtmlFor)
 {
   nsString htmlFor;
   GetHtmlFor(htmlFor);
   aHtmlFor = htmlFor;
   return NS_OK;
 }
 
+HTMLFormElement*
+HTMLLabelElement::GetForm() const
+{
+  nsGenericHTMLElement* control = GetControl();
+  if (!control) {
+    return nullptr;
+  }
+
+  // Not all labeled things have a form association.  Stick to the ones that do.
+  nsCOMPtr<nsIFormControl> formControl = do_QueryObject(control);
+  if (!formControl) {
+    return nullptr;
+  }
+
+  return static_cast<HTMLFormElement*>(formControl->GetFormElement());
+}
+
 void
 HTMLLabelElement::Focus(ErrorResult& aError)
 {
   // retarget the focus method at the for content
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm) {
     nsCOMPtr<nsIDOMElement> elem = do_QueryObject(GetLabeledElement());
     if (elem)
@@ -203,28 +222,16 @@ HTMLLabelElement::PostHandleEvent(EventC
       default:
         break;
     }
     mHandlingEvent = false;
   }
   return NS_OK;
 }
 
-nsresult
-HTMLLabelElement::Reset()
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HTMLLabelElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
-{
-  return NS_OK;
-}
-
 bool
 HTMLLabelElement::PerformAccesskey(bool aKeyCausesActivation,
                                    bool aIsTrustedEvent)
 {
   if (!aKeyCausesActivation) {
     RefPtr<Element> element = GetLabeledElement();
     if (element) {
       return element->PerformAccesskey(aKeyCausesActivation, aIsTrustedEvent);
--- a/dom/html/HTMLLabelElement.h
+++ b/dom/html/HTMLLabelElement.h
@@ -13,22 +13,22 @@
 #include "mozilla/Attributes.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMHTMLLabelElement.h"
 
 namespace mozilla {
 class EventChainPostVisitor;
 namespace dom {
 
-class HTMLLabelElement final : public nsGenericHTMLFormElement,
+class HTMLLabelElement final : public nsGenericHTMLElement,
                                public nsIDOMHTMLLabelElement
 {
 public:
   explicit HTMLLabelElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
-    : nsGenericHTMLFormElement(aNodeInfo),
+    : nsGenericHTMLElement(aNodeInfo),
       mHandlingEvent(false)
   {
   }
 
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLLabelElement, label)
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
@@ -37,38 +37,33 @@ public:
   virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override
   {
     return true;
   }
 
   // nsIDOMHTMLLabelElement
   NS_DECL_NSIDOMHTMLLABELELEMENT
 
-  using nsGenericHTMLFormElement::GetForm;
+  HTMLFormElement* GetForm() const;
   void GetHtmlFor(nsString& aHtmlFor)
   {
     GetHTMLAttr(nsGkAtoms::_for, aHtmlFor);
   }
   void SetHtmlFor(const nsAString& aHtmlFor, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::_for, aHtmlFor, aError);
   }
   nsGenericHTMLElement* GetControl() const
   {
     return GetLabeledElement();
   }
 
   using nsGenericHTMLElement::Focus;
   virtual void Focus(mozilla::ErrorResult& aError) override;
 
-  // nsIFormControl
-  NS_IMETHOD_(uint32_t) GetType() const override { return NS_FORM_LABEL; }
-  NS_IMETHOD Reset() override;
-  NS_IMETHOD SubmitNamesValues(nsFormSubmission* aFormSubmission) override;
-
   virtual bool IsDisabled() const override { return false; }
 
   // nsIContent
   virtual nsresult PostHandleEvent(
                      EventChainPostVisitor& aVisitor) override;
   virtual bool PerformAccesskey(bool aKeyCausesActivation,
                                 bool aIsTrustedEvent) override;
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -2296,17 +2296,16 @@ nsGenericHTMLFormElement::ForgetFieldSet
 }
 
 bool
 nsGenericHTMLFormElement::CanBeDisabled() const
 {
   int32_t type = GetType();
   // It's easier to test the types that _cannot_ be disabled
   return
-    type != NS_FORM_LABEL &&
     type != NS_FORM_OBJECT &&
     type != NS_FORM_OUTPUT;
 }
 
 bool
 nsGenericHTMLFormElement::IsHTMLFocusable(bool aWithMouse,
                                           bool* aIsFocusable,
                                           int32_t* aTabIndex)
--- a/dom/html/nsIFormControl.h
+++ b/dom/html/nsIFormControl.h
@@ -17,17 +17,16 @@ namespace mozilla {
 namespace dom {
 class Element;
 class HTMLFieldSetElement;
 } // namespace dom
 } // namespace mozilla
 
 enum FormControlsTypes {
   NS_FORM_FIELDSET = 1,
-  NS_FORM_LABEL,
   NS_FORM_OUTPUT,
   NS_FORM_SELECT,
   NS_FORM_TEXTAREA,
   NS_FORM_OBJECT,
   eFormControlsWithoutSubTypesMax,
   // After this, all types will have sub-types which introduce new enum lists.
   // eFormControlsWithoutSubTypesMax let us know if the previous types values
   // are not overlapping with sub-types/masks.
@@ -282,17 +281,16 @@ nsIFormControl::IsSubmittableControl() c
          type & NS_FORM_INPUT_ELEMENT;
 }
 
 bool
 nsIFormControl::AllowDraggableChildren() const
 {
   uint32_t type = GetType();
   return type == NS_FORM_OBJECT ||
-         type == NS_FORM_LABEL ||
          type == NS_FORM_FIELDSET ||
          type == NS_FORM_OUTPUT;
 }
 
 bool
 nsIFormControl::IsAutofocusable() const
 {
   uint32_t type = GetType();
--- a/dom/html/test/forms/test_form_attribute-1.html
+++ b/dom/html/test/forms/test_form_attribute-1.html
@@ -447,18 +447,20 @@ for (var name of elementNames) {
         is(formsList[i].elements.length, elementsList.length,
            "The form should contain " + elementsList.length + " elements");
       }
       for (var j=0; j<elementsList.length; ++j) {
         if (name != 'label' && name != 'meter' && name != 'progress') {
           is(formsList[i].elements[j], elementsList[j],
              "The form should contain " + elementsList[j]);
         }
-        is(elementsList[j].form, formsList[i],
-           "The form owner should be the form associated to the list");
+        if (name != 'label') {
+          is(elementsList[j].form, formsList[i],
+             "The form owner should be the form associated to the list");
+        }
       }
     }
   }
 
   // Cleaning-up.
   for (e of elements) {
     e.parentNode.removeChild(e);
     e = null;
--- a/dom/html/test/test_bug841466.html
+++ b/dom/html/test/test_bug841466.html
@@ -5,17 +5,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 -->
 <head>
   <meta charset="utf-8">
   <title>Test for Bug 841466</title>
   <script src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" href="/tests/SimpleTest/test.css">
   <script>
   /** Test for Bug 841466 **/
-var els = ['button', 'fieldset', 'input', 'keygen', 'label', 'object', 'output', 'select', 'textarea'];
+var els = ['button', 'fieldset', 'input', 'keygen', 'object', 'output', 'select', 'textarea'];
 var code = "try { is(foo, 'bar', 'expected value bar from expando on element ' + localName); } catch (e) { ok(false, String(e)); }";
 els.forEach(function(el) {
   var f = document.createElement("form");
   f.foo = "bar";
   f.innerHTML = '<' + el + ' onclick="' + code + '">';
   var e = f.firstChild
   if (el === "keygen") {
     todo_is(e.localName, "keygen", "Bug 101019");
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1687,17 +1687,17 @@ TabChild::RecvUpdateDimensions(const CSS
     ScreenIntSize screenSize = GetInnerSize();
     ScreenIntRect screenRect = GetOuterRect();
 
     // Set the size on the document viewer before we update the widget and
     // trigger a reflow. Otherwise the MobileViewportManager reads the stale
     // size from the content viewer when it computes a new CSS viewport.
     nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());
     baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height,
-                                true);
+                                nsIBaseWindow::eRepaint);
 
     mPuppetWidget->Resize(screenRect.x + clientOffset.x + chromeDisp.x,
                           screenRect.y + clientOffset.y + chromeDisp.y,
                           screenSize.width, screenSize.height, true);
 
     return true;
 }
 
@@ -3097,17 +3097,17 @@ TabChild::RecvUIResolutionChanged(const 
   if (mHasValidInnerSize && oldScreenSize != screenSize) {
     ScreenIntRect screenRect = GetOuterRect();
     mPuppetWidget->Resize(screenRect.x + mClientOffset.x + mChromeDisp.x,
                           screenRect.y + mClientOffset.y + mChromeDisp.y,
                           screenSize.width, screenSize.height, true);
 
     nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());
     baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height,
-                                true);
+                                nsIBaseWindow::eRepaint);
   }
 
   return true;
 }
 
 bool
 TabChild::RecvThemeChanged(nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache)
 {
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -873,17 +873,18 @@ TabParent::RecvSetDimensions(const uint3
 
   int32_t cy = aCy;
   if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_IGNORE_CY) {
     treeOwnerAsWin->GetSize(&unused, &cy);
   }
 
   if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION &&
       aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER) {
-    treeOwnerAsWin->SetPositionAndSize(x, y, cx, cy, true);
+    treeOwnerAsWin->SetPositionAndSize(x, y, cx, cy,
+                                       nsIBaseWindow::eRepaint);
     return true;
   }
 
   if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) {
     treeOwnerAsWin->SetPosition(x, y);
     mUpdatedDimensions = false;
     UpdatePosition();
     return true;
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -1280,16 +1280,37 @@ MediaStreamGraphImpl::ShouldUpdateMainTh
 void
 MediaStreamGraphImpl::PrepareUpdatesToMainThreadState(bool aFinalUpdate)
 {
   mMonitor.AssertCurrentThreadOwns();
 
   // We don't want to frequently update the main thread about timing update
   // when we are not running in realtime.
   if (aFinalUpdate || ShouldUpdateMainThread()) {
+    // Strip updates that will be obsoleted below, so as to keep the length of
+    // mStreamUpdates sane.
+    size_t keptUpdateCount = 0;
+    for (size_t i = 0; i < mStreamUpdates.Length(); ++i) {
+      MediaStream* stream = mStreamUpdates[i].mStream;
+      // RemoveStreamGraphThread() clears mStream in updates for
+      // streams that are removed from the graph.
+      MOZ_ASSERT(!stream || stream->GraphImpl() == this);
+      if (!stream || stream->MainThreadNeedsUpdates()) {
+        // Discard this update as it has either been cleared when the stream
+        // was destroyed or there will be a newer update below.
+        continue;
+      }
+      if (keptUpdateCount != i) {
+        mStreamUpdates[keptUpdateCount] = Move(mStreamUpdates[i]);
+        MOZ_ASSERT(!mStreamUpdates[i].mStream);
+      }
+      ++keptUpdateCount;
+    }
+    mStreamUpdates.TruncateLength(keptUpdateCount);
+
     mStreamUpdates.SetCapacity(mStreamUpdates.Length() + mStreams.Length() +
         mSuspendedStreams.Length());
     for (MediaStream* stream : AllStreams()) {
       if (!stream->MainThreadNeedsUpdates()) {
         continue;
       }
       StreamUpdate* update = mStreamUpdates.AppendElement();
       update->mStream = stream;
--- a/dom/media/platforms/wmf/DXVA2Manager.cpp
+++ b/dom/media/platforms/wmf/DXVA2Manager.cpp
@@ -14,16 +14,17 @@
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/Telemetry.h"
 #include "MediaTelemetryConstants.h"
 #include "mfapi.h"
 #include "MediaPrefs.h"
 #include "MFTDecoder.h"
 #include "DriverCrashGuard.h"
 #include "nsPrintfCString.h"
+#include "gfxCrashReporterUtils.h"
 
 const CLSID CLSID_VideoProcessorMFT =
 {
   0x88753b26,
   0x5b24,
   0x49bd,
   { 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82 }
 };
@@ -252,16 +253,18 @@ D3D9DXVA2Manager::GetDXVADeviceManager()
   return mDeviceManager;
 }
 
 HRESULT
 D3D9DXVA2Manager::Init(nsACString& aFailureReason)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+  ScopedGfxFeatureReporter reporter("DXVA2D3D9");
+
   gfx::D3D9VideoCrashGuard crashGuard;
   if (crashGuard.Crashed()) {
     NS_WARNING("DXVA2D3D9 crash detected");
     aFailureReason.AssignLiteral("DXVA2D3D9 crashes detected in the past");
     return E_FAIL;
   }
 
   // Create D3D9Ex.
@@ -414,16 +417,19 @@ D3D9DXVA2Manager::Init(nsACString& aFail
   mSyncSurface = syncSurf;
 
   mTextureClientAllocator = new D3D9RecycleAllocator(layers::ImageBridgeChild::GetSingleton(),
                                                      mDevice);
   mTextureClientAllocator->SetMaxPoolSize(5);
 
   Telemetry::Accumulate(Telemetry::MEDIA_DECODER_BACKEND_USED,
                         uint32_t(media::MediaDecoderBackend::WMFDXVA2D3D9));
+
+  reporter.SetSuccessful();
+
   return S_OK;
 }
 
 HRESULT
 D3D9DXVA2Manager::CopyToImage(IMFSample* aSample,
                               const nsIntRect& aRegion,
                               ImageContainer* aImageContainer,
                               Image** aOutImage)
@@ -598,16 +604,18 @@ D3D11DXVA2Manager::GetDXVADeviceManager(
   return mDXGIDeviceManager;
 }
 
 HRESULT
 D3D11DXVA2Manager::Init(nsACString& aFailureReason)
 {
   HRESULT hr;
 
+  ScopedGfxFeatureReporter reporter("DXVA2D3D11");
+
   gfx::D3D11VideoCrashGuard crashGuard;
   if (crashGuard.Crashed()) {
     NS_WARNING("DXVA2D3D11 crash detected");
     aFailureReason.AssignLiteral("DXVA2D3D11 crashes detected in the past");
     return E_FAIL;
   }
 
   mDevice = gfxWindowsPlatform::GetPlatform()->CreateD3D11DecoderDevice();
@@ -728,16 +736,19 @@ D3D11DXVA2Manager::Init(nsACString& aFai
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   mTextureClientAllocator = new D3D11RecycleAllocator(layers::ImageBridgeChild::GetSingleton(),
                                                       mDevice);
   mTextureClientAllocator->SetMaxPoolSize(5);
 
   Telemetry::Accumulate(Telemetry::MEDIA_DECODER_BACKEND_USED,
                         uint32_t(media::MediaDecoderBackend::WMFDXVA2D3D11));
+
+  reporter.SetSuccessful();
+
   return S_OK;
 }
 
 HRESULT
 D3D11DXVA2Manager::CreateOutputSample(RefPtr<IMFSample>& aSample, ID3D11Texture2D* aTexture)
 {
   RefPtr<IMFSample> sample;
   HRESULT hr = wmf::MFCreateSample(getter_AddRefs(sample));
--- a/dom/media/webaudio/MediaStreamAudioSourceNode.cpp
+++ b/dom/media/webaudio/MediaStreamAudioSourceNode.cpp
@@ -112,21 +112,24 @@ MediaStreamAudioSourceNode::DetachFromTr
 }
 
 void
 MediaStreamAudioSourceNode::AttachToFirstTrack(const RefPtr<DOMMediaStream>& aMediaStream)
 {
   nsTArray<RefPtr<AudioStreamTrack>> tracks;
   aMediaStream->GetAudioTracks(tracks);
 
-  if (tracks.IsEmpty()) {
+  for (const RefPtr<AudioStreamTrack>& track : tracks) {
+    if (track->Ended()) {
+      continue;
+    }
+
+    AttachToTrack(track);
     return;
   }
-
-  AttachToTrack(tracks[0]);
 }
 
 void
 MediaStreamAudioSourceNode::NotifyTrackAdded(const RefPtr<MediaStreamTrack>& aTrack)
 {
   if (mInputTrack) {
     return;
   }
--- a/dom/presentation/Presentation.cpp
+++ b/dom/presentation/Presentation.cpp
@@ -47,22 +47,30 @@ Presentation::WrapObject(JSContext* aCx,
                          JS::Handle<JSObject*> aGivenProto)
 {
   return PresentationBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
 Presentation::SetDefaultRequest(PresentationRequest* aRequest)
 {
+  if (IsInPresentedContent()) {
+    return;
+  }
+
   mDefaultRequest = aRequest;
 }
 
 already_AddRefed<PresentationRequest>
 Presentation::GetDefaultRequest() const
 {
+  if (IsInPresentedContent()) {
+    return nullptr;
+  }
+
   RefPtr<PresentationRequest> request = mDefaultRequest;
   return request.forget();
 }
 
 already_AddRefed<PresentationReceiver>
 Presentation::GetReceiver()
 {
   // return the same receiver if already created
--- a/dom/presentation/tests/mochitest/file_presentation_receiver.html
+++ b/dom/presentation/tests/mochitest/file_presentation_receiver.html
@@ -49,16 +49,30 @@ function testConnectionAvailable() {
         ok(false, "Error occurred when getting the connection: " + aError);
         finish();
         aReject();
       }
     );
   });
 }
 
+function testDefauleRequestIsNull() {
+  return new Promise(function(aResolve, aReject) {
+    navigator.presentation.defaultRequest = new PresentationRequest("http://example.com");
+    if (navigator.presentation.defaultRequest === null) {
+      ok(true, "defaultRequest should be null.");
+      aResolve();
+    }
+    else {
+      ok(false, "defaultRequest should be null.");
+      aReject();
+    }
+  });
+}
+
 function testConnectionAvailableSameOriginInnerIframe() {
   return new Promise(function(aResolve, aReject) {
     var iframe = document.createElement('iframe');
     iframe.setAttribute('src', './file_presentation_receiver_inner_iframe.html');
     document.body.appendChild(iframe);
 
     aResolve();
   });
@@ -109,16 +123,17 @@ function testTerminateConnection() {
       aResolve();
     };
 
     connection.terminate();
   });
 }
 
 testConnectionAvailable().
+then(testDefauleRequestIsNull).
 then(testConnectionAvailableSameOriginInnerIframe).
 then(testConnectionUnavailableDiffOriginInnerIframe).
 then(testConnectionReady).
 then(testIncomingMessage).
 then(testTerminateConnection).
 then(finish);
 
 </script>
--- a/dom/tests/mochitest/pointerlock/file_childIframe.html
+++ b/dom/tests/mochitest/pointerlock/file_childIframe.html
@@ -103,39 +103,32 @@ https://bugzilla.mozilla.org/show_bug.cg
         synthesizeMouseAtCenter(childDiv, {type: "mousemove"}, window);
       };
 
       var secondMoveChild = function (e) {
         secondMove.mozMovementX = e.mozMovementX;
         secondMove.mozMovementY = e.mozMovementY;
         parent.removeEventListener("mousemove", secondMoveChild);
 
+        addFullscreenChangeContinuation("exit", function() {
+          runTests();
+          SimpleTest.finish();
+        });
         document.exitFullscreen();
       };
 
       document.addEventListener("mozpointerlockchange", function () {
         if (document.mozPointerLockElement === parent) {
           parent.addEventListener("mousemove", firstMoveChild);
           synthesizeMouseAtCenter(childDiv, {type: "mousemove"}, window);
         }
       }, false);
 
-      document.addEventListener("mozpointerlockerror", function () {
-        document.exitFullscreen();
-      }, false);
-
-      document.addEventListener("fullscreenchange", function (e)  {
-        if (document.fullscreenElement === parent) {
+      function start() {
+        addFullscreenChangeContinuation("enter", function() {
           parent.mozRequestPointerLock();
-        }
-        else {
-          runTests();
-          SimpleTest.finish();
-        }
-      }, false);
-
-      function start() {
+        });
         parent.requestFullscreen();
       }
     </script>
   </pre>
 </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_doubleLock.html
+++ b/dom/tests/mochitest/pointerlock/file_doubleLock.html
@@ -35,35 +35,32 @@ https://bugzilla.mozilla.org/show_bug.cg
       function runTests () {
         is(numberOfLocks, 2, "Requesting pointer lock on a locked element " +
           "should dispatch mozpointerlockchange event");
       }
 
       document.addEventListener("mozpointerlockchange", function (e) {
         if (document.mozPointerLockElement === div) {
           if (numberOfLocks === 2) {
+            addFullscreenChangeContinuation("exit", function() {
+              runTests();
+              SimpleTest.finish();
+            });
             document.exitFullscreen();
           }
           else {
             numberOfLocks++;
             div.mozRequestPointerLock();
           }
         }
       }, false);
 
-      document.addEventListener("fullscreenchange", function (e) {
-        if (document.fullscreenElement === div) {
-          div.mozRequestPointerLock();
-        }
-        else {
-          runTests();
-          SimpleTest.finish();
-        }
-      }, false);
-
       function start() {
         console.log('started');
+        addFullscreenChangeContinuation("enter", function() {
+          div.mozRequestPointerLock();
+        });
         div.requestFullscreen();
       }
     </script>
   </pre>
 </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_escapeKey.html
+++ b/dom/tests/mochitest/pointerlock/file_escapeKey.html
@@ -24,49 +24,47 @@
        */
 
       SimpleTest.waitForExplicitFinish();
 
       var div = document.getElementById("div")
         , pointerUnLocked = false;
 
       function start() {
-        document.addEventListener("fullscreenchange", enteredFullscreen);
+        addFullscreenChangeContinuation("enter", enteredFullscreen);
         div.requestFullscreen();
       }
 
       function enteredFullscreen(e) {
-        document.removeEventListener("fullscreenchange", enteredFullscreen);
         is(document.fullscreenElement, div, "Element #div should entered fullscreen");
         ok(!document.mozPointerLockElement, "Pointer shouldn't have been locked");
         document.addEventListener("mozpointerlockchange", lockedPointer);
         div.mozRequestPointerLock();
       }
 
       function lockedPointer(e) {
         document.removeEventListener("mozpointerlockchange", lockedPointer);
         is(document.mozPointerLockElement, div, "Pointer should have been locked on #div");
         document.addEventListener("mozpointerlockchange", unlockedPointer);
-        document.addEventListener("fullscreenchange", leavedFullscreen);
+        addFullscreenChangeContinuation("exit", leavedFullscreen);
         SimpleTest.executeSoon(() => synthesizeKey("VK_ESCAPE", {}));
       }
 
       var pointerUnlocked = false;
       var exitedFullscreen = false;
 
       function unlockedPointer() {
         document.removeEventListener("mozpointerlockchange", unlockedPointer);
         ok(!pointerUnlocked, "Shouldn't have unlocked pointer before");
         ok(!document.mozPointerLockElement, "Pointer should have been unlocked now");
         pointerUnlocked = true;
         finishTest();
       }
 
       function leavedFullscreen() {
-        document.removeEventListener("fullscreenchange", leavedFullscreen);
         ok(!exitedFullscreen, "Shouldn't have exited fullscreen before");
         ok(!document.fullscreenElement, "Should have exited fullscreen now");
         exitedFullscreen = true;
         finishTest();
       }
 
       function finishTest() {
         if (pointerUnlocked && exitedFullscreen) {
--- a/dom/tests/mochitest/pointerlock/file_infiniteMovement.html
+++ b/dom/tests/mochitest/pointerlock/file_infiniteMovement.html
@@ -60,16 +60,21 @@ https://bugzilla.mozilla.org/show_bug.cg
         }
 
         var secondMoveListener = function (e) {
           info("Got second mousemove");
           totalMovementX = divCenterWidth + ((divCenterWidth / 2) * 3);
           totalMovementY = divCenterHeight + ((divCenterHeight / 2) * 3);
 
           div.removeEventListener("mousemove", secondMoveListener, false);
+          addFullscreenChangeContinuation("exit", function() {
+            info("Got fullscreenchange for exiting");
+            runTests();
+            SimpleTest.finish();
+          });
           document.exitFullscreen();
         }
 
         document.addEventListener("mozpointerlockchange", function (e) {
           if (document.mozPointerLockElement === div) {
             info("Got mozpointerlockchange for entering");
             div.addEventListener("mousemove", firstMoveListener, false);
 
@@ -79,28 +84,20 @@ https://bugzilla.mozilla.org/show_bug.cg
             synthesizeMouse(div, divCenterWidth, divCenterHeight, {
               type: "mousemove"
             }, window);
           } else {
             info("Got mozpointerlockchange for exiting");
           }
         }, false);
 
-        document.addEventListener("fullscreenchange", function() {
-          if (document.fullscreenElement === div) {
+        function start() {
+          info("Requesting fullscreen on parent");
+          addFullscreenChangeContinuation("enter", function() {
             info("Got fullscreenchange for entering");
             div.mozRequestPointerLock();
-          }
-          else {
-            info("Got fullscreenchange for exiting");
-            runTests();
-            SimpleTest.finish();
-          }
-        }, false);
-
-        function start() {
-          info("Requesting fullscreen on parent");
+          });
           div.requestFullscreen();
         }
       </script>
     </pre>
   </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_locksvgelement.html
+++ b/dom/tests/mochitest/pointerlock/file_locksvgelement.html
@@ -36,29 +36,27 @@
           elemWasLocked = false;
 
         document.addEventListener("mozpointerlockchange", function (e) {
           if (document.fullscreenElement &&
               document.mozPointerLockElement === elem) {
             elemWasLocked = true;
             document.mozExitPointerLock();
           } else {
+            addFullscreenChangeContinuation("exit", function() {
+              ok(elemWasLocked, "Expected SVG elem to become locked.");
+              SimpleTest.finish();
+            });
             document.exitFullscreen();
           }
         }, false);
 
-        document.addEventListener("fullscreenchange", function (e) {
-          if (document.fullscreenElement === elem) {
-            elem.mozRequestPointerLock();
-          } else {
-            ok(elemWasLocked, "Expected SVG elem to become locked.");
-            SimpleTest.finish();
-          }
-        }, false);
-
         function start() {
           elem = document.getElementById("svg-elem");
+          addFullscreenChangeContinuation("enter", function() {
+            elem.mozRequestPointerLock();
+          });
           elem.requestFullscreen();
         }
       </script>
     </pre>
   </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_movementXY.html
+++ b/dom/tests/mochitest/pointerlock/file_movementXY.html
@@ -78,43 +78,29 @@ https://bugzilla.mozilla.org/show_bug.cg
         var moveMouseAgain = function(e) {
           info("Got mouse move again");
           secondMove.screenX = e.screenX;
           secondMove.screenY = e.screenY;
           secondMove.mozMovementX = e.mozMovementX;
           secondMove.mozMovementY = e.mozMovementY;
 
           div.removeEventListener("mousemove", moveMouseAgain, false);
+          addFullscreenChangeContinuation("exit", function() {
+            info("Got fullscreenchange for exiting");
+            runTests();
+            SimpleTest.finish();
+          });
           document.exitFullscreen();
         };
 
-        function fullscreenchange() {
-          if (document.fullscreenElement === div) {
+        function start() {
+          info("Requesting fullscreen on parent");
+          addFullscreenChangeContinuation("enter", function() {
             info("Got fullscreenchange for entering");
-            var screenX = window.screenX;
-            var screenY = window.screenY;
-            if (screenX != 0 || screenY != 0) {
-              todo(screenX == 0 && screenY == 0,
-                "We should only receive fullscreenchange once we've finished fullscreen transition");
-              setTimeout(fullscreenchange, 250);
-              return;
-            } 
-            info("Finish waiting for fullscreenchange");
             div.addEventListener("mousemove", moveMouse, false);
             synthesizeMouseAtCenter(div, {type: "mousemove"}, window);
-          }
-          else {
-            info("Got fullscreenchange for exiting");
-            runTests();
-            SimpleTest.finish();
-          }
-        }
-        
-        document.addEventListener("fullscreenchange", fullscreenchange, false);
-
-        function start() {
-          info("Requesting fullscreen on parent");
+          });
           div.requestFullscreen();
         }
       </script>
     </pre>
   </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_nestedFullScreen.html
+++ b/dom/tests/mochitest/pointerlock/file_nestedFullScreen.html
@@ -44,37 +44,33 @@
         isnot(pointerLocked, true, "Requesting fullscreen on " +
           "childDiv while parentDiv still in fullscreen should " +
           "unlock the pointer");
       }
 
       document.addEventListener("mozpointerlockchange", function (e) {
         if (document.mozPointerLockElement === parentDiv) {
           parentDivLocked = true;
+          addFullscreenChangeContinuation("enter", function() {
+            pointerLocked = !!document.mozPointerLockElement;
+            addFullscreenChangeContinuation("exit", function() {
+              addFullscreenChangeContinuation("exit", function() {
+                runTests();
+                SimpleTest.finish();
+              });
+              document.exitFullscreen();
+            });
+            document.exitFullscreen();
+          });
           childDiv.requestFullscreen();
         }
       }, false);
 
-      document.addEventListener("fullscreenchange", function() {
-        if (document.fullscreenElement === parentDiv) {
-          if (parentDivFullScreen === true) {
-            document.exitFullscreen();
-          } else {
-            parentDivFullScreen = true;
-            parentDiv.mozRequestPointerLock();
-          }
-        }
-        else if (document.fullscreenElement === childDiv) {
-          pointerLocked = !!document.mozPointerLockElement;
-          document.exitFullscreen();
-        }
-        else {
-          runTests();
-          SimpleTest.finish();
-        }
-      }, false);
-
       function start() {
+        addFullscreenChangeContinuation("enter", function() {
+          parentDivFullScreen = true;
+          parentDiv.mozRequestPointerLock();
+        });
         parentDiv.requestFullscreen();
       }
     </script>
   </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_pointerLockPref.html
+++ b/dom/tests/mochitest/pointerlock/file_pointerLockPref.html
@@ -47,32 +47,29 @@
             SpecialPowers.setBoolPref("full-screen-api.pointer-lock.enabled",
                                       false );
             div.mozRequestPointerLock();
           }
         }, false);
 
         document.addEventListener("mozpointerlockerror", function (e) {
           prefDisabled = true;
-          document.exitFullscreen();
-        }, false);
-
-        document.addEventListener("fullscreenchange", function (e) {
-          if (document.fullscreenElement === div) {
-            SpecialPowers.setBoolPref("full-screen-api.pointer-lock.enabled",
-                                      true );
-            div.mozRequestPointerLock();
-          }
-          else {
+          addFullscreenChangeContinuation("exit", function() {
             SpecialPowers.setBoolPref("full-screen-api.pointer-lock.enabled",
                                        true );
             runTests();
             SimpleTest.finish();
-          }
+          });
+          document.exitFullscreen();
         }, false);
 
         function start() {
+          addFullscreenChangeContinuation("enter", function() {
+            SpecialPowers.setBoolPref("full-screen-api.pointer-lock.enabled",
+                                      true );
+            div.mozRequestPointerLock();
+          });
           div.requestFullscreen();
         }
       </script>
     </pre>
   </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_pointerlock-api.html
+++ b/dom/tests/mochitest/pointerlock/file_pointerlock-api.html
@@ -74,33 +74,31 @@
                           { type: "contextmenu", button: 2 },
                           window);
 
           document.addEventListener("mousemove", mouseMoveHandler, false);
           synthesizeMouseAtCenter(div, {type: "mousemove"}, window);
         } else {
           info("Got mozpointerlockchange for exiting");
           pointerUnlocked = true;
+          addFullscreenChangeContinuation("exit", function() {
+            info("Got fullscreenchange for exiting");
+            runTests();
+            SimpleTest.finish();
+          });
           document.exitFullscreen();
         }
       }, false);
 
-      document.addEventListener("fullscreenchange", function(e) {
-        if (document.fullscreenElement === div) {
-          info("Got fullscreenchange for entering");
-          hasRequestPointerLock = "mozRequestPointerLock" in div;
-          div.mozRequestPointerLock();
-        } else {
-          info("Got fullscreenchange for exiting");
-          runTests();
-          SimpleTest.finish();
-        }
-      }, false);
-
       function start() {
         div = document.getElementById("div");
         info("Requesting fullscreen on parent");
+        addFullscreenChangeContinuation("enter", function() {
+          info("Got fullscreenchange for entering");
+          hasRequestPointerLock = "mozRequestPointerLock" in div;
+          div.mozRequestPointerLock();
+        });
         div.requestFullscreen();
       }
     </script>
   </pre>
 </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_removedFromDOM.html
+++ b/dom/tests/mochitest/pointerlock/file_removedFromDOM.html
@@ -46,17 +46,17 @@ function checkPointerLockElement(elem) {
     is(document.mozPointerLockElement, elem,
        `#${elem.id} should have locked the pointer`);
   } else {
     ok(!document.mozPointerLockElement, "Pointer should have been unlocked");
   }
 }
 
 function start() {
-  listenOneDocEvent("fullscreenchange", enteredFullscreen);
+  addFullscreenChangeContinuation("enter", enteredFullscreen);
   document.documentElement.requestFullscreen();
 }
 
 function enteredFullscreen() {
   is(document.fullscreenElement, document.documentElement,
      "Root element should have entered fullscreen");
   listenOneDocEvent("mozpointerlockchange", lockedPointerOnDiv);
   div.mozRequestPointerLock();
@@ -77,17 +77,17 @@ function unlockedPointerFromDiv() {
 function lockedPointerOnInner() {
   checkPointerLockElement(inner);
   listenOneDocEvent("mozpointerlockchange", unlockedPointerFromInner);
   document.body.removeChild(outer);
 }
 
 function unlockedPointerFromInner() {
   checkPointerLockElement(null);
-  listenOneDocEvent("fullscreenchange", exitedFullscreen);
+  addFullscreenChangeContinuation("exit", exitedFullscreen);
   document.exitFullscreen();
 }
 
 function exitedFullscreen() {
   SimpleTest.finish();
 }
 </script>
 </pre>
--- a/dom/tests/mochitest/pointerlock/file_retargetMouseEvents.html
+++ b/dom/tests/mochitest/pointerlock/file_retargetMouseEvents.html
@@ -166,16 +166,21 @@ https://bugzilla.mozilla.org/show_bug.cg
 
       var parentMoveTest = function (e) {
         info("Got parent mousemove");
         parentStats.mouseMove = true;
         parent.removeEventListener("mousemove", parentMoveTest);
         child.removeEventListener("mousemove", childMoveTest);
         SimpleTest.executeSoon(function () {
           info("Exit fullscreen");
+          addFullscreenChangeContinuation("exit", function() {
+            info("Got fullscreenchange for exiting");
+            runTests();
+            SimpleTest.finish();
+          });
           document.exitFullscreen();
         });
       }
 
       document.addEventListener("mozpointerlockchange", function (e) {
         if (document.mozPointerLockElement === parent) {
           info("Got mozpointerlockchange for entering");
           parent.addEventListener("mousemove", startMouseTests);
@@ -183,27 +188,20 @@ https://bugzilla.mozilla.org/show_bug.cg
           SimpleTest.executeSoon(function () {
             synthesizeMouseAtCenter(parent, {type: "mousemove"}, window);
           });
         } else {
           info("Got mozpointerlockchange for exiting");
         }
       }, false);
 
-      document.addEventListener("fullscreenchange", function (e)  {
-        if (document.fullscreenElement === parent) {
+      function start() {
+        info("Requesting fullscreen on parent");
+        addFullscreenChangeContinuation("enter", function() {
           info("Got fullscreenchange for entering");
           parent.mozRequestPointerLock();
-        } else {
-          info("Got fullscreenchange for exiting");
-          runTests();
-          SimpleTest.finish();
-        }
-      }, false);
-
-      function start() {
-        info("Requesting fullscreen on parent");
+        });
         parent.requestFullscreen();
       }
     </script>
   </pre>
 </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_screenClientXYConst.html
+++ b/dom/tests/mochitest/pointerlock/file_screenClientXYConst.html
@@ -77,58 +77,45 @@ https://bugzilla.mozilla.org/show_bug.cg
         isLocked = !!document.mozPointerLockElement;
         lockedCoords = {
           screenX: e.screenX,
           screenY: e.screenY,
           clientX: e.clientX,
           clientY: e.clientY
         };
 
+        addFullscreenChangeContinuation("exit", function() {
+          info("Got fullscreenchange for exiting");
+          runTests();
+          SimpleTest.finish();
+        });
         document.exitFullscreen();
       }
 
       document.addEventListener("mozpointerlockchange", function (e) {
         if (document.mozPointerLockElement === div) {
           info("Got mozpointerlockchange for entering");
           div.removeEventListener("mousemove", moveUnlocked, false);
           div.addEventListener("mousemove", moveLocked, false);
           divRect = div.getBoundingClientRect();
           synthesizeNativeMouseMove(div, (divRect.width / 4) * 3,
                                     (divRect.height / 4) * 3);
         } else {
           info("Got mozpointerlockchange for exiting");
         }
       }, false);
 
-      function fullscreenchange() {
-        var screenX = window.screenX;
-        var screenY = window.screenY;
-        if (document.fullscreenElement === div) {
+      function start() {
+        div = document.getElementById("div");
+        info("Requesting fullscreen on parent");
+        addFullscreenChangeContinuation("enter", function() {
           info("Got fullscreenchange for entering");
-          if (screenX != 0 || screenY != 0) {
-            todo(screenX == 0 && screenY == 0,
-              "We should only receive fullscreenchange once we've finished fullscreen transition " +
-              "window.screenX=" + screenX + " window.screenY=" + screenY);
-            setTimeout(fullscreenchange, 250);
-            return;
-          }
-          info("Finish waiting for fullscreenchange");
           synthesizeNativeMouseMove(div, 0, 0, () => {
             div.addEventListener("mousemove", moveUnlocked, false);
             divRect = div.getBoundingClientRect();
             synthesizeNativeMouseMove(div, divRect.width / 2, divRect.height / 2);
           });
-        } else {
-          info("Got fullscreenchange for exiting");
-          runTests();
-          SimpleTest.finish();
-        }
-      }
-      document.addEventListener("fullscreenchange", fullscreenchange, false);
-
-      function start() {
-        div = document.getElementById("div");
-        info("Requesting fullscreen on parent");
+        });
         div.requestFullscreen();
       }
   </script>
 </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_suppressSomeMouseEvents.html
+++ b/dom/tests/mochitest/pointerlock/file_suppressSomeMouseEvents.html
@@ -132,30 +132,27 @@ https://bugzilla.mozilla.org/show_bug.cg
       }
 
       document.addEventListener("mozpointerlockchange", function (e) {
         if (document.mozPointerLockElement === parent) {
           addEventListeners();
           synthesizeMouseAtCenter(child, { type: "mousemove" }, window);
         }
         else {
+          addFullscreenChangeContinuation("exit", function() {
+            runTests();
+            SimpleTest.finish();
+          });
           document.exitFullscreen();
         }
       }, false);
 
-      document.addEventListener("fullscreenchange", function() {
-        if (document.fullscreenElement === parent) {
-          parent.mozRequestPointerLock();
-        }
-        else {
-          runTests();
-          SimpleTest.finish();
-        }
-      }, false);
-
       function start() {
         parent = document.getElementById("parent");
         child = document.getElementById("child");
+        addFullscreenChangeContinuation("enter", function() {
+          parent.mozRequestPointerLock();
+        });
         parent.requestFullscreen();
       }
   </script>
 </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/file_targetOutOfFocus.html
+++ b/dom/tests/mochitest/pointerlock/file_targetOutOfFocus.html
@@ -43,28 +43,26 @@
 
         input.addEventListener("focus", function() {
           div.mozRequestPointerLock();
         }, false);
 
         document.addEventListener("mozpointerlockchange", function (e) {
           if (document.mozPointerLockElement === div) {
             divPointerLock = true;
+            addFullscreenChangeContinuation("exit", function() {
+              runTests();
+              SimpleTest.finish();
+            });
             document.exitFullscreen();
           }
         }, false);
 
-        document.addEventListener("fullscreenchange", function() {
-          if (document.fullscreenElement === div) {
+        function start() {
+          addFullscreenChangeContinuation("enter", function() {
             input.focus();
-          } else {
-            runTests();
-            SimpleTest.finish();
-          }
-        }, false);
-
-        function start() {
+          });
           div.requestFullscreen();
         }
       </script>
     </pre>
   </body>
 </html>
--- a/dom/tests/mochitest/pointerlock/mochitest.ini
+++ b/dom/tests/mochitest/pointerlock/mochitest.ini
@@ -17,9 +17,9 @@ support-files =
   file_screenClientXYConst.html
   file_suppressSomeMouseEvents.html
   file_locksvgelement.html
   file_allowPointerLockSandboxFlag.html
   iframe_differentDOM.html
 
 [test_pointerlock-api.html]
 tags = fullscreen
-skip-if = buildapp == 'b2g' || toolkit == 'android' || os == 'linux' || os == 'win' # B2G - window.open focus issues using fullscreen. Linux/Win: Bug 931445
+skip-if = buildapp == 'b2g' || toolkit == 'android' || os == 'win' # B2G - window.open focus issues using fullscreen. Win: Bug 931445
--- a/dom/tests/mochitest/pointerlock/pointerlock_utils.js
+++ b/dom/tests/mochitest/pointerlock/pointerlock_utils.js
@@ -1,66 +1,120 @@
-const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
-const isOSXLion = navigator.userAgent.indexOf("Mac OS X 10.7") != -1;
+// Get test filename for page being run in popup so errors are more useful
+var testName = location.pathname.split('/').pop();
 
-// If we're running in a child window, shim things so it works the same
-// as if we were running stand-alone.
-if (window.opener) {
-  // Get test filename for page being run in popup so errors are more useful
-  var testName = location.pathname.split('/').pop();
-
-  // Wrap test functions and pass to parent window
-  window.ok = function(a, msg) {
-    opener.ok(a, testName + ": " + msg);
-  };
+// Wrap test functions and pass to parent window
+window.ok = function(a, msg) {
+  opener.ok(a, testName + ": " + msg);
+};
 
-  window.is = function(a, b, msg) {
-    opener.is(a, b, testName + ": " + msg);
-  };
-
-  window.isnot = function(a, b, msg) {
-    opener.isnot(a, b, testName + ": " + msg);
-  };
+window.is = function(a, b, msg) {
+  opener.is(a, b, testName + ": " + msg);
+};
 
-  window.todo = function(a, msg) {
-    opener.todo(a, testName + ": " + msg);
-  };
+window.isnot = function(a, b, msg) {
+  opener.isnot(a, b, testName + ": " + msg);
+};
 
-  window.todo_is = function(a, b, msg) {
-    opener.todo_is(a, b, testName + ": " + msg);
-  };
+window.todo = function(a, msg) {
+  opener.todo(a, testName + ": " + msg);
+};
 
-  window.todo_isnot = function(a, b, msg) {
-    opener.todo_isnot(a, b, testName + ": " + msg);
-  };
+window.todo_is = function(a, b, msg) {
+  opener.todo_is(a, b, testName + ": " + msg);
+};
 
-  window.info = function(msg) {
-    opener.info(testName + ": " + msg);
-  };
+window.todo_isnot = function(a, b, msg) {
+  opener.todo_isnot(a, b, testName + ": " + msg);
+};
 
-  // Override bits of SimpleTest so test files work stand-alone
-  var SimpleTest = SimpleTest || {};
-
-  SimpleTest.waitForExplicitFinish = function() {
-    dump("[POINTERLOCK] Starting " + testName+ "\n");
-  };
+window.info = function(msg) {
+  opener.info(testName + ": " + msg);
+};
 
-  SimpleTest.finish = function () {
-    dump("[POINTERLOCK] Finishing " + testName+ "\n");
-    opener.nextTest();
-  };
-} else {
-  // If we're not running in a child window, prefs need to get flipped here,
-  // otherwise it was already done in the test runner parent.
+// Override bits of SimpleTest so test files work stand-alone
+var SimpleTest = SimpleTest || {};
 
-  // Ensure the full-screen api is enabled, and will be disabled on test exit.
-  SpecialPowers.setBoolPref("full-screen-api.enabled", true);
+SimpleTest.waitForExplicitFinish = function() {
+  dump("[POINTERLOCK] Starting " + testName+ "\n");
+};
 
-  // Disable the requirement for trusted contexts only, so the tests are easier to write.
-  SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
-}
+SimpleTest.finish = function () {
+  dump("[POINTERLOCK] Finishing " + testName+ "\n");
+  opener.nextTest();
+};
 
 addLoadEvent(function() {
   if (typeof start !== 'undefined') {
     SimpleTest.waitForFocus(start);
   }
 });
 
+// Returns true if the window occupies the entire screen.
+// Note this only returns true once the transition from normal to
+// fullscreen mode is complete.
+function inFullscreenMode(win) {
+  return win.innerWidth == win.screen.width &&
+         win.innerHeight == win.screen.height;
+}
+
+// Returns true if the window is in normal mode, i.e. non fullscreen mode.
+// Note this only returns true once the transition from fullscreen back to
+// normal mode is complete.
+function inNormalMode(win) {
+  return win.innerWidth == win.normalSize.w &&
+         win.innerHeight == win.normalSize.h;
+}
+
+// Adds a listener that will be called once a fullscreen transition
+// is complete. When type==='enter', callback is called when we've
+// received a fullscreenchange event, and the fullscreen transition is
+// complete. When type==='exit', callback is called when we've
+// received a fullscreenchange event and the window dimensions match
+// the window dimensions when the window opened (so don't resize the
+// window while running your test!). inDoc is the document which
+// the listeners are added on, if absent, the listeners are added to
+// the current document.
+function addFullscreenChangeContinuation(type, callback, inDoc) {
+  var doc = inDoc || document;
+  var topWin = doc.defaultView.top;
+  // Remember the window size in non-fullscreen mode.
+  if (!topWin.normalSize) {
+    topWin.normalSize = {
+      w: window.innerWidth,
+      h: window.innerHeight
+    };
+  }
+  function checkCondition() {
+    if (type == "enter") {
+      return inFullscreenMode(topWin);
+    } else if (type == "exit") {
+      // If we just revert the state to a previous fullscreen state,
+      // the window won't back to the normal mode. Hence we check
+      // fullscreenElement first here. Note that we need to check
+      // the fullscreen element of the outmost document here instead
+      // of the current one.
+      return topWin.document.fullscreenElement || inNormalMode(topWin);
+    } else {
+      throw "'type' must be either 'enter', or 'exit'.";
+    }
+  }
+  function invokeCallback(event) {
+    // Use async call after a paint to workaround unfinished fullscreen
+    // change even when the window size has changed on Linux.
+    requestAnimationFrame(() => setTimeout(() => callback(event), 0), 0);
+  }
+  function onFullscreenChange(event) {
+    doc.removeEventListener("fullscreenchange", onFullscreenChange, false);
+    if (checkCondition()) {
+      invokeCallback(event);
+      return;
+    }
+    function onResize() {
+      if (checkCondition()) {
+        topWin.removeEventListener("resize", onResize, false);
+        invokeCallback(event);
+      }
+    }
+    topWin.addEventListener("resize", onResize, false);
+  }
+  doc.addEventListener("fullscreenchange", onFullscreenChange, false);
+}
--- a/embedding/browser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/nsDocShellTreeOwner.cpp
@@ -642,17 +642,17 @@ nsDocShellTreeOwner::GetSize(int32_t* aC
     return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER,
                                    nullptr, nullptr, aCX, aCY);
   }
   return NS_ERROR_NULL_POINTER;
 }
 
 NS_IMETHODIMP
 nsDocShellTreeOwner::SetPositionAndSize(int32_t aX, int32_t aY, int32_t aCX,
-                                        int32_t aCY, bool aRepaint)
+                                        int32_t aCY, uint32_t aFlags)
 {
   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   if (ownerWin) {
     return ownerWin->SetDimensions(
       nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER |
         nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
       aX, aY, aCX, aCY);
   }
--- a/embedding/browser/nsWebBrowser.cpp
+++ b/embedding/browser/nsWebBrowser.cpp
@@ -1145,17 +1145,17 @@ nsWebBrowser::InitWindow(nativeWindow aP
   NS_ENSURE_STATE(!mDocShell || mInitInfo);
 
   if (aParentWidget) {
     NS_ENSURE_SUCCESS(SetParentWidget(aParentWidget), NS_ERROR_FAILURE);
   } else
     NS_ENSURE_SUCCESS(SetParentNativeWindow(aParentNativeWindow),
                       NS_ERROR_FAILURE);
 
-  NS_ENSURE_SUCCESS(SetPositionAndSize(aX, aY, aCX, aCY, false),
+  NS_ENSURE_SUCCESS(SetPositionAndSize(aX, aY, aCX, aCY, 0),
                     NS_ERROR_FAILURE);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWebBrowser::Create()
 {
@@ -1320,66 +1320,68 @@ nsWebBrowser::SetPositionDesktopPix(int3
 NS_IMETHODIMP
 nsWebBrowser::SetPosition(int32_t aX, int32_t aY)
 {
   int32_t cx = 0;
   int32_t cy = 0;
 
   GetSize(&cx, &cy);
 
-  return SetPositionAndSize(aX, aY, cx, cy, false);
+  return SetPositionAndSize(aX, aY, cx, cy, 0);
 }
 
 NS_IMETHODIMP
 nsWebBrowser::GetPosition(int32_t* aX, int32_t* aY)
 {
   return GetPositionAndSize(aX, aY, nullptr, nullptr);
 }
 
 NS_IMETHODIMP
 nsWebBrowser::SetSize(int32_t aCX, int32_t aCY, bool aRepaint)
 {
   int32_t x = 0;
   int32_t y = 0;
 
   GetPosition(&x, &y);
 
-  return SetPositionAndSize(x, y, aCX, aCY, aRepaint);
+  return SetPositionAndSize(x, y, aCX, aCY,
+                            aRepaint ? nsIBaseWindow::eRepaint : 0);
 }
 
 NS_IMETHODIMP
 nsWebBrowser::GetSize(int32_t* aCX, int32_t* aCY)
 {
   return GetPositionAndSize(nullptr, nullptr, aCX, aCY);
 }
 
 NS_IMETHODIMP
 nsWebBrowser::SetPositionAndSize(int32_t aX, int32_t aY,
-                                 int32_t aCX, int32_t aCY, bool aRepaint)
+                                 int32_t aCX, int32_t aCY, uint32_t aFlags)
 {
   if (!mDocShell) {
     mInitInfo->x = aX;
     mInitInfo->y = aY;
     mInitInfo->cx = aCX;
     mInitInfo->cy = aCY;
   } else {
     int32_t doc_x = aX;
     int32_t doc_y = aY;
 
     // If there is an internal widget we need to make the docShell coordinates
     // relative to the internal widget rather than the calling app's parent.
     // We also need to resize our widget then.
     if (mInternalWidget) {
       doc_x = doc_y = 0;
-      NS_ENSURE_SUCCESS(mInternalWidget->Resize(aX, aY, aCX, aCY, aRepaint),
+      NS_ENSURE_SUCCESS(mInternalWidget->Resize(aX, aY, aCX, aCY,
+                                                !!(aFlags & nsIBaseWindow::eRepaint)),
                         NS_ERROR_FAILURE);
     }
     // Now reposition/ resize the doc
     NS_ENSURE_SUCCESS(
-      mDocShellAsWin->SetPositionAndSize(doc_x, doc_y, aCX, aCY, aRepaint),
+      mDocShellAsWin->SetPositionAndSize(doc_x, doc_y, aCX, aCY, aFlags),
       NS_ERROR_FAILURE);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWebBrowser::GetPositionAndSize(int32_t* aX, int32_t* aY,
--- a/gfx/layers/apz/test/mochitest/helper_drag_click.html
+++ b/gfx/layers/apz/test/mochitest/helper_drag_click.html
@@ -7,16 +7,18 @@
   <script type="application/javascript" src="apz_test_native_event_utils.js"></script>
   <script type="application/javascript" src="apz_test_utils.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
   <script type="application/javascript">
 
 function* test(testDriver) {
   document.addEventListener('click', clicked, false);
 
+  // Ensure the pointer is inside the window
+  yield synthesizeNativeMouseEvent(document.getElementById('b'), 5, 5, nativeMouseMoveEventMsg(), testDriver);
   // mouse down, move it around, and release it near where it went down. this
   // should generate a click at the release point
   yield synthesizeNativeMouseEvent(document.getElementById('b'), 5, 5, nativeMouseDownEventMsg(), testDriver);
   yield synthesizeNativeMouseEvent(document.getElementById('b'), 100, 100, nativeMouseMoveEventMsg(), testDriver);
   yield synthesizeNativeMouseEvent(document.getElementById('b'), 10, 10, nativeMouseMoveEventMsg(), testDriver);
   yield synthesizeNativeMouseEvent(document.getElementById('b'), 8, 8, nativeMouseUpEventMsg(), testDriver);
   dump("Finished synthesizing click with a drag in the middle\n");
 }
--- a/gfx/layers/composite/ContainerLayerComposite.h
+++ b/gfx/layers/composite/ContainerLayerComposite.h
@@ -63,16 +63,17 @@ protected:
 public:
   // LayerComposite Implementation
   virtual Layer* GetLayer() override { return this; }
 
   virtual void SetLayerManager(LayerManagerComposite* aManager) override
   {
     LayerComposite::SetLayerManager(aManager);
     mManager = aManager;
+    mLastIntermediateSurface = nullptr;
 
     for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
       LayerComposite* child = l->AsLayerComposite();
       child->SetLayerManager(aManager);
     }
   }
 
   virtual void Destroy() override;
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -1000,16 +1000,18 @@ CompositorOGL::DrawQuad(const Rect& aRec
   MOZ_ASSERT(mFrameInProgress, "frame not started");
   MOZ_ASSERT(mCurrentRenderTarget, "No destination");
 
   if (aEffectChain.mPrimaryEffect->mType == EffectTypes::VR_DISTORTION) {
     DrawVRDistortion(aRect, aClipRect, aEffectChain, aOpacity, aTransform);
     return;
   }
 
+  MakeCurrent();
+
   IntPoint offset = mCurrentRenderTarget->GetOrigin();
   IntSize size = mCurrentRenderTarget->GetSize();
 
   Rect renderBound(0, 0, size.width, size.height);
   renderBound.IntersectRect(renderBound, Rect(aClipRect));
   renderBound.MoveBy(offset);
 
   Rect destRect = aTransform.TransformAndClipBounds(aRect, renderBound);
--- a/image/imgFrame.cpp
+++ b/image/imgFrame.cpp
@@ -181,18 +181,17 @@ imgFrame::InitForDecoder(const nsIntSize
   // warn for properties related to bad content.
   if (!AllowedImageAndFrameDimensions(aImageSize, aRect)) {
     NS_WARNING("Should have legal image size");
     mAborted = true;
     return NS_ERROR_FAILURE;
   }
 
   mImageSize = aImageSize;
-  mOffset.MoveTo(aRect.x, aRect.y);
-  mSize.SizeTo(aRect.width, aRect.height);
+  mFrameRect = aRect;
 
   mFormat = aFormat;
   mPaletteDepth = aPaletteDepth;
   mNonPremult = aNonPremult;
 
   if (aPaletteDepth != 0) {
     // We're creating for a paletted image.
     if (aPaletteDepth > 8) {
@@ -200,36 +199,35 @@ imgFrame::InitForDecoder(const nsIntSize
       NS_ERROR("This Depth is not supported");
       mAborted = true;
       return NS_ERROR_FAILURE;
     }
 
     // Use the fallible allocator here. Paletted images always use 1 byte per
     // pixel, so calculating the amount of memory we need is straightforward.
     mPalettedImageData =
-      static_cast<uint8_t*>(malloc(PaletteDataLength() +
-                                   (mSize.width * mSize.height)));
+      static_cast<uint8_t*>(malloc(PaletteDataLength() + mFrameRect.Area()));
     if (!mPalettedImageData) {
       NS_WARNING("malloc for paletted image data should succeed");
     }
     NS_ENSURE_TRUE(mPalettedImageData, NS_ERROR_OUT_OF_MEMORY);
   } else {
     MOZ_ASSERT(!mImageSurface, "Called imgFrame::InitForDecoder() twice?");
 
-    mVBuf = AllocateBufferForImage(mSize, mFormat);
+    mVBuf = AllocateBufferForImage(mFrameRect.Size(), mFormat);
     if (!mVBuf) {
       mAborted = true;
       return NS_ERROR_OUT_OF_MEMORY;
     }
     if (mVBuf->OnHeap()) {
-      int32_t stride = VolatileSurfaceStride(mSize, mFormat);
+      int32_t stride = VolatileSurfaceStride(mFrameRect.Size(), mFormat);
       VolatileBufferPtr<uint8_t> ptr(mVBuf);
-      memset(ptr, 0, stride * mSize.height);
+      memset(ptr, 0, stride * mFrameRect.height);
     }
-    mImageSurface = CreateLockedSurface(mVBuf, mSize, mFormat);
+    mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
 
     if (!mImageSurface) {
       NS_WARNING("Failed to create VolatileDataSourceSurface");
       mAborted = true;
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
@@ -247,73 +245,71 @@ imgFrame::InitWithDrawable(gfxDrawable* 
   // warn for properties related to bad content.
   if (!AllowedImageSize(aSize.width, aSize.height)) {
     NS_WARNING("Should have legal image size");
     mAborted = true;
     return NS_ERROR_FAILURE;
   }
 
   mImageSize = aSize;
-  mOffset.MoveTo(0, 0);
-  mSize.SizeTo(aSize.width, aSize.height);
+  mFrameRect = IntRect(IntPoint(0, 0), aSize);
 
   mFormat = aFormat;
   mPaletteDepth = 0;
 
   RefPtr<DrawTarget> target;
 
   bool canUseDataSurface =
     gfxPlatform::GetPlatform()->CanRenderContentToDataSurface();
 
   if (canUseDataSurface) {
     // It's safe to use data surfaces for content on this platform, so we can
     // get away with using volatile buffers.
     MOZ_ASSERT(!mImageSurface, "Called imgFrame::InitWithDrawable() twice?");
 
-    mVBuf = AllocateBufferForImage(mSize, mFormat);
+    mVBuf = AllocateBufferForImage(mFrameRect.Size(), mFormat);
     if (!mVBuf) {
       mAborted = true;
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    int32_t stride = VolatileSurfaceStride(mSize, mFormat);
+    int32_t stride = VolatileSurfaceStride(mFrameRect.Size(), mFormat);
     VolatileBufferPtr<uint8_t> ptr(mVBuf);
     if (!ptr) {
       mAborted = true;
       return NS_ERROR_OUT_OF_MEMORY;
     }
     if (mVBuf->OnHeap()) {
-      memset(ptr, 0, stride * mSize.height);
+      memset(ptr, 0, stride * mFrameRect.height);
     }
-    mImageSurface = CreateLockedSurface(mVBuf, mSize, mFormat);
+    mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
 
     target = gfxPlatform::GetPlatform()->
-      CreateDrawTargetForData(ptr, mSize, stride, mFormat);
+      CreateDrawTargetForData(ptr, mFrameRect.Size(), stride, mFormat);
   } else {
     // We can't use data surfaces for content, so we'll create an offscreen
     // surface instead.  This means if someone later calls RawAccessRef(), we
     // may have to do an expensive readback, but we warned callers about that in
     // the documentation for this method.
     MOZ_ASSERT(!mOptSurface, "Called imgFrame::InitWithDrawable() twice?");
 
     target = gfxPlatform::GetPlatform()->
-      CreateOffscreenContentDrawTarget(mSize, mFormat);
+      CreateOffscreenContentDrawTarget(mFrameRect.Size(), mFormat);
   }
 
   if (!target || !target->IsValid()) {
     mAborted = true;
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   // Draw using the drawable the caller provided.
-  nsIntRect imageRect(0, 0, mSize.width, mSize.height);
   RefPtr<gfxContext> ctx = gfxContext::ForDrawTarget(target);
-  MOZ_ASSERT(ctx); // already checked the draw target above
-  gfxUtils::DrawPixelSnapped(ctx, aDrawable, mSize,
-                             ImageRegion::Create(ThebesRect(imageRect)),
+  MOZ_ASSERT(ctx);  // Already checked the draw target above.
+  gfxUtils::DrawPixelSnapped(ctx, aDrawable, mFrameRect.Size(),
+                             ImageRegion::Create(ThebesRect(mFrameRect)),
                              mFormat, aFilter, aImageFlags);
 
   if (canUseDataSurface && !mImageSurface) {
     NS_WARNING("Failed to create VolatileDataSourceSurface");
     mAborted = true;
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
@@ -360,20 +356,20 @@ imgFrame::Optimize()
   // Cairo doesn't support non-premult single-colors.
   if (mNonPremult) {
     return NS_OK;
   }
 
   /* Figure out if the entire image is a constant color */
 
   if (gfxPrefs::ImageSingleColorOptimizationEnabled() &&
-      mImageSurface->Stride() == mSize.width * 4) {
+      mImageSurface->Stride() == mFrameRect.width * 4) {
     uint32_t* imgData = (uint32_t*) ((uint8_t*) mVBufPtr);
     uint32_t firstPixel = * (uint32_t*) imgData;
-    uint32_t pixelCount = mSize.width * mSize.height + 1;
+    uint32_t pixelCount = mFrameRect.Area() + 1;
 
     while (--pixelCount && *imgData++ == firstPixel)
       ;
 
     if (pixelCount == 0) {
       // all pixels were the same
       if (mFormat == SurfaceFormat::B8G8R8A8 ||
           mFormat == SurfaceFormat::B8G8R8X8) {
@@ -402,45 +398,45 @@ imgFrame::Optimize()
 
 #ifdef ANDROID
   SurfaceFormat optFormat = gfxPlatform::GetPlatform()
     ->Optimal2DFormatForContent(gfxContentType::COLOR);
 
   if (mFormat != SurfaceFormat::B8G8R8A8 &&
       optFormat == SurfaceFormat::R5G6B5_UINT16) {
     RefPtr<VolatileBuffer> buf =
-      AllocateBufferForImage(mSize, optFormat);
+      AllocateBufferForImage(mFrameRect.Size(), optFormat);
     if (!buf) {
       return NS_OK;
     }
 
     RefPtr<DataSourceSurface> surf =
-      CreateLockedSurface(buf, mSize, optFormat);
+      CreateLockedSurface(buf, mFrameRect.Size(), optFormat);
     if (!surf) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     DataSourceSurface::MappedSurface mapping;
     if (!surf->Map(DataSourceSurface::MapType::WRITE, &mapping)) {
       gfxCriticalError() << "imgFrame::Optimize failed to map surface";
       return NS_ERROR_FAILURE;
     }
 
     RefPtr<DrawTarget> target =
       Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                        mapping.mData,
-                                       mSize,
+                                       mFrameRect.Size(),
                                        mapping.mStride,
                                        optFormat);
 
     if (!target) {
       gfxWarning() << "imgFrame::Optimize failed in CreateDrawTargetForData";
       return NS_ERROR_OUT_OF_MEMORY;
     }
-    Rect rect(0, 0, mSize.width, mSize.height);
+    Rect rect(0, 0, mFrameRect.width, mFrameRect.height);
     target->DrawSurface(mImageSurface, rect, rect);
     target->Flush();
     surf->Unmap();
 
     mImageSurface = surf;
     mVBuf = buf;
     mFormat = optFormat;
   }
@@ -541,17 +537,17 @@ imgFrame::SurfaceForDrawing(bool        
                              target->GetFormat());
   }
 
   // Not tiling, and we have a surface, so we can account for
   // padding and/or a partial decode just by twiddling parameters.
   gfxPoint paddingTopLeft(aPadding.left, aPadding.top);
   aRegion = aRegion.Intersect(available) - paddingTopLeft;
   aContext->Multiply(gfxMatrix::Translation(paddingTopLeft));
-  aImageRect = gfxRect(0, 0, mSize.width, mSize.height);
+  aImageRect = gfxRect(0, 0, mFrameRect.width, mFrameRect.height);
 
   IntSize availableSize(mDecoded.width, mDecoded.height);
   return SurfaceWithFormat(new gfxSurfaceDrawable(aSurface, availableSize),
                            mFormat);
 }
 
 bool imgFrame::Draw(gfxContext* aContext, const ImageRegion& aRegion,
                     Filter aFilter, uint32_t aImageFlags)
@@ -563,20 +559,20 @@ bool imgFrame::Draw(gfxContext* aContext
   NS_ASSERTION(!aRegion.Rect().IsEmpty(), "Drawing empty region!");
   NS_ASSERTION(!aRegion.IsRestricted() ||
                !aRegion.Rect().Intersect(aRegion.Restriction()).IsEmpty(),
                "We must be allowed to sample *some* source pixels!");
   NS_ASSERTION(!mPalettedImageData, "Directly drawing a paletted image!");
 
   MonitorAutoLock lock(mMonitor);
 
-  nsIntMargin padding(mOffset.y,
-                      mImageSize.width - (mOffset.x + mSize.width),
-                      mImageSize.height - (mOffset.y + mSize.height),
-                      mOffset.x);
+  nsIntMargin padding(mFrameRect.y,
+                      mImageSize.width - mFrameRect.XMost(),
+                      mImageSize.height - mFrameRect.YMost(),
+                      mFrameRect.x);
 
   bool doPadding = padding != nsIntMargin(0,0,0,0);
   bool doPartialDecode = !AreAllPixelsWritten();
 
   if (mSinglePixel && !doPadding && !doPartialDecode) {
     if (mSinglePixelColor.a == 0.0) {
       return true;
     }
@@ -625,20 +621,19 @@ imgFrame::ImageUpdated(const nsIntRect& 
 
 nsresult
 imgFrame::ImageUpdatedInternal(const nsIntRect& aUpdateRect)
 {
   mMonitor.AssertCurrentThreadOwns();
 
   mDecoded.UnionRect(mDecoded, aUpdateRect);
 
-  // clamp to bounds, in case someone sends a bogus updateRect (I'm looking at
-  // you, gif decoder)
-  nsIntRect boundsRect(mOffset, mSize);
-  mDecoded.IntersectRect(mDecoded, boundsRect);
+  // Clamp to the frame rect to ensure that decoder bugs don't result in a
+  // decoded rect that extends outside the bounds of the frame rect.
+  mDecoded.IntersectRect(mDecoded, mFrameRect);
 
   return NS_OK;
 }
 
 void
 imgFrame::Finish(Opacity aFrameOpacity /* = Opacity::SOME_TRANSPARENCY */,
                  DisposalMethod aDisposalMethod /* = DisposalMethod::KEEP */,
                  int32_t aRawTimeout /* = 0 */,
@@ -656,61 +651,36 @@ imgFrame::Finish(Opacity aFrameOpacity /
   mBlendMethod = aBlendMethod;
   ImageUpdatedInternal(GetRect());
   mFinished = true;
 
   // The image is now complete, wake up anyone who's waiting.
   mMonitor.NotifyAll();
 }
 
-nsIntRect
-imgFrame::GetRect() const
-{
-  return gfx::IntRect(mOffset, mSize);
-}
-
-int32_t
-imgFrame::GetStride() const
-{
-  mMonitor.AssertCurrentThreadOwns();
-
-  if (mImageSurface) {
-    return mImageSurface->Stride();
-  }
-
-  return VolatileSurfaceStride(mSize, mFormat);
-}
-
-SurfaceFormat
-imgFrame::GetFormat() const
-{
-  MonitorAutoLock lock(mMonitor);
-  return mFormat;
-}
-
 uint32_t
 imgFrame::GetImageBytesPerRow() const
 {
   mMonitor.AssertCurrentThreadOwns();
 
   if (mVBuf) {
-    return mSize.width * BytesPerPixel(mFormat);
+    return mFrameRect.width * BytesPerPixel(mFormat);
   }
 
   if (mPaletteDepth) {
-    return mSize.width;
+    return mFrameRect.width;
   }
 
   return 0;
 }
 
 uint32_t
 imgFrame::GetImageDataLength() const
 {
-  return GetImageBytesPerRow() * mSize.height;
+  return GetImageBytesPerRow() * mFrameRect.height;
 }
 
 void
 imgFrame::GetImageData(uint8_t** aData, uint32_t* aLength) const
 {
   MonitorAutoLock lock(mMonitor);
   GetImageDataInternal(aData, aLength);
 }
@@ -856,17 +826,17 @@ imgFrame::UnlockImageData()
       return NS_OK;
     }
 
     // If we're using a surface format with alpha but the image has no alpha,
     // change the format. This doesn't change the underlying data at all, but
     // allows DrawTargets to avoid blending when drawing known opaque images.
     if (mHasNoAlpha && mFormat == SurfaceFormat::B8G8R8A8 && mImageSurface) {
       mFormat = SurfaceFormat::B8G8R8X8;
-      mImageSurface = CreateLockedSurface(mVBuf, mSize, mFormat);
+      mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
     }
 
     // Convert the data surface to a GPU surface or a single color if possible.
     // This will also release mImageSurface if possible.
     Optimize();
 
     // Allow the OS to release our data surface.
     mVBufPtr = nullptr;
@@ -929,34 +899,17 @@ imgFrame::GetSurfaceInternal()
     return nullptr;
   }
 
   VolatileBufferPtr<char> buf(mVBuf);
   if (buf.WasBufferPurged()) {
     return nullptr;
   }
 
-  return CreateLockedSurface(mVBuf, mSize, mFormat);
-}
-
-already_AddRefed<DrawTarget>
-imgFrame::GetDrawTarget()
-{
-  MonitorAutoLock lock(mMonitor);
-
-  uint8_t* data;
-  uint32_t length;
-  GetImageDataInternal(&data, &length);
-  if (!data) {
-    return nullptr;
-  }
-
-  int32_t stride = GetStride();
-  return gfxPlatform::GetPlatform()->
-    CreateDrawTargetForData(data, mSize, stride, mFormat);
+  return CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
 }
 
 AnimationData
 imgFrame::GetAnimationData() const
 {
   MonitorAutoLock lock(mMonitor);
   MOZ_ASSERT(mLockCount > 0, "Image data should be locked");
 
@@ -969,30 +922,16 @@ imgFrame::GetAnimationData() const
   }
 
   bool hasAlpha = mFormat == SurfaceFormat::B8G8R8A8;
 
   return AnimationData(data, PaletteDataLength(), mTimeout, GetRect(),
                        mBlendMethod, mDisposalMethod, hasAlpha);
 }
 
-ScalingData
-imgFrame::GetScalingData() const
-{
-  MonitorAutoLock lock(mMonitor);
-  MOZ_ASSERT(mLockCount > 0, "Image data should be locked");
-  MOZ_ASSERT(!GetIsPaletted(), "GetScalingData can't handle paletted images");
-
-  uint8_t* data;
-  uint32_t length;
-  GetImageDataInternal(&data, &length);
-
-  return ScalingData(data, mSize, GetImageBytesPerRow(), mFormat);
-}
-
 void
 imgFrame::Abort()
 {
   MonitorAutoLock lock(mMonitor);
 
   mAborted = true;
 
   // Wake up anyone who's waiting.
@@ -1028,18 +967,17 @@ imgFrame::WaitUntilFinished() const
     mMonitor.Wait();
   }
 }
 
 bool
 imgFrame::AreAllPixelsWritten() const
 {
   mMonitor.AssertCurrentThreadOwns();
-  return mDecoded.IsEqualInterior(nsIntRect(mOffset.x, mOffset.y,
-                                            mSize.width, mSize.height));
+  return mDecoded.IsEqualInterior(mFrameRect);
 }
 
 bool imgFrame::GetCompositingFailed() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mCompositingFailed;
 }
 
--- a/image/imgFrame.h
+++ b/image/imgFrame.h
@@ -72,48 +72,24 @@ struct AnimationData
   uint32_t mPaletteDataLength;
   int32_t mRawTimeout;
   nsIntRect mRect;
   BlendMethod mBlendMethod;
   DisposalMethod mDisposalMethod;
   bool mHasAlpha;
 };
 
-/**
- * ScalingData contains all of the information necessary for performing
- * high-quality (CPU-based) scaling an imgFrame.
- *
- * It includes pointers to the raw image data of the underlying imgFrame, but
- * does not own that data. A RawAccessFrameRef for the underlying imgFrame must
- * outlive the ScalingData for it to remain valid.
- */
-struct ScalingData
-{
-  ScalingData(uint8_t* aRawData,
-              gfx::IntSize aSize,
-              uint32_t aBytesPerRow,
-              gfx::SurfaceFormat aFormat)
-    : mRawData(aRawData)
-    , mSize(aSize)
-    , mBytesPerRow(aBytesPerRow)
-    , mFormat(aFormat)
-  { }
-
-  uint8_t* mRawData;
-  gfx::IntSize mSize;
-  uint32_t mBytesPerRow;
-  gfx::SurfaceFormat mFormat;
-};
-
 class imgFrame
 {
   typedef gfx::Color Color;
   typedef gfx::DataSourceSurface DataSourceSurface;
   typedef gfx::DrawTarget DrawTarget;
   typedef gfx::Filter Filter;
+  typedef gfx::IntPoint IntPoint;
+  typedef gfx::IntRect IntRect;
   typedef gfx::IntSize IntSize;
   typedef gfx::SourceSurface SourceSurface;
   typedef gfx::SurfaceFormat SurfaceFormat;
 
 public:
   MOZ_DECLARE_REFCOUNTED_TYPENAME(imgFrame)
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgFrame)
 
@@ -233,47 +209,38 @@ public:
    * Returns the number of bytes per pixel this imgFrame requires.  This is a
    * worst-case value that does not take into account the effects of format
    * changes caused by Optimize(), since an imgFrame is not optimized throughout
    * its lifetime.
    */
   uint32_t GetBytesPerPixel() const { return GetIsPaletted() ? 1 : 4; }
 
   IntSize GetImageSize() const { return mImageSize; }
-  nsIntRect GetRect() const;
-  IntSize GetSize() const { return mSize; }
-  bool NeedsPadding() const { return mOffset != nsIntPoint(0, 0); }
+  IntRect GetRect() const { return mFrameRect; }
+  IntSize GetSize() const { return mFrameRect.Size(); }
+  bool NeedsPadding() const { return mFrameRect.TopLeft() != IntPoint(0, 0); }
   void GetImageData(uint8_t** aData, uint32_t* length) const;
   uint8_t* GetImageData() const;
 
   bool GetIsPaletted() const;
   void GetPaletteData(uint32_t** aPalette, uint32_t* length) const;
   uint32_t* GetPaletteData() const;
   uint8_t GetPaletteDepth() const { return mPaletteDepth; }
 
-  /**
-   * Get the SurfaceFormat for this imgFrame.
-   *
-   * This should only be used for assertions.
-   */
-  SurfaceFormat GetFormat() const;
-
   AnimationData GetAnimationData() const;
-  ScalingData GetScalingData() const;
 
   bool GetCompositingFailed() const;
   void SetCompositingFailed(bool val);
 
   void SetOptimizable();
 
   Color SinglePixelColor() const;
   bool IsSinglePixel() const;
 
   already_AddRefed<SourceSurface> GetSurface();
-  already_AddRefed<DrawTarget> GetDrawTarget();
 
   void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut,
                               size_t& aNonHeapSizeOut) const;
 
 private: // methods
 
   ~imgFrame();
 
@@ -283,17 +250,16 @@ private: // methods
 
   void AssertImageDataLocked() const;
 
   bool AreAllPixelsWritten() const;
   nsresult ImageUpdatedInternal(const nsIntRect& aUpdateRect);
   void GetImageDataInternal(uint8_t** aData, uint32_t* length) const;
   uint32_t GetImageBytesPerRow() const;
   uint32_t GetImageDataLength() const;
-  int32_t GetStride() const;
   already_AddRefed<SourceSurface> GetSurfaceInternal();
 
   uint32_t PaletteDataLength() const
   {
     return mPaletteDepth ? (size_t(1) << mPaletteDepth) * sizeof(uint32_t)
                          : 0;
   }
 
@@ -351,18 +317,17 @@ private: // data
   bool mOptimizable;
 
 
   //////////////////////////////////////////////////////////////////////////////
   // Effectively const data, only mutated in the Init methods.
   //////////////////////////////////////////////////////////////////////////////
 
   IntSize      mImageSize;
-  IntSize      mSize;
-  nsIntPoint   mOffset;
+  IntRect      mFrameRect;
 
   // The palette and image data for images that are paletted, since Cairo
   // doesn't support these images.
   // The paletted data comes first, then the image data itself.
   // Total length is PaletteDataLength() + GetImageDataLength().
   uint8_t*     mPalettedImageData;
   uint8_t      mPaletteDepth;
 
@@ -441,20 +406,20 @@ private:
 
   RefPtr<imgFrame> mFrame;
   VolatileBufferPtr<uint8_t> mRef;
 };
 
 /**
  * A reference to an imgFrame that holds the imgFrame's surface in memory in a
  * format appropriate for access as raw data. If you have a RawAccessFrameRef
- * |ref| and |if (ref)| is true, then calls to GetImageData(), GetPaletteData(),
- * and GetDrawTarget() are guaranteed to succeed. This guarantee is stronger
- * than DrawableFrameRef, so everything that a valid DrawableFrameRef guarantees
- * is also guaranteed by a valid RawAccessFrameRef.
+ * |ref| and |if (ref)| is true, then calls to GetImageData() and
+ * GetPaletteData() are guaranteed to succeed. This guarantee is stronger than
+ * DrawableFrameRef, so everything that a valid DrawableFrameRef guarantees is
+ * also guaranteed by a valid RawAccessFrameRef.
  *
  * This may be considerably more expensive than is necessary just for drawing,
  * so only use this when you need to read or write the raw underlying image data
  * that the imgFrame holds.
  *
  * Once all an imgFrame's RawAccessFrameRefs go out of scope, new
  * RawAccessFrameRefs cannot be created.
  */
--- a/js/src/asmjs/WasmAST.h
+++ b/js/src/asmjs/WasmAST.h
@@ -42,16 +42,21 @@ using AstVector = mozilla::Vector<T, 0, 
 template <class K, class V, class HP>
 using AstHashMap = HashMap<K, V, HP, LifoAllocPolicy<Fallible>>;
 
 class AstName
 {
     const char16_t* begin_;
     const char16_t* end_;
   public:
+    template <size_t Length>
+    explicit AstName(const char16_t (&str)[Length]) : begin_(str), end_(str + Length - 1) {
+      MOZ_ASSERT(str[Length - 1] == MOZ_UTF16('\0'));
+    }
+
     AstName(const char16_t* begin, size_t length) : begin_(begin), end_(begin + length) {}
     AstName() : begin_(nullptr), end_(nullptr) {}
     const char16_t* begin() const { return begin_; }
     const char16_t* end() const { return end_; }
     size_t length() const { return end_ - begin_; }
     bool empty() const { return begin_ == nullptr; }
 
     bool operator==(AstName rhs) const {
--- a/js/src/asmjs/WasmBinaryToAST.cpp
+++ b/js/src/asmjs/WasmBinaryToAST.cpp
@@ -135,16 +135,18 @@ static bool
 AstDecodeGenerateName(AstDecodeContext& c, const AstName& prefix, uint32_t index, AstName* name)
 {
     if (!c.generateNames) {
         *name = AstName();
         return true;
     }
 
     AstVector<char16_t> result(c.lifo);
+    if (!result.append(MOZ_UTF16('$')))
+        return false;
     if (!result.append(prefix.begin(), prefix.length()))
         return false;
 
     uint32_t tmp = index;
     do {
         if (!result.append(MOZ_UTF16('0')))
             return false;
         tmp /= 10;
@@ -227,17 +229,17 @@ AstDecodeCall(AstDecodeContext& c)
 
     if (calleeIndex >= c.funcSigs().length())
         return c.iter().fail("callee index out of range");
 
     uint32_t sigIndex = c.funcSigs()[calleeIndex];
     const AstSig* sig = c.module().sigs()[sigIndex];
 
     AstRef funcRef;
-    if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("$func$"), 6), calleeIndex, &funcRef))
+    if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("func")), calleeIndex, &funcRef))
         return false;
 
     AstExprVector args(c.lifo);
     if (!AstDecodeCallArgs(c, arity, *sig, &args))
         return false;
 
     if (!AstDecodeCallReturn(c, *sig))
         return false;
@@ -255,17 +257,17 @@ static bool
 AstDecodeCallIndirect(AstDecodeContext& c)
 {
     uint32_t sigIndex;
     uint32_t arity;
     if (!c.iter().readCallIndirect(&sigIndex, &arity))
         return false;
 
     AstRef sigRef;
-    if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("$type$"), 6), sigIndex, &sigRef))
+    if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("type")), sigIndex, &sigRef))
         return false;
 
     if (sigIndex >= c.module().sigs().length())
         return c.iter().fail("signature index out of range");
 
     const AstSig* sig = c.module().sigs()[sigIndex];
     AstExprVector args(c.lifo);
     if (!AstDecodeCallArgs(c, arity, *sig, &args))
@@ -297,17 +299,17 @@ AstDecodeCallImport(AstDecodeContext& c)
         return false;
 
     if (importIndex >= c.module().imports().length())
         return c.iter().fail("import index out of range");
 
     AstImport* import = c.module().imports()[importIndex];
     AstSig* sig = c.module().sigs()[import->sig().index()];
     AstRef funcRef;
-    if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("$import$"), 8), importIndex, &funcRef))
+    if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("import")), importIndex, &funcRef))
         return false;
 
     AstExprVector args(c.lifo);
     if (!AstDecodeCallArgs(c, arity, *sig, &args))
         return false;
 
     if (!AstDecodeCallReturn(c, *sig))
         return false;
@@ -327,17 +329,17 @@ AstDecodeGetBlockRef(AstDecodeContext& c
     if (!c.generateNames || depth >= c.blockLabels().length()) {
         // Also ignoring if it's a function body label.
         *ref = AstRef(AstName(), depth);
         return true;
     }
 
     uint32_t index = c.blockLabels().length() - depth - 1;
     if (c.blockLabels()[index].empty()) {
-        if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("$label$"), 7), c.nextLabelIndex(), &c.blockLabels()[index]))
+        if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("label")), c.nextLabelIndex(), &c.blockLabels()[index]))
             return false;
     }
     *ref = AstRef(c.blockLabels()[index], AstNoIndex);
     ref->setIndex(depth);
     return true;
 }
 
 static bool
@@ -656,17 +658,17 @@ AstDecodeBranch(AstDecodeContext& c, Exp
 static bool
 AstDecodeGetLocal(AstDecodeContext& c)
 {
     uint32_t getLocalId;
     if (!c.iter().readGetLocal(c.locals(), &getLocalId))
         return false;
 
     AstRef localRef;
-    if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("$var$"), 5), getLocalId, &localRef))
+    if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("var")), getLocalId, &localRef))
         return false;
 
     AstGetLocal* getLocal = new(c.lifo) AstGetLocal(localRef);
     if (!getLocal)
         return false;
 
     c.iter().setResult(AstDecodeStackItem(getLocal));
     return true;
@@ -676,17 +678,17 @@ static bool
 AstDecodeSetLocal(AstDecodeContext& c)
 {
     uint32_t setLocalId;
     AstDecodeStackItem setLocalValue;
     if (!c.iter().readSetLocal(c.locals(), &setLocalId, &setLocalValue))
         return false;
 
     AstRef localRef;
-    if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("$var$"), 5), setLocalId, &localRef))
+    if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("var")), setLocalId, &localRef))
         return false;
 
     AstSetLocal* setLocal = new(c.lifo) AstSetLocal(localRef, *setLocalValue.expr);
     if (!setLocal)
         return false;
 
     c.iter().setResult(AstDecodeStackItem(setLocal, 1));
     return true;
@@ -1047,17 +1049,17 @@ AstDecodeTypeSection(AstDecodeContext& c
             if (!c.d.readValType(&type))
                 return AstDecodeFail(c, "bad expression type");
 
             result = ToExprType(type);
         }
 
         AstSig sigNoName(Move(args), result);
         AstName sigName;
-        if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("$type$"), 6), sigIndex, &sigName))
+        if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("type")), sigIndex, &sigName))
             return false;
 
         AstSig* sig = new(c.lifo) AstSig(sigName, Move(sigNoName));
         if (!sig || !c.module().append(sig))
             return false;
     }
 
     if (!c.d.finishSection(sectionStart, sectionSize))
@@ -1168,32 +1170,32 @@ AstDecodeName(AstDecodeContext& c, AstNa
 static bool
 AstDecodeImport(AstDecodeContext& c, uint32_t importIndex, AstImport** import)
 {
     uint32_t sigIndex = AstNoIndex;
     if (!AstDecodeSignatureIndex(c, &sigIndex))
         return false;
 
     AstRef sigRef;
-    if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("$type$"), 6), sigIndex, &sigRef))
+    if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("type")), sigIndex, &sigRef))
         return false;
 
     AstName moduleName;
     if (!AstDecodeName(c, &moduleName))
         return AstDecodeFail(c, "expected import module name");
 
     if (moduleName.empty())
         return AstDecodeFail(c, "module name cannot be empty");
 
     AstName funcName;
     if (!AstDecodeName(c, &funcName))
         return AstDecodeFail(c, "expected import func name");
 
     AstName importName;
-    if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("$import$"), 8), importIndex, &importName))
+    if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("import")), importIndex, &importName))
         return false;
 
     *import = new(c.lifo) AstImport(importName, moduleName, funcName, sigRef);
     if (!*import)
         return false;
 
     return true;
 }
@@ -1260,17 +1262,17 @@ AstDecodeMemorySection(AstDecodeContext&
         return AstDecodeFail(c, "expected exported byte");
 
     c.initialSizePages.emplace(initialSizePages);
     if (initialSizePages != maxSizePages) {
       c.maxSizePages.emplace(maxSizePages);
     }
 
     if (exported) {
-        AstExport* export_ = new(c.lifo) AstExport(AstName(MOZ_UTF16("memory"), 6));
+        AstExport* export_ = new(c.lifo) AstExport(AstName(MOZ_UTF16("memory")));
         if (!export_ || !c.module().append(export_))
             return false;
     }
 
     if (!c.d.finishSection(sectionStart, sectionSize))
         return AstDecodeFail(c, "memory section byte size mismatch");
 
     return true;
@@ -1354,28 +1356,28 @@ AstDecodeFunctionBody(AstDecodeContext &
         return false;
 
     if (!DecodeLocalEntries(c.d, &locals))
         return AstDecodeFail(c, "failed decoding local entries");
 
     c.startFunction(&iter, &locals);
 
     AstName funcName;
-    if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("$func$"), 6), funcIndex, &funcName))
+    if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("func")), funcIndex, &funcName))
         return false;
 
     uint32_t numParams = sig->args().length();
     uint32_t numLocals = locals.length();
     for (uint32_t i = numParams; i < numLocals; i++) {
         if (!vars.append(locals[i]))
             return false;
     }
     for (uint32_t i = 0; i < numLocals; i++) {
         AstName varName;
-        if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("$var$"), 5), i, &varName))
+        if (!AstDecodeGenerateName(c, AstName(MOZ_UTF16("var")), i, &varName))
             return false;
         if (!localsNames.append(varName))
             return false;
     }
 
     if (!c.iter().readFunctionStart())
         return false;
 
@@ -1393,17 +1395,17 @@ AstDecodeFunctionBody(AstDecodeContext &
         return false;
 
     c.endFunction();
 
     if (c.d.currentPosition() != bodyEnd)
         return AstDecodeFail(c, "function body length mismatch");
 
     AstRef sigRef;
-    if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("$type$"), 6), sigIndex, &sigRef))
+    if (!AstDecodeGenerateRef(c, AstName(MOZ_UTF16("type")), sigIndex, &sigRef))
         return false;
 
     *func = new(c.lifo) AstFunc(funcName, sigRef, Move(vars), Move(localsNames), Move(body));
     if (!*func)
         return false;
 
     return true;
 }
--- a/js/src/jit-test/tests/wasm/totext2.js
+++ b/js/src/jit-test/tests/wasm/totext2.js
@@ -29,21 +29,21 @@ runTest(`
      )
      (i32.store16 (i32.const 8) (i32.const 128))
 
      (return (f64.const 0))
   )
   (export "test" 0)
   (memory 1 10)
 )`,
-"type $type$0 of function (i32) : (f64) " +
-"export $func$0 as \"test\" " +
-"function $func$0($var$0:i32) : (f64) {" +
-" var $var$1:f32 { $var$1 = 0.0f loop { br_if $var$0,$label$0 br $label$1 $label$0: }" +
-" if (1) { f64.min -1.0 0.0 } else { 0.5 + f64.load [0] } $label$1: }" +
+"type $type0 of function (i32) : (f64) " +
+"export $func0 as \"test\" " +
+"function $func0($var0:i32) : (f64) {" +
+" var $var1:f32 { $var1 = 0.0f loop { br_if $var0,$label0 br $label1 $label0: }" +
+" if (1) { f64.min -1.0 0.0 } else { 0.5 + f64.load [0] } $label1: }" +
 " i32.store16 [8],128 return 0.0 "+
 "} memory 1,10 {} ");
 
 // function calls
 runTest(`
 (module
   (type $type1 (func (param i32) (result i32)))
   (import $import1 "mod" "test" (param f32) (result f32))
@@ -54,19 +54,19 @@ runTest(`
     (call $func1
       (call_indirect $type1 (i32.const 1) (i32.const 2))
       (call_import $import1 (f32.const 1.0))
     )
   )
   (export "test" $test)
   (memory 1 65535)
 )`,
-"type $type$0 of function (i32) : (i32) " +
-"type $type$1 of function (f32) : (f32) " +
-"type $type$2 of function (i32,f32) : () " +
-"type $type$3 of function () : () " +
-"import \"test\" as $import$0 from \"mod\" typeof function (f32) : (f32) " +
-"table [$func$0,$func$1] export $func$2 as \"test\" " +
-"function $func$0($var$0:i32,$var$1:f32) : () { nop } " +
-"function $func$1($var$0:i32) : (i32) { $var$0 } " +
-"function $func$2() : () {" +
-" call $func$0 (call_indirect $type$0 [1] (2),call_import $import$0 (1.0f)) " +
+"type $type0 of function (i32) : (i32) " +
+"type $type1 of function (f32) : (f32) " +
+"type $type2 of function (i32,f32) : () " +
+"type $type3 of function () : () " +
+"import \"test\" as $import0 from \"mod\" typeof function (f32) : (f32) " +
+"table [$func0,$func1] export $func2 as \"test\" " +
+"function $func0($var0:i32,$var1:f32) : () { nop } " +
+"function $func1($var0:i32) : (i32) { $var0 } " +
+"function $func2() : () {" +
+" call $func0 (call_indirect $type0 [1] (2),call_import $import0 (1.0f)) " +
 "} memory 1,65535 {} ");
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6417,17 +6417,20 @@ DescribeScriptedCaller(JSContext* cx, Au
 {
     if (filename)
         filename->reset();
     if (lineno)
         *lineno = 0;
     if (column)
         *column = 0;
 
-    NonBuiltinFrameIter i(cx, FrameIter::STOP_AT_SAVED);
+    if (!cx->compartment())
+        return false;
+
+    NonBuiltinFrameIter i(cx, cx->compartment()->principals());
     if (i.done())
         return false;
 
     // If the caller is hidden, the embedding wants us to return false here so
     // that it can check its own stack (see HideScriptedCaller).
     if (i.activation()->scriptedCallerIsHidden())
         return false;
 
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -241,16 +241,18 @@ SavedFrame::HashPolicy::hash(const Looku
                      lookup.asyncCause,
                      SavedFramePtrHasher::hash(lookup.parent),
                      JSPrincipalsPtrHasher::hash(lookup.principals));
 }
 
 /* static */ bool
 SavedFrame::HashPolicy::match(SavedFrame* existing, const Lookup& lookup)
 {
+    MOZ_ASSERT(existing);
+
     if (existing->getLine() != lookup.line)
         return false;
 
     if (existing->getColumn() != lookup.column)
         return false;
 
     if (existing->getParent() != lookup.parent)
         return false;
--- a/js/xpconnect/idl/nsIXPConnect.idl
+++ b/js/xpconnect/idl/nsIXPConnect.idl
@@ -261,17 +261,17 @@ interface nsIXPCFunctionThisTranslator :
 %{ C++
 // For use with the service manager
 // {CB6593E0-F9B2-11d2-BDD6-000064657374}
 #define NS_XPCONNECT_CID \
 { 0xcb6593e0, 0xf9b2, 0x11d2, \
     { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
 %}
 
-[noscript, uuid(f339ea52-10ce-4103-b1f2-fd9659040e3c)]
+[noscript, uuid(768507b5-b981-40c7-8276-f6a1da502a24)]
 interface nsIXPConnect : nsISupports
 {
 %{ C++
   NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCONNECT_CID)
 %}
 
     /**
      * Creates a new global object using the given aCOMObj as the global
@@ -495,24 +495,16 @@ interface nsIXPConnect : nsISupports
      *         to this method.
      */
     [noscript] jsval evalInSandboxObject(in AString source, in string filename,
                                          in JSContextPtr cx,
                                          in JSObjectPtr sandbox,
                                          in int32_t version);
 
     /**
-     * Whether or not XPConnect should report all JS exceptions when returning
-     * from JS into C++. False by default, although any value set in the
-     * MOZ_REPORT_ALL_JS_EXCEPTIONS environment variable will override the value
-     * passed here.
-     */
-    void setReportAllJSExceptions(in boolean reportAllJSExceptions);
-
-    /**
      * Trigger a JS garbage collection.
      * Use a js::gcreason::Reason from jsfriendapi.h for the kind.
      */
     void GarbageCollect(in uint32_t reason);
 
     /**
      * Signals a good place to do an incremental GC slice, because the
      * browser is drawing a frame.
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -586,31 +586,31 @@ mozJSSubScriptLoader::DoLoadSubScriptWit
     RootedObject result_obj(cx, targetObj);
     targetObj = JS_FindCompilationScope(cx, targetObj);
     if (!targetObj)
         return NS_ERROR_FAILURE;
 
     if (targetObj != result_obj)
         principal = GetObjectPrincipal(targetObj);
 
-    JSAutoCompartment ac(cx, targetObj);
-
     /* load up the url.  From here on, failures are reflected as ``custom''
      * js exceptions */
     nsCOMPtr<nsIURI> uri;
     nsAutoCString uriStr;
     nsAutoCString scheme;
 
     // Figure out who's calling us
     JS::AutoFilename filename;
     if (!JS::DescribeScriptedCaller(cx, &filename)) {
         // No scripted frame means we don't know who's calling, bail.
         return NS_ERROR_FAILURE;
     }
 
+    JSAutoCompartment ac(cx, targetObj);
+
     // Suppress caching if we're compiling as content.
     StartupCache* cache = (principal == mSystemPrincipal)
                           ? StartupCache::GetSingleton()
                           : nullptr;
     nsCOMPtr<nsIIOService> serv = do_GetService(NS_IOSERVICE_CONTRACTID);
     if (!serv) {
         return ReportError(cx, LOAD_ERROR_NOSERVICE);
     }
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -769,18 +769,17 @@ nsXPCWrappedJSClass::CleanupOutparams(JS
         *static_cast<void**>(p) = nullptr;
     }
 }
 
 nsresult
 nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
                                        AutoEntryScript& aes,
                                        const char * aPropertyName,
-                                       const char * anInterfaceName,
-                                       bool aForceReport)
+                                       const char * anInterfaceName)
 {
     XPCContext * xpcc = ccx.GetXPCContext();
     JSContext * cx = ccx.GetJSContext();
     MOZ_ASSERT(cx == aes.cx());
     nsCOMPtr<nsIException> xpc_exception;
     /* this one would be set by our error reporter */
 
     xpcc->GetException(getter_AddRefs(xpc_exception));
@@ -813,38 +812,22 @@ nsXPCWrappedJSClass::CheckForException(X
     aes.ClearException();
 
     if (xpc_exception) {
         nsresult e_result;
         if (NS_SUCCEEDED(xpc_exception->GetResult(&e_result))) {
             // Figure out whether or not we should report this exception.
             bool reportable = xpc_IsReportableErrorCode(e_result);
             if (reportable) {
-                // Always want to report forced exceptions and XPConnect's own
-                // errors.
-                reportable = aForceReport ||
-                    NS_ERROR_GET_MODULE(e_result) == NS_ERROR_MODULE_XPCONNECT;
-
-                // See if an environment variable was set or someone has told us
-                // that a user pref was set indicating that we should report all
-                // exceptions.
-                if (!reportable)
-                    reportable = nsXPConnect::ReportAllJSExceptions();
-
-                // Finally, check to see if this is the last JS frame on the
-                // stack. If so then we always want to report it.
-                if (!reportable)
-                    reportable = !JS::DescribeScriptedCaller(cx);
-
                 // Ugly special case for GetInterface. It's "special" in the
                 // same way as QueryInterface in that a failure is not
                 // exceptional and shouldn't be reported. We have to do this
                 // check here instead of in xpcwrappedjs (like we do for QI) to
                 // avoid adding extra code to all xpcwrappedjs objects.
-                if (reportable && e_result == NS_ERROR_NO_INTERFACE &&
+                if (e_result == NS_ERROR_NO_INTERFACE &&
                     !strcmp(anInterfaceName, "nsIInterfaceRequestor") &&
                     !strcmp(aPropertyName, "getInterface")) {
                     reportable = false;
                 }
 
                 // More special case, see bug 877760.
                 if (e_result == NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED) {
                     reportable = false;
@@ -992,17 +975,17 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
     // [implicit_jscontext] and [optional_argc] have a different calling
     // convention, which we don't support for JS-implemented components.
     if (info->WantsOptArgc() || info->WantsContext()) {
         const char* str = "IDL methods marked with [implicit_jscontext] "
                           "or [optional_argc] may not be implemented in JS";
         // Throw and warn for good measure.
         JS_ReportError(cx, str);
         NS_WARNING(str);
-        return CheckForException(ccx, aes, name, GetInterfaceName(), false);
+        return CheckForException(ccx, aes, name, GetInterfaceName());
     }
 
     RootedValue fval(cx);
     RootedObject obj(cx, wrapper->GetJSObject());
     RootedObject thisObj(cx, obj);
 
     JSAutoCompartment ac(cx, obj);
 
@@ -1254,27 +1237,18 @@ pre_call_clean_up:
                                            nullptr, getter_AddRefs(e), nullptr, nullptr);
             xpcc->SetException(e);
             if (sz)
                 JS_smprintf_free(sz);
             success = false;
         }
     }
 
-    if (!success) {
-        bool forceReport;
-        if (NS_FAILED(mInfo->IsFunction(&forceReport)))
-            forceReport = false;
-
-        // May also want to check if we're moving from content->chrome and force
-        // a report in that case.
-
-        return CheckForException(ccx, aes, name, GetInterfaceName(),
-                                 forceReport);
-    }
+    if (!success)
+        return CheckForException(ccx, aes, name, GetInterfaceName());
 
     XPCJSRuntime::Get()->SetPendingException(nullptr); // XXX necessary?
 
     // convert out args and result
     // NOTE: this is the total number of native params, not just the args
     // Convert independent params only.
     // When we later convert the dependent params (if any) we will know that
     // the params upon which they depend will have already been converted -
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -38,17 +38,16 @@ using namespace mozilla;
 using namespace mozilla::dom;
 using namespace xpc;
 using namespace JS;
 
 NS_IMPL_ISUPPORTS(nsXPConnect, nsIXPConnect)
 
 nsXPConnect* nsXPConnect::gSelf = nullptr;
 bool         nsXPConnect::gOnceAliveNowDead = false;
-uint32_t     nsXPConnect::gReportAllJSExceptions = 0;
 
 // Global cache of the default script security manager (QI'd to
 // nsIScriptSecurityManager) and the system principal.
 nsIScriptSecurityManager* nsXPConnect::gScriptSecurityManager = nullptr;
 nsIPrincipal* nsXPConnect::gSystemPrincipal = nullptr;
 
 const char XPC_CONTEXT_STACK_CONTRACTID[] = "@mozilla.org/js/xpc/ContextStack;1";
 const char XPC_EXCEPTION_CONTRACTID[]     = "@mozilla.org/js/xpc/Exception;1";
@@ -62,20 +61,16 @@ const char XPC_XPCONNECT_CONTRACTID[]   
 nsXPConnect::nsXPConnect()
     :   mRuntime(nullptr),
         mShuttingDown(false)
 {
     mRuntime = XPCJSRuntime::newXPCJSRuntime();
     if (!mRuntime) {
         NS_RUNTIMEABORT("Couldn't create XPCJSRuntime.");
     }
-
-    char* reportableEnv = PR_GetEnv("MOZ_REPORT_ALL_JS_EXCEPTIONS");
-    if (reportableEnv && *reportableEnv)
-        gReportAllJSExceptions = 1;
 }
 
 nsXPConnect::~nsXPConnect()
 {
     mRuntime->DeleteSingletonScopes();
     mRuntime->DestroyJSContextStack();
 
     // In order to clean up everything properly, we need to GC twice: once now,
@@ -978,26 +973,16 @@ nsXPConnect::JSToVariant(JSContext* ctx,
     RefPtr<XPCVariant> variant = XPCVariant::newVariant(ctx, value);
     variant.forget(_retval);
     if (!(*_retval))
         return NS_ERROR_FAILURE;
 
     return NS_OK;
 }
 
-NS_IMETHODIMP
-nsXPConnect::SetReportAllJSExceptions(bool newval)
-{
-    // Ignore if the environment variable was set.
-    if (gReportAllJSExceptions != 1)
-        gReportAllJSExceptions = newval ? 2 : 0;
-
-    return NS_OK;
-}
-
 /* virtual */
 JSContext*
 nsXPConnect::GetCurrentJSContext()
 {
     return GetRuntime()->GetJSContextStack()->Peek();
 }
 
 /* virtual */
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -298,37 +298,29 @@ public:
     virtual nsIPrincipal* GetPrincipal(JSObject* obj,
                                        bool allowShortCircuit) const override;
 
     void RecordTraversal(void* p, nsISupports* s);
     virtual char* DebugPrintJSStack(bool showArgs,
                                     bool showLocals,
                                     bool showThisProps) override;
 
-
-    static bool ReportAllJSExceptions()
-    {
-      return gReportAllJSExceptions > 0;
-    }
-
 protected:
     virtual ~nsXPConnect();
 
     nsXPConnect();
 
 private:
     // Singleton instance
     static nsXPConnect*             gSelf;
     static bool                     gOnceAliveNowDead;
 
     XPCJSRuntime*                   mRuntime;
     bool                            mShuttingDown;
 
-    static uint32_t gReportAllJSExceptions;
-
 public:
     static nsIScriptSecurityManager* gScriptSecurityManager;
     static nsIPrincipal* gSystemPrincipal;
 };
 
 /***************************************************************************/
 
 class XPCRootSetElem
@@ -2295,18 +2287,17 @@ public:
                                               JSObject* aJSObj,
                                               const nsAString& aName,
                                               nsIVariant** aResult);
 
 private:
     static nsresult CheckForException(XPCCallContext & ccx,
                                       mozilla::dom::AutoEntryScript& aes,
                                       const char * aPropertyName,
-                                      const char * anInterfaceName,
-                                      bool aForceReport);
+                                      const char * anInterfaceName);
     virtual ~nsXPCWrappedJSClass();
 
     nsXPCWrappedJSClass();   // not implemented
     nsXPCWrappedJSClass(JSContext* cx, REFNSIID aIID,
                         nsIInterfaceInfo* aInfo);
 
     bool IsReflectable(uint16_t i) const
         {return (bool)(mDescriptors[i/32] & (1 << (i%32)));}
--- a/layout/base/MobileViewportManager.cpp
+++ b/layout/base/MobileViewportManager.cpp
@@ -369,17 +369,21 @@ MobileViewportManager::RefreshViewportSi
       displayWidthChangeRatio);
     MVM_LOG("%p: New zoom is %f\n", this, zoom.scale);
     UpdateSPCSPS(displaySize, zoom);
   }
   if (gfxPlatform::AsyncPanZoomEnabled()) {
     UpdateDisplayPortMargins();
   }
 
+  CSSSize oldSize = mMobileViewportSize;
+
   // Update internal state.
   mIsFirstPaint = false;
   mMobileViewportSize = viewport;
 
   // Kick off a reflow.
   mPresShell->ResizeReflowIgnoreOverride(
     nsPresContext::CSSPixelsToAppUnits(viewport.width),
-    nsPresContext::CSSPixelsToAppUnits(viewport.height));
+    nsPresContext::CSSPixelsToAppUnits(viewport.height),
+    nsPresContext::CSSPixelsToAppUnits(oldSize.width),
+    nsPresContext::CSSPixelsToAppUnits(oldSize.height));
 }
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -1900,32 +1900,33 @@ nsDocumentViewer::SetPreviousViewer(nsIC
     }
   }
 
   mPreviousViewer = aViewer;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocumentViewer::SetBounds(const nsIntRect& aBounds)
+nsDocumentViewer::SetBoundsWithFlags(const nsIntRect& aBounds, uint32_t aFlags)
 {
   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
 
   mBounds = aBounds;
 
   if (mWindow && !mAttachedToParent) {
     // Resize the widget, but don't trigger repaint. Layout will generate
     // repaint requests during reflow.
     mWindow->Resize(aBounds.x, aBounds.y,
                     aBounds.width, aBounds.height,
                     false);
   } else if (mPresContext && mViewManager) {
     int32_t p2a = mPresContext->AppUnitsPerDevPixel();
     mViewManager->SetWindowDimensions(NSIntPixelsToAppUnits(mBounds.width, p2a),
-                                      NSIntPixelsToAppUnits(mBounds.height, p2a));
+                                      NSIntPixelsToAppUnits(mBounds.height, p2a),
+                                      !!(aFlags & nsIContentViewer::eDelayResize));
   }
 
   // If there's a previous viewer, it's the one that's actually showing,
   // so be sure to resize it as well so it paints over the right area.
   // This may slow down the performance of the new page load, but resize
   // during load is also probably a relatively unusual condition
   // relating to things being hidden while something is loaded.  It so
   // happens that Firefox does this a good bit with its infobar, and it
@@ -1934,16 +1935,22 @@ nsDocumentViewer::SetBounds(const nsIntR
     nsCOMPtr<nsIContentViewer> previousViewer = mPreviousViewer;
     previousViewer->SetBounds(aBounds);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDocumentViewer::SetBounds(const nsIntRect& aBounds)
+{
+  return SetBoundsWithFlags(aBounds, 0);
+}
+
+NS_IMETHODIMP
 nsDocumentViewer::Move(int32_t aX, int32_t aY)
 {
   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
   mBounds.MoveTo(aX, aY);
   if (mWindow) {
     mWindow->Move(aX, aY);
   }
   return NS_OK;
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -413,22 +413,22 @@ public:
    * Calling Initialize can execute arbitrary script.
    */
   virtual nsresult Initialize(nscoord aWidth, nscoord aHeight) = 0;
 
   /**
    * Reflow the frame model into a new width and height.  The
    * coordinates for aWidth and aHeight must be in standard nscoord's.
    */
-  virtual nsresult ResizeReflow(nscoord aWidth, nscoord aHeight) = 0;
+  virtual nsresult ResizeReflow(nscoord aWidth, nscoord aHeight, nscoord aOldWidth = 0, nscoord aOldHeight = 0) = 0;
   /**
    * Do the same thing as ResizeReflow but even if ResizeReflowOverride was
    * called previously.
    */
-  virtual nsresult ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight) = 0;
+  virtual nsresult ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight) = 0;
 
   /**
    * Returns true if ResizeReflowOverride has been called.
    */
   virtual bool GetIsViewportOverridden() = 0;
 
   /**
    * Return true if the presshell expects layout flush.
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1796,65 +1796,64 @@ PresShell::sPaintSuppressionCallback(nsI
 
 void
 PresShell::AsyncResizeEventCallback(nsITimer* aTimer, void* aPresShell)
 {
   static_cast<PresShell*>(aPresShell)->FireResizeEvent();
 }
 
 nsresult
-PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight)
+PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight)
 {
   if (mZoomConstraintsClient) {
     // If we have a ZoomConstraintsClient and the available screen area
     // changed, then we might need to disable double-tap-to-zoom, so notify
     // the ZCC to update itself.
     mZoomConstraintsClient->ScreenSizeChanged();
   }
   if (mMobileViewportManager) {
     // If we have a mobile viewport manager, request a reflow from it. It can
     // recompute the final CSS viewport and trigger a call to
     // ResizeReflowIgnoreOverride if it changed.
     mMobileViewportManager->RequestReflow();
     return NS_OK;
   }
 
-  return ResizeReflowIgnoreOverride(aWidth, aHeight);
+  return ResizeReflowIgnoreOverride(aWidth, aHeight, aOldWidth, aOldHeight);
 }
 
 nsresult
-PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight)
+PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight)
 {
   NS_PRECONDITION(!mIsReflowing, "Shouldn't be in reflow here!");
 
   // If we don't have a root frame yet, that means we haven't had our initial
   // reflow... If that's the case, and aWidth or aHeight is unconstrained,
   // ignore them altogether.
   nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
   if (!rootFrame && aHeight == NS_UNCONSTRAINEDSIZE) {
     // We can't do the work needed for SizeToContent without a root
     // frame, and we want to return before setting the visible area.
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  nsSize oldVisibleSize = mPresContext->GetVisibleArea().Size();
   mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
 
   // There isn't anything useful we can do if the initial reflow hasn't happened.
   if (!rootFrame) {
     return NS_OK;
   }
 
   WritingMode wm = rootFrame->GetWritingMode();
   NS_PRECONDITION((wm.IsVertical() ? aHeight : aWidth) != NS_UNCONSTRAINEDSIZE,
                   "shouldn't use unconstrained isize anymore");
 
   const bool isBSizeChanging = wm.IsVertical()
-                               ? oldVisibleSize.width != aWidth
-                               : oldVisibleSize.height != aHeight;
+                               ? aOldWidth != aWidth
+                               : aOldHeight != aHeight;
 
   RefPtr<nsViewManager> viewManagerDeathGrip = mViewManager;
   // Take this ref after viewManager so it'll make sure to go away first.
   nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
 
   if (!GetPresContext()->SuppressingResizeReflow()) {
     // Have to make sure that the content notifications are flushed before we
     // start messing with the frame model; otherwise we can get content doubling.
@@ -3643,16 +3642,26 @@ PresShell::ScheduleViewManagerFlush(Pain
   if (presContext) {
     presContext->RefreshDriver()->ScheduleViewManagerFlush();
   }
   if (mDocument) {
     mDocument->SetNeedLayoutFlush();
   }
 }
 
+bool
+FlushLayoutRecursive(nsIDocument* aDocument,
+                     void* aData = nullptr)
+{
+  MOZ_ASSERT(!aData);
+  aDocument->EnumerateSubDocuments(FlushLayoutRecursive, nullptr);
+  aDocument->FlushPendingNotifications(Flush_Layout);
+  return true;
+}
+
 void
 PresShell::DispatchSynthMouseMove(WidgetGUIEvent* aEvent,
                                   bool aFlushOnHoverChange)
 {
   RestyleManagerHandle restyleManager = mPresContext->RestyleManager();
   if (restyleManager->IsServo()) {
     NS_ERROR("stylo: cannot dispatch synthetic mouse moves when using a "
              "ServoRestyleManager yet");
@@ -3667,17 +3676,20 @@ PresShell::DispatchSynthMouseMove(Widget
   targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status);
   if (MOZ_UNLIKELY(mIsDestroying)) {
     return;
   }
   if (aFlushOnHoverChange &&
       hoverGenerationBefore != restyleManager->AsGecko()->GetHoverGeneration()) {
     // Flush so that the resulting reflow happens now so that our caller
     // can suppress any synthesized mouse moves caused by that reflow.
-    FlushPendingNotifications(Flush_Layout);
+    // This code only ever runs for the root document, but :hover changes
+    // can happen in descendant documents too, so make sure we flush
+    // all of them.
+    FlushLayoutRecursive(mDocument);
   }
 }
 
 void
 PresShell::ClearMouseCaptureOnView(nsView* aView)
 {
   if (gCaptureInfo.mContent) {
     if (aView) {
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -113,18 +113,18 @@ public:
   NS_IMETHOD GetDisplaySelection(int16_t *aToggle) override;
   NS_IMETHOD ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion,
                                      int16_t aFlags) override;
   NS_IMETHOD RepaintSelection(SelectionType aType) override;
 
   virtual void BeginObservingDocument() override;
   virtual void EndObservingDocument() override;
   virtual nsresult Initialize(nscoord aWidth, nscoord aHeight) override;
-  virtual nsresult ResizeReflow(nscoord aWidth, nscoord aHeight) override;
-  virtual nsresult ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight) override;
+  virtual nsresult ResizeReflow(nscoord aWidth, nscoord aHeight, nscoord aOldWidth = 0, nscoord aOldHeight = 0) override;
+  virtual nsresult ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight, nscoord aOldWidth, nscoord aOldHeight) override;
   virtual nsIPageSequenceFrame* GetPageSequenceFrame() const override;
   virtual nsCanvasFrame* GetCanvasFrame() const override;
 
   virtual nsIFrame* GetPlaceholderFrameFor(nsIFrame* aFrame) const override;
   virtual void FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
                                 nsFrameState aBitToAdd,
                                 ReflowRootHandling aRootHandling =
                                   eInferFromBitToAdd) override;
--- a/layout/generic/nsBlockDebugFlags.h
+++ b/layout/generic/nsBlockDebugFlags.h
@@ -1,21 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsBlockDebugFlags_h__
 #define nsBlockDebugFlags_h__
 
-#undef NOISY_FIRST_LINE           // enables debug output for first-line specific layout
-#undef REALLY_NOISY_FIRST_LINE    // enables extra debug output for first-line specific layout
 #undef NOISY_FIRST_LETTER         // enables debug output for first-letter specific layout
-#undef NOISY_MAX_ELEMENT_SIZE     // enables debug output for max element size computation
-#undef NOISY_MAXIMUM_WIDTH        // enables debug output for max width computation
 #undef NOISY_FLOAT                // enables debug output for float reflow (the in/out metrics for the floated block)
 #undef NOISY_FLOAT_CLEARING
 #undef NOISY_FINAL_SIZE           // enables debug output for desired width/height computation, once all children have been reflowed
 #undef NOISY_REMOVE_FRAME
 #undef NOISY_COMBINED_AREA        // enables debug output for combined area computation
 #undef NOISY_BLOCK_DIR_MARGINS
 #undef NOISY_REFLOW_REASON        // gives a little info about why each reflow was requested
 #undef REFLOW_STATUS_COVERAGE     // I think this is most useful for printing, to see which frames return "incomplete"
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -226,34 +226,16 @@ const char* nsBlockFrame::kReflowCommand
   "ContentChanged",
   "StyleChanged",
   "ReflowDirty",
   "Timeout",
   "UserDefined",
 };
 #endif
 
-#ifdef REALLY_NOISY_FIRST_LINE
-static void
-DumpStyleGeneaology(nsIFrame* aFrame, const char* gap)
-{
-  fputs(gap, stdout);
-  nsFrame::ListTag(stdout, aFrame);
-  printf(": ");
-  nsStyleContext* sc = aFrame->StyleContext();
-  while (nullptr != sc) {
-    nsStyleContext* psc;
-    printf("%p ", sc);
-    psc = sc->GetParent();
-    sc = psc;
-  }
-  printf("\n");
-}
-#endif
-
 #ifdef REFLOW_STATUS_COVERAGE
 static void
 RecordReflowStatus(bool aChildIsBlock, nsReflowStatus aFrameReflowStatus)
 {
   static uint32_t record[2];
 
   // 0: child-is-block
   // 1: child-is-inline
@@ -1500,17 +1482,17 @@ nsBlockFrame::ComputeFinalSize(const nsH
                                nscoord*                 aBEndEdgeOfChildren)
 {
   WritingMode wm = aState.mReflowState.GetWritingMode();
   const LogicalMargin& borderPadding = aState.BorderPadding();
 #ifdef NOISY_FINAL_SIZE
   ListTag(stdout);
   printf(": mBCoord=%d mIsBEndMarginRoot=%s mPrevBEndMargin=%d bp=%d,%d\n",
          aState.mBCoord, aState.GetFlag(BRS_ISBENDMARGINROOT) ? "yes" : "no",
-         aState.mPrevBEndMargin,
+         aState.mPrevBEndMargin.get(),
          borderPadding.BStart(wm), borderPadding.BEnd(wm));
 #endif
 
   // Compute final inline size
   LogicalSize finalSize(wm);
   finalSize.ISize(wm) =
     NSCoordSaturatingAdd(NSCoordSaturatingAdd(borderPadding.IStart(wm),
                                               aReflowState.ComputedISize()),
@@ -1727,17 +1709,20 @@ nsBlockFrame::ComputeOverflowAreas(const
     }
 
     ConsiderBlockEndEdgeOfChildren(GetWritingMode(),
                                    aBEndEdgeOfChildren, areas);
   }
 
 #ifdef NOISY_COMBINED_AREA
   ListTag(stdout);
-  printf(": ca=%d,%d,%d,%d\n", area.x, area.y, area.width, area.height);
+  const nsRect& vis = areas.VisualOverflow();
+  printf(": VisualOverflowArea CA=%d,%d,%d,%d\n", vis.x, vis.y, vis.width, vis.height);
+  const nsRect& scr = areas.ScrollableOverflow();
+  printf(": ScrollableOverflowArea CA=%d,%d,%d,%d\n", scr.x, scr.y, scr.width, scr.height);
 #endif
 
   aOverflowAreas = areas;
 }
 
 void
 nsBlockFrame::UnionChildOverflow(nsOverflowAreas& aOverflowAreas)
 {
@@ -3639,17 +3624,17 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
             // flow block. Since we just continued the child block frame,
             // we know that line->mFirstChild is not the last flow block
             // therefore zero out the running margin value.
 #ifdef NOISY_BLOCK_DIR_MARGINS
             ListTag(stdout);
             printf(": reflow incomplete, frame=");
             nsFrame::ListTag(stdout, frame);
             printf(" prevBEndMargin=%d, setting to zero\n",
-                   aState.mPrevBEndMargin);
+                   aState.mPrevBEndMargin.get());
 #endif
             aState.mPrevBEndMargin.Zero();
           }
           else { // frame is complete but its overflow is not complete
             // Disconnect the next-in-flow and put it in our overflow tracker
             if (!madeContinuation &&
                 !(NS_FRAME_IS_OVERFLOW_CONTAINER & nextFrame->GetStateBits())) {
               // It already exists, but as a normal next-in-flow, so we need
@@ -3667,38 +3652,38 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
             aState.mOverflowTracker->Insert(nextFrame, frameReflowStatus);
             NS_MergeReflowStatusInto(&aState.mReflowStatus, frameReflowStatus);
 
 #ifdef NOISY_BLOCK_DIR_MARGINS
             ListTag(stdout);
             printf(": reflow complete but overflow incomplete for ");
             nsFrame::ListTag(stdout, frame);
             printf(" prevBEndMargin=%d collapsedBEndMargin=%d\n",
-                   aState.mPrevBEndMargin, collapsedBEndMargin.get());
+                   aState.mPrevBEndMargin.get(), collapsedBEndMargin.get());
 #endif
             aState.mPrevBEndMargin = collapsedBEndMargin;
           }
         }
         else { // frame is fully complete
 #ifdef NOISY_BLOCK_DIR_MARGINS
           ListTag(stdout);
           printf(": reflow complete for ");
           nsFrame::ListTag(stdout, frame);
           printf(" prevBEndMargin=%d collapsedBEndMargin=%d\n",
-                 aState.mPrevBEndMargin, collapsedBEndMargin.get());
+                 aState.mPrevBEndMargin.get(), collapsedBEndMargin.get());
 #endif
           aState.mPrevBEndMargin = collapsedBEndMargin;
         }
 #ifdef NOISY_BLOCK_DIR_MARGINS
         ListTag(stdout);
         printf(": frame=");
         nsFrame::ListTag(stdout, frame);
         printf(" carriedOutBEndMargin=%d collapsedBEndMargin=%d => %d\n",
-               brc.GetCarriedOutBEndMargin(), collapsedBEndMargin.get(),
-               aState.mPrevBEndMargin);
+               brc.GetCarriedOutBEndMargin().get(), collapsedBEndMargin.get(),
+               aState.mPrevBEndMargin.get());
 #endif
       } else {
         if ((aLine == mLines.front() && !GetPrevInFlow()) ||
             ShouldAvoidBreakInside(aState.mReflowState)) {
           // If it's our very first line *or* we're not at the top of the page
           // and we have page-break-inside:avoid, then we need to be pushed to
           // our parent's next-in-flow.
           aState.mReflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
@@ -4101,17 +4086,17 @@ nsBlockFrame::ReflowInlineFrame(nsBlockR
   nsReflowStatus frameReflowStatus;
   bool           pushedFrame;
   aLineLayout.ReflowFrame(aFrame, frameReflowStatus, nullptr, pushedFrame);
 
   if (frameReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW) {
     aLineLayout.SetDirtyNextLine();
   }
 
-#ifdef REALLY_NOISY_REFLOW_CHILD
+#ifdef REALLY_NOISY_REFLOW
   nsFrame::ListTag(stdout, aFrame);
   printf(": status=%x\n", frameReflowStatus);
 #endif
 
 #if defined(REFLOW_STATUS_COVERAGE)
   RecordReflowStatus(false, frameReflowStatus);
 #endif
 
@@ -6134,18 +6119,18 @@ nsBlockFrame::ReflowFloat(nsBlockReflowS
                   "aFloat must be an out-of-flow frame");
   // Reflow the float.
   aReflowStatus = NS_FRAME_COMPLETE;
 
   WritingMode wm = aState.mReflowState.GetWritingMode();
 #ifdef NOISY_FLOAT
   printf("Reflow Float %p in parent %p, availSpace(%d,%d,%d,%d)\n",
          aFloat, this,
-         aFloatAvailableSpace.IStart(wm), aFloatAvailableSpace.BStart(wm),
-         aFloatAvailableSpace.ISize(wm), aFloatAvailableSpace.BSize(wm)
+         aAdjustedAvailableSpace.IStart(wm), aAdjustedAvailableSpace.BStart(wm),
+         aAdjustedAvailableSpace.ISize(wm), aAdjustedAvailableSpace.BSize(wm)
   );
 #endif
 
   nsHTMLReflowState
     floatRS(aState.mPresContext, aState.mReflowState, aFloat,
             aAdjustedAvailableSpace.Size(wm).ConvertTo(aFloat->GetWritingMode(),
                                                        wm));
 
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -3463,16 +3463,21 @@ public:
   void ListTag(FILE* out) const {
     ListTag(out, this);
   }
   static void ListTag(FILE* out, const nsIFrame* aFrame) {
     nsAutoCString t;
     ListTag(t, aFrame);
     fputs(t.get(), out);
   }
+  static void ListTag(FILE* out, const nsFrameList& aFrameList) {
+    for (nsIFrame* frame : aFrameList) {
+      ListTag(out, frame);
+    }
+  }
   void ListTag(nsACString& aTo) const;
   nsAutoCString ListTag() const {
     nsAutoCString tag;
     ListTag(tag);
     return tag;
   }
   static void ListTag(nsACString& aTo, const nsIFrame* aFrame);
   void ListGeneric(nsACString& aTo, const char* aPrefix = "", uint32_t aFlags = 0) const;
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -207,16 +207,17 @@ RenderFrameParent::OwnerContentChanged(n
 {
   MOZ_ASSERT(!mFrameLoader || mFrameLoader->GetOwnerContent() == aContent,
              "Don't build new map if owner is same!");
 
   RefPtr<LayerManager> lm = mFrameLoader ? GetFrom(mFrameLoader) : nullptr;
   // Perhaps the document containing this frame currently has no presentation?
   if (lm && lm->AsClientLayerManager()) {
     lm->AsClientLayerManager()->GetRemoteRenderer()->SendAdoptChild(mLayersId);
+    FrameLayerBuilder::InvalidateAllLayers(lm);
   }
 }
 
 void
 RenderFrameParent::ActorDestroy(ActorDestroyReason why)
 {
   if (mLayersId != 0) {
     if (XRE_IsParentProcess()) {
--- a/layout/reftests/pagination/resize-reflow-001.inner.html
+++ b/layout/reftests/pagination/resize-reflow-001.inner.html
@@ -7,17 +7,17 @@
     html { overflow: hidden }
   </style>
 </head>
 <body>
 
 <div style="-moz-column-width: 12em;
             border: silver solid;
             height: 5em;">
-  <div style="border: dotted;
+  <div style="border: solid;
               background: aqua;
               color: gray;">
         blah<br>
         blah<br>
         blah<br>
         blah
   </div>
 </div>
--- a/layout/reftests/pagination/resize-reflow-001.ref.html
+++ b/layout/reftests/pagination/resize-reflow-001.ref.html
@@ -3,17 +3,17 @@
 <head>
   <title>Resize Reflow Test</title>
 </head>
 <body style="width: 28em">
 
 <div style="-moz-column-width: 12em;
             border: silver solid;
             height: 5em;">
-  <div style="border: dotted;
+  <div style="border: solid;
               background: aqua;
               color: gray;">
         blah<br>
         blah<br>
         blah<br>
         blah
   </div>
 </div>
--- a/layout/style/test/chrome/hover_helper.html
+++ b/layout/style/test/chrome/hover_helper.html
@@ -141,136 +141,121 @@ function step5() {
 }
 
 var step6called = false;
 function step6() {
     is(step6called, false, "step6 called only once");
     step6called = true;
     is(getComputedStyle(divtwo, "").backgroundColor, "transparent",
        ":hover does not apply");
-    setResize("step7()");
     synthesizeMouse(divtwoparent, 2, 5, moveEvent, window);
+    setTimeout(step7, 500); // time to detect oscillations if they exist
 }
 
 var step7called = false;
 function step7() {
-    is(step7called, false, "step7 called only once");
-    step7called = true;
-    if (getComputedStyle(iframe, "").width == "50px") {
-        // The two resize events may be coalesced into a single one.
-        step8();
+    is(step7called, false, "step7 called only once (more than two cycles of oscillation)");
+    if (step7called)
         return;
-    }
-    is(getComputedStyle(divtwo, "").backgroundColor, "rgb(0, 255, 0)",
-       ":hover applies");
-    setResize("step8()");
-    /* expect to get a second resize from the oscillation */
+    step7called = true;
+    is(getComputedStyle(divtwo, "").backgroundColor, "transparent",
+       ":hover does not apply");
+    setTimeout(step8, 500); // time to detect oscillations if they exist
 }
 
+/* test the same case with scrolltop */
+
 var step8called = false;
 function step8() {
-    is(step8called, false, "step8 called only once (more than two cycles of oscillation)");
-    if (step8called)
-        return;
+    is(step8called, false, "step8 called only once");
     step8called = true;
-    is(getComputedStyle(divtwo, "").backgroundColor, "transparent",
-       ":hover does not apply");
-    setTimeout(step9, 500); // time to detect oscillations if they exist
+    iframe.contentDocument.body.removeAttribute("onresize");
+    /* move the mouse out of the way */
+    synthesizeMouse(divtwoparent, 200, 5, moveEvent, window);
+    divtwoparent.scrollLeft = 5;
+    setResize("step9()");
+    synthesizeMouse(divtwoparent, 2, 5, moveEvent, window);
+    /* mouse now over 7, 5 */
 }
 
-/* test the same case with scrolltop */
-
 var step9called = false;
 function step9() {
     is(step9called, false, "step9 called only once");
     step9called = true;
-    iframe.contentDocument.body.removeAttribute("onresize");
-    /* move the mouse out of the way */
-    synthesizeMouse(divtwoparent, 200, 5, moveEvent, window);
-    divtwoparent.scrollLeft = 5;
+    is(getComputedStyle(divtwo, "").backgroundColor, "rgb(0, 255, 0)",
+       ":hover applies");
     setResize("step10()");
-    synthesizeMouse(divtwoparent, 2, 5, moveEvent, window);
-    /* mouse now over 7, 5 */
+    divtwoparent.scrollLeft = 0; /* mouse now over 2,5 */
 }
 
 var step10called = false;
 function step10() {
     is(step10called, false, "step10 called only once");
     step10called = true;
-    is(getComputedStyle(divtwo, "").backgroundColor, "rgb(0, 255, 0)",
-       ":hover applies");
+    if (getComputedStyle(iframe, "").width == "100px") {
+        // The two resize events may be coalesced into a single one.
+        step11();
+        return;
+    }
+    is(getComputedStyle(divtwo, "").backgroundColor, "transparent",
+       ":hover does not apply");
     setResize("step11()");
-    divtwoparent.scrollLeft = 0; /* mouse now over 2,5 */
+    /* expect to get a second resize from the oscillation */
 }
 
 var step11called = false;
 function step11() {
-    is(step11called, false, "step11 called only once");
-    step11called = true;
-    if (getComputedStyle(iframe, "").width == "100px") {
-        // The two resize events may be coalesced into a single one.
-        step12();
+    is(step11called, false, "step11 called only once (more than two cycles of oscillation)");
+    if (step11called)
         return;
-    }
-    is(getComputedStyle(divtwo, "").backgroundColor, "transparent",
-       ":hover does not apply");
-    setResize("step12()");
-    /* expect to get a second resize from the oscillation */
+    step11called = true;
+    is(getComputedStyle(divtwo, "").backgroundColor, "rgb(0, 255, 0)",
+       ":hover applies");
+    setTimeout(step12, 500); // time to detect oscillations if they exist
 }
 
 var step12called = false;
 function step12() {
-    is(step12called, false, "step12 called only once (more than two cycles of oscillation)");
-    if (step12called)
-        return;
+    is(step12called, false, "step12 called only once");
     step12called = true;
-    is(getComputedStyle(divtwo, "").backgroundColor, "rgb(0, 255, 0)",
-       ":hover applies");
-    setTimeout(step13, 500); // time to detect oscillations if they exist
+    setResize("step13()");
+    divtwoparent.scrollLeft = 25; /* mouse now over 27,5 */
 }
 
 var step13called = false;
 function step13() {
     is(step13called, false, "step13 called only once");
     step13called = true;
+    is(getComputedStyle(divtwo, "").backgroundColor, "transparent",
+       ":hover does not apply");
     setResize("step14()");
-    divtwoparent.scrollLeft = 25; /* mouse now over 27,5 */
+    divtwoparent.scrollLeft = 0; /* mouse now over 2,5 */
 }
 
 var step14called = false;
 function step14() {
     is(step14called, false, "step14 called only once");
     step14called = true;
-    is(getComputedStyle(divtwo, "").backgroundColor, "transparent",
-       ":hover does not apply");
+    if (getComputedStyle(iframe, "").width == "50px") {
+        // The two resize events may be coalesced into a single one.
+        step15();
+        return;
+    }
+    is(getComputedStyle(divtwo, "").backgroundColor, "rgb(0, 255, 0)",
+       ":hover applies");
     setResize("step15()");
-    divtwoparent.scrollLeft = 0; /* mouse now over 2,5 */
+    /* expect to get a second resize from the oscillation */
 }
 
 var step15called = false;
 function step15() {
-    is(step15called, false, "step15 called only once");
-    step15called = true;
-    if (getComputedStyle(iframe, "").width == "50px") {
-        // The two resize events may be coalesced into a single one.
-        step16();
+    is(step15called, false, "step15 called only once (more than two cycles of oscillation)");
+    if (step15called)
         return;
-    }
-    is(getComputedStyle(divtwo, "").backgroundColor, "rgb(0, 255, 0)",
-       ":hover applies");
-    setResize("step16()");
-    /* expect to get a second resize from the oscillation */
-}
-
-var step16called = false;
-function step16() {
-    is(step16called, false, "step16 called only once (more than two cycles of oscillation)");
-    if (step16called)
-        return;
-    step16called = true;
+    step15called = true;
     is(getComputedStyle(divtwo, "").backgroundColor, "transparent",
        ":hover does not apply");
     setTimeout(finish, 500); // time to detect oscillations if they exist
 }
 
 function finish() {
     document.getElementById("display").style.display = "none";
 
--- a/layout/xul/nsResizerFrame.cpp
+++ b/layout/xul/nsResizerFrame.cpp
@@ -280,17 +280,18 @@ nsResizerFrame::HandleEvent(nsPresContex
             (!menuPopupFrame->IsAnchored() ||
              menuPopupFrame->PopupLevel() != ePopupLevelParent)) {
 
           CSSPoint cssPos = rect.TopLeft() / aPresContext->CSSToDevPixelScale();
           menuPopupFrame->MoveTo(RoundedToInt(cssPos), true);
         }
       }
       else {
-        window->SetPositionAndSize(rect.x, rect.y, rect.width, rect.height, true); // do the repaint.
+        window->SetPositionAndSize(rect.x, rect.y, rect.width, rect.height,
+                                   nsIBaseWindow::eRepaint); // do the repaint.
       }
 
       doDefault = false;
     }
   }
   break;
 
   case eMouseClick: {
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -652,17 +652,16 @@ pref("browser.dom.window.dump.enabled", 
 
 // SimplePush
 pref("services.push.enabled", false);
 
 // controls if we want camera support
 pref("device.camera.enabled", true);
 pref("media.realtime_decoder.enabled", true);
 
-pref("dom.report_all_js_exceptions", true);
 pref("javascript.options.showInConsole", true);
 
 pref("full-screen-api.enabled", true);
 
 pref("direct-texture.force.enabled", false);
 pref("direct-texture.force.disabled", false);
 
 // This fraction in 1000ths of velocity remains after every animation frame when the velocity is low.
--- a/mobile/android/base/AppConstants.java.in
+++ b/mobile/android/base/AppConstants.java.in
@@ -165,27 +165,16 @@ public class AppConstants {
 
     public static final boolean MOZ_EXCLUDE_HYPHENATION_DICTIONARIES =
 //#ifdef MOZ_EXCLUDE_HYPHENATION_DICTIONARIES
     true;
 //#else
     false;
 //#endif
 
-    /**
-     * Whether this APK was built with constrained resources --
-     * no xhdpi+ images, for example.
-     */
-    public static final boolean MOZ_ANDROID_RESOURCE_CONSTRAINED =
-//#ifdef MOZ_ANDROID_RESOURCE_CONSTRAINED
-    true;
-//#else
-    false;
-//#endif
-
     public static final boolean MOZ_SERVICES_HEALTHREPORT =
 //#ifdef MOZ_SERVICES_HEALTHREPORT
     true;
 //#else
     false;
 //#endif
 
     public static final boolean MOZ_TELEMETRY_ON_BY_DEFAULT =
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -457,18 +457,16 @@ ANDROID_AAPT_IGNORE := !.svn:!.git:.*:<d
 # 3: name of ap_ file to write.
 # 4: directory to write R.java into.
 # 5: directory to write R.txt into.
 # We touch the target file before invoking aapt so that aapt's outputs
 # are fresher than the target, preventing a subsequent invocation from
 # thinking aapt's outputs are stale.  This is safe because Make
 # removes the target file if any recipe command fails.
 
-CONSTRAINED_AAPT_CONFIGURATIONS := hdpi
-
 define aapt_command
 $(1): $$(call mkdir_deps,$(filter-out ./,$(dir $(3) $(4) $(5)))) $(2)
 	@$$(TOUCH) $$@
 	$$(AAPT) package -f -m \
 		-M AndroidManifest.xml \
 		-I $(ANDROID_SDK)/android.jar \
 		$(if $(MOZ_ANDROID_MAX_SDK_VERSION),--max-res-version $(MOZ_ANDROID_MAX_SDK_VERSION),) \
 		--auto-add-overlay \
@@ -476,17 +474,16 @@ define aapt_command
 		$$(addprefix -A ,$$(ANDROID_ASSETS_DIRS)) \
 		$(if $(ANDROID_EXTRA_PACKAGES),--extra-packages $$(subst $$(NULL) ,:,$$(strip $$(ANDROID_EXTRA_PACKAGES)))) \
 		$(if $(ANDROID_EXTRA_RES_DIRS),$$(addprefix -S ,$$(ANDROID_EXTRA_RES_DIRS))) \
 		--custom-package org.mozilla.gecko \
 		--non-constant-id \
 		-F $(3) \
 		-J $(4) \
 		--output-text-symbols $(5) \
-		$(if $(MOZ_ANDROID_RESOURCE_CONSTRAINED),-c $(CONSTRAINED_AAPT_CONFIGURATIONS),) \
 		--ignore-assets "$$(ANDROID_AAPT_IGNORE)"
 endef
 
 # [Comment 3/3] The first of these rules is used during regular
 # builds.  The second writes an ap_ file that is only used during
 # packaging.  It doesn't write the normal ap_, or R.java, since we
 # don't want the packaging step to write anything that would make a
 # further no-op build do work.  See also
--- a/mobile/android/confvars.sh
+++ b/mobile/android/confvars.sh
@@ -40,21 +40,18 @@ MOZ_APP_ID={aa3c5121-dab2-40e2-81ca-7ea2
 MOZ_APP_STATIC_INI=1
 
 # Enable on-demand decompression.  This requires a host compile toolchain to
 # build szip to use during packaging.
 if test "$COMPILE_ENVIRONMENT"; then
 MOZ_ENABLE_SZIP=1
 fi
 
-# Enable second screen using native Android libraries, provided we're
-# not resource constrained.
-if test -z "$MOZ_ANDROID_RESOURCE_CONSTRAINED"; then
-  MOZ_NATIVE_DEVICES=1
-fi
+# Enable second screen using native Android libraries.
+MOZ_NATIVE_DEVICES=1
 
 # Enable install tracking SDK if we have Google Play support; MOZ_NATIVE_DEVICES
 # is a proxy flag for that support.
 if test "$RELEASE_BUILD"; then
 if test "$MOZ_NATIVE_DEVICES"; then
   MOZ_INSTALL_TRACKING=1
 fi
 fi
--- a/netwerk/base/nsStreamListenerTee.cpp
+++ b/netwerk/base/nsStreamListenerTee.cpp
@@ -44,20 +44,19 @@ nsStreamListenerTee::OnStopRequest(nsIRe
     if (mEventTarget) {
       NS_ProxyRelease(mEventTarget, mSink.forget());
     }
     else {
         mSink = 0;
     }
 
     nsresult rv = mListener->OnStopRequest(request, context, status);
-    mListener = nullptr;
     if (mObserver)
         mObserver->OnStopRequest(request, context, status);
-    mObserver = nullptr;
+    mObserver = 0;
     return rv;
 }
 
 NS_IMETHODIMP
 nsStreamListenerTee::OnDataAvailable(nsIRequest *request,
                                      nsISupports *context,
                                      nsIInputStream *input,
                                      uint64_t offset,
--- a/netwerk/base/nsStreamListenerWrapper.h
+++ b/netwerk/base/nsStreamListenerWrapper.h
@@ -22,34 +22,20 @@ class nsStreamListenerWrapper final : pu
 public:
   explicit nsStreamListenerWrapper(nsIStreamListener *listener)
     : mListener(listener)
   {
     NS_ASSERTION(mListener, "no stream listener specified");
   }
 
   NS_DECL_ISUPPORTS
+  NS_FORWARD_NSIREQUESTOBSERVER(mListener->)
   NS_FORWARD_NSISTREAMLISTENER(mListener->)
   NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
 
-  //  Don't use NS_FORWARD_NSIREQUESTOBSERVER(mListener->) here, because we need
-  //  to release mListener in OnStopRequest, and IDL-generated function doesn't.
-  NS_IMETHOD OnStartRequest(nsIRequest *aRequest,
-                            nsISupports *aContext) override
-  {
-    return mListener->OnStartRequest(aRequest, aContext);
-  }
-  NS_IMETHOD OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
-                           nsresult aStatusCode) override
-  {
-    nsresult rv = mListener->OnStopRequest(aRequest, aContext, aStatusCode);
-    mListener = nullptr;
-    return rv;
-  }
-
 private:
   ~nsStreamListenerWrapper() {}
   nsCOMPtr<nsIStreamListener> mListener;
 };
 
 } // namespace net
 } // namespace mozilla
 
--- a/netwerk/protocol/http/nsCORSListenerProxy.cpp
+++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp
@@ -994,23 +994,25 @@ nsCORSListenerProxy::CheckPreflightNeede
 // doing the initial OPTIONS request for a CORS check
 class nsCORSPreflightListener final : public nsIStreamListener,
                                       public nsIInterfaceRequestor,
                                       public nsIChannelEventSink
 {
 public:
   nsCORSPreflightListener(nsIPrincipal* aReferrerPrincipal,
                           nsICorsPreflightCallback* aCallback,
+                          nsILoadContext* aLoadContext,
                           bool aWithCredentials,
                           const nsCString& aPreflightMethod,
                           const nsTArray<nsCString>& aPreflightHeaders)
    : mPreflightMethod(aPreflightMethod),
      mPreflightHeaders(aPreflightHeaders),
      mReferrerPrincipal(aReferrerPrincipal),
      mCallback(aCallback),
+     mLoadContext(aLoadContext),
      mWithCredentials(aWithCredentials)
   {
   }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSIINTERFACEREQUESTOR
@@ -1022,16 +1024,17 @@ private:
   ~nsCORSPreflightListener() {}
 
   void AddResultToCache(nsIRequest* aRequest);
 
   nsCString mPreflightMethod;
   nsTArray<nsCString> mPreflightHeaders;
   nsCOMPtr<nsIPrincipal> mReferrerPrincipal;
   nsCOMPtr<nsICorsPreflightCallback> mCallback;
+  nsCOMPtr<nsILoadContext> mLoadContext;
   bool mWithCredentials;
 };
 
 NS_IMPL_ISUPPORTS(nsCORSPreflightListener, nsIStreamListener,
                   nsIRequestObserver, nsIInterfaceRequestor,
                   nsIChannelEventSink)
 
 void
@@ -1290,16 +1293,22 @@ nsCORSPreflightListener::CheckPreflightR
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCORSPreflightListener::GetInterface(const nsIID & aIID, void **aResult)
 {
+  if (aIID.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
+    nsCOMPtr<nsILoadContext> copy = mLoadContext;
+    copy.forget(aResult);
+    return NS_OK;
+  }
+
   return QueryInterface(aIID, aResult);
 }
 
 void
 nsCORSListenerProxy::RemoveFromCorsPreflightCache(nsIURI* aURI,
                                                   nsIPrincipal* aRequestingPrincipal)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
@@ -1364,16 +1373,25 @@ nsCORSListenerProxy::StartCORSPreflight(
   nsCOMPtr<nsILoadInfo> loadInfo = static_cast<mozilla::LoadInfo*>
     (originalLoadInfo.get())->CloneForNewRequest();
   static_cast<mozilla::LoadInfo*>(loadInfo.get())->SetIsPreflight();
 
   nsCOMPtr<nsILoadGroup> loadGroup;
   rv = aRequestChannel->GetLoadGroup(getter_AddRefs(loadGroup));
   NS_ENSURE_SUCCESS(rv, rv);
 
+  // We want to give the preflight channel's notification callbacks the same
+  // load context as the original channel's notification callbacks had.  We
+  // don't worry about a load context provided via the loadgroup here, since
+  // they have the same loadgroup.
+  nsCOMPtr<nsIInterfaceRequestor> callbacks;
+  rv = aRequestChannel->GetNotificationCallbacks(getter_AddRefs(callbacks));
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
+
   nsLoadFlags loadFlags;
   rv = aRequestChannel->GetLoadFlags(&loadFlags);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Preflight requests should never be intercepted by service workers and
   // are always anonymous.
   // NOTE: We ignore CORS checks on synthesized responses (see the CORS
   // preflights, then we need to extend the GetResponseSynthesized() check in
@@ -1421,18 +1439,18 @@ nsCORSListenerProxy::StartCORSPreflight(
     rv = preHttp->
       SetRequestHeader(NS_LITERAL_CSTRING("Access-Control-Request-Headers"),
                        headers, false);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Set up listener which will start the original channel
   RefPtr<nsCORSPreflightListener> preflightListener =
-    new nsCORSPreflightListener(principal, aCallback, withCredentials,
-                                method, preflightHeaders);
+    new nsCORSPreflightListener(principal, aCallback, loadContext,
+                                withCredentials, method, preflightHeaders);
 
   rv = preflightChannel->SetNotificationCallbacks(preflightListener);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Start preflight
   rv = preflightChannel->AsyncOpen2(preflightListener);
   NS_ENSURE_SUCCESS(rv, rv);
   
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -6229,17 +6229,16 @@ nsHttpChannel::OnStopRequest(nsIRequest 
         // if this transaction has been replaced, then bail.
         if (mTransactionReplaced)
             return NS_OK;
 
         if (mUpgradeProtocolCallback && stickyConn &&
             mResponseHead && mResponseHead->Status() == 101) {
             gHttpHandler->ConnMgr()->CompleteUpgrade(stickyConn,
                                                      mUpgradeProtocolCallback);
-            mUpgradeProtocolCallback = nullptr;
         }
     }
 
     // if needed, check cache entry has all data we expect
     if (mCacheEntry && mCachePump &&
         mConcurentCacheAccess && contentComplete) {
         int64_t size, contentLength;
         nsresult rv = CheckPartial(mCacheEntry, &size, &contentLength);
--- a/old-configure.in
+++ b/old-configure.in
@@ -2770,28 +2770,16 @@ AC_SUBST(MOZ_BING_API_KEY)
 
 # Allow specifying an Adjust SDK key file that contains the app token used for
 # Adjust SDK requests.
 MOZ_ARG_WITH_STRING(adjust-sdk-keyfile,
 [  --with-adjust-sdk-keyfile=file   Use the app token contained in the given keyfile for Adjust SDK requests],
   MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN=`cat $withval`)
 AC_SUBST(MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN)
 
-# Whether this APK is destined for resource constrained devices.
-# We want this in mobile/android/confvars.sh, so it goes early.
-MOZ_ARG_ENABLE_BOOL(android-resource-constrained,
-[  --enable-android-resource-constrained
-                          Exclude hi-res images and similar from the final APK],
-    MOZ_ANDROID_RESOURCE_CONSTRAINED=1)
-
-if test -n "$MOZ_ANDROID_RESOURCE_CONSTRAINED"; then
-    AC_DEFINE(MOZ_ANDROID_RESOURCE_CONSTRAINED)
-fi
-AC_SUBST(MOZ_ANDROID_RESOURCE_CONSTRAINED)
-
 # Optional Firefox for Android partner distribution directory.
 MOZ_ARG_WITH_STRING(android-distribution-directory,
 [  --with-android-distribution-directory=dir
                           Optional Firefox for Android partner distribution directory.],
   MOZ_ANDROID_DISTRIBUTION_DIRECTORY=$withval)
 
 if test -n "$MOZ_ANDROID_DISTRIBUTION_DIRECTORY"; then
   # A distribution directory must have an assets/distribution directory.
--- a/parser/html/javasrc/ElementName.java
+++ b/parser/html/javasrc/ElementName.java
@@ -323,18 +323,18 @@ public final class ElementName
 //            case TreeBuilder.TD_OR_TH:
 //                return "TD_OR_TH";
 //            case TreeBuilder.DD_OR_DT:
 //                return "DD_OR_DT";
 //            case TreeBuilder.H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6:
 //                return "H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6";
 //            case TreeBuilder.OBJECT:
 //                return "OBJECT";
-//            case TreeBuilder.OUTPUT_OR_LABEL:
-//                return "OUTPUT_OR_LABEL";
+//            case TreeBuilder.OUTPUT:
+//                return "OUTPUT";
 //            case TreeBuilder.MARQUEE_OR_APPLET:
 //                return "MARQUEE_OR_APPLET";
 //            case TreeBuilder.PRE_OR_LISTING:
 //                return "PRE_OR_LISTING";
 //            case TreeBuilder.B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
 //                return "B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U";
 //            case TreeBuilder.UL_OR_OL_OR_DL:
 //                return "UL_OR_OL_OR_DL";
@@ -567,17 +567,17 @@ public final class ElementName
     public static final ElementName FRAME = new ElementName("frame", "frame", TreeBuilder.FRAME | SPECIAL);
     public static final ElementName FALSE = new ElementName("false", "false", TreeBuilder.OTHER);
     public static final ElementName FLOOR = new ElementName("floor", "floor", TreeBuilder.OTHER);
     public static final ElementName GLYPH = new ElementName("glyph", "glyph", TreeBuilder.OTHER);
     public static final ElementName HKERN = new ElementName("hkern", "hkern", TreeBuilder.OTHER);
     public static final ElementName IMAGE = new ElementName("image", "image", TreeBuilder.IMAGE);
     public static final ElementName IDENT = new ElementName("ident", "ident", TreeBuilder.OTHER);
     public static final ElementName INPUT = new ElementName("input", "input", TreeBuilder.INPUT | SPECIAL);
-    public static final ElementName LABEL = new ElementName("label", "label", TreeBuilder.OUTPUT_OR_LABEL);
+    public static final ElementName LABEL = new ElementName("label", "label", TreeBuilder.OTHER);
     public static final ElementName LIMIT = new ElementName("limit", "limit", TreeBuilder.OTHER);
     public static final ElementName MFRAC = new ElementName("mfrac", "mfrac", TreeBuilder.OTHER);
     public static final ElementName MPATH = new ElementName("mpath", "mpath", TreeBuilder.OTHER);
     public static final ElementName METER = new ElementName("meter", "meter", TreeBuilder.OTHER);
     public static final ElementName MOVER = new ElementName("mover", "mover", TreeBuilder.OTHER);
     public static final ElementName MINUS = new ElementName("minus", "minus", TreeBuilder.OTHER);
     public static final ElementName MROOT = new ElementName("mroot", "mroot", TreeBuilder.OTHER);
     public static final ElementName MSQRT = new ElementName("msqrt", "msqrt", TreeBuilder.OTHER);
@@ -635,17 +635,17 @@ public final class ElementName
     public static final ElementName MEDIAN = new ElementName("median", "median", TreeBuilder.OTHER);
     public static final ElementName MUNDER = new ElementName("munder", "munder", TreeBuilder.OTHER);
     public static final ElementName MARKER = new ElementName("marker", "marker", TreeBuilder.OTHER);
     public static final ElementName MERROR = new ElementName("merror", "merror", TreeBuilder.OTHER);
     public static final ElementName MOMENT = new ElementName("moment", "moment", TreeBuilder.OTHER);
     public static final ElementName MATRIX = new ElementName("matrix", "matrix", TreeBuilder.OTHER);
     public static final ElementName OPTION = new ElementName("option", "option", TreeBuilder.OPTION | OPTIONAL_END_TAG);
     public static final ElementName OBJECT = new ElementName("object", "object", TreeBuilder.OBJECT | SPECIAL | SCOPING);
-    public static final ElementName OUTPUT = new ElementName("output", "output", TreeBuilder.OUTPUT_OR_LABEL);
+    public static final ElementName OUTPUT = new ElementName("output", "output", TreeBuilder.OUTPUT);
     public static final ElementName PRIMES = new ElementName("primes", "primes", TreeBuilder.OTHER);
     public static final ElementName SOURCE = new ElementName("source", "source", TreeBuilder.PARAM_OR_SOURCE_OR_TRACK);
     public static final ElementName STRIKE = new ElementName("strike", "strike", TreeBuilder.B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U);
     public static final ElementName STRONG = new ElementName("strong", "strong", TreeBuilder.B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U);
     public static final ElementName SWITCH = new ElementName("switch", "switch", TreeBuilder.OTHER);
     public static final ElementName SYMBOL = new ElementName("symbol", "symbol", TreeBuilder.OTHER);
     public static final ElementName SELECT = new ElementName("select", "select", TreeBuilder.SELECT | SPECIAL);
     public static final ElementName SUBSET = new ElementName("subset", "subset", TreeBuilder.OTHER);
--- a/parser/html/javasrc/TreeBuilder.java
+++ b/parser/html/javasrc/TreeBuilder.java
@@ -184,17 +184,17 @@ public abstract class TreeBuilder<T> imp
     final static int ANNOTATION_XML = 58;
 
     final static int FOREIGNOBJECT_OR_DESC = 59;
 
     final static int NOEMBED = 60;
 
     final static int FIELDSET = 61;
 
-    final static int OUTPUT_OR_LABEL = 62;
+    final static int OUTPUT = 62;
 
     final static int OBJECT = 63;
 
     final static int FONT = 64;
 
     final static int KEYGEN = 65;
 
     final static int MENUITEM = 66;
@@ -2548,17 +2548,17 @@ public abstract class TreeBuilder<T> imp
                             case TBODY_OR_THEAD_OR_TFOOT:
                             case TR:
                             case TD_OR_TH:
                             case FRAME:
                             case FRAMESET:
                             case HEAD:
                                 errStrayStartTag(name);
                                 break starttagloop;
-                            case OUTPUT_OR_LABEL:
+                            case OUTPUT:
                                 reconstructTheActiveFormattingElements();
                                 appendToCurrentNodeAndPushElementMayFoster(
                                         elementName,
                                         attributes, formPointer);
                                 attributes = null; // CPP
                                 break starttagloop;
                             default:
                                 reconstructTheActiveFormattingElements();
--- a/parser/html/nsHtml5ElementName.cpp
+++ b/parser/html/nsHtml5ElementName.cpp
@@ -695,17 +695,17 @@ nsHtml5ElementName::initializeStatics()
   ELT_FRAME = new nsHtml5ElementName(nsHtml5Atoms::frame, nsHtml5Atoms::frame, NS_HTML5TREE_BUILDER_FRAME | NS_HTML5ELEMENT_NAME_SPECIAL);
   ELT_FALSE = new nsHtml5ElementName(nsHtml5Atoms::false_, nsHtml5Atoms::false_, NS_HTML5TREE_BUILDER_OTHER);
   ELT_FLOOR = new nsHtml5ElementName(nsHtml5Atoms::floor, nsHtml5Atoms::floor, NS_HTML5TREE_BUILDER_OTHER);
   ELT_GLYPH = new nsHtml5ElementName(nsHtml5Atoms::glyph, nsHtml5Atoms::glyph, NS_HTML5TREE_BUILDER_OTHER);
   ELT_HKERN = new nsHtml5ElementName(nsHtml5Atoms::hkern, nsHtml5Atoms::hkern, NS_HTML5TREE_BUILDER_OTHER);
   ELT_IMAGE = new nsHtml5ElementName(nsHtml5Atoms::image, nsHtml5Atoms::image, NS_HTML5TREE_BUILDER_IMAGE);
   ELT_IDENT = new nsHtml5ElementName(nsHtml5Atoms::ident, nsHtml5Atoms::ident, NS_HTML5TREE_BUILDER_OTHER);
   ELT_INPUT = new nsHtml5ElementName(nsHtml5Atoms::input, nsHtml5Atoms::input, NS_HTML5TREE_BUILDER_INPUT | NS_HTML5ELEMENT_NAME_SPECIAL);
-  ELT_LABEL = new nsHtml5ElementName(nsHtml5Atoms::label, nsHtml5Atoms::label, NS_HTML5TREE_BUILDER_OUTPUT_OR_LABEL);
+  ELT_LABEL = new nsHtml5ElementName(nsHtml5Atoms::label, nsHtml5Atoms::label, NS_HTML5TREE_BUILDER_OTHER);
   ELT_LIMIT = new nsHtml5ElementName(nsHtml5Atoms::limit, nsHtml5Atoms::limit, NS_HTML5TREE_BUILDER_OTHER);
   ELT_MFRAC = new nsHtml5ElementName(nsHtml5Atoms::mfrac, nsHtml5Atoms::mfrac, NS_HTML5TREE_BUILDER_OTHER);
   ELT_MPATH = new nsHtml5ElementName(nsHtml5Atoms::mpath, nsHtml5Atoms::mpath, NS_HTML5TREE_BUILDER_OTHER);
   ELT_METER = new nsHtml5ElementName(nsHtml5Atoms::meter, nsHtml5Atoms::meter, NS_HTML5TREE_BUILDER_OTHER);
   ELT_MOVER = new nsHtml5ElementName(nsHtml5Atoms::mover, nsHtml5Atoms::mover, NS_HTML5TREE_BUILDER_OTHER);
   ELT_MINUS = new nsHtml5ElementName(nsHtml5Atoms::minus, nsHtml5Atoms::minus, NS_HTML5TREE_BUILDER_OTHER);
   ELT_MROOT = new nsHtml5ElementName(nsHtml5Atoms::mroot, nsHtml5Atoms::mroot, NS_HTML5TREE_BUILDER_OTHER);
   ELT_MSQRT = new nsHtml5ElementName(nsHtml5Atoms::msqrt, nsHtml5Atoms::msqrt, NS_HTML5TREE_BUILDER_OTHER);
@@ -763,17 +763,17 @@ nsHtml5ElementName::initializeStatics()
   ELT_MEDIAN = new nsHtml5ElementName(nsHtml5Atoms::median, nsHtml5Atoms::median, NS_HTML5TREE_BUILDER_OTHER);
   ELT_MUNDER = new nsHtml5ElementName(nsHtml5Atoms::munder, nsHtml5Atoms::munder, NS_HTML5TREE_BUILDER_OTHER);
   ELT_MARKER = new nsHtml5ElementName(nsHtml5Atoms::marker, nsHtml5Atoms::marker, NS_HTML5TREE_BUILDER_OTHER);
   ELT_MERROR = new nsHtml5ElementName(nsHtml5Atoms::merror, nsHtml5Atoms::merror, NS_HTML5TREE_BUILDER_OTHER);
   ELT_MOMENT = new nsHtml5ElementName(nsHtml5Atoms::moment, nsHtml5Atoms::moment, NS_HTML5TREE_BUILDER_OTHER);
   ELT_MATRIX = new nsHtml5ElementName(nsHtml5Atoms::matrix, nsHtml5Atoms::matrix, NS_HTML5TREE_BUILDER_OTHER);
   ELT_OPTION = new nsHtml5ElementName(nsHtml5Atoms::option, nsHtml5Atoms::option, NS_HTML5TREE_BUILDER_OPTION | NS_HTML5ELEMENT_NAME_OPTIONAL_END_TAG);
   ELT_OBJECT = new nsHtml5ElementName(nsHtml5Atoms::object, nsHtml5Atoms::object, NS_HTML5TREE_BUILDER_OBJECT | NS_HTML5ELEMENT_NAME_SPECIAL | NS_HTML5ELEMENT_NAME_SCOPING);
-  ELT_OUTPUT = new nsHtml5ElementName(nsHtml5Atoms::output, nsHtml5Atoms::output, NS_HTML5TREE_BUILDER_OUTPUT_OR_LABEL);
+  ELT_OUTPUT = new nsHtml5ElementName(nsHtml5Atoms::output, nsHtml5Atoms::output, NS_HTML5TREE_BUILDER_OUTPUT);
   ELT_PRIMES = new nsHtml5ElementName(nsHtml5Atoms::primes, nsHtml5Atoms::primes, NS_HTML5TREE_BUILDER_OTHER);
   ELT_SOURCE = new nsHtml5ElementName(nsHtml5Atoms::source, nsHtml5Atoms::source, NS_HTML5TREE_BUILDER_PARAM_OR_SOURCE_OR_TRACK);
   ELT_STRIKE = new nsHtml5ElementName(nsHtml5Atoms::strike, nsHtml5Atoms::strike, NS_HTML5TREE_BUILDER_B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U);
   ELT_STRONG = new nsHtml5ElementName(nsHtml5Atoms::strong, nsHtml5Atoms::strong, NS_HTML5TREE_BUILDER_B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U);
   ELT_SWITCH = new nsHtml5ElementName(nsHtml5Atoms::switch_, nsHtml5Atoms::switch_, NS_HTML5TREE_BUILDER_OTHER);
   ELT_SYMBOL = new nsHtml5ElementName(nsHtml5Atoms::symbol, nsHtml5Atoms::symbol, NS_HTML5TREE_BUILDER_OTHER);
   ELT_SELECT = new nsHtml5ElementName(nsHtml5Atoms::select, nsHtml5Atoms::select, NS_HTML5TREE_BUILDER_SELECT | NS_HTML5ELEMENT_NAME_SPECIAL);
   ELT_SUBSET = new nsHtml5ElementName(nsHtml5Atoms::subset, nsHtml5Atoms::subset, NS_HTML5TREE_BUILDER_OTHER);
--- a/parser/html/nsHtml5TreeBuilder.cpp
+++ b/parser/html/nsHtml5TreeBuilder.cpp
@@ -1407,17 +1407,17 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
             case NS_HTML5TREE_BUILDER_TR:
             case NS_HTML5TREE_BUILDER_TD_OR_TH:
             case NS_HTML5TREE_BUILDER_FRAME:
             case NS_HTML5TREE_BUILDER_FRAMESET:
             case NS_HTML5TREE_BUILDER_HEAD: {
               errStrayStartTag(name);
               NS_HTML5_BREAK(starttagloop);
             }
-            case NS_HTML5TREE_BUILDER_OUTPUT_OR_LABEL: {
+            case NS_HTML5TREE_BUILDER_OUTPUT: {
               reconstructTheActiveFormattingElements();
               appendToCurrentNodeAndPushElementMayFoster(elementName, attributes, formPointer);
               attributes = nullptr;
               NS_HTML5_BREAK(starttagloop);
             }
             default: {
               reconstructTheActiveFormattingElements();
               appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
--- a/parser/html/nsHtml5TreeBuilder.h
+++ b/parser/html/nsHtml5TreeBuilder.h
@@ -329,17 +329,17 @@ class nsHtml5TreeBuilder : public nsAHtm
 #define NS_HTML5TREE_BUILDER_RB_OR_RTC 53
 #define NS_HTML5TREE_BUILDER_PARAM_OR_SOURCE_OR_TRACK 55
 #define NS_HTML5TREE_BUILDER_MGLYPH_OR_MALIGNMARK 56
 #define NS_HTML5TREE_BUILDER_MI_MO_MN_MS_MTEXT 57
 #define NS_HTML5TREE_BUILDER_ANNOTATION_XML 58
 #define NS_HTML5TREE_BUILDER_FOREIGNOBJECT_OR_DESC 59
 #define NS_HTML5TREE_BUILDER_NOEMBED 60
 #define NS_HTML5TREE_BUILDER_FIELDSET 61
-#define NS_HTML5TREE_BUILDER_OUTPUT_OR_LABEL 62
+#define NS_HTML5TREE_BUILDER_OUTPUT 62
 #define NS_HTML5TREE_BUILDER_OBJECT 63
 #define NS_HTML5TREE_BUILDER_FONT 64
 #define NS_HTML5TREE_BUILDER_KEYGEN 65
 #define NS_HTML5TREE_BUILDER_MENUITEM 66
 #define NS_HTML5TREE_BUILDER_TEMPLATE 67
 #define NS_HTML5TREE_BUILDER_IMG 68
 #define NS_HTML5TREE_BUILDER_RT_OR_RP 69
 #define NS_HTML5TREE_BUILDER_IN_ROW 0
--- a/security/manager/ssl/nsIX509CertDB.idl
+++ b/security/manager/ssl/nsIX509CertDB.idl
@@ -385,9 +385,15 @@ interface nsIX509CertDB : nsISupports {
    * @param aName name of the cert for display purposes.
    */
   void addCertFromBase64(in string base64, in string aTrust, in string aName);
 
   /*
    * Get all the known certs in the database
    */
   nsIX509CertList getCerts();
+
+  /*
+   * Get a list of imported enterprise root certificates (currently only
+   * implemented on Windows).
+   */
+  nsIX509CertList getEnterpriseRoots();
 };
--- a/security/manager/ssl/nsNSSCertificateDB.cpp
+++ b/security/manager/ssl/nsNSSCertificateDB.cpp
@@ -1471,16 +1471,42 @@ nsNSSCertificateDB::GetCerts(nsIX509Cert
   // nsNSSCertList 1) adopts certList, and 2) handles the nullptr case fine.
   // (returns an empty list) 
   nssCertList = new nsNSSCertList(Move(certList), locker);
 
   nssCertList.forget(_retval);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsNSSCertificateDB::GetEnterpriseRoots(nsIX509CertList** enterpriseRoots)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!NS_IsMainThread()) {
+    return NS_ERROR_NOT_SAME_THREAD;
+  }
+
+  NS_ENSURE_ARG_POINTER(enterpriseRoots);
+
+  nsNSSShutDownPreventionLock locker;
+  if (isAlreadyShutDown()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+#ifdef XP_WIN
+  nsCOMPtr<nsINSSComponent> psm(do_GetService(PSM_COMPONENT_CONTRACTID));
+  if (!psm) {
+    return NS_ERROR_FAILURE;
+  }
+  return psm->GetEnterpriseRoots(enterpriseRoots);
+#else
+  return NS_ERROR_NOT_IMPLEMENTED;
+#endif
+}
+
 nsresult
 VerifyCertAtTime(nsIX509Cert* aCert,
                  int64_t /*SECCertificateUsage*/ aUsage,
                  uint32_t aFlags,
                  const char* aHostname,
                  mozilla::pkix::Time aTime,
                  nsIX509CertList** aVerifiedChain,
                  bool* aHasEVPolicy,
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -7,23 +7,25 @@
 #include "nsNSSComponent.h"
 
 #include "ExtendedValidation.h"
 #include "NSSCertDBTrustDomain.h"
 #include "ScopedNSSTypes.h"
 #include "SharedSSLState.h"
 #include "cert.h"
 #include "certdb.h"
+#include "mozilla/ArrayUtils.h"
 #include "mozilla/Casting.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/PublicSSL.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/SyncRunnable.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/unused.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsCRT.h"
 #include "nsCertVerificationThread.h"
 #include "nsClientAuthRemember.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsICertOverrideService.h"
 #include "nsIFile.h"
@@ -437,17 +439,17 @@ GetUserSid(nsAString& sidString)
   DWORD lcAccountName = sizeof(lpAccountName) / sizeof(lpAccountName[0]);
   BOOL success = GetUserName(lpAccountName, &lcAccountName);
   if (!success) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("GetUserName failed"));
     return false;
   }
   char sid_buffer[SECURITY_MAX_SID_SIZE];
   SID* sid = BitwiseCast<SID*, char*>(sid_buffer);
-  DWORD cbSid = MOZ_ARRAY_LENGTH(sid_buffer);
+  DWORD cbSid = ArrayLength(sid_buffer);
   SID_NAME_USE eUse;
   // There doesn't appear to be a defined maximum length for the domain name
   // here. To deal with this, we start with a reasonable buffer length and
   // see if that works. If it fails and the error indicates insufficient length,
   // we use the indicated required length and try again.
   DWORD cchReferencedDomainName = 128;
   auto ReferencedDomainName(MakeUnique<WCHAR[]>(cchReferencedDomainName));
   success = LookupAccountName(nullptr, lpAccountName, sid, &cbSid,
@@ -647,77 +649,92 @@ AccountHasFamilySafetyEnabled(bool& enab
             ("failed to read value of Web\\Filter On"));
     return rv;
   }
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Web\\Filter On: %u", webFilterOn));
   enabled = loggingRequired == 1 || webFilterOn == 1;
   return NS_OK;
 }
 
-const char* kImportedFamilySafetyRootPref =
-  "security.family_safety.imported_root.db_key";
+// It would be convenient to just use nsIX509CertDB in the following code.
+// However, since nsIX509CertDB depends on nsNSSComponent initialization (and
+// since this code runs during that initialization), we can't use it. Instead,
+// we can use NSS APIs directly (as long as we're called late enough in
+// nsNSSComponent initialization such that those APIs are safe to use).
 
-static nsresult
-MaybeImportFamilySafetyRoot(PCCERT_CONTEXT certificate,
-                            bool& wasFamilySafetyRoot)
+// Helper function to convert a PCCERT_CONTEXT (i.e. a certificate obtained via
+// a Windows API) to a temporary CERTCertificate (i.e. a certificate for use
+// with NSS APIs).
+static UniqueCERTCertificate
+PCCERT_CONTEXTToCERTCertificate(PCCERT_CONTEXT pccert)
 {
-  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("MaybeImportFamilySafetyRoot"));
-  wasFamilySafetyRoot = false;
-
-  // It would be convenient to just use nsIX509CertDB here. However, since
-  // nsIX509CertDB depends on nsNSSComponent initialization, we can't use it.
-  // Instead, we can use NSS APIs directly (as long as we're called late enough
-  // in nsNSSComponent initialization such that those APIs are safe to use).
+  MOZ_ASSERT(pccert);
+  if (!pccert) {
+    return nullptr;
+  }
 
   SECItem derCert = {
     siBuffer,
-    certificate->pbCertEncoded,
-    certificate->cbCertEncoded
+    pccert->pbCertEncoded,
+    pccert->cbCertEncoded
   };
-  UniqueCERTCertificate nssCertificate(
+  return UniqueCERTCertificate(
     CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert,
                             nullptr, // nickname unnecessary
                             false, // not permanent
                             true)); // copy DER
+}
+
+static const char* kMicrosoftFamilySafetyCN = "Microsoft Family Safety";
+
+nsresult
+nsNSSComponent::MaybeImportFamilySafetyRoot(PCCERT_CONTEXT certificate,
+                                            bool& wasFamilySafetyRoot)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!NS_IsMainThread()) {
+    return NS_ERROR_NOT_SAME_THREAD;
+  }
+  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("MaybeImportFamilySafetyRoot"));
+  wasFamilySafetyRoot = false;
+
+  UniqueCERTCertificate nssCertificate(
+    PCCERT_CONTEXTToCERTCertificate(certificate));
   if (!nssCertificate) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't decode certificate"));
     return NS_ERROR_FAILURE;
   }
   // Looking for a certificate with the common name 'Microsoft Family Safety'
   UniquePORTString subjectName(CERT_GetCommonName(&nssCertificate->subject));
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
           ("subject name is '%s'", subjectName.get()));
-  if (nsCRT::strcmp(subjectName.get(), "Microsoft Family Safety") == 0) {
+  if (nsCRT::strcmp(subjectName.get(), kMicrosoftFamilySafetyCN) == 0) {
     wasFamilySafetyRoot = true;
     CERTCertTrust trust = {
       CERTDB_TRUSTED_CA | CERTDB_VALID_CA | CERTDB_USER,
       0,
       0
     };
-    SECStatus srv = __CERT_AddTempCertToPerm(
-      nssCertificate.get(), "Microsoft Family Safety", &trust);
-    if (srv != SECSuccess) {
+    if (CERT_ChangeCertTrust(nullptr, nssCertificate.get(), &trust)
+          != SECSuccess) {
       MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
-              ("couldn't permanently add certificate"));
+              ("couldn't trust certificate for TLS server auth"));
       return NS_ERROR_FAILURE;
     }
-    nsAutoCString dbKey;
-    nsresult rv = nsNSSCertificate::GetDbKey(nssCertificate, dbKey);
-    if (NS_FAILED(rv)) {
-      MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("GetDbKey failed"));
-      return rv;
-    }
-    Preferences::SetCString(kImportedFamilySafetyRootPref, dbKey);
+    MOZ_ASSERT(!mFamilySafetyRoot);
+    mFamilySafetyRoot = Move(nssCertificate);
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("added Family Safety root"));
   }
   return NS_OK;
 }
 
 // Because HCERTSTORE is just a typedef void*, we can't use any of the nice
-// scoped pointer templates.
+// scoped or unique pointer templates. To elaborate, any attempt would
+// instantiate those templates with T = void. When T gets used in the context
+// of T&, this results in void&, which isn't legal.
 class ScopedCertStore final
 {
 public:
   explicit ScopedCertStore(HCERTSTORE certstore) : certstore(certstore) {}
 
   ~ScopedCertStore()
   {
     CertCloseStore(certstore, 0);
@@ -729,77 +746,71 @@ public:
   }
 
 private:
   ScopedCertStore(const ScopedCertStore&) = delete;
   ScopedCertStore& operator=(const ScopedCertStore&) = delete;
   HCERTSTORE certstore;
 };
 
-static const wchar_t* WindowsDefaultRootStoreName = L"ROOT";
+static const wchar_t* kWindowsDefaultRootStoreName = L"ROOT";
 
-static nsresult
-LoadFamilySafetyRoot()
+nsresult
+nsNSSComponent::LoadFamilySafetyRoot()
 {
   ScopedCertStore certstore(
-    CertOpenSystemStore(0, WindowsDefaultRootStoreName));
+    CertOpenSystemStore(0, kWindowsDefaultRootStoreName));
   if (!certstore.get()) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
-            ("couldn't get certstore '%S'", WindowsDefaultRootStoreName));
+            ("couldn't get certstore '%S'", kWindowsDefaultRootStoreName));
     return NS_ERROR_FAILURE;
   }
   // Any resources held by the certificate are released by the next call to
   // CertFindCertificateInStore.
   PCCERT_CONTEXT certificate = nullptr;
-  while (certificate = CertFindCertificateInStore(certstore.get(),
-                                                  X509_ASN_ENCODING, 0,
-                                                  CERT_FIND_ANY, nullptr,
-                                                  certificate)) {
+  while ((certificate = CertFindCertificateInStore(certstore.get(),
+                                                   X509_ASN_ENCODING, 0,
+                                                   CERT_FIND_ANY, nullptr,
+                                                   certificate))) {
     bool wasFamilySafetyRoot = false;
     nsresult rv = MaybeImportFamilySafetyRoot(certificate,
                                               wasFamilySafetyRoot);
     if (NS_SUCCEEDED(rv) && wasFamilySafetyRoot) {
       return NS_OK; // We're done (we're only expecting one root).
     }
   }
   return NS_ERROR_FAILURE;
 }
 
-static void
-UnloadFamilySafetyRoot()
+void
+nsNSSComponent::UnloadFamilySafetyRoot()
 {
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!NS_IsMainThread()) {
+    return;
+  }
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("UnloadFamilySafetyRoot"));
-  nsAdoptingCString dbKey = Preferences::GetCString(
-    kImportedFamilySafetyRootPref);
-  if (!dbKey || dbKey.IsEmpty()) {
-    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
-            ("Family Safety root wasn't previously imported"));
+  if (!mFamilySafetyRoot) {
+    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Family Safety Root wasn't present"));
     return;
   }
-  UniqueCERTCertificate cert;
-  nsresult rv = nsNSSCertificateDB::FindCertByDBKey(dbKey, cert);
-  if (NS_FAILED(rv)) {
-    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
-            ("finding previously-imported Family Safety root failed"));
-    return;
-  }
-  if (!cert) {
+  // It would be intuitive to set the trust to { 0, 0, 0 } here. However, this
+  // doesn't work for temporary certificates because CERT_ChangeCertTrust first
+  // looks up the current trust settings in the permanent cert database, finds
+  // that such trust doesn't exist, considers the current trust to be
+  // { 0, 0, 0 }, and decides that it doesn't need to update the trust since
+  // they're the same. To work around this, we set a non-zero flag to ensure
+  // that the trust will get updated.
+  CERTCertTrust trust = { CERTDB_USER, 0, 0 };
+  if (CERT_ChangeCertTrust(nullptr, mFamilySafetyRoot.get(), &trust)
+        != SECSuccess) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
-            ("previously-imported Family Safety root not found"));
-    return;
+            ("couldn't untrust certificate for TLS server auth"));
   }
-  SECStatus srv = SEC_DeletePermCertificate(cert.get());
-  if (srv != SECSuccess) {
-    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
-            ("couldn't delete previously-imported Family Safety root"));
-    return;
-  }
-  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
-          ("deleted previously-imported Family Safety root"));
-  Preferences::ClearUser(kImportedFamilySafetyRootPref);
+  mFamilySafetyRoot = nullptr;
 }
 
 #endif // XP_WIN
 
 // The supported values of this pref are:
 // 0: disable detecting Family Safety mode and importing the root
 // 1: only attempt to detect Family Safety mode (don't import the root)
 // 2: detect Family Safety mode and import the root
@@ -807,18 +818,18 @@ const char* kFamilySafetyModePref = "sec
 
 // The telemetry gathered by this function is as follows:
 // 0-2: the value of the Family Safety mode pref
 // 3: detecting Family Safety mode failed
 // 4: Family Safety was not enabled
 // 5: Family Safety was enabled
 // 6: failed to import the Family Safety root
 // 7: successfully imported the root
-static void
-MaybeEnableFamilySafetyCompatibility()
+void
+nsNSSComponent::MaybeEnableFamilySafetyCompatibility()
 {
 #ifdef XP_WIN
   UnloadFamilySafetyRoot();
   if (!(IsWin8Point1OrLater() && !IsWin10OrLater())) {
     return;
   }
   // Detect but don't import by default.
   uint32_t familySafetyMode = Preferences::GetUint(kFamilySafetyModePref, 1);
@@ -848,16 +859,221 @@ MaybeEnableFamilySafetyCompatibility()
               ("failed to load Family Safety root"));
     } else {
       Telemetry::Accumulate(Telemetry::FAMILY_SAFETY, 7);
     }
   }
 #endif // XP_WIN
 }
 
+#ifdef XP_WIN
+// Helper function to determine if the OS considers the given certificate to be
+// a trust anchor for TLS server auth certificates. This is to be used in the
+// context of importing what are presumed to be root certificates from the OS.
+// If this function returns true but it turns out that the given certificate is
+// in some way unsuitable to issue certificates, mozilla::pkix will never build
+// a valid chain that includes the certificate, so importing it even if it
+// isn't a valid CA poses no risk.
+static bool
+CertIsTrustAnchorForTLSServerAuth(PCCERT_CONTEXT certificate)
+{
+  MOZ_ASSERT(certificate);
+  if (!certificate) {
+    return false;
+  }
+
+  PCCERT_CHAIN_CONTEXT pChainContext = nullptr;
+  CERT_ENHKEY_USAGE enhkeyUsage;
+  memset(&enhkeyUsage, 0, sizeof(CERT_ENHKEY_USAGE));
+  LPSTR identifiers[] = {
+    "1.3.6.1.5.5.7.3.1", // id-kp-serverAuth
+  };
+  enhkeyUsage.cUsageIdentifier = ArrayLength(identifiers);
+  enhkeyUsage.rgpszUsageIdentifier = identifiers;
+  CERT_USAGE_MATCH certUsage;
+  memset(&certUsage, 0, sizeof(CERT_USAGE_MATCH));
+  certUsage.dwType = USAGE_MATCH_TYPE_AND;
+  certUsage.Usage = enhkeyUsage;
+  CERT_CHAIN_PARA chainPara;
+  memset(&chainPara, 0, sizeof(CERT_CHAIN_PARA));
+  chainPara.cbSize = sizeof(CERT_CHAIN_PARA);
+  chainPara.RequestedUsage = certUsage;
+
+  if (!CertGetCertificateChain(nullptr, certificate, nullptr, nullptr,
+                               &chainPara, 0, nullptr, &pChainContext)) {
+    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CertGetCertificateChain failed"));
+    return false;
+  }
+  bool trusted = pChainContext->TrustStatus.dwErrorStatus ==
+                 CERT_TRUST_NO_ERROR;
+  bool isRoot = pChainContext->cChain == 1;
+  CertFreeCertificateChain(pChainContext);
+  if (trusted && isRoot) {
+    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
+            ("certificate is trust anchor for TLS server auth"));
+    return true;
+  }
+  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
+          ("certificate not trust anchor for TLS server auth"));
+  return false;
+}
+
+void
+nsNSSComponent::UnloadEnterpriseRoots()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!NS_IsMainThread()) {
+    return;
+  }
+  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("UnloadEnterpriseRoots"));
+  if (!mEnterpriseRoots) {
+    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("no enterprise roots were present"));
+    return;
+  }
+  // It would be intuitive to set the trust to { 0, 0, 0 } here. However, this
+  // doesn't work for temporary certificates because CERT_ChangeCertTrust first
+  // looks up the current trust settings in the permanent cert database, finds
+  // that such trust doesn't exist, considers the current trust to be
+  // { 0, 0, 0 }, and decides that it doesn't need to update the trust since
+  // they're the same. To work around this, we set a non-zero flag to ensure
+  // that the trust will get updated.
+  CERTCertTrust trust = { CERTDB_USER, 0, 0 };
+  for (CERTCertListNode* n = CERT_LIST_HEAD(mEnterpriseRoots.get());
+       !CERT_LIST_END(n, mEnterpriseRoots.get()); n = CERT_LIST_NEXT(n)) {
+    if (!n || !n->cert) {
+      MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
+              ("library failure: CERTCertListNode null or lacks cert"));
+      continue;
+    }
+    if (CERT_ChangeCertTrust(nullptr, n->cert, &trust) != SECSuccess) {
+      MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
+              ("couldn't untrust certificate for TLS server auth"));
+    }
+  }
+  mEnterpriseRoots = nullptr;
+  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("unloaded enterprise roots"));
+}
+
+NS_IMETHODIMP
+nsNSSComponent::GetEnterpriseRoots(nsIX509CertList** enterpriseRoots)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!NS_IsMainThread()) {
+    return NS_ERROR_NOT_SAME_THREAD;
+  }
+  NS_ENSURE_ARG_POINTER(enterpriseRoots);
+
+  nsNSSShutDownPreventionLock lock;
+  // nsNSSComponent isn't a nsNSSShutDownObject, so we can't check
+  // isAlreadyShutDown(). However, since mEnterpriseRoots is cleared when NSS
+  // shuts down, we can use that as a proxy for checking for NSS shutdown.
+  // (Of course, it may also be the case that no enterprise roots were imported,
+  // so we should just return a null list and NS_OK in this case.)
+  if (!mEnterpriseRoots) {
+    *enterpriseRoots = nullptr;
+    return NS_OK;
+  }
+  UniqueCERTCertList enterpriseRootsCopy(
+    nsNSSCertList::DupCertList(mEnterpriseRoots, lock));
+  if (!enterpriseRootsCopy) {
+    return NS_ERROR_FAILURE;
+  }
+  nsCOMPtr<nsIX509CertList> enterpriseRootsCertList(
+    new nsNSSCertList(Move(enterpriseRootsCopy), lock));
+  if (!enterpriseRootsCertList) {
+    return NS_ERROR_FAILURE;
+  }
+  enterpriseRootsCertList.forget(enterpriseRoots);
+  return NS_OK;
+}
+#endif // XP_WIN
+
+static const char* kEnterpriseRootModePref = "security.enterprise_roots.enabled";
+
+void
+nsNSSComponent::MaybeImportEnterpriseRoots()
+{
+#ifdef XP_WIN
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!NS_IsMainThread()) {
+    return;
+  }
+  UnloadEnterpriseRoots();
+  bool importEnterpriseRoots = Preferences::GetBool(kEnterpriseRootModePref,
+                                                    false);
+  if (!importEnterpriseRoots) {
+    return;
+  }
+  DWORD flags = CERT_SYSTEM_STORE_LOCAL_MACHINE |
+                CERT_STORE_OPEN_EXISTING_FLAG |
+                CERT_STORE_READONLY_FLAG;
+  // The certificate store being opened should consist only of certificates
+  // added by a user or administrator and not any certificates that are part
+  // of Microsoft's root store program.
+  // The 3rd parameter to CertOpenStore should be NULL according to
+  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa376559%28v=vs.85%29.aspx
+  ScopedCertStore enterpriseRootStore(CertOpenStore(
+    CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0, NULL, flags,
+    kWindowsDefaultRootStoreName));
+  if (!enterpriseRootStore.get()) {
+    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("failed to open enterprise root store"));
+    return;
+  }
+  MOZ_ASSERT(!mEnterpriseRoots);
+  mEnterpriseRoots.reset(CERT_NewCertList());
+  CERTCertTrust trust = {
+    CERTDB_TRUSTED_CA | CERTDB_VALID_CA | CERTDB_USER,
+    0,
+    0
+  };
+  PCCERT_CONTEXT certificate = nullptr;
+  uint32_t numImported = 0;
+  while ((certificate = CertFindCertificateInStore(enterpriseRootStore.get(),
+                                                   X509_ASN_ENCODING, 0,
+                                                   CERT_FIND_ANY, nullptr,
+                                                   certificate))) {
+    if (!CertIsTrustAnchorForTLSServerAuth(certificate)) {
+      MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
+              ("skipping cert not trust anchor for TLS server auth"));
+      continue;
+    }
+    UniqueCERTCertificate nssCertificate(
+      PCCERT_CONTEXTToCERTCertificate(certificate));
+    if (!nssCertificate) {
+      MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't decode certificate"));
+      continue;
+    }
+    // Don't import the Microsoft Family Safety root (this prevents the
+    // Enterprise Roots feature from interacting poorly with the Family
+    // Safety support).
+    UniquePORTString subjectName(
+      CERT_GetCommonName(&nssCertificate->subject));
+    if (nsCRT::strcmp(subjectName.get(), kMicrosoftFamilySafetyCN) == 0) {
+      MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("skipping Family Safety Root"));
+      continue;
+    }
+    if (CERT_AddCertToListTail(mEnterpriseRoots.get(), nssCertificate.get())
+          != SECSuccess) {
+      MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't add cert to list"));
+      continue;
+    }
+    if (CERT_ChangeCertTrust(nullptr, nssCertificate.get(), &trust)
+          != SECSuccess) {
+      MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
+              ("couldn't trust certificate for TLS server auth"));
+    }
+    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Imported '%s'", subjectName.get()));
+    numImported++;
+    // now owned by mEnterpriseRoots
+    Unused << nssCertificate.release();
+  }
+  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("imported %u roots", numImported));
+#endif // XP_WIN
+}
+
 void
 nsNSSComponent::LoadLoadableRoots()
 {
   nsNSSShutDownPreventionLock locker;
   SECMODModule* RootsModule = nullptr;
 
   // In the past we used SECMOD_AddNewModule to load our module containing
   // root CA certificates. This caused problems, refer to bug 176501.
@@ -1554,16 +1770,17 @@ nsNSSComponent::InitializeNSS()
   }
 
   DisableMD5();
   // Initialize the certverifier log before calling any functions that library.
   InitCertVerifierLog();
   LoadLoadableRoots();
 
   MaybeEnableFamilySafetyCompatibility();
+  MaybeImportEnterpriseRoots();
 
   ConfigureTLSSessionIdentifiers();
 
   bool requireSafeNegotiation =
     Preferences::GetBool("security.ssl.require_safe_negotiation",
                          REQUIRE_SAFE_NEGOTIATION_DEFAULT);
   SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, requireSafeNegotiation);
 
@@ -1652,16 +1869,21 @@ nsNSSComponent::ShutdownNSS()
 
   if (mNSSInitialized) {
     mNSSInitialized = false;
 
     PK11_SetPasswordFunc((PK11PasswordFunc)nullptr);
 
     Preferences::RemoveObserver(this, "security.");
 
+#ifdef XP_WIN
+    mFamilySafetyRoot = nullptr;
+    mEnterpriseRoots = nullptr;
+#endif
+
 #ifndef MOZ_NO_SMART_CARDS
     ShutdownSmartCardThreads();
 #endif
     SSL_ClearSessionCache();
     // TLSServerSocket may be run with the session cache enabled. This ensures
     // those resources are cleaned up.
     Unused << SSL_ShutdownServerSessionIDCache();
     UnloadLoadableRoots();
@@ -1795,16 +2017,18 @@ nsNSSComponent::Observe(nsISupports* aSu
       mTestBuiltInRootHash = Preferences::GetString("security.test.built_in_root_hash");
 #endif // DEBUG
     } else if (prefName.Equals(kFamilySafetyModePref)) {
       MaybeEnableFamilySafetyCompatibility();
     } else if (prefName.EqualsLiteral("security.content.signature.root_hash")) {
       MutexAutoLock lock(mutex);
       mContentSigningRootHash =
         Preferences::GetString("security.content.signature.root_hash");
+    } else if (prefName.Equals(kEnterpriseRootModePref)) {
+      MaybeImportEnterpriseRoots();
     } else {
       clearSessionCache = false;
     }
     if (clearSessionCache)
       SSL_ClearSessionCache();
   }
 
   return NS_OK;
--- a/security/manager/ssl/nsNSSComponent.h
+++ b/security/manager/ssl/nsNSSComponent.h
@@ -2,28 +2,35 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _nsNSSComponent_h_
 #define _nsNSSComponent_h_
 
+#include "ScopedNSSTypes.h"
+#include "SharedCertVerifier.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
+#include "nsIObserver.h"
 #include "nsIStringBundle.h"
-#include "nsIObserver.h"
 #include "nsNSSCallbacks.h"
-#include "SharedCertVerifier.h"
 #include "prerror.h"
 #include "sslt.h"
 
+#ifdef XP_WIN
+#include "windows.h" // this needs to be before the following includes
+#include "wincrypt.h"
+#endif // XP_WIN
+
 class nsIDOMWindow;
 class nsIPrompt;
+class nsIX509CertList;
 class SmartCardThreadList;
 
 namespace mozilla { namespace psm {
 
 MOZ_MUST_USE
   ::already_AddRefed<mozilla::psm::SharedCertVerifier>
   GetDefaultCertVerifier();
 
@@ -82,16 +89,20 @@ public:
   NS_IMETHOD IsNSSInitialized(bool* initialized) = 0;
 
 #ifdef DEBUG
   NS_IMETHOD IsCertTestBuiltInRoot(CERTCertificate* cert, bool& result) = 0;
 #endif
 
   NS_IMETHOD IsCertContentSigningRoot(CERTCertificate* cert, bool& result) = 0;
 
+#ifdef XP_WIN
+  NS_IMETHOD GetEnterpriseRoots(nsIX509CertList** enterpriseRoots) = 0;
+#endif
+
   virtual ::already_AddRefed<mozilla::psm::SharedCertVerifier>
     GetDefaultCertVerifier() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsINSSComponent, NS_INSSCOMPONENT_IID)
 
 class nsNSSShutDownList;
 class nsCertVerificationThread;
@@ -136,16 +147,20 @@ public:
   NS_IMETHOD IsNSSInitialized(bool* initialized) override;
 
 #ifdef DEBUG
   NS_IMETHOD IsCertTestBuiltInRoot(CERTCertificate* cert, bool& result) override;
 #endif
 
   NS_IMETHOD IsCertContentSigningRoot(CERTCertificate* cert, bool& result) override;
 
+#ifdef XP_WIN
+  NS_IMETHOD GetEnterpriseRoots(nsIX509CertList** enterpriseRoots) override;
+#endif
+
   ::already_AddRefed<mozilla::psm::SharedCertVerifier>
     GetDefaultCertVerifier() override;
 
   // The following two methods are thread-safe.
   static bool AreAnyWeakCiphersEnabled();
   static void UseWeakCiphersOnSocket(PRFileDesc* fd);
 
   static void FillTLSVersionRange(SSLVersionRange& rangeOut,
@@ -166,16 +181,30 @@ private:
                             const mozilla::MutexAutoLock& lock);
   nsresult setEnabledTLSVersions();
   nsresult InitializePIPNSSBundle();
   nsresult ConfigureInternalPKCS11Token();
   nsresult RegisterObservers();
 
   void DoProfileBeforeChange();
 
+  void MaybeEnableFamilySafetyCompatibility();
+  void MaybeImportEnterpriseRoots();
+#ifdef XP_WIN
+  nsresult MaybeImportFamilySafetyRoot(PCCERT_CONTEXT certificate,
+                                       bool& wasFamilySafetyRoot);
+  nsresult LoadFamilySafetyRoot();
+  void UnloadFamilySafetyRoot();
+
+  void UnloadEnterpriseRoots();
+
+  mozilla::UniqueCERTCertificate mFamilySafetyRoot;
+  mozilla::UniqueCERTCertList mEnterpriseRoots;
+#endif // XP_WIN
+
   mozilla::Mutex mutex;
 
   nsCOMPtr<nsIStringBundle> mPIPNSSBundle;
   nsCOMPtr<nsIStringBundle> mNSSErrorsBundle;
   bool mNSSInitialized;
   static int mInstanceCount;
 #ifndef MOZ_NO_SMART_CARDS
   SmartCardThreadList* mThreadList;
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_enterprise_roots.js
@@ -0,0 +1,58 @@
+// -*- 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";
+
+// Tests enterprise root certificate support. When configured to do so, the
+// platform will attempt to find and import enterprise root certificates. This
+// feature is specific to Windows.
+
+do_get_profile(); // must be called before getting nsIX509CertDB
+
+function check_no_enterprise_roots_imported(certDB, dbKey = undefined) {
+  let enterpriseRoots = certDB.getEnterpriseRoots();
+  equal(enterpriseRoots, null, "should not have imported any enterprise roots");
+  if (dbKey) {
+    let cert = certDB.findCertByDBKey(dbKey);
+    // If the garbage-collector hasn't run, there may be reachable copies of
+    // imported enterprise root certificates. If so, they shouldn't be trusted
+    // to issue TLS server auth certificates.
+    if (cert) {
+      ok(!certDB.isCertTrusted(cert, Ci.nsIX509Cert.CA_CERT,
+                               Ci.nsIX509CertDB.TRUSTED_SSL),
+         "previously-imported enterprise root shouldn't be trusted to issue " +
+         "TLS server auth certificates");
+    }
+  }
+}
+
+function check_some_enterprise_roots_imported(certDB) {
+  let enterpriseRoots = certDB.getEnterpriseRoots();
+  notEqual(enterpriseRoots, null, "should have imported some enterprise roots");
+  let enumerator = enterpriseRoots.getEnumerator();
+  let foundNonBuiltIn = false;
+  let savedDBKey = null;
+  while (enumerator.hasMoreElements()) {
+    let cert = enumerator.getNext().QueryInterface(Ci.nsIX509Cert);
+    if (!cert.isBuiltInRoot && !savedDBKey) {
+      foundNonBuiltIn = true;
+      savedDBKey = cert.dbKey;
+      do_print("saving dbKey from " + cert.commonName);
+    }
+  }
+  ok(foundNonBuiltIn, "should have found non-built-in root");
+  return savedDBKey;
+}
+
+function run_test() {
+  let certDB = Cc["@mozilla.org/security/x509certdb;1"]
+                 .getService(Ci.nsIX509CertDB);
+  Services.prefs.setBoolPref("security.enterprise_roots.enabled", false);
+  check_no_enterprise_roots_imported(certDB);
+  Services.prefs.setBoolPref("security.enterprise_roots.enabled", true);
+  let savedDBKey = check_some_enterprise_roots_imported(certDB);
+  Services.prefs.setBoolPref("security.enterprise_roots.enabled", false);
+  check_no_enterprise_roots_imported(certDB, savedDBKey);
+}
--- a/security/manager/ssl/tests/unit/xpcshell.ini
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -52,16 +52,18 @@ run-sequentially = hardcoded ports
 [test_cert_version.js]
 [test_certDB_import.js]
 [test_certDB_import_pkcs12.js]
 [test_certviewer_invalid_oids.js]
 skip-if = toolkit == 'android' || buildapp == 'b2g'
 [test_constructX509FromBase64.js]
 [test_content_signing.js]
 [test_datasignatureverifier.js]
+[test_enterprise_roots.js]
+skip-if = os != 'win' # tests a Windows-specific feature
 [test_ev_certs.js]
 run-sequentially = hardcoded ports
 [test_getchain.js]
 [test_hash_algorithms.js]
 [test_hash_algorithms_wrap.js]
 # bug 1124289 - run_test_in_child violates the sandbox on b2g and android
 skip-if = toolkit == 'android' || toolkit == 'gonk'
 [test_hmac.js]
--- a/security/sandbox/mac/Sandbox.mm
+++ b/security/sandbox/mac/Sandbox.mm
@@ -17,24 +17,127 @@
 
 // XXX There are currently problems with the /usr/include/sandbox.h file on
 // some/all of the Macs in Mozilla's build system.  For the time being (until
 // this problem is resolved), we refer directly to what we need from it,
 // rather than including it here.
 extern "C" int sandbox_init(const char *profile, uint64_t flags, char **errorbuf);
 extern "C" void sandbox_free_error(char *errorbuf);
 
+#define MAC_OS_X_VERSION_10_0_HEX  0x00001000
+#define MAC_OS_X_VERSION_10_6_HEX  0x00001060
+#define MAC_OS_X_VERSION_10_7_HEX  0x00001070
+#define MAC_OS_X_VERSION_10_8_HEX  0x00001080
+#define MAC_OS_X_VERSION_10_9_HEX  0x00001090
+#define MAC_OS_X_VERSION_10_10_HEX 0x000010A0
+
+// Note about "major", "minor" and "bugfix" in the following code:
+//
+// The code decomposes an OS X version number into these components, and in
+// doing so follows Apple's terminology in Gestalt.h.  But this is very
+// misleading, because in other contexts Apple uses the "minor" component of
+// an OS X version number to indicate a "major" release (for example the "9"
+// in OS X 10.9.5), and the "bugfix" component to indicate a "minor" release
+// (for example the "5" in OS X 10.9.5).
+
+class OSXVersion {
+public:
+  static bool OnLionOrLater();
+  static int32_t OSXVersionMinor();
+
+private:
+  static void GetSystemVersion(int32_t& aMajor, int32_t& aMinor, int32_t& aBugFix);
+  static int32_t GetVersionNumber();
+  static int32_t mOSXVersion;
+};
+
+int32_t OSXVersion::mOSXVersion = -1;
+
+bool OSXVersion::OnLionOrLater()
+{
+  return (GetVersionNumber() >= MAC_OS_X_VERSION_10_7_HEX);
+}
+
+int32_t OSXVersion::OSXVersionMinor()
+{
+  return (GetVersionNumber() & 0xF0) >> 4;
+}
+
+void
+OSXVersion::GetSystemVersion(int32_t& aMajor, int32_t& aMinor, int32_t& aBugFix)
+{
+  SInt32 major = 0, minor = 0, bugfix = 0;
+
+  CFURLRef url =
+    CFURLCreateWithString(kCFAllocatorDefault,
+                          CFSTR("file:///System/Library/CoreServices/SystemVersion.plist"),
+                          NULL);
+  CFReadStreamRef stream =
+    CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
+  CFReadStreamOpen(stream);
+  CFDictionaryRef sysVersionPlist = (CFDictionaryRef)
+    CFPropertyListCreateWithStream(kCFAllocatorDefault,
+                                   stream, 0, kCFPropertyListImmutable,
+                                   NULL, NULL);
+  CFReadStreamClose(stream);
+  CFRelease(stream);
+  CFRelease(url);
+
+  CFStringRef versionString = (CFStringRef)
+    CFDictionaryGetValue(sysVersionPlist, CFSTR("ProductVersion"));
+  CFArrayRef versions =
+    CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault,
+                                           versionString, CFSTR("."));
+  CFIndex count = CFArrayGetCount(versions);
+  if (count > 0) {
+    CFStringRef component = (CFStringRef) CFArrayGetValueAtIndex(versions, 0);
+    major = CFStringGetIntValue(component);
+    if (count > 1) {
+      component = (CFStringRef) CFArrayGetValueAtIndex(versions, 1);
+      minor = CFStringGetIntValue(component);
+      if (count > 2) {
+        component = (CFStringRef) CFArrayGetValueAtIndex(versions, 2);
+        bugfix = CFStringGetIntValue(component);
+      }
+    }
+  }
+  CFRelease(sysVersionPlist);
+  CFRelease(versions);
+
+  // If 'major' isn't what we expect, assume the oldest version of OS X we
+  // currently support (OS X 10.6).
+  if (major != 10) {
+    aMajor = 10; aMinor = 6; aBugFix = 0;
+  } else {
+    aMajor = major; aMinor = minor; aBugFix = bugfix;
+  }
+}
+
+int32_t
+OSXVersion::GetVersionNumber()
+{
+  if (mOSXVersion == -1) {
+    int32_t major, minor, bugfix;
+    GetSystemVersion(major, minor, bugfix);
+    mOSXVersion = MAC_OS_X_VERSION_10_0_HEX + (minor << 4) + bugfix;
+  }
+  return mOSXVersion;
+}
+
 namespace mozilla {
 
 static const char pluginSandboxRules[] =
   "(version 1)\n"
   "(deny default)\n"
   "(allow signal (target self))\n"
   "(allow sysctl-read)\n"
-  "(allow iokit-open (iokit-user-client-class \"IOHIDParamUserClient\"))\n"
+  // Illegal syntax on OS X 10.6, needed on 10.7 and up.
+  "%s(allow iokit-open (iokit-user-client-class \"IOHIDParamUserClient\"))\n"
+  // Needed only on OS X 10.6
+  "%s(allow file-read-data (literal \"%s\"))\n"
   "(allow mach-lookup\n"
   "    (global-name \"com.apple.cfprefsd.agent\")\n"
   "    (global-name \"com.apple.cfprefsd.daemon\")\n"
   "    (global-name \"com.apple.system.opendirectoryd.libinfo\")\n"
   "    (global-name \"com.apple.system.logger\")\n"
   "    (global-name \"com.apple.ls.boxd\"))\n"
   "(allow file-read*\n"
   "    (regex #\"^/etc$\")\n"
@@ -49,316 +152,328 @@ static const char pluginSandboxRules[] =
 
 static const char widevinePluginSandboxRulesAddend[] =
   "(allow mach-lookup (global-name \"com.apple.windowserver.active\"))\n";
 
 static const char contentSandboxRules[] =
   "(version 1)\n"
   "\n"
   "(define sandbox-level %d)\n"
+  "(define macosMinorVersion %d)\n"
   "(define appPath \"%s\")\n"
   "(define appBinaryPath \"%s\")\n"
   "(define appDir \"%s\")\n"
   "(define appTempDir \"%s\")\n"
   "(define home-path \"%s\")\n"
   "\n"
   "(import \"/System/Library/Sandbox/Profiles/system.sb\")\n"
   "\n"
-  "(begin\n"
-  "  (deny default)\n"
-  "  (debug deny)\n"
-  "\n"
-  "  (define resolving-literal literal)\n"
-  "  (define resolving-subpath subpath)\n"
-  "  (define resolving-regex regex)\n"
-  "\n"
-  "  (define container-path appPath)\n"
-  "  (define appdir-path appDir)\n"
-  "  (define var-folders-re \"^/private/var/folders/[^/][^/]\")\n"
-  "  (define var-folders2-re (string-append var-folders-re \"/[^/]+/[^/]\"))\n"
+  "(if \n"
+  "  (or\n"
+  "    (< macosMinorVersion 9)\n"
+  "    (< sandbox-level 1))\n"
+  "  (allow default)\n"
+  "  (begin\n"
+  "    (deny default)\n"
+  "    (debug deny)\n"
   "\n"
-  "  (define (home-regex home-relative-regex)\n"
-  "    (resolving-regex (string-append \"^\" (regex-quote home-path) home-relative-regex)))\n"
-  "  (define (home-subpath home-relative-subpath)\n"
-  "    (resolving-subpath (string-append home-path home-relative-subpath)))\n"
-  "  (define (home-literal home-relative-literal)\n"
-  "    (resolving-literal (string-append home-path home-relative-literal)))\n"
+  "    (define resolving-literal literal)\n"
+  "    (define resolving-subpath subpath)\n"
+  "    (define resolving-regex regex)\n"
   "\n"
-  "  (define (container-regex container-relative-regex)\n"
-  "    (resolving-regex (string-append \"^\" (regex-quote container-path) container-relative-regex)))\n"
-  "  (define (container-subpath container-relative-subpath)\n"
-  "    (resolving-subpath (string-append container-path container-relative-subpath)))\n"
-  "  (define (container-literal container-relative-literal)\n"
-  "    (resolving-literal (string-append container-path container-relative-literal)))\n"
+  "    (define container-path appPath)\n"
+  "    (define appdir-path appDir)\n"
+  "    (define var-folders-re \"^/private/var/folders/[^/][^/]\")\n"
+  "    (define var-folders2-re (string-append var-folders-re \"/[^/]+/[^/]\"))\n"
+  "\n"
+  "    (define (home-regex home-relative-regex)\n"
+  "      (resolving-regex (string-append \"^\" (regex-quote home-path) home-relative-regex)))\n"
+  "    (define (home-subpath home-relative-subpath)\n"
+  "      (resolving-subpath (string-append home-path home-relative-subpath)))\n"
+  "    (define (home-literal home-relative-literal)\n"
+  "      (resolving-literal (string-append home-path home-relative-literal)))\n"
   "\n"
-  "  (define (var-folders-regex var-folders-relative-regex)\n"
-  "    (resolving-regex (string-append var-folders-re var-folders-relative-regex)))\n"
-  "  (define (var-folders2-regex var-folders2-relative-regex)\n"
-  "    (resolving-regex (string-append var-folders2-re var-folders2-relative-regex)))\n"
+  "    (define (container-regex container-relative-regex)\n"
+  "      (resolving-regex (string-append \"^\" (regex-quote container-path) container-relative-regex)))\n"
+  "    (define (container-subpath container-relative-subpath)\n"
+  "      (resolving-subpath (string-append container-path container-relative-subpath)))\n"
+  "    (define (container-literal container-relative-literal)\n"
+  "      (resolving-literal (string-append container-path container-relative-literal)))\n"
   "\n"
-  "  (define (appdir-regex appdir-relative-regex)\n"
-  "    (resolving-regex (string-append \"^\" (regex-quote appdir-path) appdir-relative-regex)))\n"
-  "  (define (appdir-subpath appdir-relative-subpath)\n"
-  "    (resolving-subpath (string-append appdir-path appdir-relative-subpath)))\n"
-  "  (define (appdir-literal appdir-relative-literal)\n"
-  "    (resolving-literal (string-append appdir-path appdir-relative-literal)))\n"
+  "    (define (var-folders-regex var-folders-relative-regex)\n"
+  "      (resolving-regex (string-append var-folders-re var-folders-relative-regex)))\n"
+  "    (define (var-folders2-regex var-folders2-relative-regex)\n"
+  "      (resolving-regex (string-append var-folders2-re var-folders2-relative-regex)))\n"
   "\n"
-  "  (define (allow-shared-preferences-read domain)\n"
-  "        (begin\n"
-  "          (if (defined? `user-preference-read)\n"
-  "            (allow user-preference-read (preference-domain domain)))\n"
-  "          (allow file-read*\n"
-  "                 (home-literal (string-append \"/Library/Preferences/\" domain \".plist\"))\n"
-  "                 (home-regex (string-append \"/Library/Preferences/ByHost/\" (regex-quote domain) \"\\..*\\.plist$\")))\n"
-  "          ))\n"
+  "    (define (appdir-regex appdir-relative-regex)\n"
+  "      (resolving-regex (string-append \"^\" (regex-quote appdir-path) appdir-relative-regex)))\n"
+  "    (define (appdir-subpath appdir-relative-subpath)\n"
+  "      (resolving-subpath (string-append appdir-path appdir-relative-subpath)))\n"
+  "    (define (appdir-literal appdir-relative-literal)\n"
+  "      (resolving-literal (string-append appdir-path appdir-relative-literal)))\n"
   "\n"
-  "  (define (allow-shared-list domain)\n"
-  "    (allow file-read*\n"
-  "           (home-regex (string-append \"/Library/Preferences/\" (regex-quote domain)))))\n"
+  "    (define (allow-shared-preferences-read domain)\n"
+  "          (begin\n"
+  "            (if (defined? `user-preference-read)\n"
+  "              (allow user-preference-read (preference-domain domain)))\n"
+  "            (allow file-read*\n"
+  "                   (home-literal (string-append \"/Library/Preferences/\" domain \".plist\"))\n"
+  "                   (home-regex (string-append \"/Library/Preferences/ByHost/\" (regex-quote domain) \"\\..*\\.plist$\")))\n"
+  "            ))\n"
   "\n"
-  "  (allow file-read-metadata)\n"
+  "    (define (allow-shared-list domain)\n"
+  "      (allow file-read*\n"
+  "             (home-regex (string-append \"/Library/Preferences/\" (regex-quote domain)))))\n"
   "\n"
-  "  (allow ipc-posix-shm\n"
-  "      (ipc-posix-name-regex \"^/tmp/com.apple.csseed:\")\n"
-  "      (ipc-posix-name-regex \"^CFPBS:\")\n"
-  "      (ipc-posix-name-regex \"^AudioIO\"))\n"
+  "    (allow file-read-metadata)\n"
+  "\n"
+  "    (allow ipc-posix-shm\n"
+  "        (ipc-posix-name-regex \"^/tmp/com.apple.csseed:\")\n"
+  "        (ipc-posix-name-regex \"^CFPBS:\")\n"
+  "        (ipc-posix-name-regex \"^AudioIO\"))\n"
   "\n"
-  "  (allow file-read-metadata\n"
-  "      (literal \"/home\")\n"
-  "      (literal \"/net\")\n"
-  "      (regex \"^/private/tmp/KSInstallAction\\.\")\n"
-  "      (var-folders-regex \"/\")\n"
-  "      (home-subpath \"/Library\"))\n"
+  "    (allow file-read-metadata\n"
+  "        (literal \"/home\")\n"
+  "        (literal \"/net\")\n"
+  "        (regex \"^/private/tmp/KSInstallAction\\.\")\n"
+  "        (var-folders-regex \"/\")\n"
+  "        (home-subpath \"/Library\"))\n"
   "\n"
-  "  (allow signal (target self))\n"
-  "  (allow job-creation (literal \"/Library/CoreMediaIO/Plug-Ins/DAL\"))\n"
-  "  (allow iokit-set-properties (iokit-property \"IOAudioControlValue\"))\n"
+  "    (allow signal (target self))\n"
+  "    (allow job-creation (literal \"/Library/CoreMediaIO/Plug-Ins/DAL\"))\n"
+  "    (allow iokit-set-properties (iokit-property \"IOAudioControlValue\"))\n"
   "\n"
-  "  (allow mach-lookup\n"
-  "      (global-name \"com.apple.coreservices.launchservicesd\")\n"
-  "      (global-name \"com.apple.coreservices.appleevents\")\n"
-  "      (global-name \"com.apple.pasteboard.1\")\n"
-  "      (global-name \"com.apple.window_proxies\")\n"
-  "      (global-name \"com.apple.windowserver.active\")\n"
-  "      (global-name \"com.apple.audio.coreaudiod\")\n"
-  "      (global-name \"com.apple.audio.audiohald\")\n"
-  "      (global-name \"com.apple.PowerManagement.control\")\n"
-  "      (global-name \"com.apple.cmio.VDCAssistant\")\n"
-  "      (global-name \"com.apple.SystemConfiguration.configd\")\n"
-  "      (global-name \"com.apple.iconservices\")\n"
-  "      (global-name \"com.apple.cookied\")\n"
-  "      (global-name \"com.apple.printuitool.agent\")\n"
-  "      (global-name \"com.apple.printtool.agent\")\n"
-  "      (global-name \"com.apple.cache_delete\")\n"
-  "      (global-name \"com.apple.pluginkit.pkd\")\n"
-  "      (global-name \"com.apple.bird\")\n"
-  "      (global-name \"com.apple.ocspd\")\n"
-  "      (global-name \"com.apple.cmio.AppleCameraAssistant\")\n"
-  "      (global-name \"com.apple.DesktopServicesHelper\")\n"
-  "      (global-name \"com.apple.printtool.daemon\"))\n"
+  "    (allow mach-lookup\n"
+  "        (global-name \"com.apple.coreservices.launchservicesd\")\n"
+  "        (global-name \"com.apple.coreservices.appleevents\")\n"
+  "        (global-name \"com.apple.pasteboard.1\")\n"
+  "        (global-name \"com.apple.window_proxies\")\n"
+  "        (global-name \"com.apple.windowserver.active\")\n"
+  "        (global-name \"com.apple.audio.coreaudiod\")\n"
+  "        (global-name \"com.apple.audio.audiohald\")\n"
+  "        (global-name \"com.apple.PowerManagement.control\")\n"
+  "        (global-name \"com.apple.cmio.VDCAssistant\")\n"
+  "        (global-name \"com.apple.SystemConfiguration.configd\")\n"
+  "        (global-name \"com.apple.iconservices\")\n"
+  "        (global-name \"com.apple.cookied\")\n"
+  "        (global-name \"com.apple.printuitool.agent\")\n"
+  "        (global-name \"com.apple.printtool.agent\")\n"
+  "        (global-name \"com.apple.cache_delete\")\n"
+  "        (global-name \"com.apple.pluginkit.pkd\")\n"
+  "        (global-name \"com.apple.bird\")\n"
+  "        (global-name \"com.apple.ocspd\")\n"
+  "        (global-name \"com.apple.cmio.AppleCameraAssistant\")\n"
+  "        (global-name \"com.apple.DesktopServicesHelper\")\n"
+  "        (global-name \"com.apple.printtool.daemon\"))\n"
   "\n"
-  "  (allow iokit-open\n"
-  "      (iokit-user-client-class \"IOHIDParamUserClient\")\n"
-  "      (iokit-user-client-class \"IOAudioControlUserClient\")\n"
-  "      (iokit-user-client-class \"IOAudioEngineUserClient\")\n"
-  "      (iokit-user-client-class \"IGAccelDevice\")\n"
-  "      (iokit-user-client-class \"nvDevice\")\n"
-  "      (iokit-user-client-class \"nvSharedUserClient\")\n"
-  "      (iokit-user-client-class \"nvFermiGLContext\")\n"
-  "      (iokit-user-client-class \"IGAccelGLContext\")\n"
-  "      (iokit-user-client-class \"IGAccelSharedUserClient\")\n"
-  "      (iokit-user-client-class \"IGAccelVideoContextMain\")\n"
-  "      (iokit-user-client-class \"IGAccelVideoContextMedia\")\n"
-  "      (iokit-user-client-class \"IGAccelVideoContextVEBox\")\n"
-  "      (iokit-user-client-class \"RootDomainUserClient\")\n"
-  "      (iokit-user-client-class \"IOUSBDeviceUserClientV2\")\n"
-  "      (iokit-user-client-class \"IOUSBInterfaceUserClientV2\"))\n"
+  "    (allow iokit-open\n"
+  "        (iokit-user-client-class \"IOHIDParamUserClient\")\n"
+  "        (iokit-user-client-class \"IOAudioControlUserClient\")\n"
+  "        (iokit-user-client-class \"IOAudioEngineUserClient\")\n"
+  "        (iokit-user-client-class \"IGAccelDevice\")\n"
+  "        (iokit-user-client-class \"nvDevice\")\n"
+  "        (iokit-user-client-class \"nvSharedUserClient\")\n"
+  "        (iokit-user-client-class \"nvFermiGLContext\")\n"
+  "        (iokit-user-client-class \"IGAccelGLContext\")\n"
+  "        (iokit-user-client-class \"IGAccelSharedUserClient\")\n"
+  "        (iokit-user-client-class \"IGAccelVideoContextMain\")\n"
+  "        (iokit-user-client-class \"IGAccelVideoContextMedia\")\n"
+  "        (iokit-user-client-class \"IGAccelVideoContextVEBox\")\n"
+  "        (iokit-user-client-class \"RootDomainUserClient\")\n"
+  "        (iokit-user-client-class \"IOUSBDeviceUserClientV2\")\n"
+  "        (iokit-user-client-class \"IOUSBInterfaceUserClientV2\"))\n"
   "\n"
   "; depending on systems, the 1st, 2nd or both rules are necessary\n"
-  "  (allow-shared-preferences-read \"com.apple.HIToolbox\")\n"
-  "  (allow file-read-data (literal \"/Library/Preferences/com.apple.HIToolbox.plist\"))\n"
+  "    (allow-shared-preferences-read \"com.apple.HIToolbox\")\n"
+  "    (allow file-read-data (literal \"/Library/Preferences/com.apple.HIToolbox.plist\"))\n"
   "\n"
-  "  (allow-shared-preferences-read \"com.apple.ATS\")\n"
-  "  (allow file-read-data (literal \"/Library/Preferences/.GlobalPreferences.plist\"))\n"
+  "    (allow-shared-preferences-read \"com.apple.ATS\")\n"
+  "    (allow file-read-data (literal \"/Library/Preferences/.GlobalPreferences.plist\"))\n"
   "\n"
-  "  (allow file-read*\n"
-  "      (subpath \"/Library/Fonts\")\n"
-  "      (subpath \"/Library/Audio/Plug-Ins\")\n"
-  "      (subpath \"/Library/CoreMediaIO/Plug-Ins/DAL\")\n"
-  "      (subpath \"/Library/Spelling\")\n"
-  "      (subpath \"/private/etc/cups/ppd\")\n"
-  "      (subpath \"/private/var/run/cupsd\")\n"
-  "      (literal \"/\")\n"
-  "      (literal \"/private/tmp\")\n"
-  "      (literal \"/private/var/tmp\")\n"
+  "    (allow file-read*\n"
+  "        (subpath \"/Library/Fonts\")\n"
+  "        (subpath \"/Library/Audio/Plug-Ins\")\n"
+  "        (subpath \"/Library/CoreMediaIO/Plug-Ins/DAL\")\n"
+  "        (subpath \"/Library/Spelling\")\n"
+  "        (subpath \"/private/etc/cups/ppd\")\n"
+  "        (subpath \"/private/var/run/cupsd\")\n"
+  "        (literal \"/\")\n"
+  "        (literal \"/private/tmp\")\n"
+  "        (literal \"/private/var/tmp\")\n"
   "\n"
-  "      (home-literal \"/.CFUserTextEncoding\")\n"
-  "      (home-literal \"/Library/Preferences/com.apple.DownloadAssessment.plist\")\n"
-  "      (home-subpath \"/Library/Colors\")\n"
-  "      (home-subpath \"/Library/Fonts\")\n"
-  "      (home-subpath \"/Library/FontCollections\")\n"
-  "      (home-subpath \"/Library/Keyboard Layouts\")\n"
-  "      (home-subpath \"/Library/Input Methods\")\n"
-  "      (home-subpath \"/Library/PDF Services\")\n"
-  "      (home-subpath \"/Library/Spelling\")\n"
+  "        (home-literal \"/.CFUserTextEncoding\")\n"
+  "        (home-literal \"/Library/Preferences/com.apple.DownloadAssessment.plist\")\n"
+  "        (home-subpath \"/Library/Colors\")\n"
+  "        (home-subpath \"/Library/Fonts\")\n"
+  "        (home-subpath \"/Library/FontCollections\")\n"
+  "        (home-subpath \"/Library/Keyboard Layouts\")\n"
+  "        (home-subpath \"/Library/Input Methods\")\n"
+  "        (home-subpath \"/Library/PDF Services\")\n"
+  "        (home-subpath \"/Library/Spelling\")\n"
   "\n"
-  "      (subpath appdir-path)\n"
+  "        (subpath appdir-path)\n"
   "\n"
-  "      (literal appPath)\n"
-  "      (literal appBinaryPath))\n"
+  "        (literal appPath)\n"
+  "        (literal appBinaryPath))\n"
   "\n"
-  "  (allow-shared-list \"org.mozilla.plugincontainer\")\n"
+  "    (allow-shared-list \"org.mozilla.plugincontainer\")\n"
   "\n"
   "; the following 2 rules should be removed when microphone and camera access\n"
   "; are brokered through the content process\n"
-  "  (allow device-microphone)\n"
-  "  (allow device-camera)\n"
+  "    (allow device-microphone)\n"
+  "    (allow device-camera)\n"
   "\n"
-  "  (allow file* (var-folders2-regex \"/com\\.apple\\.IntlDataCache\\.le$\"))\n"
-  "  (allow file-read*\n"
-  "      (var-folders2-regex \"/com\\.apple\\.IconServices/\")\n"
-  "      (var-folders2-regex \"/[^/]+\\.mozrunner/extensions/[^/]+/chrome/[^/]+/content/[^/]+\\.j(s|ar)$\"))\n"
+  "    (allow file* (var-folders2-regex \"/com\\.apple\\.IntlDataCache\\.le$\"))\n"
+  "    (allow file-read*\n"
+  "        (var-folders2-regex \"/com\\.apple\\.IconServices/\")\n"
+  "        (var-folders2-regex \"/[^/]+\\.mozrunner/extensions/[^/]+/chrome/[^/]+/content/[^/]+\\.j(s|ar)$\"))\n"
   "\n"
-  "  (allow file-write* (var-folders2-regex \"/org\\.chromium\\.[a-zA-Z0-9]*$\"))\n"
-  "  (allow file-read*\n"
-  "      (home-regex \"/Library/Application Support/[^/]+/Extensions/[^/]/\")\n"
-  "      (resolving-regex \"/Library/Application Support/[^/]+/Extensions/[^/]/\")\n"
-  "      (home-regex \"/Library/Application Support/Firefox/Profiles/[^/]+/extensions/\")\n"
-  "      (home-regex \"/Library/Application Support/Firefox/Profiles/[^/]+/weave/\"))\n"
+  "    (allow file-write* (var-folders2-regex \"/org\\.chromium\\.[a-zA-Z0-9]*$\"))\n"
+  "    (allow file-read*\n"
+  "        (home-regex \"/Library/Application Support/[^/]+/Extensions/[^/]/\")\n"
+  "        (resolving-regex \"/Library/Application Support/[^/]+/Extensions/[^/]/\")\n"
+  "        (home-regex \"/Library/Application Support/Firefox/Profiles/[^/]+/extensions/\")\n"
+  "        (home-regex \"/Library/Application Support/Firefox/Profiles/[^/]+/weave/\"))\n"
   "\n"
   "; the following rules should be removed when printing and \n"
   "; opening a file from disk are brokered through the main process\n"
-  "  (if\n"
-  "    (< sandbox-level 2)\n"
-  "    (allow file*\n"
-  "        (require-not\n"
-  "            (home-subpath \"/Library\")))\n"
-  "    (allow file*\n"
-  "        (require-all\n"
-  "            (subpath home-path)\n"
-  "            (require-not\n"
-  "                (home-subpath \"/Library\")))))\n"
+  "    (if\n"
+  "      (< sandbox-level 2)\n"
+  "      (allow file*\n"
+  "          (require-not\n"
+  "              (home-subpath \"/Library\")))\n"
+  "      (allow file*\n"
+  "          (require-all\n"
+  "              (subpath home-path)\n"
+  "              (require-not\n"
+  "                  (home-subpath \"/Library\")))))\n"
   "\n"
   "; printing\n"
-  "  (allow authorization-right-obtain\n"
-  "         (right-name \"system.print.operator\")\n"
-  "         (right-name \"system.printingmanager\"))\n"
-  "  (allow mach-lookup\n"
-  "         (global-name \"com.apple.printuitool.agent\")\n"
-  "         (global-name \"com.apple.printtool.agent\")\n"
-  "         (global-name \"com.apple.printtool.daemon\")\n"
-  "         (global-name \"com.apple.sharingd\")\n"
-  "         (global-name \"com.apple.metadata.mds\")\n"
-  "         (global-name \"com.apple.mtmd.xpc\")\n"
-  "         (global-name \"com.apple.FSEvents\")\n"
-  "         (global-name \"com.apple.locum\")\n"
-  "         (global-name \"com.apple.ImageCaptureExtension2.presence\"))\n"
-  "  (allow file-read*\n"
-  "         (home-literal \"/.cups/lpoptions\")\n"
-  "         (home-literal \"/.cups/client.conf\")\n"
-  "         (literal \"/private/etc/cups/lpoptions\")\n"
-  "         (literal \"/private/etc/cups/client.conf\")\n"
-  "         (subpath \"/private/etc/cups/ppd\")\n"
-  "         (literal \"/private/var/run/cupsd\"))\n"
-  "  (allow-shared-preferences-read \"org.cups.PrintingPrefs\")\n"
-  "  (allow-shared-preferences-read \"com.apple.finder\")\n"
-  "  (allow-shared-preferences-read \"com.apple.LaunchServices\")\n"
-  "  (allow-shared-preferences-read \".GlobalPreferences\")\n"
-  "  (allow network-outbound\n"
-  "      (literal \"/private/var/run/cupsd\")\n"
-  "      (literal \"/private/var/run/mDNSResponder\"))\n"
+  "    (allow authorization-right-obtain\n"
+  "           (right-name \"system.print.operator\")\n"
+  "           (right-name \"system.printingmanager\"))\n"
+  "    (allow mach-lookup\n"
+  "           (global-name \"com.apple.printuitool.agent\")\n"
+  "           (global-name \"com.apple.printtool.agent\")\n"
+  "           (global-name \"com.apple.printtool.daemon\")\n"
+  "           (global-name \"com.apple.sharingd\")\n"
+  "           (global-name \"com.apple.metadata.mds\")\n"
+  "           (global-name \"com.apple.mtmd.xpc\")\n"
+  "           (global-name \"com.apple.FSEvents\")\n"
+  "           (global-name \"com.apple.locum\")\n"
+  "           (global-name \"com.apple.ImageCaptureExtension2.presence\"))\n"
+  "    (allow file-read*\n"
+  "           (home-literal \"/.cups/lpoptions\")\n"
+  "           (home-literal \"/.cups/client.conf\")\n"
+  "           (literal \"/private/etc/cups/lpoptions\")\n"
+  "           (literal \"/private/etc/cups/client.conf\")\n"
+  "           (subpath \"/private/etc/cups/ppd\")\n"
+  "           (literal \"/private/var/run/cupsd\"))\n"
+  "    (allow-shared-preferences-read \"org.cups.PrintingPrefs\")\n"
+  "    (allow-shared-preferences-read \"com.apple.finder\")\n"
+  "    (allow-shared-preferences-read \"com.apple.LaunchServices\")\n"
+  "    (allow-shared-preferences-read \".GlobalPreferences\")\n"
+  "    (allow network-outbound\n"
+  "        (literal \"/private/var/run/cupsd\")\n"
+  "        (literal \"/private/var/run/mDNSResponder\"))\n"
   "\n"
   "; print preview\n"
-  "  (allow lsopen)\n"
-  "  (allow file-write* file-issue-extension (var-folders2-regex \"/\"))\n"
-  "  (allow file-read-xattr (literal \"/Applications/Preview.app\"))\n"
-  "  (allow mach-task-name)\n"
-  "  (allow mach-register)\n"
-  "  (allow file-read-data\n"
-  "      (regex \"^/Library/Printers/[^/]+/PDEs/[^/]+.plugin\")\n"
-  "      (subpath \"/Library/PDF Services\")\n"
-  "      (subpath \"/Applications/Preview.app\")\n"
-  "      (home-literal \"/Library/Preferences/com.apple.ServicesMenu.Services.plist\"))\n"
-  "  (allow mach-lookup\n"
-  "      (global-name \"com.apple.pbs.fetch_services\")\n"
-  "      (global-name \"com.apple.tsm.uiserver\")\n"
-  "      (global-name \"com.apple.ls.boxd\")\n"
-  "      (global-name \"com.apple.coreservices.quarantine-resolver\")\n"
-  "      (global-name-regex \"_OpenStep$\"))\n"
-  "  (allow appleevent-send\n"
-  "      (appleevent-destination \"com.apple.preview\")\n"
-  "      (appleevent-destination \"com.apple.imagecaptureextension2\"))\n"
+  "    (if (> macosMinorVersion 9)\n"
+  "        (allow lsopen))\n"
+  "    (allow file-write* file-issue-extension (var-folders2-regex \"/\"))\n"
+  "    (allow file-read-xattr (literal \"/Applications/Preview.app\"))\n"
+  "    (allow mach-task-name)\n"
+  "    (allow mach-register)\n"
+  "    (allow file-read-data\n"
+  "        (regex \"^/Library/Printers/[^/]+/PDEs/[^/]+.plugin\")\n"
+  "        (subpath \"/Library/PDF Services\")\n"
+  "        (subpath \"/Applications/Preview.app\")\n"
+  "        (home-literal \"/Library/Preferences/com.apple.ServicesMenu.Services.plist\"))\n"
+  "    (allow mach-lookup\n"
+  "        (global-name \"com.apple.pbs.fetch_services\")\n"
+  "        (global-name \"com.apple.tsm.uiserver\")\n"
+  "        (global-name \"com.apple.ls.boxd\")\n"
+  "        (global-name \"com.apple.coreservices.quarantine-resolver\")\n"
+  "        (global-name-regex \"_OpenStep$\"))\n"
+  "    (allow appleevent-send\n"
+  "        (appleevent-destination \"com.apple.preview\")\n"
+  "        (appleevent-destination \"com.apple.imagecaptureextension2\"))\n"
   "\n"
   "; accelerated graphics\n"
-  "  (allow-shared-preferences-read \"com.apple.opengl\")\n"
-  "  (allow-shared-preferences-read \"com.nvidia.OpenGL\")\n"
-  "  (allow mach-lookup\n"
-  "      (global-name \"com.apple.cvmsServ\"))\n"
-  "  (allow iokit-open\n"
-  "      (iokit-connection \"IOAccelerator\")\n"
-  "      (iokit-user-client-class \"IOAccelerationUserClient\")\n"
-  "      (iokit-user-client-class \"IOSurfaceRootUserClient\")\n"
-  "      (iokit-user-client-class \"IOSurfaceSendRight\")\n"
-  "      (iokit-user-client-class \"IOFramebufferSharedUserClient\")\n"
-  "      (iokit-user-client-class \"AppleSNBFBUserClient\")\n"
-  "      (iokit-user-client-class \"AGPMClient\")\n"
-  "      (iokit-user-client-class \"AppleGraphicsControlClient\")\n"
-  "      (iokit-user-client-class \"AppleGraphicsPolicyClient\"))\n"
+  "    (allow-shared-preferences-read \"com.apple.opengl\")\n"
+  "    (allow-shared-preferences-read \"com.nvidia.OpenGL\")\n"
+  "    (allow mach-lookup\n"
+  "        (global-name \"com.apple.cvmsServ\"))\n"
+  "    (allow iokit-open\n"
+  "        (iokit-connection \"IOAccelerator\")\n"
+  "        (iokit-user-client-class \"IOAccelerationUserClient\")\n"
+  "        (iokit-user-client-class \"IOSurfaceRootUserClient\")\n"
+  "        (iokit-user-client-class \"IOSurfaceSendRight\")\n"
+  "        (iokit-user-client-class \"IOFramebufferSharedUserClient\")\n"
+  "        (iokit-user-client-class \"AppleSNBFBUserClient\")\n"
+  "        (iokit-user-client-class \"AGPMClient\")\n"
+  "        (iokit-user-client-class \"AppleGraphicsControlClient\")\n"
+  "        (iokit-user-client-class \"AppleGraphicsPolicyClient\"))\n"
   "\n"
   "; bug 1153809\n"
-  "  (allow iokit-open\n"
-  "      (iokit-user-client-class \"NVDVDContextTesla\")\n"
-  "      (iokit-user-client-class \"Gen6DVDContext\"))\n"
+  "    (allow iokit-open\n"
+  "        (iokit-user-client-class \"NVDVDContextTesla\")\n"
+  "        (iokit-user-client-class \"Gen6DVDContext\"))\n"
   "\n"
   "; bug 1190032\n"
-  "  (allow file*\n"
-  "      (home-regex \"/Library/Caches/TemporaryItems/plugtmp.*\"))\n"
+  "    (allow file*\n"
+  "        (home-regex \"/Library/Caches/TemporaryItems/plugtmp.*\"))\n"
   "\n"
   "; bug 1201935\n"
-  "  (allow file-read*\n"
-  "      (home-subpath \"/Library/Caches/TemporaryItems\"))\n"
+  "    (allow file-read*\n"
+  "        (home-subpath \"/Library/Caches/TemporaryItems\"))\n"
   "\n"
   "; bug 1237847\n"
-  "  (allow file-read*\n"
-  "      (subpath appTempDir))\n"
-  "  (allow file-write*\n"
-  "      (subpath appTempDir))\n"
+  "    (allow file-read*\n"
+  "        (subpath appTempDir))\n"
+  "    (allow file-write*\n"
+  "        (subpath appTempDir))\n"
+  "  )\n"
   ")\n";
 
 bool StartMacSandbox(MacSandboxInfo aInfo, std::string &aErrorMessage)
 {
   char *profile = NULL;
   if (aInfo.type == MacSandboxType_Plugin) {
-    asprintf(&profile, pluginSandboxRules,
-             aInfo.pluginInfo.pluginBinaryPath.c_str(),
-             aInfo.appPath.c_str(),
-             aInfo.appBinaryPath.c_str());
+    if (OSXVersion::OnLionOrLater()) {
+      asprintf(&profile, pluginSandboxRules, "", ";",
+               aInfo.pluginInfo.pluginPath.c_str(),
+               aInfo.pluginInfo.pluginBinaryPath.c_str(),
+               aInfo.appPath.c_str(),
+               aInfo.appBinaryPath.c_str());
+    } else {
+      asprintf(&profile, pluginSandboxRules, ";", "",
+               aInfo.pluginInfo.pluginPath.c_str(),
+               aInfo.pluginInfo.pluginBinaryPath.c_str(),
+               aInfo.appPath.c_str(),
+               aInfo.appBinaryPath.c_str());
+    }
 
     if (profile &&
       aInfo.pluginInfo.type == MacSandboxPluginType_GMPlugin_EME_Widevine) {
       char *widevineProfile = NULL;
       asprintf(&widevineProfile, "%s%s", profile,
         widevinePluginSandboxRulesAddend);
       free(profile);
       profile = widevineProfile;
     }
   }
   else if (aInfo.type == MacSandboxType_Content) {
-    if (aInfo.level >= 1) {
-      asprintf(&profile, contentSandboxRules, aInfo.level,
-               aInfo.appPath.c_str(),
-               aInfo.appBinaryPath.c_str(),
-               aInfo.appDir.c_str(),
-               aInfo.appTempDir.c_str(),
-               getenv("HOME"));
-    } else {
-      fprintf(stderr,
-        "Content sandbox disabled due to sandbox level setting\n");
-      return (true);
-    }
+    asprintf(&profile, contentSandboxRules, aInfo.level,
+             OSXVersion::OSXVersionMinor(),
+             aInfo.appPath.c_str(),
+             aInfo.appBinaryPath.c_str(),
+             aInfo.appDir.c_str(),
+             aInfo.appTempDir.c_str(),
+             getenv("HOME"));
   }
   else {
     char *msg = NULL;
     asprintf(&msg, "Unexpected sandbox type %u", aInfo.type);
     if (msg) {
       aErrorMessage.assign(msg);
       free(msg);
     }
--- a/testing/marionette/client/marionette_driver/geckoinstance.py
+++ b/testing/marionette/client/marionette_driver/geckoinstance.py
@@ -200,17 +200,16 @@ class DesktopInstance(GeckoInstance):
         'browser.safebrowsing.forbiddenURIs.enabled': False,
         'browser.safebrowsing.malware.enabled': False,
         'browser.safebrowsing.blockedURIs.enabled': False,
         'browser.search.update': False,
         'browser.tabs.animate': False,
         'browser.tabs.warnOnClose': False,
         'browser.tabs.warnOnOpen': False,
         'browser.uitour.enabled': False,
-        'dom.report_all_js_exceptions': True,
         'extensions.getAddons.cache.enabled': False,
         'extensions.installDistroAddons': False,
         'extensions.showMismatchUI': False,
         'extensions.update.enabled': False,
         'extensions.update.notifyUser': False,
         'geo.provider.testing': True,
         'javascript.options.showInConsole': True,
         'privacy.trackingprotection.enabled': False,
--- a/testing/taskcluster/tasks/branches/base_job_flags.yml
+++ b/testing/taskcluster/tasks/branches/base_job_flags.yml
@@ -52,16 +52,20 @@ flags:
     mochitest-bc-e10s: /mochitest-browser-chrome-e10s.*/
     mochitest-browser-chrome: /mochitest-browser-chrome.*/
     mochitest-browser-chrome-e10s: /mochitest-browser-chrome-e10s.*/
     mochitest-chrome: /.*mochitest-chrome.*/
     mochitest-dt: /mochitest-devtools-chrome.*/
     mochitest-dt-e10s: /mochitest-devtools-chrome-e10s.*/
     mochitest-gl: /mochitest-webgl.*/
     mochitest-gl-e10s: /mochitest-webgl-e10s.*/
+    mochitest-gpu: /mochitest-gpu.*/
+    mochitest-gpu-e10s: /mochitest-gpu-e10s.*/
+    mochitest-clipboard: /mochitest-clipboard.*/
+    mochitest-clipboard-e10s: /mochitest-clipboard-e10s.*/
     mochitest-jetpack: /mochitest-jetpack.*/
     mochitest-media: /mochitest-media.*/
     mochitest-media-e10s: /mochitest-media-e10s.*/
     mochitest-vg: /mochitest-valgrind.*/
     reftest: /(plain-)?reftest.*/
     reftest-no-accel: /(plain-)?reftest-no-accel.*/
     reftests: /(plain-)?reftest.*/
     reftests-e10s: /(plain-)?reftest-e10s.*/
@@ -126,16 +130,20 @@ flags:
     - mochitest-devtools-chrome
     - mochitest-devtools-chrome-e10s
     - mochitest-e10s
     - mochitest-jetpack
     - mochitest-media
     - mochitest-media-e10s
     - mochitest-webgl
     - mochitest-webgl-e10s
+    - mochitest-gpu
+    - mochitest-gpu-e10s
+    - mochitest-clipboard
+    - mochitest-clipboard-e10s
     - mochitest-valgrind
     - mozmill
     - reftest
     - reftest-e10s
     - reftest-no-accel
     - reftest-no-accel-e10s
     - web-platform-tests
     - web-platform-tests-e10s
--- a/testing/taskcluster/tasks/branches/base_jobs.yml
+++ b/testing/taskcluster/tasks/branches/base_jobs.yml
@@ -377,16 +377,48 @@ tests:
   mochitest-webgl-e10s:
     allowed_build_tasks:
       tasks/builds/opt_linux64.yml:
         task: tasks/tests/fx_linux64_mochitest_gl_e10s_opt.yml
       tasks/builds/dbg_linux64.yml:
         task: tasks/tests/fx_linux64_mochitest_gl_e10s_dbg.yml
       tasks/builds/opt_linux64_pgo.yml:
         task: tasks/tests/fx_linux64_mochitest_gl_e10s_opt.yml
+  mochitest-gpu:
+    allowed_build_tasks:
+      tasks/builds/opt_linux64.yml:
+        task: tasks/tests/fx_linux64_mochitest_gpu_opt.yml
+      tasks/builds/dbg_linux64.yml:
+        task: tasks/tests/fx_linux64_mochitest_gpu_dbg.yml
+      tasks/builds/opt_linux64_pgo.yml:
+        task: tasks/tests/fx_linux64_mochitest_gpu_opt.yml
+  mochitest-gpu-e10s:
+    allowed_build_tasks:
+      tasks/builds/opt_linux64.yml:
+        task: tasks/tests/fx_linux64_mochitest_gpu_e10s_opt.yml
+      tasks/builds/dbg_linux64.yml:
+        task: tasks/tests/fx_linux64_mochitest_gpu_e10s_dbg.yml
+      tasks/builds/opt_linux64_pgo.yml:
+        task: tasks/tests/fx_linux64_mochitest_gpu_e10s_opt.yml
+  mochitest-clipboard:
+    allowed_build_tasks:
+      tasks/builds/opt_linux64.yml:
+        task: tasks/tests/fx_linux64_mochitest_clipboard_opt.yml
+      tasks/builds/dbg_linux64.yml:
+        task: tasks/tests/fx_linux64_mochitest_clipboard_dbg.yml
+      tasks/builds/opt_linux64_pgo.yml:
+        task: tasks/tests/fx_linux64_mochitest_clipboard_opt.yml
+  mochitest-clipboard-e10s:
+    allowed_build_tasks:
+      tasks/builds/opt_linux64.yml:
+        task: tasks/tests/fx_linux64_mochitest_clipboard_e10s_opt.yml
+      tasks/builds/dbg_linux64.yml:
+        task: tasks/tests/fx_linux64_mochitest_clipboard_e10s_dbg.yml
+      tasks/builds/opt_linux64_pgo.yml:
+        task: tasks/tests/fx_linux64_mochitest_clipboard_e10s_opt.yml
   reftest:
     allowed_build_tasks:
       tasks/builds/mulet_linux.yml:
         task: tasks/tests/mulet_reftests.yml
       tasks/builds/opt_linux64.yml:
         task: tasks/tests/fx_linux64_reftest_opt.yml
       tasks/builds/dbg_linux64.yml:
         task: tasks/tests/fx_linux64_reftest_dbg.yml
new file mode 100644
--- /dev/null
+++ b/testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard.yml
@@ -0,0 +1,34 @@
+---
+$inherits:
+  from: 'tasks/tests/fx_desktop_generic.yml'
+task:
+  payload:
+    capabilities:
+      devices:
+        loopbackVideo: true
+    command:
+      - --no-read-buildbot-config
+      - --installer-url={{build_url}}
+      - --test-packages-url={{test_packages_url}}
+      - --{{suite}}-suite={{flavor}}
+      - --total-chunk={{total_chunks}}
+      - --this-chunk={{chunk}}
+    env:
+        MOZHARNESS_SCRIPT: 'mozharness/scripts/desktop_unittest.py'
+        # TODO move linux_unittest.py to a platform specific config
+        MOZHARNESS_CONFIG: >
+          mozharness/configs/unittests/linux_unittest.py
+          mozharness/configs/remove_executables.py
+  scopes:
+    - 'docker-worker:capability:device:loopbackVideo'
+  metadata:
+    name: '[TC] Linux64 mochitest-clipboard'
+    description: Mochitest clipboard run
+  extra:
+    suite:
+      name: mochitest
+      flavor: plain-clipboard,chrome-clipboard,browser-chrome-clipboard,jetpack-package-clipboard
+    treeherder:
+      groupName: Desktop mochitests
+      groupSymbol: tc-M
+      symbol: cl
new file mode 100644
--- /dev/null
+++ b/testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard_dbg.yml
@@ -0,0 +1,6 @@
+$inherits:
+  from: 'tasks/tests/fx_linux64_mochitest_clipboard.yml'
+task:
+  payload:
+    command:
+      - --download-symbols=true
new file mode 100644
--- /dev/null
+++ b/testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard_e10s.yml
@@ -0,0 +1,35 @@
+---
+$inherits:
+  from: 'tasks/tests/fx_desktop_generic.yml'
+task:
+  payload:
+    capabilities:
+      devices:
+        loopbackVideo: true
+    command:
+      - --no-read-buildbot-config
+      - --installer-url={{build_url}}
+      - --test-packages-url={{test_packages_url}}
+      - --{{suite}}-suite={{flavor}}
+      - --total-chunk={{total_chunks}}
+      - --this-chunk={{chunk}}
+      - --e10s
+    env:
+        MOZHARNESS_SCRIPT: 'mozharness/scripts/desktop_unittest.py'
+        # TODO move linux_unittest.py to a platform specific config
+        MOZHARNESS_CONFIG: >
+          mozharness/configs/unittests/linux_unittest.py
+          mozharness/configs/remove_executables.py
+  scopes:
+    - 'docker-worker:capability:device:loopbackVideo'
+  metadata:
+    name: '[TC] Linux64 mochitest-clipboard-e10s'
+    description: Mochitest clipboard e10s run
+  extra:
+    suite:
+      name: mochitest
+      flavor: plain-clipboard,chrome-clipboard,browser-chrome-clipboard,jetpack-package-clipboard
+    treeherder:
+      groupName: Desktop mochitests
+      groupSymbol: tc-M-e10s
+      symbol: cl
new file mode 100644
--- /dev/null
+++ b/testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard_e10s_dbg.yml
@@ -0,0 +1,7 @@
+$inherits:
+  from: 'tasks/tests/fx_linux64_mochitest_clipboard_e10s.yml'
+task:
+  payload:
+    command:
+      - --download-symbols=true
+
new file mode 100644
--- /dev/null
+++ b/testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard_e10s_opt.yml
@@ -0,0 +1,10 @@
+---
+$inherits:
+  from: 'tasks/tests/fx_linux64_mochitest_clipboard_e10s.yml'
+task:
+  payload:
+    command:
+      - --download-symbols=ondemand
+  extra:
+    treeherder:
+      tier: 2
new file mode 100644
--- /dev/null
+++ b/testing/taskcluster/tasks/tests/fx_linux64_mochitest_clipboard_opt.yml
@@ -0,0 +1,9 @@
+$inherits:
+  from: 'tasks/tests/fx_linux64_mochitest_clipboard.yml'
+task:
+  payload:
+    command:
+      - --download-symbols=ondemand
+  extra:
+    treeherder:
+      tier: 2
new file mode 100644
--- /dev/null
+++ b/testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu.yml
@@ -0,0 +1,33 @@
+$inherits:
+  from: 'tasks/tests/fx_desktop_generic.yml'
+task:
+  payload:
+    capabilities:
+      devices:
+        loopbackVideo: true
+    command:
+      - --no-read-buildbot-config
+      - --installer-url={{build_url}}
+      - --test-packages-url={{test_packages_url}}
+      - --{{suite}}-suite={{flavor}}
+      - --total-chunk={{total_chunks}}
+      - --this-chunk={{chunk}}
+    env:
+        MOZHARNESS_SCRIPT: 'mozharness/scripts/desktop_unittest.py'
+        # TODO move linux_unittest.py to a platform specific config
+        MOZHARNESS_CONFIG: >
+          mozharness/configs/unittests/linux_unittest.py
+          mozharness/configs/remove_executables.py
+  scopes:
+    - 'docker-worker:capability:device:loopbackVideo'
+  metadata:
+    name: '[TC] Linux64 mochitest-gpu'
+    description: Mochitest GPU run
+  extra:
+    suite:
+      name: mochitest
+      flavor: plain-gpu,chrome-gpu,browser-chrome-gpu
+    treeherder:
+      groupName: Desktop mochitests
+      groupSymbol: tc-M
+      symbol: gpu
new file mode 100644
--- /dev/null
+++ b/testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu_dbg.yml
@@ -0,0 +1,6 @@
+$inherits:
+  from: 'tasks/tests/fx_linux64_mochitest_gpu.yml'
+task:
+  payload:
+    command:
+      - --download-symbols=true
new file mode 100644
--- /dev/null
+++ b/testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu_e10s.yml
@@ -0,0 +1,34 @@
+$inherits:
+  from: 'tasks/tests/fx_desktop_generic.yml'
+task:
+  payload:
+    capabilities:
+      devices:
+        loopbackVideo: true
+    command:
+      - --no-read-buildbot-config
+      - --installer-url={{build_url}}
+      - --test-packages-url={{test_packages_url}}
+      - --{{suite}}-suite={{flavor}}
+      - --total-chunk={{total_chunks}}
+      - --this-chunk={{chunk}}
+      - --e10s
+    env:
+        MOZHARNESS_SCRIPT: 'mozharness/scripts/desktop_unittest.py'
+        # TODO move linux_unittest.py to a platform specific config
+        MOZHARNESS_CONFIG: >
+          mozharness/configs/unittests/linux_unittest.py
+          mozharness/configs/remove_executables.py
+  scopes:
+    - 'docker-worker:capability:device:loopbackVideo'
+  metadata:
+    name: '[TC] Linux64 mochitest-gpu-e10s'
+    description: Mochitest GPU e10s run
+  extra:
+    suite:
+      name: mochitest
+      flavor: plain-gpu,chrome-gpu,browser-chrome-gpu
+    treeherder:
+      groupName: Desktop mochitests
+      groupSymbol: tc-M-e10s
+      symbol: gpu
new file mode 100644
--- /dev/null
+++ b/testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu_e10s_dbg.yml
@@ -0,0 +1,7 @@
+$inherits:
+  from: 'tasks/tests/fx_linux64_mochitest_gpu_e10s.yml'
+task:
+  payload:
+    command:
+      - --download-symbols=true
+
new file mode 100644
--- /dev/null
+++ b/testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu_e10s_opt.yml
@@ -0,0 +1,9 @@
+$inherits:
+  from: 'tasks/tests/fx_linux64_mochitest_gpu_e10s.yml'
+task:
+  payload:
+    command:
+      - --download-symbols=ondemand
+  extra:
+    treeherder:
+      tier: 2
new file mode 100644
--- /dev/null
+++ b/testing/taskcluster/tasks/tests/fx_linux64_mochitest_gpu_opt.yml
@@ -0,0 +1,9 @@
+$inherits:
+  from: 'tasks/tests/fx_linux64_mochitest_gpu.yml'
+task:
+  payload:
+    command:
+      - --download-symbols=ondemand
+  extra:
+    treeherder:
+      tier: 2
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -36030,16 +36030,22 @@
             "url": "/html/semantics/embedded-content/the-embed-element/embed-in-object-fallback.html"
           }
         ],
         "web-animations/timing-model/animations/current-time.html": [
           {
             "path": "web-animations/timing-model/animations/current-time.html",
             "url": "/web-animations/timing-model/animations/current-time.html"
           }
+        ],
+        "web-animations/timing-model/animations/set-the-timeline-of-an-animation.html": [
+          {
+            "path": "web-animations/timing-model/animations/set-the-timeline-of-an-animation.html",
+            "url": "/web-animations/timing-model/animations/set-the-timeline-of-an-animation.html"
+          }
         ]
       }
     },
     "reftest_nodes": {}
   },
   "reftest_nodes": {
     "2dcontext/building-paths/canvas_complexshapes_arcto_001.htm": [
       {
deleted file mode 100644
--- a/testing/web-platform/meta/html/semantics/forms/form-control-infrastructure/form.html.ini
+++ /dev/null
@@ -1,20 +0,0 @@
-[form.html]
-  type: testharness
-  [label.form]
-    expected: FAIL
-
-  [label-form.form]
-    expected: FAIL
-
-  [label-form-form2.form]
-    expected: FAIL
-
-  [label-for-control-form-in-form.form]
-    expected: FAIL
-
-  [label-for-control-form.form]
-    expected: FAIL
-
-  [label-in-table.form]
-    expected: FAIL
-
--- a/testing/web-platform/meta/html/semantics/forms/the-label-element/label-attributes.html.ini
+++ b/testing/web-platform/meta/html/semantics/forms/the-label-element/label-attributes.html.ini
@@ -10,14 +10,8 @@
     expected: FAIL
 
   [A form control has no label 2.]
     expected: FAIL
 
   [A form control has an implicit label.]
     expected: FAIL
 
-  [A label in a form without a control]
-    expected: FAIL
-
-  [A label outside a form with a control inside the form]
-    expected: FAIL
-
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/web-animations/timing-model/animations/set-the-timeline-of-an-animation.html.ini
@@ -0,0 +1,73 @@
+[set-the-timeline-of-an-animation.html]
+  type: testharness
+  [After setting timeline on paused animation it is still paused]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After setting timeline on animation paused outside active interval it is still paused]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After setting timeline on an idle animation without a start time it is still idle]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After setting timeline on an idle animation with a start time it is running]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After setting timeline on an idle animation with a sufficiently ancient start time it is finished]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After setting timeline on a play-pending animation it is still pending]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After setting timeline on a play-pending animation it begins playing after pending]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After setting timeline on a pause-pending animation it is still pending]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After setting timeline on a pause-pending animation it becomes paused after pending]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After clearing timeline on paused animation it is still paused]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After clearing timeline on finished animation it is idle]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After clearing timeline on running animation it is idle]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After clearing timeline on idle animation it is still idle]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After clearing timeline on play-pending animation it is still pending]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After clearing and re-setting timeline on play-pending animation it begins to play]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After clearing timeline on a pause-pending animation it is still pending]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After clearing and re-setting timeline on a pause-pending animation it becomes paused]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
+
+  [After clearing and re-setting timeline on an animation in the middle of an aborted pause, it continues playing using the same start time]
+    expected: FAIL
+    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1178662
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/web-animations/timing-model/animations/set-the-timeline-of-an-animation.html
@@ -0,0 +1,276 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Setting the timeline tests</title>
+<link rel="help" href="https://w3c.github.io/web-animations/#setting-the-timeline">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../testcommon.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+// ---------------------------------------------------------------------
+//
+// Tests from no timeline to timeline
+//
+// ---------------------------------------------------------------------
+
+test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  null);
+  animation.currentTime = 50 * MS_PER_SEC;
+  assert_equals(animation.playState, 'paused');
+
+  animation.timeline = document.timeline;
+
+  assert_equals(animation.playState, 'paused');
+  assert_times_equal(animation.currentTime, 50 * MS_PER_SEC);
+}, 'After setting timeline on paused animation it is still paused');
+
+test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  null);
+  animation.currentTime = 200 * MS_PER_SEC;
+  assert_equals(animation.playState, 'paused');
+
+  animation.timeline = document.timeline;
+
+  assert_equals(animation.playState, 'paused');
+  assert_times_equal(animation.currentTime, 200 * MS_PER_SEC);
+}, 'After setting timeline on animation paused outside active interval'
+   + ' it is still paused');
+
+test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  null);
+  assert_equals(animation.playState, 'idle');
+
+  animation.timeline = document.timeline;
+
+  assert_equals(animation.playState, 'idle');
+}, 'After setting timeline on an idle animation without a start time'
+   + ' it is still idle');
+
+test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  null);
+  animation.startTime = document.timeline.currentTime;
+  assert_equals(animation.playState, 'idle');
+
+  animation.timeline = document.timeline;
+
+  assert_equals(animation.playState, 'running');
+}, 'After setting timeline on an idle animation with a start time'
+   + ' it is running');
+
+test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  null);
+  animation.startTime = document.timeline.currentTime - 200 * MS_PER_SEC;
+  assert_equals(animation.playState, 'idle');
+
+  animation.timeline = document.timeline;
+
+  assert_equals(animation.playState, 'finished');
+}, 'After setting timeline on an idle animation with a sufficiently ancient'
+   + ' start time it is finished');
+
+test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  null);
+  animation.play();
+  assert_equals(animation.playState, 'pending');
+
+  animation.timeline = document.timeline;
+
+  assert_equals(animation.playState, 'pending');
+}, 'After setting timeline on a play-pending animation it is still pending');
+
+promise_test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  null);
+  animation.play();
+  assert_equals(animation.playState, 'pending');
+
+  animation.timeline = document.timeline;
+
+  return animation.ready.then(function() {
+    assert_equals(animation.playState, 'running');
+  });
+}, 'After setting timeline on a play-pending animation it begins playing'
+   + ' after pending');
+
+test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  null);
+  animation.startTime = document.timeline.currentTime;
+  animation.pause();
+  animation.timeline = null;
+  assert_equals(animation.playState, 'pending');
+
+  animation.timeline = document.timeline;
+
+  assert_equals(animation.playState, 'pending');
+}, 'After setting timeline on a pause-pending animation it is still pending');
+
+promise_test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  null);
+  animation.startTime = document.timeline.currentTime;
+  animation.pause();
+  animation.timeline = null;
+  assert_equals(animation.playState, 'pending');
+
+  animation.timeline = document.timeline;
+
+  return animation.ready.then(function() {
+    assert_equals(animation.playState, 'paused');
+  });
+}, 'After setting timeline on a pause-pending animation it becomes paused'
+   + ' after pending');
+
+// ---------------------------------------------------------------------
+//
+// Tests from timeline to no timeline
+//
+// ---------------------------------------------------------------------
+
+test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  document.timeline);
+  animation.currentTime = 50 * MS_PER_SEC;
+  assert_equals(animation.playState, 'paused');
+
+  animation.timeline = null;
+
+  assert_equals(animation.playState, 'paused');
+  assert_times_equal(animation.currentTime, 50 * MS_PER_SEC);
+}, 'After clearing timeline on paused animation it is still paused');
+
+test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  document.timeline);
+  var initialStartTime = document.timeline.currentTime - 200 * MS_PER_SEC;
+  animation.startTime = initialStartTime;
+  assert_equals(animation.playState, 'finished');
+
+  animation.timeline = null;
+
+  assert_equals(animation.playState, 'idle');
+  assert_times_equal(animation.startTime, initialStartTime);
+}, 'After clearing timeline on finished animation it is idle');
+
+test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  document.timeline);
+  var initialStartTime = document.timeline.currentTime - 50 * MS_PER_SEC;
+  animation.startTime = initialStartTime;
+  assert_equals(animation.playState, 'running');
+
+  animation.timeline = null;
+
+  assert_equals(animation.playState, 'idle');
+  assert_times_equal(animation.startTime, initialStartTime);
+}, 'After clearing timeline on running animation it is idle');
+
+test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  document.timeline);
+  assert_equals(animation.playState, 'idle');
+
+  animation.timeline = null;
+
+  assert_equals(animation.playState, 'idle');
+  assert_equals(animation.startTime, null);
+}, 'After clearing timeline on idle animation it is still idle');
+
+test(function(t) {
+  var animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
+  assert_equals(animation.playState, 'pending');
+
+  animation.timeline = null;
+
+  assert_equals(animation.playState, 'pending');
+}, 'After clearing timeline on play-pending animation it is still pending');
+
+promise_test(function(t) {
+  var animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
+  assert_equals(animation.playState, 'pending');
+
+  animation.timeline = null;
+  animation.timeline = document.timeline;
+
+  assert_equals(animation.playState, 'pending');
+  return animation.ready.then(function() {
+    assert_equals(animation.playState, 'running');
+  });
+}, 'After clearing and re-setting timeline on play-pending animation it'
+   + ' begins to play');
+
+test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  document.timeline);
+  animation.startTime = document.timeline.currentTime;
+  animation.pause();
+  assert_equals(animation.playState, 'pending');
+
+  animation.timeline = null;
+
+  assert_equals(animation.playState, 'pending');
+}, 'After clearing timeline on a pause-pending animation it is still pending');
+
+promise_test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  document.timeline);
+  animation.startTime = document.timeline.currentTime;
+  animation.pause();
+  assert_equals(animation.playState, 'pending');
+
+  animation.timeline = null;
+  animation.timeline = document.timeline;
+
+  assert_equals(animation.playState, 'pending');
+  return animation.ready.then(function() {
+    assert_equals(animation.playState, 'paused');
+  });
+}, 'After clearing and re-setting timeline on a pause-pending animation it'
+   + ' becomes paused');
+
+promise_test(function(t) {
+  var animation =
+    new Animation(new KeyframeEffect(createDiv(t), null, 100 * MS_PER_SEC),
+                  document.timeline);
+  var initialStartTime = document.timeline.currentTime - 50 * MS_PER_SEC;
+  animation.startTime = initialStartTime;
+  animation.pause();
+  animation.play();
+
+  animation.timeline = null;
+  animation.timeline = document.timeline;
+  assert_equals(animation.playState, 'pending');
+
+  return animation.ready.then(function() {
+    assert_equals(animation.playState, 'running');
+    assert_times_equal(animation.startTime, initialStartTime);
+  });
+}, 'After clearing and re-setting timeline on an animation in the middle of'
+   + ' an aborted pause, it continues playing using the same start time');
+
+</script>
+</body>
--- a/toolkit/components/extensions/ExtensionContent.jsm
+++ b/toolkit/components/extensions/ExtensionContent.jsm
@@ -150,16 +150,17 @@ var api = context => {
 };
 
 // Represents a content script.
 function Script(options, deferred = PromiseUtils.defer()) {
   this.options = options;
   this.run_at = this.options.run_at;
   this.js = this.options.js || [];
   this.css = this.options.css || [];
+  this.remove_css = this.options.remove_css;
 
   this.deferred = deferred;
 
   this.matches_ = new MatchPattern(this.options.matches);
   this.exclude_matches_ = new MatchPattern(this.options.exclude_matches || null);
   // TODO: MatchPattern should pre-mangle host-only patterns so that we
   // don't need to call a separate match function.
   this.matches_host_ = new MatchPattern(this.options.matchesHost || null);
@@ -206,25 +207,35 @@ Script.prototype = {
       this.deferred.reject({message: "No matching window"});
       return;
     }
 
     if (shouldRun("document_start")) {
       let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
                            .getInterface(Ci.nsIDOMWindowUtils);
 
-      for (let url of this.css) {
-        url = extension.baseURI.resolve(url);
-        runSafeSyncWithoutClone(winUtils.loadSheetUsingURIString, url, winUtils.AUTHOR_SHEET);
-        this.deferred.resolve();
+      // We can handle CSS urls (css) and CSS code (cssCode).
+      let cssUrls = [];
+      for (let cssUrl of this.css) {
+        cssUrl = extension.baseURI.resolve(cssUrl);
+        cssUrls.push(cssUrl);
       }
 
       if (this.options.cssCode) {
-        let url = "data:text/css;charset=utf-8," + encodeURIComponent(this.options.cssCode);
-        runSafeSyncWithoutClone(winUtils.loadSheetUsingURIString, url, winUtils.AUTHOR_SHEET);
+        let cssUrl = "data:text/css;charset=utf-8," + encodeURIComponent(this.options.cssCode);
+        cssUrls.push(cssUrl);
+      }
+
+      // We can insertCSS and removeCSS.
+      let method = this.remove_css ? winUtils.removeSheetUsingURIString : winUtils.loadSheetUsingURIString;
+      for (let cssUrl of cssUrls) {
+        runSafeSyncWithoutClone(method, cssUrl, winUtils.AUTHOR_SHEET);
+      }
+
+      if (cssUrls.length > 0) {
         this.deferred.resolve();
       }
     }
 
     let result;
     let scheduled = this.run_at || "document_idle";
     if (shouldRun(scheduled)) {
       for (let url of this.js) {
@@ -543,16 +554,17 @@ DocumentManager = {
 
     if (event.type == "DOMContentLoaded") {
       this.trigger("document_end", window);
     } else if (event.type == "load") {
       this.trigger("document_idle", window);
     }
   },
 
+  // Used to executeScript, insertCSS and removeCSS.
   executeScript(global, extensionId, options) {
     let executeInWin = (window) => {
       let deferred = PromiseUtils.defer();
       let script = new Script(options, deferred);
 
       if (script.matches(window)) {
         let context = this.getContentScriptContext(extensionId, window);
         context.addScript(script);
@@ -876,16 +888,17 @@ class ExtensionGlobal {
 
       let encoding = doc.characterSet;
 
       return LanguageDetector.detectLanguage({language, tld, text, encoding})
                              .then(result => result.language);
     });
   }
 
+  // Used to executeScript, insertCSS and removeCSS.
   handleExtensionExecute(target, extensionId, options) {
     return DocumentManager.executeScript(target, extensionId, options).then(result => {
       try {
         // Make sure we can structured-clone the result value before
         // we try to send it back over the message manager.
         Cu.cloneInto(result, target);
       } catch (e) {
         return Promise.reject({message: "Script returned non-structured-clonable data"});
--- a/toolkit/modules/SelectContentHelper.jsm
+++ b/toolkit/modules/SelectContentHelper.jsm
@@ -119,21 +119,30 @@ this.SelectContentHelper.prototype = {
           });
           this.element.dispatchEvent(inputEvent);
 
           let changeEvent = new win.Event("change", {
             bubbles: true,
           });
           this.element.dispatchEvent(changeEvent);
 
-          let dwu = win.QueryInterface(Ci.nsIInterfaceRequestor)
-                       .getInterface(Ci.nsIDOMWindowUtils);
-          let rect = this.element.getBoundingClientRect();
-          dwu.sendMouseEvent("mousedown", rect.left, rect.top, 0, 1, 0, true);
-          dwu.sendMouseEvent("mouseup", rect.left, rect.top, 0, 1, 0, true);
+          // Going for mostly-Blink parity here, which (at least on Windows)
+          // fires a mouseup and click event after each selection -
+          // even by keyboard. We're firing a mousedown too, since that
+          // seems to make more sense. Unfortunately, the spec on form
+          // control behaviours for these events is really not clear.
+          const MOUSE_EVENTS = ["mousedown", "mouseup", "click"];
+          for (let eventName of MOUSE_EVENTS) {
+            let mouseEvent = new win.MouseEvent(eventName, {
+              view: win,
+              bubbles: true,
+              cancelable: true,
+            });
+            this.element.dispatchEvent(mouseEvent);
+          }
         }
 
         this.uninit();
         break;
 
       case "Forms:MouseOver":
         DOMUtils.setContentState(this.element, kStateHover);
         break;
--- a/view/nsViewManager.cpp
+++ b/view/nsViewManager.cpp
@@ -184,17 +184,17 @@ void nsViewManager::DoSetWindowDimension
 {
   nsRect oldDim = mRootView->GetDimensions();
   nsRect newDim(0, 0, aWidth, aHeight);
   // We care about resizes even when one dimension is already zero.
   if (!oldDim.IsEqualEdges(newDim)) {
     // Don't resize the widget. It is already being set elsewhere.
     mRootView->SetDimensions(newDim, true, false);
     if (mPresShell)
-      mPresShell->ResizeReflow(aWidth, aHeight);
+      mPresShell->ResizeReflow(aWidth, aHeight, oldDim.width, oldDim.height);
   }
 }
 
 bool
 nsViewManager::ShouldDelayResize() const
 {
   MOZ_ASSERT(mRootView);
   if (!mRootView->IsEffectivelyVisible() ||
@@ -205,20 +205,20 @@ nsViewManager::ShouldDelayResize() const
     if (rd->IsResizeSuppressed()) {
       return true;
     }
   }
   return false;
 }
 
 void
-nsViewManager::SetWindowDimensions(nscoord aWidth, nscoord aHeight)
+nsViewManager::SetWindowDimensions(nscoord aWidth, nscoord aHeight, bool aDelayResize)
 {
   if (mRootView) {
-    if (!ShouldDelayResize()) {
+    if (!ShouldDelayResize() && !aDelayResize) {
       if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
           mDelayedResize != nsSize(aWidth, aHeight)) {
         // We have a delayed resize; that now obsolete size may already have
         // been flushed to the PresContext so we need to update the PresContext
         // with the new size because if the new size is exactly the same as the
         // root view's current size then DoSetWindowDimensions will not
         // request a resize reflow (which would correct it). See bug 617076.
         mDelayedResize = nsSize(aWidth, aHeight);
--- a/view/nsViewManager.h
+++ b/view/nsViewManager.h
@@ -84,17 +84,18 @@ public:
 
   /**
    * Set the dimensions of the root window.
    * Called if the root window is resized. The dimensions are in
    * twips
    * @param aWidth of window in twips
    * @param aHeight of window in twips
    */
-  void SetWindowDimensions(nscoord aWidth, nscoord aHeight);
+  void SetWindowDimensions(nscoord aWidth, nscoord aHeight,
+                           bool aDelayResize = false);
 
   /**
    * Do any resizes that are pending.
    */
   void FlushDelayedResize(bool aDoReflow);
 
   /**
    * Called to inform the view manager that the entire area of a view
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -309,17 +309,21 @@ private:
       case eCompositionEventClass:
         // XXX compositionstart is cancelable in draft of DOM3 Events.
         //     However, it doesn't make sense for us, we cannot cancel
         //     composition when we send compositionstart event.
         mFlags.mCancelable = false;
         mFlags.mBubbles = true;
         break;
       default:
-        mFlags.mCancelable = true;
+        if (mMessage == eResize) {
+          mFlags.mCancelable = false;
+        } else {
+          mFlags.mCancelable = true;
+        }
         mFlags.mBubbles = true;
         break;
     }
   }
 
 protected:
   WidgetEvent(bool aIsTrusted,
               EventMessage aMessage,
--- a/widget/nsIBaseWindow.idl
+++ b/widget/nsIBaseWindow.idl
@@ -108,22 +108,28 @@ interface nsIBaseWindow : nsISupports
 	*/
 	void setSize(in long cx, in long cy, in boolean fRepaint);
 
 	/*
 	Gets the width and height of the control.
 	*/
 	void getSize(out long cx, out long cy);
 
+	/**
+	 * The 'flags' argument to setPositionAndSize is a set of these bits.
+	 */
+	const unsigned long eRepaint = 1;
+	const unsigned long eDelayResize = 2;
+
 	/*
 	Convenience function combining the SetPosition and SetSize into one call.
 	Also is more efficient than calling both.
 	*/
 	void setPositionAndSize(in long x, in long y, in long cx, in long cy, 
-		in boolean fRepaint);
+		in unsigned long flags);
 		
 	/*
 	Convenience function combining the GetPosition and GetSize into one call.
 	Also is more efficient than calling both.
 	*/
 	void getPositionAndSize(out long x, out long y, out long cx, out long cy);
 	 
 	/** 
--- a/xpfe/appshell/nsChromeTreeOwner.cpp
+++ b/xpfe/appshell/nsChromeTreeOwner.cpp
@@ -352,17 +352,17 @@ nsChromeTreeOwner::GetTargetableShellCou
 //*****************************************************************************
 // nsChromeTreeOwner::nsIBaseWindow
 //*****************************************************************************   
 
 NS_IMETHODIMP nsChromeTreeOwner::InitWindow(nativeWindow aParentNativeWindow,
    nsIWidget* parentWidget, int32_t x, int32_t y, int32_t cx, int32_t cy)   
 {
    // Ignore widget parents for now.  Don't think those are a vaild thing to call.
-   NS_ENSURE_SUCCESS(SetPositionAndSize(x, y, cx, cy, false), NS_ERROR_FAILURE);
+   NS_ENSURE_SUCCESS(SetPositionAndSize(x, y, cx, cy, 0), NS_ERROR_FAILURE);
 
    return NS_OK;
 }
 
 NS_IMETHODIMP nsChromeTreeOwner::Create()
 {
    NS_ASSERTION(false, "You can't call this");
    return NS_ERROR_UNEXPECTED;
@@ -412,20 +412,20 @@ NS_IMETHODIMP nsChromeTreeOwner::SetSize
 
 NS_IMETHODIMP nsChromeTreeOwner::GetSize(int32_t* cx, int32_t* cy)
 {
    NS_ENSURE_STATE(mXULWindow);
    return mXULWindow->GetSize(cx, cy);
 }
 
 NS_IMETHODIMP nsChromeTreeOwner::SetPositionAndSize(int32_t x, int32_t y, int32_t cx,
-   int32_t cy, bool fRepaint)
+   int32_t cy, uint32_t aFlags)
 {
    NS_ENSURE_STATE(mXULWindow);
-   return mXULWindow->SetPositionAndSize(x, y, cx, cy, fRepaint);
+   return mXULWindow->SetPositionAndSize(x, y, cx, cy, aFlags);
 }
 
 NS_IMETHODIMP nsChromeTreeOwner::GetPositionAndSize(int32_t* x, int32_t* y, int32_t* cx,
    int32_t* cy)
 {
    NS_ENSURE_STATE(mXULWindow);
    return mXULWindow->GetPositionAndSize(x, y, cx, cy);
 }
--- a/xpfe/appshell/nsContentTreeOwner.cpp
+++ b/xpfe/appshell/nsContentTreeOwner.cpp
@@ -594,17 +594,17 @@ NS_IMETHODIMP nsContentTreeOwner::ExitMo
 //*****************************************************************************
 // nsContentTreeOwner::nsIBaseWindow
 //*****************************************************************************   
 
 NS_IMETHODIMP nsContentTreeOwner::InitWindow(nativeWindow aParentNativeWindow,
    nsIWidget* parentWidget, int32_t x, int32_t y, int32_t cx, int32_t cy)   
 {
    // Ignore wigdet parents for now.  Don't think those are a vaild thing to call.
-   NS_ENSURE_SUCCESS(SetPositionAndSize(x, y, cx, cy, false), NS_ERROR_FAILURE);
+   NS_ENSURE_SUCCESS(SetPositionAndSize(x, y, cx, cy, 0), NS_ERROR_FAILURE);
 
    return NS_OK;
 }
 
 NS_IMETHODIMP nsContentTreeOwner::Create()
 {
    NS_ASSERTION(false, "You can't call this");
    return NS_ERROR_UNEXPECTED;
@@ -654,20 +654,20 @@ NS_IMETHODIMP nsContentTreeOwner::SetSiz
 
 NS_IMETHODIMP nsContentTreeOwner::GetSize(int32_t* aCX, int32_t* aCY)
 {
    NS_ENSURE_STATE(mXULWindow);
    return mXULWindow->GetSize(aCX, aCY);
 }
 
 NS_IMETHODIMP nsContentTreeOwner::SetPositionAndSize(int32_t aX, int32_t aY,
-   int32_t aCX, int32_t aCY, bool aRepaint)
+   int32_t aCX, int32_t aCY, uint32_t aFlags)
 {
    NS_ENSURE_STATE(mXULWindow);
-   return mXULWindow->SetPositionAndSize(aX, aY, aCX, aCY, aRepaint);
+   return mXULWindow->SetPositionAndSize(aX, aY, aCX, aCY, aFlags);
 }
 
 NS_IMETHODIMP nsContentTreeOwner::GetPositionAndSize(int32_t* aX, int32_t* aY,
    int32_t* aCX, int32_t* aCY)
 {
    NS_ENSURE_STATE(mXULWindow);
    return mXULWindow->GetPositionAndSize(aX, aY, aCX, aCY); 
 }
@@ -1053,17 +1053,18 @@ NS_INTERFACE_MAP_BEGIN(nsSiteWindow)
   NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow)
 NS_INTERFACE_MAP_END_AGGREGATED(mAggregator)
 
 NS_IMETHODIMP
 nsSiteWindow::SetDimensions(uint32_t aFlags,
                     int32_t aX, int32_t aY, int32_t aCX, int32_t aCY)
 {
   // XXX we're ignoring aFlags
-  return mAggregator->SetPositionAndSize(aX, aY, aCX, aCY, true);
+  return mAggregator->SetPositionAndSize(aX, aY, aCX, aCY,
+                                         nsIBaseWindow::eRepaint);
 }
 
 NS_IMETHODIMP
 nsSiteWindow::GetDimensions(uint32_t aFlags,
                     int32_t *aX, int32_t *aY, int32_t *aCX, int32_t *aCY)
 {
   // XXX we're ignoring aFlags
   return mAggregator->GetPositionAndSize(aX, aY, aCX, aCY);
--- a/xpfe/appshell/nsWebShellWindow.cpp
+++ b/xpfe/appshell/nsWebShellWindow.cpp
@@ -276,17 +276,17 @@ nsWebShellWindow::WindowMoved(nsIWidget*
   return false;
 }
 
 bool
 nsWebShellWindow::WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight)
 {
   nsCOMPtr<nsIBaseWindow> shellAsWin(do_QueryInterface(mDocShell));
   if (shellAsWin) {
-    shellAsWin->SetPositionAndSize(0, 0, aWidth, aHeight, false);
+    shellAsWin->SetPositionAndSize(0, 0, aWidth, aHeight, 0);
   }
   // Persist size, but not immediately, in case this OS is firing
   // repeated size events as the user drags the sizing handle
   if (!IsLocked())
     SetPersistenceTimer(PAD_POSITION | PAD_SIZE | PAD_MISC);
   return true;
 }
 
--- a/xpfe/appshell/nsXULWindow.cpp
+++ b/xpfe/appshell/nsXULWindow.cpp
@@ -636,29 +636,29 @@ NS_IMETHODIMP nsXULWindow::SetSize(int32
 }
 
 NS_IMETHODIMP nsXULWindow::GetSize(int32_t* aCX, int32_t* aCY)
 {
   return GetPositionAndSize(nullptr, nullptr, aCX, aCY);
 }
 
 NS_IMETHODIMP nsXULWindow::SetPositionAndSize(int32_t aX, int32_t aY, 
-   int32_t aCX, int32_t aCY, bool aRepaint)
+   int32_t aCX, int32_t aCY, uint32_t aFlags)
 {
   /* any attempt to set the window's size or position overrides the window's
      zoom state. this is important when these two states are competing while
      the window is being opened. but it should probably just always be so. */
   mWindow->SetSizeMode(nsSizeMode_Normal);
 
   mIntrinsicallySized = false;
 
   DesktopToLayoutDeviceScale scale = mWindow->GetDesktopToDeviceScale();
   DesktopRect rect = LayoutDeviceIntRect(aX, aY, aCX, aCY) / scale;
   nsresult rv = mWindow->Resize(rect.x, rect.y, rect.width, rect.height,
-                                aRepaint);
+                                !!(aFlags & nsIBaseWindow::eRepaint));
   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
   if (!mChromeLoaded) {
     // If we're called before the chrome is loaded someone obviously wants this
     // window at this size and position. We don't persist this one-time setting.
     mIgnoreXULPosition = true;
     mIgnoreXULSize = true;
     mIgnoreXULSizeMode = true;
     return NS_OK;