merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 03 Mar 2016 11:54:40 +0100
changeset 286575 2b5237c178ea02133a777396c24dd2b713f2b8ee
parent 286445 7e43bdd93e439b8c8d6e62d48d9de3e293655560 (current diff)
parent 286574 a269b54d4fb5f3b3bfcdf5ea87899d469f7ea552 (diff)
child 286576 20d8879ac256a9c7ff81edc69748c37c3b310865
child 286580 68b6defee155efdc00bb6b4602b30bcb26da5a5a
child 286659 eb9b1d97740d8b0131438177cd1ef8833fe2f530
push id30050
push usercbook@mozilla.com
push dateThu, 03 Mar 2016 10:54:59 +0000
treeherdermozilla-central@2b5237c178ea [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone47.0a1
first release with
nightly linux32
2b5237c178ea / 47.0a1 / 20160303030253 / files
nightly linux64
2b5237c178ea / 47.0a1 / 20160303030253 / files
nightly mac
2b5237c178ea / 47.0a1 / 20160303030253 / files
nightly win32
2b5237c178ea / 47.0a1 / 20160303030253 / files
nightly win64
2b5237c178ea / 47.0a1 / 20160303030253 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
js/src/tests/js1_7/geniter/regress-351514.js
testing/taskcluster/tasks/tests/fx_linux64_firefox_ui.yml
testing/taskcluster/tasks/tests/fx_linux64_firefox_ui_e10s.yml
testing/web-platform/meta/fetch/api/policies/referrer-origin.html.ini
toolkit/components/telemetry/Histograms.json
--- a/accessible/atk/DocAccessibleWrap.cpp
+++ b/accessible/atk/DocAccessibleWrap.cpp
@@ -9,18 +9,17 @@
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocAccessibleWrap
 ////////////////////////////////////////////////////////////////////////////////
 
 DocAccessibleWrap::
-  DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                    nsIPresShell* aPresShell) :
-  DocAccessible(aDocument, aRootContent, aPresShell), mActivated(false)
+  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  DocAccessible(aDocument, aPresShell), mActivated(false)
 {
 }
 
 DocAccessibleWrap::~DocAccessibleWrap()
 {
 }
 
--- a/accessible/atk/DocAccessibleWrap.h
+++ b/accessible/atk/DocAccessibleWrap.h
@@ -14,18 +14,17 @@
 #include "DocAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 class DocAccessibleWrap : public DocAccessible
 {
 public:
-  DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                    nsIPresShell* aPresShell);
+  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
   virtual ~DocAccessibleWrap();
 
   bool mActivated;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -465,27 +465,25 @@ DocManager::CreateDocOrRootAccessible(ns
     NS_ASSERTION(parentDocAcc,
                  "Can't create an accessible for the document!");
     if (!parentDocAcc)
       return nullptr;
   }
 
   // We only create root accessibles for the true root, otherwise create a
   // doc accessible.
-  nsIContent *rootElm = nsCoreUtils::GetRoleContent(aDocument);
   RefPtr<DocAccessible> docAcc = isRootDoc ?
-    new RootAccessibleWrap(aDocument, rootElm, presShell) :
-    new DocAccessibleWrap(aDocument, rootElm, presShell);
+    new RootAccessibleWrap(aDocument, presShell) :
+    new DocAccessibleWrap(aDocument, presShell);
 
   // Cache the document accessible into document cache.
   mDocAccessibleCache.Put(aDocument, docAcc);
 
   // Initialize the document accessible.
   docAcc->Init();
-  docAcc->SetRoleMapEntry(aria::GetRoleMap(aDocument));
 
   // Bind the document to the tree.
   if (isRootDoc) {
     if (!ApplicationAcc()->AppendChild(docAcc)) {
       docAcc->Shutdown();
       return nullptr;
     }
 
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -71,19 +71,18 @@ static nsIAtom** kRelationAttrs[] =
 };
 
 static const uint32_t kRelationAttrsLen = ArrayLength(kRelationAttrs);
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor/desctructor
 
 DocAccessible::
-  DocAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
-                  nsIPresShell* aPresShell) :
-  HyperTextAccessibleWrap(aRootContent, this),
+  DocAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  HyperTextAccessibleWrap(nullptr, this),
   // XXX aaronl should we use an algorithm for the initial cache size?
   mAccessibleCache(kDefaultCacheLength),
   mNodeToAccessibleMap(kDefaultCacheLength),
   mDocumentNode(aDocument),
   mScrollPositionChangedTicks(0),
   mLoadState(eTreeConstructionPending), mDocFlags(0), mLoadEventType(0),
   mVirtualCursor(nullptr),
   mPresShell(aPresShell), mIPCDoc(nullptr)
@@ -1460,17 +1459,17 @@ DocAccessible::DoInitialUpdate()
     mDocFlags |= eTabDocument;
 
   mLoadState |= eTreeConstructed;
 
   // The content element may be changed before the initial update and then we
   // miss the notification (since content tree change notifications are ignored
   // prior to initial update). Make sure the content element is valid.
   nsIContent* contentElm = nsCoreUtils::GetRoleContent(mDocumentNode);
-  if (mContent != contentElm) {
+  if (contentElm) {
     mContent = contentElm;
     SetRoleMapEntry(aria::GetRoleMap(mContent));
   }
 
   // Build initial tree.  Since its the initial tree there's no group info to
   // invalidate.
   AutoTreeMutation mut(this, false);
   CacheChildrenInSubtree(this);
--- a/accessible/generic/DocAccessible.h
+++ b/accessible/generic/DocAccessible.h
@@ -45,18 +45,17 @@ class DocAccessible : public HyperTextAc
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocAccessible, Accessible)
 
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIACCESSIBLEPIVOTOBSERVER
 
 public:
 
-  DocAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
-                nsIPresShell* aPresShell);
+  DocAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell);
 
   // nsIScrollPositionListener
   virtual void ScrollPositionWillChange(nscoord aX, nscoord aY) override {}
   virtual void ScrollPositionDidChange(nscoord aX, nscoord aY) override;
 
   // nsIDocumentObserver
   NS_DECL_NSIDOCUMENTOBSERVER
 
--- a/accessible/generic/RootAccessible.cpp
+++ b/accessible/generic/RootAccessible.cpp
@@ -54,19 +54,18 @@ using namespace mozilla::dom;
 // nsISupports
 
 NS_IMPL_ISUPPORTS_INHERITED0(RootAccessible, DocAccessible)
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor/destructor
 
 RootAccessible::
-  RootAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
-                 nsIPresShell* aPresShell) :
-  DocAccessibleWrap(aDocument, aRootContent, aPresShell)
+  RootAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  DocAccessibleWrap(aDocument, aPresShell)
 {
   mType = eRootType;
 }
 
 RootAccessible::~RootAccessible()
 {
 }
 
--- a/accessible/generic/RootAccessible.h
+++ b/accessible/generic/RootAccessible.h
@@ -17,18 +17,17 @@ namespace mozilla {
 namespace a11y {
 
 class RootAccessible : public DocAccessibleWrap,
                        public nsIDOMEventListener
 {
   NS_DECL_ISUPPORTS_INHERITED
 
 public:
-  RootAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
-                 nsIPresShell* aPresShell);
+  RootAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell);
 
   // nsIDOMEventListener
   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override;
 
   // Accessible
   virtual void Shutdown() override;
   virtual mozilla::a11y::ENameValueFlag Name(nsString& aName) override;
   virtual Relation RelationByType(RelationType aType) override;
--- a/accessible/jsat/AccessFu.jsm
+++ b/accessible/jsat/AccessFu.jsm
@@ -339,17 +339,17 @@ this.AccessFu = { // jshint ignore:line
       case 'Accessibility:MoveByGranularity':
         this.Input.moveByGranularity(JSON.parse(aData));
         break;
       case 'remote-browser-shown':
       case 'inprocess-browser-shown':
       {
         // Ignore notifications that aren't from a BrowserOrApp
         let frameLoader = aSubject.QueryInterface(Ci.nsIFrameLoader);
-        if (!frameLoader.ownerIsBrowserOrAppFrame) {
+        if (!frameLoader.ownerIsMozBrowserOrAppFrame) {
           return;
         }
         this._handleMessageManager(frameLoader.messageManager);
         break;
       }
     }
   },
 
--- a/accessible/mac/DocAccessibleWrap.h
+++ b/accessible/mac/DocAccessibleWrap.h
@@ -9,18 +9,17 @@
 #include "DocAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 class DocAccessibleWrap : public DocAccessible
 {
 public:
-  DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                    nsIPresShell* aPresShell);
+  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
   virtual ~DocAccessibleWrap();
 
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/mac/DocAccessibleWrap.mm
+++ b/accessible/mac/DocAccessibleWrap.mm
@@ -5,18 +5,17 @@
 
 #include "DocAccessibleWrap.h"
 
 #import "mozAccessible.h"
 
 using namespace mozilla::a11y;
 
 DocAccessibleWrap::
-  DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                    nsIPresShell* aPresShell) :
-  DocAccessible(aDocument, aRootContent, aPresShell)
+  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  DocAccessible(aDocument, aPresShell)
 {
 }
 
 DocAccessibleWrap::~DocAccessibleWrap()
 {
 }
 
--- a/accessible/mac/RootAccessibleWrap.h
+++ b/accessible/mac/RootAccessibleWrap.h
@@ -13,18 +13,17 @@
 #include "RootAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 class RootAccessibleWrap : public RootAccessible
 {
 public:
-  RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                     nsIPresShell* aPresShell);
+  RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
   virtual ~RootAccessibleWrap();
 
     Class GetNativeType ();
 
     // let's our native accessible get in touch with the
     // native cocoa view that is our accessible parent.
     void GetNativeWidget (void **aOutView);
 };
--- a/accessible/mac/RootAccessibleWrap.mm
+++ b/accessible/mac/RootAccessibleWrap.mm
@@ -11,19 +11,18 @@
 #include "nsObjCExceptions.h"
 #include "nsIFrame.h"
 #include "nsView.h"
 #include "nsIWidget.h"
 
 using namespace mozilla::a11y;
 
 RootAccessibleWrap::
-  RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                     nsIPresShell* aPresShell) :
-  RootAccessible(aDocument, aRootContent, aPresShell)
+  RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  RootAccessible(aDocument, aPresShell)
 {
 }
 
 RootAccessibleWrap::~RootAccessibleWrap()
 {
 }
 
 Class
--- a/accessible/tests/mochitest/events/test_valuechange.html
+++ b/accessible/tests/mochitest/events/test_valuechange.html
@@ -15,18 +15,16 @@
           src="../common.js"></script>
   <script type="application/javascript"
           src="../events.js"></script>
 
   <script type="application/javascript"
           src="../value.js"></script>
 
   <script type="application/javascript">
-
-
     /**
      * Do tests.
      */
     var gQueue = null;
 
     // Value change invoker
     function changeARIAValue(aNodeOrID, aValuenow, aValuetext)
     {
@@ -127,16 +125,39 @@
       }
 
       this.getID = function changeRangeValue_getID()
       {
         return prettyName(aID) + " range value changed";
       }
     }
 
+    function changeSelectValue(aID, aKey, aValue)
+    {
+      this.eventSeq = [new invokerChecker(EVENT_TEXT_VALUE_CHANGE, aID)];
+
+      this.invoke = function changeSelectValue_invoke()
+      {
+        getNode(aID).focus();
+        synthesizeKey(aKey, {}, window);
+      }
+
+      this.finalCheck = function changeSelectValue_finalCheck()
+      {
+        is(getAccessible(aID).value, aValue, "Wrong value for " + prettyName(aID));
+      }
+
+      this.getID = function changeSelectValue_getID()
+      {
+        return `${prettyName(aID)} closed select value change on '${aKey}'' key press`;
+      }
+    }
+
+    //enableLogging("DOMEvents");
+    //gA11yEventDumpToConsole = true;
     function doTests()
     {
       // Test initial values
       testValue("slider_vn", "5", 5, 0, 1000, 0);
       testValue("slider_vnvt", "plain", 0, 0, 5, 0);
       testValue("slider_vt", "hi", 0, 0, 3, 0);
       testValue("scrollbar", "5", 5, 0, 1000, 0);
       testValue("progress", "22%", 22, 0, 100, 0);
@@ -150,16 +171,19 @@
       gQueue.push(new changeARIAValue("slider_vnvt", "3", "sweet"));
       gQueue.push(new changeARIAValue("scrollbar", "6", undefined));
 
       gQueue.push(new changeValue("combobox", "hello"));
 
       gQueue.push(new changeProgressValue("progress", "50"));
       gQueue.push(new changeRangeValue("range"));
 
+      gQueue.push(new changeSelectValue("select", "VK_DOWN", "2nd"));
+      gQueue.push(new changeSelectValue("select", "3", "3rd"));
+
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 </head>
 
@@ -216,10 +240,15 @@
   <input id="combobox" role="combobox" aria-autocomplete="inline">
 
   <!-- progress bar -->
   <progress id="progress" value="22" max="100"></progress>
 
   <!-- input@type="range" -->
   <input type="range" id="range" min="0" max="10" value="6">
 
+  <select id="select">
+    <option>1st</option>
+    <option>2nd</option>
+    <option>3rd</option>
+  </select>
 </body>
 </html>
--- a/accessible/windows/msaa/DocAccessibleWrap.cpp
+++ b/accessible/windows/msaa/DocAccessibleWrap.cpp
@@ -20,19 +20,18 @@
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocAccessibleWrap
 ////////////////////////////////////////////////////////////////////////////////
 
 DocAccessibleWrap::
-  DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                    nsIPresShell* aPresShell) :
-  DocAccessible(aDocument, aRootContent, aPresShell), mHWND(nullptr)
+  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  DocAccessible(aDocument, aPresShell), mHWND(nullptr)
 {
 }
 
 DocAccessibleWrap::~DocAccessibleWrap()
 {
 }
 
 IMPL_IUNKNOWN_QUERY_HEAD(DocAccessibleWrap)
--- a/accessible/windows/msaa/DocAccessibleWrap.h
+++ b/accessible/windows/msaa/DocAccessibleWrap.h
@@ -10,18 +10,17 @@
 #include "DocAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 class DocAccessibleWrap : public DocAccessible
 {
 public:
-  DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                    nsIPresShell* aPresShell);
+  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
   virtual ~DocAccessibleWrap();
 
   DECL_IUNKNOWN_INHERITED
 
   // IAccessible
 
     // Override get_accValue to provide URL when no other value is available
     virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accValue( 
--- a/accessible/windows/msaa/RootAccessibleWrap.cpp
+++ b/accessible/windows/msaa/RootAccessibleWrap.cpp
@@ -10,19 +10,18 @@
 #include "nsWinUtils.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor/desctructor
 
 RootAccessibleWrap::
-  RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                     nsIPresShell* aPresShell) :
-  RootAccessible(aDocument, aRootContent, aPresShell)
+  RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  RootAccessible(aDocument, aPresShell)
 {
 }
 
 RootAccessibleWrap::~RootAccessibleWrap()
 {
 }
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/accessible/windows/msaa/RootAccessibleWrap.h
+++ b/accessible/windows/msaa/RootAccessibleWrap.h
@@ -9,18 +9,17 @@
 #include "RootAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 class RootAccessibleWrap : public RootAccessible
 {
 public:
-  RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
-                     nsIPresShell* aPresShell);
+  RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
   virtual ~RootAccessibleWrap();
 
   // RootAccessible
   virtual void DocumentActivated(DocAccessible* aDocument);
 };
 
 } // namespace a11y
 } // namespace mozilla
--- a/addon-sdk/source/lib/sdk/context-menu.js
+++ b/addon-sdk/source/lib/sdk/context-menu.js
@@ -62,18 +62,19 @@ const OVERFLOW_POPUP_CLASS = "addon-cont
 
 // Holds private properties for API objects
 var internal = ns();
 
 // A little hacky but this is the last process ID that last opened the context
 // menu
 var lastContextProcessId = null;
 
+var uuidModule = require('./util/uuid');
 function uuid() {
-  return require('./util/uuid').uuid().toString();
+  return uuidModule.uuid().toString();
 }
 
 function getScheme(spec) {
   try {
     return URL(spec).scheme;
   }
   catch(e) {
     return null;
--- a/b2g/chrome/content/runapp.js
+++ b/b2g/chrome/content/runapp.js
@@ -52,17 +52,17 @@ function AppRunner(aName) {
   this._apps = [];
 }
 AppRunner.prototype = {
   observe: function(aSubject, aTopic, aData) {
     let frameLoader = aSubject;
     // get a ref to the app <iframe>
     frameLoader.QueryInterface(Ci.nsIFrameLoader);
     // Ignore notifications that aren't from a BrowserOrApp
-    if (!frameLoader.ownerIsBrowserOrAppFrame) {
+    if (!frameLoader.ownerIsMozBrowserOrAppFrame) {
       return;
     }
 
     let frame = frameLoader.ownerElement;
     if (!frame.appManifestURL) { // Ignore all frames but app frames
       return;
     }
 
--- a/b2g/components/AboutServiceWorkers.jsm
+++ b/b2g/components/AboutServiceWorkers.jsm
@@ -139,17 +139,17 @@ this.AboutServiceWorkers = {
         self.sendResult(message.id, true);
         break;
 
       case "unregister":
         if (!message.principal ||
             !message.principal.origin ||
             !message.principal.originAttributes ||
             !message.principal.originAttributes.appId ||
-            (message.principal.originAttributes.inBrowser == null)) {
+            (message.principal.originAttributes.inIsolatedMozBrowser == null)) {
           self.sendError(message.id, "MissingPrincipal");
           return;
         }
 
         let principal = Services.scriptSecurityManager.createCodebasePrincipal(
           // TODO: Bug 1196652. use originNoSuffix
           Services.io.newURI(message.principal.origin, null, null),
           message.principal.originAttributes);
--- a/b2g/components/ErrorPage.jsm
+++ b/b2g/components/ErrorPage.jsm
@@ -172,16 +172,16 @@ var ErrorPage = {
   init: function errorPageInit() {
     Services.obs.addObserver(this, 'inprocess-browser-shown', false);
     Services.obs.addObserver(this, 'remote-browser-shown', false);
   },
 
   observe: function errorPageObserve(aSubject, aTopic, aData) {
     let frameLoader = aSubject.QueryInterface(Ci.nsIFrameLoader);
     // Ignore notifications that aren't from a BrowserOrApp
-    if (!frameLoader.ownerIsBrowserOrAppFrame) {
+    if (!frameLoader.ownerIsMozBrowserOrAppFrame) {
       return;
     }
     this._listenError(frameLoader);
   }
 };
 
 ErrorPage.init();
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1372,16 +1372,19 @@ pref("browser.newtabpage.columns", 5);
 pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/v3/links/fetch/%LOCALE%/%CHANNEL%");
 
 // endpoint to send newtab click and view pings
 pref("browser.newtabpage.directory.ping", "https://tiles.services.mozilla.com/v3/links/");
 
 // activates the remote-hosted newtab page
 pref("browser.newtabpage.remote", false);
 
+// Toggles endpoints allowed for remote newtab communications
+pref("browser.newtabpage.remote.mode", "production");
+
 // Enable the DOM fullscreen API.
 pref("full-screen-api.enabled", true);
 
 // Startup Crash Tracking
 // number of startup crashes that can occur before starting into safe mode automatically
 // (this pref has no effect if more than 6 hours have passed since the last crash)
 pref("toolkit.startup.max_resumed_crashes", 3);
 
@@ -1650,8 +1653,11 @@ pref("toolkit.pageThumbs.minHeight", 190
 #ifdef NIGHTLY_BUILD
 // Enable speech synthesis, only Nightly for now
 pref("media.webspeech.synth.enabled", true);
 #endif
 
 pref("browser.esedbreader.loglevel", "Error");
 
 pref("browser.laterrun.enabled", false);
+
+// Enable browser frames for use on desktop.  Only exposed to chrome callers.
+pref("dom.mozBrowserFramesEnabled", true);
--- a/browser/components/newtab/NewTabPrefsProvider.jsm
+++ b/browser/components/newtab/NewTabPrefsProvider.jsm
@@ -13,16 +13,17 @@ Cu.import("resource://gre/modules/XPCOMU
 XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() {
   const {EventEmitter} = Cu.import("resource://devtools/shared/event-emitter.js", {});
   return EventEmitter;
 });
 
 // Supported prefs and data type
 const gPrefsMap = new Map([
   ["browser.newtabpage.remote", "bool"],
+  ["browser.newtabpage.remote.mode", "str"],
   ["browser.newtabpage.enabled", "bool"],
   ["browser.newtabpage.enhanced", "bool"],
   ["browser.newtabpage.pinned", "str"],
   ["intl.locale.matchOS", "bool"],
   ["general.useragent.locale", "localized"],
 ]);
 
 let PrefsProvider = function PrefsProvider() {
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/NewTabRemoteResources.jsm
@@ -0,0 +1,13 @@
+/* exported MODE_CHANNEL_MAP */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["MODE_CHANNEL_MAP"];
+
+const MODE_CHANNEL_MAP = {
+  "production": {origin: "https://content.cdn.mozilla.net"},
+  "staging": {origin: "https://content-cdn.stage.mozaws.net"},
+  "test": {origin: "https://example.com"},
+  "test2": {origin: "http://mochi.test:8888"},
+  "dev": {origin: "http://localhost:8888"}
+};
--- a/browser/components/newtab/aboutNewTabService.js
+++ b/browser/components/newtab/aboutNewTabService.js
@@ -1,54 +1,60 @@
 /*
  * 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/.
 */
 
 /* globals XPCOMUtils, NewTabPrefsProvider, Services,
-  Locale, UpdateUtils
+  Locale, UpdateUtils, MODE_CHANNEL_MAP
 */
 "use strict";
 
 const {utils: Cu, interfaces: Ci} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
                                   "resource://gre/modules/UpdateUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
                                   "resource:///modules/NewTabPrefsProvider.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Locale",
                                   "resource://gre/modules/Locale.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "MODE_CHANNEL_MAP",
+                                  "resource:///modules/NewTabRemoteResources.jsm");
 
 const LOCAL_NEWTAB_URL = "chrome://browser/content/newtab/newTab.xhtml";
 
-const REMOTE_NEWTAB_URL = "https://newtab.cdn.mozilla.net/" +
-                              "v%VERSION%/%CHANNEL%/%LOCALE%/index.html";
+const REMOTE_NEWTAB_PATH = "/v%VERSION%/%CHANNEL%/%LOCALE%/index.html";
 
 const ABOUT_URL = "about:newtab";
 
 // Pref that tells if remote newtab is enabled
 const PREF_REMOTE_ENABLED = "browser.newtabpage.remote";
 
 // The preference that tells whether to match the OS locale
 const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
 
 // The preference that tells what locale the user selected
 const PREF_SELECTED_LOCALE = "general.useragent.locale";
 
+// The preference that tells what remote mode is enabled.
+const PREF_REMOTE_MODE = "browser.newtabpage.remote.mode";
+
 const VALID_CHANNELS = new Set(["esr", "release", "beta", "aurora", "nightly"]);
 
 const REMOTE_NEWTAB_VERSION = "0";
 
 function AboutNewTabService() {
   NewTabPrefsProvider.prefs.on(PREF_REMOTE_ENABLED, this._handleToggleEvent.bind(this));
 
+  this._updateRemoteMaybe = this._updateRemoteMaybe.bind(this);
+
   // trigger remote change if needed, according to pref
   this.toggleRemote(Services.prefs.getBoolPref(PREF_REMOTE_ENABLED));
 }
 
 /*
  * A service that allows for the overriding, at runtime, of the newtab page's url.
  * Additionally, the service manages pref state between a remote and local newtab page.
  *
@@ -119,40 +125,48 @@ AboutNewTabService.prototype = {
       // exit there is no change of state
       return false;
     }
 
     if (stateEnabled) {
       this._remoteURL = this.generateRemoteURL();
       NewTabPrefsProvider.prefs.on(
         PREF_SELECTED_LOCALE,
-        this._updateRemoteMaybe.bind(this));
+        this._updateRemoteMaybe);
       NewTabPrefsProvider.prefs.on(
         PREF_MATCH_OS_LOCALE,
-        this._updateRemoteMaybe.bind(this));
+        this._updateRemoteMaybe);
+      NewTabPrefsProvider.prefs.on(
+        PREF_REMOTE_MODE,
+        this._updateRemoteMaybe);
       this._remoteEnabled = true;
     } else {
       NewTabPrefsProvider.prefs.off(PREF_SELECTED_LOCALE, this._updateRemoteMaybe);
       NewTabPrefsProvider.prefs.off(PREF_MATCH_OS_LOCALE, this._updateRemoteMaybe);
+      NewTabPrefsProvider.prefs.off(PREF_REMOTE_MODE, this._updateRemoteMaybe);
       this._remoteEnabled = false;
     }
     this._newTabURL = ABOUT_URL;
     return true;
   },
 
   /*
-   * Generate a default url based on locale and update channel
+   * Generate a default url based on remote mode, version, locale and update channel
    */
   generateRemoteURL() {
     let releaseName = this.releaseFromUpdateChannel(UpdateUtils.UpdateChannel);
-    let url = REMOTE_NEWTAB_URL
+    let path = REMOTE_NEWTAB_PATH
       .replace("%VERSION%", REMOTE_NEWTAB_VERSION)
       .replace("%LOCALE%", Locale.getLocale())
       .replace("%CHANNEL%", releaseName);
-    return url;
+    let mode = Services.prefs.getCharPref(PREF_REMOTE_MODE, "production");
+    if (!(mode in MODE_CHANNEL_MAP)) {
+      mode = "production";
+    }
+    return MODE_CHANNEL_MAP[mode].origin + path;
   },
 
   /*
    * Returns the default URL.
    *
    * This URL only depends on the browser.newtabpage.remote pref. Overriding
    * the newtab page has no effect on the result of this function.
    *
--- a/browser/components/newtab/moz.build
+++ b/browser/components/newtab/moz.build
@@ -7,16 +7,17 @@
 BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
 
 XPCSHELL_TESTS_MANIFESTS += [
     'tests/xpcshell/xpcshell.ini',
 ]
 
 EXTRA_JS_MODULES += [
     'NewTabPrefsProvider.jsm',
+    'NewTabRemoteResources.jsm',
     'NewTabURL.jsm',
     'PlacesProvider.jsm'
 ]
 
 XPIDL_SOURCES += [
     'nsIAboutNewTabService.idl',
 ]
 
--- a/browser/components/newtab/tests/xpcshell/test_AboutNewTabService.js
+++ b/browser/components/newtab/tests/xpcshell/test_AboutNewTabService.js
@@ -100,35 +100,50 @@ add_task(function* test_override_remote_
 add_task(function* test_updates() {
   /*
    * Simulates a "cold-boot" situation, with some pref already set before testing a series
    * of changes.
    */
   Preferences.set("browser.newtabpage.remote", true);
   aboutNewTabService.resetNewTabURL(); // need to set manually because pref notifs are off
   let notificationPromise;
-  let expectedHref = "https://newtab.cdn.mozilla.net" +
-                     `/v${aboutNewTabService.remoteVersion}` +
+  let productionModeBaseUrl = "https://content.cdn.mozilla.net";
+  let testModeBaseUrl = "https://example.com";
+  let expectedPath = `/v${aboutNewTabService.remoteVersion}` +
                      `/${aboutNewTabService.remoteReleaseName}` +
                      "/en-GB" +
                      "/index.html";
+  let expectedHref = productionModeBaseUrl + expectedPath;
   Preferences.set("intl.locale.matchOS", true);
   Preferences.set("general.useragent.locale", "en-GB");
+  Preferences.set("browser.newtabpage.remote.mode", "production");
   NewTabPrefsProvider.prefs.init();
 
   // test update checks for prefs
   notificationPromise = nextChangeNotificationPromise(
     expectedHref, "Remote href should be updated");
   Preferences.set("intl.locale.matchOS", false);
   yield notificationPromise;
 
   notificationPromise = nextChangeNotificationPromise(
     DEFAULT_HREF, "Remote href changes back to default");
   Preferences.set("general.useragent.locale", "en-US");
+  yield notificationPromise;
 
+  // test update fires when mode is changed
+  expectedPath = expectedPath.replace("/en-GB/", "/en-US/");
+  notificationPromise = nextChangeNotificationPromise(
+    testModeBaseUrl + expectedPath, "Remote href changes back to origin of test mode");
+  Preferences.set("browser.newtabpage.remote.mode", "test");
+  yield notificationPromise;
+
+  // test invalid mode ends up pointing to production url
+  notificationPromise = nextChangeNotificationPromise(
+    DEFAULT_HREF, "Remote href changes back to production default");
+  Preferences.set("browser.newtabpage.remote.mode", "invalid");
   yield notificationPromise;
 
   // test update fires on override and reset
   let testURL = "https://example.com/";
   notificationPromise = nextChangeNotificationPromise(
     testURL, "a notification occurs on override");
   aboutNewTabService.newTabURL = testURL;
   yield notificationPromise;
--- a/browser/components/sessionstore/SessionHistory.jsm
+++ b/browser/components/sessionstore/SessionHistory.jsm
@@ -140,16 +140,20 @@ var SessionHistoryInternal = {
       entry.referrer = shEntry.referrerURI.spec;
       entry.referrerPolicy = shEntry.referrerPolicy;
     }
 
     if (shEntry.originalURI) {
       entry.originalURI = shEntry.originalURI.spec;
     }
 
+    if (shEntry.loadReplace) {
+      entry.loadReplace = shEntry.loadReplace;
+    }
+
     if (shEntry.srcdocData)
       entry.srcdocData = shEntry.srcdocData;
 
     if (shEntry.isSrcdocEntry)
       entry.isSrcdocEntry = shEntry.isSrcdocEntry;
 
     if (shEntry.baseURI)
       entry.baseURI = shEntry.baseURI.spec;
@@ -311,16 +315,19 @@ var SessionHistoryInternal = {
       shEntry.contentType = entry.contentType;
     if (entry.referrer) {
       shEntry.referrerURI = Utils.makeURI(entry.referrer);
       shEntry.referrerPolicy = entry.referrerPolicy;
     }
     if (entry.originalURI) {
       shEntry.originalURI = Utils.makeURI(entry.originalURI);
     }
+    if (entry.loadReplace) {
+      shEntry.loadReplace = entry.loadReplace;
+    }
     if (entry.isSrcdocEntry)
       shEntry.srcdocData = entry.srcdocData;
     if (entry.baseURI)
       shEntry.baseURI = Utils.makeURI(entry.baseURI);
 
     if (entry.cacheKey) {
       var cacheKey = Cc["@mozilla.org/supports-PRUint32;1"].
                      createInstance(Ci.nsISupportsPRUint32);
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -31,72 +31,72 @@ namespace mozilla {
 
 using dom::URLParams;
 
 void
 PrincipalOriginAttributes::InheritFromDocShellToDoc(const DocShellOriginAttributes& aAttrs,
                                                     const nsIURI* aURI)
 {
   mAppId = aAttrs.mAppId;
-  mInBrowser = aAttrs.mInBrowser;
+  mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
 
   // addonId is computed from the principal URI and never propagated
   mUserContextId = aAttrs.mUserContextId;
 
   // TODO:
   // Bug 1225349 - PrincipalOriginAttributes should inherit mSignedPkg
   // accordingly by URI
   mSignedPkg = aAttrs.mSignedPkg;
 }
 
 void
 PrincipalOriginAttributes::InheritFromNecko(const NeckoOriginAttributes& aAttrs)
 {
   mAppId = aAttrs.mAppId;
-  mInBrowser = aAttrs.mInBrowser;
+  mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
 
   // addonId is computed from the principal URI and never propagated
   mUserContextId = aAttrs.mUserContextId;
   mSignedPkg = aAttrs.mSignedPkg;
 }
 
 void
 DocShellOriginAttributes::InheritFromDocToChildDocShell(const PrincipalOriginAttributes& aAttrs)
 {
   mAppId = aAttrs.mAppId;
-  mInBrowser = aAttrs.mInBrowser;
+  mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
 
   // addonId is computed from the principal URI and never propagated
   mUserContextId = aAttrs.mUserContextId;
 
   // TODO:
   // Bug 1225353 - DocShell/NeckoOriginAttributes should inherit
   // mSignedPkg accordingly by mSignedPkgInBrowser
   mSignedPkg = aAttrs.mSignedPkg;
 }
 
 void
 NeckoOriginAttributes::InheritFromDocToNecko(const PrincipalOriginAttributes& aAttrs)
 {
   mAppId = aAttrs.mAppId;
-  mInBrowser = aAttrs.mInBrowser;
+  mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
 
   // addonId is computed from the principal URI and never propagated
   mUserContextId = aAttrs.mUserContextId;
 
   // TODO:
   // Bug 1225353 - DocShell/NeckoOriginAttributes should inherit
   // mSignedPkg accordingly by mSignedPkgInBrowser
 }
 
 void
 NeckoOriginAttributes::InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs)
 {
   mAppId = aAttrs.mAppId;
-  mInBrowser = aAttrs.mInBrowser;
+  mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
 
   // addonId is computed from the principal URI and never propagated
   mUserContextId = aAttrs.mUserContextId;
 
   // TODO:
   // Bug 1225353 - DocShell/NeckoOriginAttributes should inherit
   // mSignedPkg accordingly by mSignedPkgInBrowser
 }
@@ -114,17 +114,17 @@ OriginAttributes::CreateSuffix(nsACStrin
   // naming (see addonId below).
   //
 
   if (mAppId != nsIScriptSecurityManager::NO_APP_ID) {
     value.AppendInt(mAppId);
     params->Set(NS_LITERAL_STRING("appId"), value);
   }
 
-  if (mInBrowser) {
+  if (mInIsolatedMozBrowser) {
     params->Set(NS_LITERAL_STRING("inBrowser"), NS_LITERAL_STRING("1"));
   }
 
   if (!mAddonId.IsEmpty()) {
     if (mAddonId.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) != kNotFound) {
 #ifdef MOZ_CRASHREPORTER
       CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Crash_AddonId"),
                                          NS_ConvertUTF16toUTF8(mAddonId));
@@ -186,17 +186,17 @@ public:
       return true;
     }
 
     if (aName.EqualsLiteral("inBrowser")) {
       if (!aValue.EqualsLiteral("1")) {
         return false;
       }
 
-      mOriginAttributes->mInBrowser = true;
+      mOriginAttributes->mInIsolatedMozBrowser = true;
       return true;
     }
 
     if (aName.EqualsLiteral("addonId")) {
       MOZ_RELEASE_ASSERT(mOriginAttributes->mAddonId.IsEmpty());
       mOriginAttributes->mAddonId.Assign(aValue);
       return true;
     }
@@ -464,17 +464,17 @@ BasePrincipal::GetIsSystemPrincipal(bool
 {
   *aResult = Kind() == eSystemPrincipal;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BasePrincipal::GetJarPrefix(nsACString& aJarPrefix)
 {
-  mozilla::GetJarPrefix(mOriginAttributes.mAppId, mOriginAttributes.mInBrowser, aJarPrefix);
+  mozilla::GetJarPrefix(mOriginAttributes.mAppId, mOriginAttributes.mInIsolatedMozBrowser, aJarPrefix);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BasePrincipal::GetOriginAttributes(JSContext* aCx, JS::MutableHandle<JS::Value> aVal)
 {
   if (NS_WARN_IF(!ToJSValue(aCx, mOriginAttributes, aVal))) {
     return NS_ERROR_FAILURE;
@@ -518,19 +518,19 @@ BasePrincipal::GetAppId(uint32_t* aAppId
 NS_IMETHODIMP
 BasePrincipal::GetUserContextId(uint32_t* aUserContextId)
 {
   *aUserContextId = UserContextId();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-BasePrincipal::GetIsInBrowserElement(bool* aIsInBrowserElement)
+BasePrincipal::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement)
 {
-  *aIsInBrowserElement = IsInBrowserElement();
+  *aIsInIsolatedMozBrowserElement = IsInIsolatedMozBrowserElement();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BasePrincipal::GetUnknownAppId(bool* aUnknownAppId)
 {
   *aUnknownAppId = AppId() == nsIScriptSecurityManager::UNKNOWN_APP_ID;
   return NS_OK;
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -25,17 +25,17 @@ namespace mozilla {
 // Base OriginAttributes class. This has several subclass flavors, and is not
 // directly constructable itself.
 class OriginAttributes : public dom::OriginAttributesDictionary
 {
 public:
   bool operator==(const OriginAttributes& aOther) const
   {
     return mAppId == aOther.mAppId &&
-           mInBrowser == aOther.mInBrowser &&
+           mInIsolatedMozBrowser == aOther.mInIsolatedMozBrowser &&
            mAddonId == aOther.mAddonId &&
            mUserContextId == aOther.mUserContextId &&
            mSignedPkg == aOther.mSignedPkg;
   }
   bool operator!=(const OriginAttributes& aOther) const
   {
     return !(*this == aOther);
   }
@@ -70,20 +70,20 @@ class NeckoOriginAttributes;
 // flavors, and a variety of InheritFrom* methods to implement the transfer
 // behavior.
 
 // For OriginAttributes stored on principals.
 class PrincipalOriginAttributes : public OriginAttributes
 {
 public:
   PrincipalOriginAttributes() {}
-  PrincipalOriginAttributes(uint32_t aAppId, bool aInBrowser)
+  PrincipalOriginAttributes(uint32_t aAppId, bool aInIsolatedMozBrowser)
   {
     mAppId = aAppId;
-    mInBrowser = aInBrowser;
+    mInIsolatedMozBrowser = aInIsolatedMozBrowser;
   }
 
   // Inheriting OriginAttributes from docshell to document when user navigates.
   //
   // @param aAttrs  Origin Attributes of the docshell.
   // @param aURI    The URI of the document.
   void InheritFromDocShellToDoc(const DocShellOriginAttributes& aAttrs,
                                 const nsIURI* aURI);
@@ -92,39 +92,39 @@ public:
   void InheritFromNecko(const NeckoOriginAttributes& aAttrs);
 };
 
 // For OriginAttributes stored on docshells / loadcontexts / browsing contexts.
 class DocShellOriginAttributes : public OriginAttributes
 {
 public:
   DocShellOriginAttributes() {}
-  DocShellOriginAttributes(uint32_t aAppId, bool aInBrowser)
+  DocShellOriginAttributes(uint32_t aAppId, bool aInIsolatedMozBrowser)
   {
     mAppId = aAppId;
-    mInBrowser = aInBrowser;
+    mInIsolatedMozBrowser = aInIsolatedMozBrowser;
   }
 
   // Inheriting OriginAttributes from document to child docshell when an
   // <iframe> is created.
   //
   // @param aAttrs  Origin Attributes of the document.
   void
   InheritFromDocToChildDocShell(const PrincipalOriginAttributes& aAttrs);
 };
 
 // For OriginAttributes stored on Necko.
 class NeckoOriginAttributes : public OriginAttributes
 {
 public:
   NeckoOriginAttributes() {}
-  NeckoOriginAttributes(uint32_t aAppId, bool aInBrowser)
+  NeckoOriginAttributes(uint32_t aAppId, bool aInIsolatedMozBrowser)
   {
     mAppId = aAppId;
-    mInBrowser = aInBrowser;
+    mInIsolatedMozBrowser = aInIsolatedMozBrowser;
   }
 
   // Inheriting OriginAttributes from document to necko when a network request
   // is made.
   void InheritFromDocToNecko(const PrincipalOriginAttributes& aAttrs);
 
   void InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs);
 };
@@ -154,17 +154,17 @@ public:
 
   // Performs a match of |aAttrs| against this pattern.
   bool Matches(const OriginAttributes& aAttrs) const
   {
     if (mAppId.WasPassed() && mAppId.Value() != aAttrs.mAppId) {
       return false;
     }
 
-    if (mInBrowser.WasPassed() && mInBrowser.Value() != aAttrs.mInBrowser) {
+    if (mInIsolatedMozBrowser.WasPassed() && mInIsolatedMozBrowser.Value() != aAttrs.mInIsolatedMozBrowser) {
       return false;
     }
 
     if (mAddonId.WasPassed() && mAddonId.Value() != aAttrs.mAddonId) {
       return false;
     }
 
     if (mUserContextId.WasPassed() && mUserContextId.Value() != aAttrs.mUserContextId) {
@@ -210,33 +210,33 @@ public:
   NS_IMETHOD GetIsCodebasePrincipal(bool* aResult) override;
   NS_IMETHOD GetIsExpandedPrincipal(bool* aResult) override;
   NS_IMETHOD GetIsSystemPrincipal(bool* aResult) override;
   NS_IMETHOD GetJarPrefix(nsACString& aJarPrefix) final;
   NS_IMETHOD GetOriginAttributes(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) final;
   NS_IMETHOD GetOriginSuffix(nsACString& aOriginSuffix) final;
   NS_IMETHOD GetAppStatus(uint16_t* aAppStatus) final;
   NS_IMETHOD GetAppId(uint32_t* aAppStatus) final;
-  NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement) final;
+  NS_IMETHOD GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement) final;
   NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId) final;
   NS_IMETHOD GetUserContextId(uint32_t* aUserContextId) final;
 
   virtual bool IsOnCSSUnprefixingWhitelist() override { return false; }
 
   virtual bool IsCodebasePrincipal() const { return false; };
 
   static BasePrincipal* Cast(nsIPrincipal* aPrin) { return static_cast<BasePrincipal*>(aPrin); }
   static already_AddRefed<BasePrincipal>
   CreateCodebasePrincipal(nsIURI* aURI, const PrincipalOriginAttributes& aAttrs);
   static already_AddRefed<BasePrincipal> CreateCodebasePrincipal(const nsACString& aOrigin);
 
   const PrincipalOriginAttributes& OriginAttributesRef() { return mOriginAttributes; }
   uint32_t AppId() const { return mOriginAttributes.mAppId; }
   uint32_t UserContextId() const { return mOriginAttributes.mUserContextId; }
-  bool IsInBrowserElement() const { return mOriginAttributes.mInBrowser; }
+  bool IsInIsolatedMozBrowserElement() const { return mOriginAttributes.mInIsolatedMozBrowser; }
 
   enum PrincipalKind {
     eNullPrincipal,
     eCodebasePrincipal,
     eExpandedPrincipal,
     eSystemPrincipal
   };
 
--- a/caps/nsIPrincipal.idl
+++ b/caps/nsIPrincipal.idl
@@ -298,20 +298,23 @@ interface nsIPrincipal : nsISerializable
     /**
      * Gets the id of the user context this principal is inside.  If this
      * principal is inside the default userContext, this returns
      * nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID.
      */
     [infallible] readonly attribute unsigned long userContextId;
 
     /**
-     * Returns true iff the principal is inside a browser element.  (<iframe
-     * mozbrowser mozapp> does not count as a browser element.)
+     * Returns true iff the principal is inside an isolated mozbrowser element.
+     * <iframe mozbrowser mozapp> and <xul:browser> are not considered to be
+     * mozbrowser elements.  <iframe mozbrowser noisolation> does not count as
+     * isolated since isolation is disabled.  Isolation can only be disabled if
+     * the containing document is chrome.
      */
-    [infallible] readonly attribute boolean isInBrowserElement;
+    [infallible] readonly attribute boolean isInIsolatedMozBrowserElement;
 
     /**
      * Returns true if this principal has an unknown appId. This shouldn't
      * generally be used. We only expose it due to not providing the correct
      * appId everywhere where we construct principals.
      */
     [infallible] readonly attribute boolean unknownAppId;
 
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -255,23 +255,35 @@ nsScriptSecurityManager::SecurityHashURI
 {
     return NS_SecurityHashURI(aURI);
 }
 
 uint16_t
 nsScriptSecurityManager::AppStatusForPrincipal(nsIPrincipal *aPrin)
 {
     uint32_t appId = aPrin->GetAppId();
-    bool inMozBrowser = aPrin->GetIsInBrowserElement();
+
+    // After bug 1238160, the principal no longer knows how to answer "is this a
+    // browser element", which is really what this code path wants. Currently,
+    // desktop is the only platform where we intend to disable isolation on a
+    // browser frame, so non-desktop should be able to assume that
+    // inIsolatedMozBrowser is true for all mozbrowser frames.  Additionally,
+    // apps are no longer used on desktop, so appId is always NO_APP_ID.  We use
+    // a release assertion in nsFrameLoader::OwnerIsIsolatedMozBrowserFrame so
+    // that platforms with apps can assume inIsolatedMozBrowser is true for all
+    // mozbrowser frames.
+    bool inIsolatedMozBrowser = aPrin->GetIsInIsolatedMozBrowserElement();
+
     NS_WARN_IF_FALSE(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
                      "Asking for app status on a principal with an unknown app id");
     // Installed apps have a valid app id (not NO_APP_ID or UNKNOWN_APP_ID)
     // and they are not inside a mozbrowser.
     if (appId == nsIScriptSecurityManager::NO_APP_ID ||
-        appId == nsIScriptSecurityManager::UNKNOWN_APP_ID || inMozBrowser)
+        appId == nsIScriptSecurityManager::UNKNOWN_APP_ID ||
+        inIsolatedMozBrowser)
     {
         return nsIPrincipal::APP_STATUS_NOT_INSTALLED;
     }
 
     nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
     NS_ENSURE_TRUE(appsService, nsIPrincipal::APP_STATUS_NOT_INSTALLED);
 
     nsCOMPtr<mozIApplication> app;
@@ -286,17 +298,17 @@ nsScriptSecurityManager::AppStatusForPri
     NS_ENSURE_SUCCESS(app->GetOrigin(appOrigin),
                       nsIPrincipal::APP_STATUS_NOT_INSTALLED);
     nsCOMPtr<nsIURI> appURI;
     NS_ENSURE_SUCCESS(NS_NewURI(getter_AddRefs(appURI), appOrigin),
                       nsIPrincipal::APP_STATUS_NOT_INSTALLED);
 
     // The app could contain a cross-origin iframe - make sure that the content
     // is actually same-origin with the app.
-    MOZ_ASSERT(inMozBrowser == false, "Checked this above");
+    MOZ_ASSERT(inIsolatedMozBrowser == false, "Checked this above");
     PrincipalOriginAttributes attrs(appId, false);
     nsCOMPtr<nsIPrincipal> appPrin = BasePrincipal::CreateCodebasePrincipal(appURI, attrs);
     NS_ENSURE_TRUE(appPrin, nsIPrincipal::APP_STATUS_NOT_INSTALLED);
     return aPrin->Equals(appPrin) ? status
                                   : nsIPrincipal::APP_STATUS_NOT_INSTALLED;
 }
 
 /*
@@ -585,17 +597,17 @@ nsScriptSecurityManager::CheckLoadURIFro
  * CheckLoadURIWithPrincipal means denying loading if the given URI has certain
  * nsIProtocolHandler flags set.
  * @return if success, access is allowed. Otherwise, deny access
  */
 static nsresult
 DenyAccessIfURIHasFlags(nsIURI* aURI, uint32_t aURIFlags)
 {
     NS_PRECONDITION(aURI, "Must have URI!");
-    
+
     bool uriHasFlags;
     nsresult rv =
         NS_URIChainHasFlags(aURI, aURIFlags, &uriHasFlags);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (uriHasFlags) {
         return NS_ERROR_DOM_BAD_URI;
     }
@@ -719,17 +731,17 @@ nsScriptSecurityManager::CheckLoadURIWit
             }
             // None of our whitelisted principals worked.
             return NS_ERROR_DOM_BAD_URI;
         }
         NS_ERROR("Non-system principals or expanded principal passed to CheckLoadURIWithPrincipal "
                  "must have a URI!");
         return NS_ERROR_UNEXPECTED;
     }
-    
+
     // Automatic loads are not allowed from certain protocols.
     if (aFlags & nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT) {
         nsresult rv =
             DenyAccessIfURIHasFlags(sourceURI,
                                     nsIProtocolHandler::URI_FORBIDS_AUTOMATIC_DOCUMENT_REPLACEMENT);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
@@ -953,17 +965,17 @@ nsScriptSecurityManager::CheckLoadURIWit
         if (NS_SUCCEEDED(rv)) {
             nsCOMPtr<nsIConsoleService> console(
               do_GetService("@mozilla.org/consoleservice;1"));
             NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
 
             console->LogStringMessage(message.get());
         }
     }
-    
+
     return NS_OK;
 }
 
 nsresult
 nsScriptSecurityManager::ReportError(JSContext* cx, const nsAString& messageTag,
                                      nsIURI* aSource, nsIURI* aTarget)
 {
     nsresult rv;
@@ -1165,23 +1177,23 @@ nsScriptSecurityManager::CreateExpandedP
   nsCOMPtr<nsIPrincipal> p = new nsExpandedPrincipal(principals);
   p.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI,
                                                  uint32_t aAppId,
-                                                 bool aInMozBrowser,
+                                                 bool aInIsolatedMozBrowser,
                                                  nsIPrincipal** aPrincipal)
 {
   NS_ENSURE_TRUE(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
                  NS_ERROR_INVALID_ARG);
 
-  PrincipalOriginAttributes attrs(aAppId, aInMozBrowser);
+  PrincipalOriginAttributes attrs(aAppId, aInIsolatedMozBrowser);
   nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
   prin.forget(aPrincipal);
   return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsScriptSecurityManager::
   GetLoadContextCodebasePrincipal(nsIURI* aURI,
@@ -1561,50 +1573,50 @@ nsScriptSecurityManager::InitPrefs()
     Preferences::AddStrongObservers(this, kObservedPrefs);
 
     return NS_OK;
 }
 
 namespace mozilla {
 
 void
-GetJarPrefix(uint32_t aAppId, bool aInMozBrowser, nsACString& aJarPrefix)
+GetJarPrefix(uint32_t aAppId, bool aInIsolatedMozBrowser, nsACString& aJarPrefix)
 {
   MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
 
   if (aAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
     aAppId = nsIScriptSecurityManager::NO_APP_ID;
   }
 
   aJarPrefix.Truncate();
 
   // Fallback.
-  if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInMozBrowser) {
+  if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInIsolatedMozBrowser) {
     return;
   }
 
   // aJarPrefix = appId + "+" + { 't', 'f' } + "+";
   aJarPrefix.AppendInt(aAppId);
   aJarPrefix.Append('+');
-  aJarPrefix.Append(aInMozBrowser ? 't' : 'f');
+  aJarPrefix.Append(aInIsolatedMozBrowser ? 't' : 'f');
   aJarPrefix.Append('+');
 
   return;
 }
 
 } // namespace mozilla
 
 NS_IMETHODIMP
 nsScriptSecurityManager::GetJarPrefix(uint32_t aAppId,
-                                      bool aInMozBrowser,
+                                      bool aInIsolatedMozBrowser,
                                       nsACString& aJarPrefix)
 {
   MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
 
-  mozilla::GetJarPrefix(aAppId, aInMozBrowser, aJarPrefix);
+  mozilla::GetJarPrefix(aAppId, aInIsolatedMozBrowser, aJarPrefix);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScriptSecurityManager::GetDomainPolicyActive(bool *aRv)
 {
     *aRv = !!mDomainPolicy;
     return NS_OK;
@@ -1689,9 +1701,8 @@ nsScriptSecurityManager::PolicyAllowsScr
     rv = superExceptions->ContainsSuperDomain(aURI, &contains);
     NS_ENSURE_SUCCESS(rv, rv);
     if (contains) {
         *aRv = !*aRv;
     }
 
     return NS_OK;
 }
-
--- a/caps/nsScriptSecurityManager.h
+++ b/caps/nsScriptSecurityManager.h
@@ -146,14 +146,14 @@ private:
     static nsIStringBundle *sStrBundle;
     static JSRuntime       *sRuntime;
 };
 
 namespace mozilla {
 
 void
 GetJarPrefix(uint32_t aAppid,
-             bool aInMozBrowser,
+             bool aInIsolatedMozBrowser,
              nsACString& aJarPrefix);
 
 } // namespace mozilla
 
 #endif // nsScriptSecurityManager_h__
--- a/caps/tests/gtest/TestOriginAttributes.cpp
+++ b/caps/tests/gtest/TestOriginAttributes.cpp
@@ -19,19 +19,19 @@ TestSuffix(const PrincipalOriginAttribut
 }
 
 TEST(PrincipalOriginAttributes, Suffix_default)
 {
   PrincipalOriginAttributes attrs;
   TestSuffix(attrs);
 }
 
-TEST(PrincipalOriginAttributes, Suffix_appId_inBrowser)
+TEST(PrincipalOriginAttributes, Suffix_appId_inIsolatedMozBrowser)
 {
   PrincipalOriginAttributes attrs(1, true);
   TestSuffix(attrs);
 }
 
-TEST(PrincipalOriginAttributes, Suffix_maxAppId_inBrowser)
+TEST(PrincipalOriginAttributes, Suffix_maxAppId_inIsolatedMozBrowser)
 {
   PrincipalOriginAttributes attrs(4294967295, true);
   TestSuffix(attrs);
 }
--- a/caps/tests/mochitest/test_principal_jarprefix_origin_appid_appstatus.html
+++ b/caps/tests/mochitest/test_principal_jarprefix_origin_appid_appstatus.html
@@ -28,16 +28,18 @@ SimpleTest.waitForExplicitFinish();
  * - app: gives the app manifest URL, will set mozapp to it on the iframe;
  * - origin: gives the origin of the iframe. This is the URL thas is going to
  *           to be passed as iframe.src but also the expected principal's
  *           origin.
  * - isapp: tells if the iframe is really a mozapp. If the manifest url isn't
  *          valid, the iframe will not be considered as a mozapp.
  * - browser: say if the iframe should be a mozbrowser. This is implicit when
  *            app is set.
+ * - isolated: if origin isolation is enabled with browser frames.  Defaults to
+ *             true if unset.
  * - test: an array of tests to run for this test case:
  *   - eo-unique: the extendedOrigin of the prinicpal must be unique in the
  *                current list.
  *   - eo-as-last: the extendedOrigin of the principal must be the same as the
  *                 last added to the list.
  */
 var gData = [
   {
@@ -225,25 +227,68 @@ var gData = [
     browser: false,
     child: {
       src: "http://example.org/chrome/",
       isapp: false,
       browser: true,
     },
     test: [ "child-has-different-eo", "child-has-same-appstatus", "child-has-same-appid" ],
   },
-  // browser containing an iframe is part of the browser
+  // browser containing an iframe that is part of the browser
   {
     src: "http://example.org/",
     isapp: false,
     browser: true,
     child: {
       src: "http://example.org/chrome/",
       isapp: false,
-      inBrowser: true,
+      inIsolatedMozBrowser: true,
+    },
+    test: [ "child-has-same-eo" ],
+  },
+  // iframe containing a browser with isolation disabled
+  // (only chrome documents can disable isolation)
+  {
+    src: "http://example.org/",
+    isapp: false,
+    browser: false,
+    child: {
+      src: "http://example.org/chrome/",
+      isapp: false,
+      browser: true,
+      isolated: false,
+      inIsolatedMozBrowser: true,
+    },
+    test: [ "child-has-different-eo" ],
+  },
+  // browser with isolation disabled containing an iframe that is part of the browser
+  {
+    src: "http://example.org/",
+    isapp: false,
+    browser: true,
+    isolated: false,
+    child: {
+      src: "http://example.org/chrome/",
+      isapp: false,
+      inIsolatedMozBrowser: false,
+    },
+    test: [ "child-has-same-eo" ],
+  },
+  // iframe with isolation enabled containing an iframe with isolation disabled
+  // (isolated only has an effect on browsers)
+  {
+    src: "http://example.org/",
+    isapp: false,
+    browser: false,
+    isolated: true,
+    child: {
+      src: "http://example.org/chrome/",
+      isapp: false,
+      browser: false,
+      isolated: false,
     },
     test: [ "child-has-same-eo" ],
   },
 ];
 
 // The list of all data ids generated by this test.
 var eoList = [];
 
@@ -275,46 +320,60 @@ function checkIFrame(aFrame, data) {
     }
   } else {
     is(principal.appStatus, Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED,
        'this should not be an installed app');
     is(principal.appId, Ci.nsIScriptSecurityManager.NO_APP_ID,
        "principals from non-installed app should have NO_APP_ID");
   }
 
-  if (!data.isapp && !data.browser) {
+  if (!data.isapp && !data.browser ||
+      (data.browser && data.isolated === false)) {
     is(principal.jarPrefix, "",
-       'jarPrefix should return an empty string for non-app and non-browsers principals');
+       "jarPrefix should return an empty string for non-app, non-browsers, " +
+       "and browsers with isolation disabled");
   } else {
     isnot(principal.jarPrefix, "",
-          'jarPrefix should not return an empty string for apps or mozbrowsers');
+          "jarPrefix should not return an empty string for apps or browsers " +
+          "with isolation enabled");
   }
 
   if (data.test.indexOf("eo-unique") != -1) {
     is(eoList.indexOf(principal.jarPrefix + principal.origin), -1,
        "extended origin should be unique");
   }
   if (data.test.indexOf("eo-as-last") != -1) {
     is(principal.jarPrefix + principal.origin, eoList[eoList.length-1],
        "extended origin should be the same as the last inserted one");
   }
 
-  is(principal.isInBrowserElement, !!data.browser,
-     "check principal.isInBrowserElement");
+  let isolationExpected = false;
+  if (data.isolated !== false) {
+    isolationExpected = !!data.browser;
+  }
+  is(principal.isInIsolatedMozBrowserElement, isolationExpected,
+     "check principal.isInIsolatedMozBrowserElement");
 
   if (data.child) {
     let childPrincipal = aFrame.contentWindow.frames[0].document.nodePrincipal;
 
     if (data.child.isapp) {
       is(childPrincipal.appStatus, Ci.nsIPrincipal.APP_STATUS_INSTALLED,
          "child should be an installed app");
     }
 
-    is(childPrincipal.isInBrowserElement, !!data.child.browser || !!data.child.inBrowser,
-       "check childPrincipal.isInBrowserElement");
+    let childIsolationExpected = false;
+    if (data.child.isolated !== false) {
+      childIsolationExpected = !!data.child.browser;
+    }
+    if (data.child.inIsolatedMozBrowser !== undefined) {
+      childIsolationExpected = data.child.inIsolatedMozBrowser;
+    }
+    is(childPrincipal.isInIsolatedMozBrowserElement, childIsolationExpected,
+       "check childPrincipal.isInIsolatedMozBrowserElement");
 
     if (data.test.indexOf("child-has-same-eo") != -1) {
       is(childPrincipal.jarPrefix + childPrincipal.origin,
          principal.jarPrefix + principal.origin,
          "child should have the same extended origin as parent");
       is(childPrincipal.appStatus, principal.appStatus,
          "child should have the same appStatus if it has the same extended origin");
       is(childPrincipal.appId, principal.appId,
@@ -387,46 +446,55 @@ function runTest() {
 
       if (data.child.app) {
         childFrame.setAttribute('mozapp', data.child.app)
         childFrame.setAttribute('mozbrowser', '');
       } else if (data.child.browser) {
         childFrame.setAttribute('mozbrowser', '');
       }
 
+      if (data.child.isolated === false) {
+        childFrame.setAttribute("noisolation", "");
+      }
+
       childFrame.src = data.child.src;
 
       this.removeEventListener('load', this.addChild.bind(this));
       childFrame.addEventListener('load', this.check.bind(this));
 
       this.contentDocument.body.appendChild(childFrame);
     };
 
     if (data.app) {
       iframe.setAttribute('mozapp', data.app);
       iframe.setAttribute('mozbrowser', '');
     } else if (data.browser) {
       iframe.setAttribute('mozbrowser', '');
     }
 
+    if (data.isolated === false) {
+      iframe.setAttribute("noisolation", "");
+    }
+
     iframe.src = data.src;
 
     if (data.child) {
       iframe.addEventListener('load', iframe.addChild.bind(iframe));
     } else {
       iframe.addEventListener('load', iframe.check.bind(iframe));
     }
 
     content.appendChild(iframe);
 
     yield;
   }
 }
 
 var gTestRunner = runTest();
 
-SpecialPowers.pushPrefEnv({'set':[["dom.mozBrowserFramesEnabled", true]]},
-                           function() { gTestRunner.next(); });
+SpecialPowers.pushPrefEnv({"set": [
+  ["dom.mozBrowserFramesEnabled", true],
+]}, function() { gTestRunner.next(); });
 
 </script>
 </pre>
 </body>
 </html>
--- a/caps/tests/unit/test_origin.js
+++ b/caps/tests/unit/test_origin.js
@@ -19,45 +19,45 @@ function checkCrossOrigin(a, b) {
   do_check_false(a.subsumesConsideringDomain(b));
   do_check_false(b.subsumes(a));
   do_check_false(b.subsumesConsideringDomain(a));
 }
 
 function checkOriginAttributes(prin, attrs, suffix) {
   attrs = attrs || {};
   do_check_eq(prin.originAttributes.appId, attrs.appId || 0);
-  do_check_eq(prin.originAttributes.inBrowser, attrs.inBrowser || false);
+  do_check_eq(prin.originAttributes.inIsolatedMozBrowser, attrs.inIsolatedMozBrowser || false);
   do_check_eq(prin.originSuffix, suffix || '');
   do_check_eq(ChromeUtils.originAttributesToSuffix(attrs), suffix || '');
   do_check_true(ChromeUtils.originAttributesMatchPattern(prin.originAttributes, attrs));
   if (!prin.isNullPrincipal && !prin.origin.startsWith('[')) {
     do_check_true(ssm.createCodebasePrincipalFromOrigin(prin.origin).equals(prin));
   } else {
     checkThrows(() => ssm.createCodebasePrincipalFromOrigin(prin.origin));
   }
 }
 
 // utility function useful for debugging
 function printAttrs(name, attrs) {
   do_print(name + " {\n" +
            "\tappId: " + attrs.appId + ",\n" +
            "\tuserContextId: " + attrs.userContextId + ",\n" +
-           "\tinBrowser: " + attrs.inBrowser + ",\n" +
+           "\tinIsolatedMozBrowser: " + attrs.inIsolatedMozBrowser + ",\n" +
            "\taddonId: '" + attrs.addonId + "',\n" +
            "\tsignedPkg: '" + attrs.signedPkg + "'\n}");
 }
 
 
 function checkValues(attrs, values) {
   values = values || {};
   //printAttrs("attrs", attrs);
   //printAttrs("values", values);
   do_check_eq(attrs.appId, values.appId || 0);
   do_check_eq(attrs.userContextId, values.userContextId || 0);
-  do_check_eq(attrs.inBrowser, values.inBrowser || false);
+  do_check_eq(attrs.inIsolatedMozBrowser, values.inIsolatedMozBrowser || false);
   do_check_eq(attrs.addonId, values.addonId || '');
   do_check_eq(attrs.signedPkg, values.signedPkg || '');
 }
 
 function run_test() {
   // Attributeless origins.
   do_check_eq(ssm.getSystemPrincipal().origin, '[System Principal]');
   checkOriginAttributes(ssm.getSystemPrincipal());
@@ -94,32 +94,32 @@ function run_test() {
   // Just app.
   var exampleOrg_app = ssm.createCodebasePrincipal(makeURI('http://example.org'), {appId: 42});
   var nullPrin_app = ssm.createNullPrincipal({appId: 42});
   checkOriginAttributes(exampleOrg_app, {appId: 42}, '^appId=42');
   checkOriginAttributes(nullPrin_app, {appId: 42}, '^appId=42');
   do_check_eq(exampleOrg_app.origin, 'http://example.org^appId=42');
 
   // Just browser.
-  var exampleOrg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inBrowser: true});
-  var nullPrin_browser = ssm.createNullPrincipal({inBrowser: true});
-  checkOriginAttributes(exampleOrg_browser, {inBrowser: true}, '^inBrowser=1');
-  checkOriginAttributes(nullPrin_browser, {inBrowser: true}, '^inBrowser=1');
+  var exampleOrg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inIsolatedMozBrowser: true});
+  var nullPrin_browser = ssm.createNullPrincipal({inIsolatedMozBrowser: true});
+  checkOriginAttributes(exampleOrg_browser, {inIsolatedMozBrowser: true}, '^inBrowser=1');
+  checkOriginAttributes(nullPrin_browser, {inIsolatedMozBrowser: true}, '^inBrowser=1');
   do_check_eq(exampleOrg_browser.origin, 'http://example.org^inBrowser=1');
 
   // App and browser.
-  var exampleOrg_appBrowser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inBrowser: true, appId: 42});
-  var nullPrin_appBrowser = ssm.createNullPrincipal({inBrowser: true, appId: 42});
-  checkOriginAttributes(exampleOrg_appBrowser, {appId: 42, inBrowser: true}, '^appId=42&inBrowser=1');
-  checkOriginAttributes(nullPrin_appBrowser, {appId: 42, inBrowser: true}, '^appId=42&inBrowser=1');
+  var exampleOrg_appBrowser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inIsolatedMozBrowser: true, appId: 42});
+  var nullPrin_appBrowser = ssm.createNullPrincipal({inIsolatedMozBrowser: true, appId: 42});
+  checkOriginAttributes(exampleOrg_appBrowser, {appId: 42, inIsolatedMozBrowser: true}, '^appId=42&inBrowser=1');
+  checkOriginAttributes(nullPrin_appBrowser, {appId: 42, inIsolatedMozBrowser: true}, '^appId=42&inBrowser=1');
   do_check_eq(exampleOrg_appBrowser.origin, 'http://example.org^appId=42&inBrowser=1');
 
   // App and browser, different domain.
-  var exampleCom_appBrowser = ssm.createCodebasePrincipal(makeURI('https://www.example.com:123'), {appId: 42, inBrowser: true});
-  checkOriginAttributes(exampleCom_appBrowser, {appId: 42, inBrowser: true}, '^appId=42&inBrowser=1');
+  var exampleCom_appBrowser = ssm.createCodebasePrincipal(makeURI('https://www.example.com:123'), {appId: 42, inIsolatedMozBrowser: true});
+  checkOriginAttributes(exampleCom_appBrowser, {appId: 42, inIsolatedMozBrowser: true}, '^appId=42&inBrowser=1');
   do_check_eq(exampleCom_appBrowser.origin, 'https://www.example.com:123^appId=42&inBrowser=1');
 
   // Addon.
   var exampleOrg_addon = ssm.createCodebasePrincipal(makeURI('http://example.org'), {addonId: 'dummy'});
   checkOriginAttributes(exampleOrg_addon, { addonId: "dummy" }, '^addonId=dummy');
   do_check_eq(exampleOrg_addon.origin, 'http://example.org^addonId=dummy');
 
   // Make sure we don't crash when serializing principals with UNKNOWN_APP_ID.
@@ -156,18 +156,18 @@ function run_test() {
   do_check_eq(exampleOrg_userContextApp.origin, 'http://example.org^appId=24&userContextId=42');
 
   // Just signedPkg
   var exampleOrg_signedPkg = ssm.createCodebasePrincipal(makeURI('http://example.org'), {signedPkg: 'whatever'});
   checkOriginAttributes(exampleOrg_signedPkg, { signedPkg: 'whatever' }, '^signedPkg=whatever');
   do_check_eq(exampleOrg_signedPkg.origin, 'http://example.org^signedPkg=whatever');
 
   // signedPkg and browser
-  var exampleOrg_signedPkg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {signedPkg: 'whatever', inBrowser: true});
-  checkOriginAttributes(exampleOrg_signedPkg_browser, { signedPkg: 'whatever', inBrowser: true }, '^inBrowser=1&signedPkg=whatever');
+  var exampleOrg_signedPkg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {signedPkg: 'whatever', inIsolatedMozBrowser: true});
+  checkOriginAttributes(exampleOrg_signedPkg_browser, { signedPkg: 'whatever', inIsolatedMozBrowser: true }, '^inBrowser=1&signedPkg=whatever');
   do_check_eq(exampleOrg_signedPkg_browser.origin, 'http://example.org^inBrowser=1&signedPkg=whatever');
 
   // Just signedPkg (but different value from 'exampleOrg_signedPkg_app')
   var exampleOrg_signedPkg_another = ssm.createCodebasePrincipal(makeURI('http://example.org'), {signedPkg: 'whatup'});
 
   // Check that all of the above are cross-origin.
   checkCrossOrigin(exampleOrg_app, exampleOrg);
   checkCrossOrigin(exampleOrg_app, nullPrin_app);
@@ -207,20 +207,20 @@ function run_test() {
   checkValues(emptyAttrs);
 
   var uri = "http://example.org";
   var tests = [
     [ "", {} ],
     [ "^appId=5", {appId: 5} ],
     [ "^userContextId=3", {userContextId: 3} ],
     [ "^addonId=fooBar", {addonId: "fooBar"} ],
-    [ "^inBrowser=1", {inBrowser: true} ],
+    [ "^inBrowser=1", {inIsolatedMozBrowser: true} ],
     [ "^signedPkg=bazQux", {signedPkg: "bazQux"} ],
     [ "^appId=3&inBrowser=1&userContextId=6",
-      {appId: 3, userContextId: 6, inBrowser: true} ] ];
+      {appId: 3, userContextId: 6, inIsolatedMozBrowser: true} ] ];
 
   // check that we can create an origin attributes from an origin properly
   tests.forEach(function(t) {
     let attrs = ChromeUtils.createOriginAttributesFromOrigin(uri + t[0]);
     checkValues(attrs, t[1]);
     do_check_eq(ChromeUtils.originAttributesToSuffix(attrs), t[0]);
   });
 
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -109,16 +109,17 @@ skip-if = e10s # Bug 1091612
 [browser_net_security-warnings.js]
 [browser_net_send-beacon.js]
 [browser_net_send-beacon-other-tab.js]
 [browser_net_simple-init.js]
 [browser_net_simple-request-data.js]
 [browser_net_simple-request-details.js]
 [browser_net_simple-request.js]
 [browser_net_sort-01.js]
+skip-if = (e10s && debug && os == 'mac') # Bug 1253037
 [browser_net_sort-02.js]
 [browser_net_sort-03.js]
 [browser_net_statistics-01.js]
 [browser_net_statistics-02.js]
 [browser_net_statistics-03.js]
 [browser_net_status-codes.js]
 [browser_net_timeline_ticks.js]
 [browser_net_timing-division.js]
--- a/devtools/shared/layout/utils.js
+++ b/devtools/shared/layout/utils.js
@@ -29,17 +29,17 @@ const utilsFor = memoize(
  * @param {DOMWindow} win
  * @return {DOMWindow}
  */
 function getTopWindow(win) {
   let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIWebNavigation)
                     .QueryInterface(Ci.nsIDocShell);
 
-  if (!docShell.isBrowserOrApp) {
+  if (!docShell.isMozBrowserOrApp) {
     return win.top;
   }
 
   let topDocShell = docShell.getSameTypeRootTreeItemIgnoreBrowserAndAppBoundaries();
 
   return topDocShell
           ? topDocShell.contentViewer.DOMDocument.defaultView
           : null;
@@ -89,17 +89,17 @@ function getParentWindow(win) {
   if (isTopWindow(win)) {
     return null;
   }
 
   let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
                  .getInterface(Ci.nsIWebNavigation)
                  .QueryInterface(Ci.nsIDocShell);
 
-  if (!docShell.isBrowserOrApp) {
+  if (!docShell.isMozBrowserOrApp) {
     return win.parent;
   }
 
   let parentDocShell = docShell.getSameTypeParentIgnoreBrowserAndAppBoundaries();
 
   return parentDocShell
           ? parentDocShell.contentViewer.DOMDocument.defaultView
           : null;
--- a/docshell/base/LoadContext.cpp
+++ b/docshell/base/LoadContext.cpp
@@ -29,17 +29,17 @@ nsILoadContext::GetOriginAttributes(mozi
   JSAutoCompartment ac(jsapi.cx(), obj);
 
   mozilla::DocShellOriginAttributes attrs;
   ok = attrs.Init(jsapi.cx(), v);
   NS_ENSURE_TRUE(ok, false);
   aAttrs = attrs;
   return true;
 }
-  
+
 namespace mozilla {
 
 NS_IMPL_ISUPPORTS(LoadContext, nsILoadContext, nsIInterfaceRequestor)
 
 LoadContext::LoadContext(nsIPrincipal* aPrincipal,
                          nsILoadContext* aOptionalBase)
   : mTopFrameElement(nullptr)
   , mNestedFrameId(0)
@@ -167,23 +167,23 @@ LoadContext::SetRemoteTabs(bool aUseRemo
 {
   MOZ_ASSERT(mIsNotNull);
 
   // We shouldn't need this on parent...
   return NS_ERROR_UNEXPECTED;
 }
 
 NS_IMETHODIMP
-LoadContext::GetIsInBrowserElement(bool* aIsInBrowserElement)
+LoadContext::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement)
 {
   MOZ_ASSERT(mIsNotNull);
 
-  NS_ENSURE_ARG_POINTER(aIsInBrowserElement);
+  NS_ENSURE_ARG_POINTER(aIsInIsolatedMozBrowserElement);
 
-  *aIsInBrowserElement = mOriginAttributes.mInBrowser;
+  *aIsInIsolatedMozBrowserElement = mOriginAttributes.mInIsolatedMozBrowser;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 LoadContext::GetAppId(uint32_t* aAppId)
 {
   MOZ_ASSERT(mIsNotNull);
 
--- a/docshell/base/LoadContext.h
+++ b/docshell/base/LoadContext.h
@@ -34,35 +34,35 @@ class LoadContext final
   : public nsILoadContext
   , public nsIInterfaceRequestor
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSILOADCONTEXT
   NS_DECL_NSIINTERFACEREQUESTOR
 
-  // AppId/inBrowser arguments override those in SerializedLoadContext provided
-  // by child process.
+  // appId/inIsolatedMozBrowser arguments override those in SerializedLoadContext
+  // provided by child process.
   LoadContext(const IPC::SerializedLoadContext& aToCopy,
               dom::Element* aTopFrameElement,
               DocShellOriginAttributes& aAttrs)
     : mTopFrameElement(do_GetWeakReference(aTopFrameElement))
     , mNestedFrameId(0)
     , mIsContent(aToCopy.mIsContent)
     , mUsePrivateBrowsing(aToCopy.mUsePrivateBrowsing)
     , mUseRemoteTabs(aToCopy.mUseRemoteTabs)
     , mOriginAttributes(aAttrs)
 #ifdef DEBUG
     , mIsNotNull(aToCopy.mIsNotNull)
 #endif
   {
   }
 
-  // AppId/inBrowser arguments override those in SerializedLoadContext provided
-  // by child process.
+  // appId/inIsolatedMozBrowser arguments override those in SerializedLoadContext
+  // provided by child process.
   LoadContext(const IPC::SerializedLoadContext& aToCopy,
               uint64_t aNestedFrameId,
               DocShellOriginAttributes& aAttrs)
     : mTopFrameElement(nullptr)
     , mNestedFrameId(aNestedFrameId)
     , mIsContent(aToCopy.mIsContent)
     , mUsePrivateBrowsing(aToCopy.mUsePrivateBrowsing)
     , mUseRemoteTabs(aToCopy.mUseRemoteTabs)
--- a/docshell/base/nsDSURIContentListener.cpp
+++ b/docshell/base/nsDSURIContentListener.cpp
@@ -327,17 +327,17 @@ nsDSURIContentListener::CheckOneFrameOpt
 
   // Traverse up the parent chain and stop when we see a docshell whose
   // parent has a system principal, or a docshell corresponding to
   // <iframe mozbrowser>.
   while (NS_SUCCEEDED(
            curDocShellItem->GetParent(getter_AddRefs(parentDocShellItem))) &&
          parentDocShellItem) {
     nsCOMPtr<nsIDocShell> curDocShell = do_QueryInterface(curDocShellItem);
-    if (curDocShell && curDocShell->GetIsBrowserOrApp()) {
+    if (curDocShell && curDocShell->GetIsMozBrowserOrApp()) {
       break;
     }
 
     bool system = false;
     topDoc = parentDocShellItem->GetDocument();
     if (topDoc) {
       if (NS_SUCCEEDED(
             ssm->IsSystemPrincipal(topDoc->NodePrincipal(), &system)) &&
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -775,16 +775,17 @@ nsDocShell::nsDocShell()
   , mAllowContentRetargetingOnChildren(true)
   , mCreatingDocument(false)
   , mUseErrorPages(false)
   , mObserveErrorPages(true)
   , mAllowAuth(true)
   , mAllowKeywordFixup(false)
   , mIsOffScreenBrowser(false)
   , mIsActive(true)
+  , mDisableMetaRefreshWhenInactive(false)
   , mIsPrerendered(false)
   , mIsAppTab(false)
   , mUseGlobalHistory(false)
   , mInPrivateBrowsing(false)
   , mUseRemoteTabs(false)
   , mDeviceSizeIsPageSize(false)
   , mWindowDraggingAllowed(false)
   , mInFrameSwap(false)
@@ -800,16 +801,17 @@ nsDocShell::nsDocShell()
   , mInEnsureScriptEnv(false)
 #endif
   , mAffectPrivateSessionLifetime(true)
   , mInvisible(false)
   , mHasLoadedNonBlankURI(false)
   , mDefaultLoadFlags(nsIRequest::LOAD_NORMAL)
   , mBlankTiming(false)
   , mFrameType(eFrameTypeRegular)
+  , mIsInIsolatedMozBrowser(false)
   , mOwnOrContainingAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID)
   , mUserContextId(nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID)
   , mParentCharsetSource(0)
   , mJSRunToCompletionDepth(0)
 {
   mHistoryID = ++gDocshellIDCounter;
   if (gDocShellCount++ == 0) {
     NS_ASSERTION(sURIFixup == nullptr,
@@ -879,26 +881,23 @@ nsresult
 nsDocShell::Init()
 {
   nsresult rv = nsDocLoader::Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ASSERTION(mLoadGroup, "Something went wrong!");
 
   mContentListener = new nsDSURIContentListener(this);
-  NS_ENSURE_TRUE(mContentListener, NS_ERROR_OUT_OF_MEMORY);
-
   rv = mContentListener->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // We want to hold a strong ref to the loadgroup, so it better hold a weak
   // ref to us...  use an InterfaceRequestorProxy to do this.
   nsCOMPtr<nsIInterfaceRequestor> proxy =
     new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor*>(this));
-  NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY);
   mLoadGroup->SetNotificationCallbacks(proxy);
 
   rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Add as |this| a progress listener to itself.  A little weird, but
   // simpler than reproducing all the listener-notification logic in
   // overrides of the various methods via which nsDocLoader can be
@@ -1645,17 +1644,16 @@ nsDocShell::LoadStream(nsIInputStream* a
                     NS_ERROR_FAILURE);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo** aLoadInfo)
 {
   nsDocShellLoadInfo* loadInfo = new nsDocShellLoadInfo();
-  NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
   nsCOMPtr<nsIDocShellLoadInfo> localRef(loadInfo);
 
   localRef.forget(aLoadInfo);
   return NS_OK;
 }
 
 /*
  * Reset state to a new content model within the current document and the
@@ -2551,17 +2549,17 @@ nsDocShell::GetFullscreenAllowed(bool* a
   // Otherwise, we have a parent, continue the checking for
   // mozFullscreenAllowed in the parent docshell's ancestors.
   return parent->GetFullscreenAllowed(aFullscreenAllowed);
 }
 
 NS_IMETHODIMP
 nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed)
 {
-  if (!nsIDocShell::GetIsBrowserOrApp()) {
+  if (!nsIDocShell::GetIsMozBrowserOrApp()) {
     // Only allow setting of fullscreenAllowed on content/process boundaries.
     // At non-boundaries the fullscreenAllowed attribute is calculated based on
     // whether all enclosing frames have the "mozFullscreenAllowed" attribute
     // set to "true". fullscreenAllowed is set at the process boundaries to
     // propagate the value of the parent's "mozFullscreenAllowed" attribute
     // across process boundaries.
     return NS_ERROR_UNEXPECTED;
   }
@@ -2610,20 +2608,16 @@ nsDocShell::GetDocShellEnumerator(int32_
 
   RefPtr<nsDocShellEnumerator> docShellEnum;
   if (aDirection == ENUMERATE_FORWARDS) {
     docShellEnum = new nsDocShellForwardsEnumerator;
   } else {
     docShellEnum = new nsDocShellBackwardsEnumerator;
   }
 
-  if (!docShellEnum) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
   nsresult rv = docShellEnum->SetEnumDocShellType(aItemType);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   rv = docShellEnum->SetEnumerationRootItem((nsIDocShellTreeItem*)this);
   if (NS_FAILED(rv)) {
     return rv;
@@ -3359,17 +3353,17 @@ nsDocShell::SetDocLoaderParent(nsDocLoad
 }
 
 NS_IMETHODIMP
 nsDocShell::GetSameTypeParent(nsIDocShellTreeItem** aParent)
 {
   NS_ENSURE_ARG_POINTER(aParent);
   *aParent = nullptr;
 
-  if (nsIDocShell::GetIsBrowserOrApp()) {
+  if (nsIDocShell::GetIsMozBrowserOrApp()) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIDocShellTreeItem> parent =
     do_QueryInterface(GetAsSupports(mParent));
   if (!parent) {
     return NS_OK;
   }
@@ -3495,17 +3489,18 @@ nsDocShell::CanAccessItem(nsIDocShellTre
 
   nsCOMPtr<nsIDocShell> targetDS = do_QueryInterface(aTargetItem);
   nsCOMPtr<nsIDocShell> accessingDS = do_QueryInterface(aAccessingItem);
   if (!targetDS || !accessingDS) {
     // We must be able to convert both to nsIDocShell.
     return false;
   }
 
-  if (targetDS->GetIsInBrowserElement() != accessingDS->GetIsInBrowserElement() ||
+  if (targetDS->GetIsInIsolatedMozBrowserElement() !=
+        accessingDS->GetIsInIsolatedMozBrowserElement() ||
       targetDS->GetAppId() != accessingDS->GetAppId()) {
     return false;
   }
 
   // A private document can't access a non-private one, and vice versa.
   if (static_cast<nsDocShell*>(targetDS.get())->UsePrivateBrowsing() !=
       static_cast<nsDocShell*>(accessingDS.get())->UsePrivateBrowsing()) {
     return false;
@@ -4010,16 +4005,17 @@ nsDocShell::AddChild(nsIDocShellTreeItem
   }
 
   if (aChild->ItemType() != mItemType) {
     return NS_OK;
   }
 
   aChild->SetTreeOwner(mTreeOwner);
   childDocShell->SetUserContextId(mUserContextId);
+  childDocShell->SetIsInIsolatedMozBrowserElement(mIsInIsolatedMozBrowser);
 
   nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild));
   if (!childAsDocShell) {
     return NS_OK;
   }
 
   // charset, style-disabling, and zoom will be inherited in SetupNewViewer()
 
@@ -5630,16 +5626,20 @@ nsDocShell::Create()
 
   if (!gAddedPreferencesVarCache) {
     Preferences::AddBoolVarCache(&sUseErrorPages,
                                  "browser.xul.error_pages.enabled",
                                  mUseErrorPages);
     gAddedPreferencesVarCache = true;
   }
 
+  mDisableMetaRefreshWhenInactive =
+    Preferences::GetBool("browser.meta_refresh_when_inactive.disabled",
+                         mDisableMetaRefreshWhenInactive);
+
   mDeviceSizeIsPageSize =
     Preferences::GetBool("docshell.device_size_is_page_size",
                          mDeviceSizeIsPageSize);
 
   nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
   if (serv) {
     const char* msg = mItemType == typeContent ?
       NS_WEBNAVIGATION_CREATE : NS_CHROME_WEBNAVIGATION_CREATE;
@@ -5815,20 +5815,24 @@ nsDocShell::SetPosition(int32_t aX, int3
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::SetPositionDesktopPix(int32_t aX, int32_t aY)
 {
-  // Added to nsIBaseWindow in bug 1247335;
-  // implement if a use-case is found.
-  NS_ASSERTION(false, "implement me!");
-  return NS_ERROR_NOT_IMPLEMENTED;
+  nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
+  if (ownerWindow) {
+    return ownerWindow->SetPositionDesktopPix(aX, aY);
+  }
+
+  double scale = 1.0;
+  GetDevicePixelsPerDesktopPixel(&scale);
+  return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale));
 }
 
 NS_IMETHODIMP
 nsDocShell::GetPosition(int32_t* aX, int32_t* aY)
 {
   return GetPositionAndSize(aX, aY, nullptr, nullptr);
 }
 
@@ -6119,25 +6123,34 @@ nsDocShell::SetIsActiveInternal(bool aIs
   // children; they handle their state separately.
   nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
   while (iter.HasMore()) {
     nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext());
     if (!docshell) {
       continue;
     }
 
-    if (!docshell->GetIsBrowserOrApp()) {
+    if (!docshell->GetIsMozBrowserOrApp()) {
       if (aIsHidden) {
         docshell->SetIsActive(aIsActive);
       } else {
         docshell->SetIsActiveAndForeground(aIsActive);
       }
     }
   }
 
+  // Restart or stop meta refresh timers if necessary
+  if (mDisableMetaRefreshWhenInactive) {
+    if (mIsActive) {
+      ResumeRefreshURIs();
+    } else {
+      SuspendRefreshURIs();
+    }
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetIsActive(bool* aIsActive)
 {
   *aIsActive = mIsActive;
   return NS_OK;
@@ -6573,37 +6586,35 @@ nsDocShell::RefreshURI(nsIURI* aURI, int
   if (NS_FAILED(rv)) {
     sameURI = false;
   }
   if (!RefreshAttempted(this, aURI, aDelay, sameURI)) {
     return NS_OK;
   }
 
   nsRefreshTimer* refreshTimer = new nsRefreshTimer();
-  NS_ENSURE_TRUE(refreshTimer, NS_ERROR_OUT_OF_MEMORY);
   uint32_t busyFlags = 0;
   GetBusyFlags(&busyFlags);
 
   nsCOMPtr<nsISupports> dataRef = refreshTimer;  // Get the ref count to 1
 
   refreshTimer->mDocShell = this;
   refreshTimer->mURI = aURI;
   refreshTimer->mDelay = aDelay;
   refreshTimer->mRepeat = aRepeat;
   refreshTimer->mMetaRefresh = aMetaRefresh;
 
   if (!mRefreshURIList) {
     NS_ENSURE_SUCCESS(NS_NewISupportsArray(getter_AddRefs(mRefreshURIList)),
                       NS_ERROR_FAILURE);
   }
 
-  if (busyFlags & BUSY_FLAGS_BUSY) {
-    // We are busy loading another page. Don't create the
-    // timer right now. Instead queue up the request and trigger the
-    // timer in EndPageLoad().
+  if (busyFlags & BUSY_FLAGS_BUSY || (!mIsActive && mDisableMetaRefreshWhenInactive)) {
+    // We don't  want to create the timer right now. Instead queue up the request
+    // and trigger the timer in EndPageLoad() or whenever we become active.
     mRefreshURIList->AppendElement(refreshTimer);
   } else {
     // There is no page loading going on right now.  Create the
     // timer and fire it right away.
     nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
     NS_ENSURE_TRUE(timer, NS_ERROR_FAILURE);
 
     mRefreshURIList->AppendElement(timer);  // owning timer ref
@@ -7546,17 +7557,18 @@ nsDocShell::EndPageLoad(nsIWebProgress* 
     mLSHE->SetLoadType(nsIDocShellLoadInfo::loadHistory);
 
     // Clear the mLSHE reference to indicate document loading is done one
     // way or another.
     SetHistoryEntry(&mLSHE, nullptr);
   }
   // if there's a refresh header in the channel, this method
   // will set it up for us.
-  RefreshURIFromQueue();
+  if (mIsActive || !mDisableMetaRefreshWhenInactive)
+    RefreshURIFromQueue();
 
   // Test whether this is the top frame or a subframe
   bool isTopFrame = true;
   nsCOMPtr<nsIDocShellTreeItem> targetParentTreeItem;
   rv = GetSameTypeParent(getter_AddRefs(targetParentTreeItem));
   if (NS_SUCCEEDED(rv) && targetParentTreeItem) {
     isTopFrame = false;
   }
@@ -13881,39 +13893,32 @@ nsDocShell::SetUserContextId(uint32_t aU
 
     docshell->SetUserContextId(aUserContextId);
   }
 
   return NS_OK;
 }
 
 /* [infallible] */ NS_IMETHODIMP
-nsDocShell::GetIsBrowserElement(bool* aIsBrowser)
-{
-  *aIsBrowser = (mFrameType == eFrameTypeBrowser);
-  return NS_OK;
-}
-
-/* [infallible] */ NS_IMETHODIMP
 nsDocShell::GetIsApp(bool* aIsApp)
 {
   *aIsApp = (mFrameType == eFrameTypeApp);
   return NS_OK;
 }
 
 /* [infallible] */ NS_IMETHODIMP
-nsDocShell::GetIsBrowserOrApp(bool* aIsBrowserOrApp)
+nsDocShell::GetIsMozBrowserOrApp(bool* aIsMozBrowserOrApp)
 {
   switch (mFrameType) {
     case eFrameTypeRegular:
-      *aIsBrowserOrApp = false;
+      *aIsMozBrowserOrApp = false;
       break;
     case eFrameTypeBrowser:
     case eFrameTypeApp:
-      *aIsBrowserOrApp = true;
+      *aIsMozBrowserOrApp = true;
       break;
   }
 
   return NS_OK;
 }
 
 nsDocShell::FrameType
 nsDocShell::GetInheritedFrameType()
@@ -13929,32 +13934,52 @@ nsDocShell::GetInheritedFrameType()
   if (!parent) {
     return eFrameTypeRegular;
   }
 
   return static_cast<nsDocShell*>(parent.get())->GetInheritedFrameType();
 }
 
 /* [infallible] */ NS_IMETHODIMP
-nsDocShell::GetIsInBrowserElement(bool* aIsInBrowserElement)
-{
-  *aIsInBrowserElement = (GetInheritedFrameType() == eFrameTypeBrowser);
+nsDocShell::GetIsIsolatedMozBrowserElement(bool* aIsIsolatedMozBrowserElement)
+{
+  bool result = mFrameType == eFrameTypeBrowser && mIsInIsolatedMozBrowser;
+  *aIsIsolatedMozBrowserElement = result;
   return NS_OK;
 }
 
 /* [infallible] */ NS_IMETHODIMP
-nsDocShell::GetIsInBrowserOrApp(bool* aIsInBrowserOrApp)
+nsDocShell::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement)
+{
+  MOZ_ASSERT(!mIsInIsolatedMozBrowser ||
+             (GetInheritedFrameType() == eFrameTypeBrowser),
+             "Isolated mozbrowser should only be true inside browser frames");
+  bool result = (GetInheritedFrameType() == eFrameTypeBrowser) &&
+                mIsInIsolatedMozBrowser;
+  *aIsInIsolatedMozBrowserElement = result;
+  return NS_OK;
+}
+
+/* [infallible] */ NS_IMETHODIMP
+nsDocShell::SetIsInIsolatedMozBrowserElement(bool aIsInIsolatedMozBrowserElement)
+{
+  mIsInIsolatedMozBrowser = aIsInIsolatedMozBrowserElement;
+  return NS_OK;
+}
+
+/* [infallible] */ NS_IMETHODIMP
+nsDocShell::GetIsInMozBrowserOrApp(bool* aIsInMozBrowserOrApp)
 {
   switch (GetInheritedFrameType()) {
     case eFrameTypeRegular:
-      *aIsInBrowserOrApp = false;
+      *aIsInMozBrowserOrApp = false;
       break;
     case eFrameTypeBrowser:
     case eFrameTypeApp:
-      *aIsInBrowserOrApp = true;
+      *aIsInMozBrowserOrApp = true;
       break;
   }
 
   return NS_OK;
 }
 
 /* [infallible] */ NS_IMETHODIMP
 nsDocShell::GetAppId(uint32_t* aAppId)
@@ -13990,20 +14015,17 @@ nsDocShell::GetOriginAttributes()
     attrs.mSignedPkg = mSignedPkg;
   }
 
   if (mOwnOrContainingAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
     attrs.mAppId = mOwnOrContainingAppId;
   }
 
   attrs.mUserContextId = mUserContextId;
-
-  if (mFrameType == eFrameTypeBrowser) {
-    attrs.mInBrowser = true;
-  }
+  attrs.mInIsolatedMozBrowser = mIsInIsolatedMozBrowser;
 
   return attrs;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetOriginAttributes(JS::MutableHandle<JS::Value> aVal)
 {
   JSContext* cx = nsContentUtils::GetCurrentJSContext();
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -933,16 +933,17 @@ protected:
   bool mAllowContentRetargetingOnChildren;
   bool mCreatingDocument; // (should be) debugging only
   bool mUseErrorPages;
   bool mObserveErrorPages;
   bool mAllowAuth;
   bool mAllowKeywordFixup;
   bool mIsOffScreenBrowser;
   bool mIsActive;
+  bool mDisableMetaRefreshWhenInactive;
   bool mIsPrerendered;
   bool mIsAppTab;
   bool mUseGlobalHistory;
   bool mInPrivateBrowsing;
   bool mUseRemoteTabs;
   bool mDeviceSizeIsPageSize;
   bool mWindowDraggingAllowed;
   bool mInFrameSwap;
@@ -995,16 +996,19 @@ protected:
   // This flag means that mTiming has been initialized but nulled out.
   // We will check the innerWin's timing before creating a new one
   // in MaybeInitTiming()
   bool mBlankTiming;
 
   // Are we a regular frame, a browser frame, or an app frame?
   FrameType mFrameType;
 
+  // Whether we are in an isolated mozbrowser frame.
+  bool mIsInIsolatedMozBrowser;
+
   // We only expect mOwnOrContainingAppId to be something other than
   // UNKNOWN_APP_ID if mFrameType != eFrameTypeRegular. For vanilla iframes
   // inside an app, we'll retrieve the containing app-id by walking up the
   // docshell hierarchy.
   //
   // (This needs to be the docshell's own /or containing/ app id because the
   // containing app frame might be in another process, in which case we won't
   // find it by walking up the docshell hierarchy.)
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -759,53 +759,64 @@ interface nsIDocShell : nsIDocShellTreeI
 
   /**
    * Notify all attached observers that the scroll position of some element
    * has changed.
    */
   [noscript] void notifyScrollObservers();
 
   /**
-   * Returns true if this docshell corresponds to an <iframe mozbrowser>.
-   * (<iframe mozapp mozbrowser> is not considered a browser.)
-   */
-  [infallible] readonly attribute boolean isBrowserElement;
-
-  /**
    * Returns true iff the docshell corresponds to an <iframe mozapp>.
    */
   [infallible] readonly attribute boolean isApp;
 
   /**
-   * Returns isBrowserElement || isApp.
+   * Returns true if this docshell corresponds to an <iframe mozbrowser> or
+   * <iframe mozapp>.  <xul:browser> returns false here.
    */
-  [infallible] readonly attribute boolean isBrowserOrApp;
+  [infallible] readonly attribute boolean isMozBrowserOrApp;
 
   /**
-   * Returns true if this docshell corresponds to an <iframe mozbrowser> or if
-   * the docshell is contained in an <iframe mozbrowser>.  (<iframe mozapp
-   * mozbrowser> does not count as a browser.)
+   * Returns true if this docshell corresponds to an isolated <iframe
+   * mozbrowser>.
+   *
+   * <iframe mozbrowser mozapp> and <xul:browser> are not considered to be
+   * mozbrowser elements.  <iframe mozbrowser noisolation> does not count as
+   * isolated since isolation is disabled.  Isolation can only be disabled if
+   * the containing document is chrome.
+   */
+  [infallible] readonly attribute boolean isIsolatedMozBrowserElement;
+
+  /**
+   * Returns true if this docshell corresponds to an isolated <iframe
+   * mozbrowser> or if the docshell is contained in an isolated <iframe
+   * mozbrowser>.
+   *
+   * <iframe mozbrowser mozapp> and <xul:browser> are not considered to be
+   * mozbrowser elements.  <iframe mozbrowser noisolation> does not count as
+   * isolated since isolation is disabled.  Isolation can only be disabled if
+   * the containing document is chrome.
    *
    * Our notion here of "contained in" means: Walk up the docshell hierarchy in
    * this process until we hit an <iframe mozapp> or <iframe mozbrowser> (or
    * until the hierarchy ends).  Return true iff the docshell we stopped on has
-   * isBrowserElement == true.
+   * isIsolatedMozBrowserElement == true.
    */
-  [infallible] readonly attribute boolean isInBrowserElement;
+  [infallible] attribute boolean isInIsolatedMozBrowserElement;
 
   /**
    * Returns true if this docshell corresponds to an <iframe mozbrowser> or
    * <iframe mozapp>, or if this docshell is contained in an <iframe mozbrowser>
-   * or <iframe mozapp>.
+   * or <iframe mozapp>.  <xul:browser> returns false here.
    *
    * To compute this value, we walk up the docshell hierarchy.  If we encounter
-   * a docshell with isBrowserElement or isApp before we hit the end of the
-   * hierarchy, we return true.  Otherwise, we return false.
+   * a docshell with isMozBrowserOrApp before we hit the end of the hierarchy,
+   * we return true.  Otherwise, we return false.
    */
-  [infallible] readonly attribute boolean isInBrowserOrApp;
+  [infallible] readonly attribute boolean isInMozBrowserOrApp;
 
    /**
     * Indicate that this docshell corresponds to an app with the given app id.
     *
     * You may pass NO_APP_ID or UNKNOWN_APP_ID for containingAppId.  If you
     * pass NO_APP_ID, then this docshell will return NO_APP_ID for appId.  If
     * you pass UNKNOWN_APP_ID, then this docshell will search its hiearchy for
     * an app frame and use that frame's appId.
--- a/docshell/base/nsILoadContext.idl
+++ b/docshell/base/nsILoadContext.idl
@@ -111,19 +111,23 @@ interface nsILoadContext : nsISupports
   [noscript] void SetPrivateBrowsing(in boolean aInPrivateBrowsing);
 
   /**
    * Set the remote tabs state of the load context, meant to be used internally.
    */
   [noscript] void SetRemoteTabs(in boolean aUseRemoteTabs);
 
   /**
-   * Returns true iff the load is occurring inside a browser element.
+   * Returns true iff the load is occurring inside an isolated mozbrowser
+   * element. <iframe mozbrowser mozapp> and <xul:browser> are not considered to
+   * be mozbrowser elements.  <iframe mozbrowser noisolation> does not count as
+   * isolated since isolation is disabled.  Isolation can only be disabled if
+   * the containing document is chrome.
    */
-  readonly attribute boolean isInBrowserElement;
+  readonly attribute boolean isInIsolatedMozBrowserElement;
 
   /**
    * Returns the app id of the app the load is occurring is in. Returns
    * nsIScriptSecurityManager::NO_APP_ID if the load is not part of an app.
    */
   readonly attribute unsigned long appId;
 
   /**
--- a/dom/animation/AnimationTimeline.h
+++ b/dom/animation/AnimationTimeline.h
@@ -86,16 +86,27 @@ public:
   /**
    * Inform this timeline that |aAnimation| which is or was observing the
    * timeline, has been updated. This serves as both the means to associate
    * AND disassociate animations with a timeline. The timeline itself will
    * determine if it needs to begin, continue or stop tracking this animation.
    */
   virtual void NotifyAnimationUpdated(Animation& aAnimation);
 
+  /**
+   * Returns true if any CSS animations, CSS transitions or Web animations are
+   * currently associated with this timeline.  As soon as an animation is
+   * applied to an element it is associated with the timeline even if it has a
+   * delayed start, so this includes animations that may not be active for some
+   * time.
+   */
+  bool HasAnimations() const {
+    return !mAnimations.IsEmpty();
+  }
+
   void RemoveAnimation(Animation* aAnimation);
 
 protected:
   nsCOMPtr<nsIGlobalObject> mWindow;
 
   // Animations observing this timeline
   //
   // We store them in (a) a hashset for quick lookup, and (b) an array
--- a/dom/apps/AppsService.js
+++ b/dom/apps/AppsService.js
@@ -101,16 +101,20 @@ AppsService.prototype = {
     return DOMApplicationRegistry.getCoreAppsBasePath();
   },
 
   getWebAppsBasePath: function getWebAppsBasePath() {
     debug("getWebAppsBasePath()");
     return DOMApplicationRegistry.getWebAppsBasePath();
   },
 
+  areAnyAppsInstalled: function() {
+    return DOMApplicationRegistry.areAnyAppsInstalled();
+  },
+
   getAppInfo: function getAppInfo(aAppId) {
     debug("getAppInfo()");
     return DOMApplicationRegistry.getAppInfo(aAppId);
   },
 
   getRedirect: function getRedirect(aLocalId, aURI) {
     debug("getRedirect for " + aLocalId + " " + aURI.spec);
     if (this.isInvalidId(aLocalId)) {
--- a/dom/apps/AppsServiceChild.jsm
+++ b/dom/apps/AppsServiceChild.jsm
@@ -407,16 +407,20 @@ this.DOMApplicationRegistry = {
     return null;
   },
 
   getWebAppsBasePath: function getWebAppsBasePath() {
     debug("getWebAppsBasePath() not yet supported on child!");
     return null;
   },
 
+  areAnyAppsInstalled: function() {
+    return AppsUtils.areAnyAppsInstalled(this.webapps);
+  },
+
   getAppInfo: function getAppInfo(aAppId) {
     return AppsUtils.getAppInfo(this.webapps, aAppId);
   },
 
   updateDataStoreEntriesFromLocalId: function(aLocalId) {
     debug("updateDataStoreEntriesFromLocalId() not yet supported on child!");
   }
 }
--- a/dom/apps/AppsUtils.jsm
+++ b/dom/apps/AppsUtils.jsm
@@ -144,26 +144,27 @@ function _setAppProperties(aObj, aApp) {
 this.AppsUtils = {
   // Clones a app, without the manifest.
   cloneAppObject: function(aApp) {
     let obj = {};
     _setAppProperties(obj, aApp);
     return obj;
   },
 
-  // Creates a nsILoadContext object with a given appId and isBrowser flag.
-  createLoadContext: function createLoadContext(aAppId, aIsBrowser) {
+  // Creates a nsILoadContext object with a given appId and inIsolatedMozBrowser
+  // flag.
+  createLoadContext: function createLoadContext(aAppId, aInIsolatedMozBrowser) {
     return {
        associatedWindow: null,
        topWindow : null,
        appId: aAppId,
-       isInBrowserElement: aIsBrowser,
+       isInIsolatedMozBrowserElement: aInIsolatedMozBrowser,
        originAttributes: {
          appId: aAppId,
-         inBrowser: aIsBrowser
+         inIsolatedMozBrowser: aInIsolatedMozBrowser
        },
        usePrivateBrowsing: false,
        isContent: false,
 
        isAppOfType: function(appType) {
          throw Cr.NS_ERROR_NOT_IMPLEMENTED;
        },
 
@@ -339,16 +340,20 @@ this.AppsUtils = {
       if (app.localId == aLocalId) {
         return app.manifestURL;
       }
     }
 
     return "";
   },
 
+  areAnyAppsInstalled: function(aApps) {
+    return Object.getOwnPropertyNames(aApps).length > 0;
+  },
+
   getCoreAppsBasePath: function getCoreAppsBasePath() {
     debug("getCoreAppsBasePath()");
     try {
       return FileUtils.getDir("coreAppsDir", ["webapps"], false).path;
     } catch(e) {
       return null;
     }
   },
--- a/dom/apps/Webapps.js
+++ b/dom/apps/Webapps.js
@@ -178,17 +178,17 @@ WebappsRegistry.prototype = {
                     categories: categories
                   },
 
              from: installURL,
              oid: this._id,
              topId: this._topId,
              requestID: requestID,
              appId: principal.appId,
-             isBrowser: principal.isInBrowserElement,
+             isBrowser: principal.isInIsolatedMozBrowserElement,
              isPackage: isPackage
            };
   },
 
   // mozIDOMApplicationRegistry implementation
 
   install: function(aURL, aParams) {
     let request = this.createRequest();
--- a/dom/apps/Webapps.jsm
+++ b/dom/apps/Webapps.jsm
@@ -3531,20 +3531,20 @@ this.DOMApplicationRegistry = {
           lastProgressTime = now;
           this._saveApps();
         }
       }).bind(this),
       onStatus: function(aRequest, aContext, aStatus, aStatusArg) { },
 
       // nsILoadContext
       appId: aOldApp.installerAppId,
-      isInBrowserElement: aOldApp.installerIsBrowser,
+      isInIsolatedMozBrowserElement: aOldApp.installerIsBrowser,
       originAttributes: {
         appId: aOldApp.installerAppId,
-        inBrowser: aOldApp.installerIsBrowser
+        inIsolatedMozBrowser: aOldApp.installerIsBrowser
       },
       usePrivateBrowsing: false,
       isContent: false,
       associatedWindow: null,
       topWindow : null,
       isAppOfType: function(appType) {
         throw Cr.NS_ERROR_NOT_IMPLEMENTED;
       }
@@ -4794,16 +4794,20 @@ this.DOMApplicationRegistry = {
   getCoreAppsBasePath: function() {
     return AppsUtils.getCoreAppsBasePath();
   },
 
   getWebAppsBasePath: function() {
     return OS.Path.dirname(this.appsFile);
   },
 
+  areAnyAppsInstalled: function() {
+    return AppsUtils.areAnyAppsInstalled(this.webapps);
+  },
+
   updateDataStoreEntriesFromLocalId: function(aLocalId) {
     let app = appsService.getAppByLocalId(aLocalId);
     if (app) {
       this.updateDataStoreForApp(app.id);
     }
   },
 
   _isLaunchable: function(aApp) {
@@ -4897,17 +4901,17 @@ this.DOMApplicationRegistry = {
     };
     this._clearOriginData(appId, browserOnly);
     this._notifyCategoryAndObservers(subject, "webapps-clear-data", null, msg);
   },
 
   _clearOriginData: function(appId, browserOnly) {
     let attributes = {appId: appId};
     if (browserOnly) {
-      attributes.inBrowser = true;
+      attributes.inIsolatedMozBrowser = true;
     }
     this._notifyCategoryAndObservers(null, "clear-origin-data", JSON.stringify(attributes));
   }
 };
 
 /**
  * Appcache download observer
  */
--- a/dom/apps/tests/unit/test_moziapplication.js
+++ b/dom/apps/tests/unit/test_moziapplication.js
@@ -48,16 +48,16 @@ add_test(() => {
                  "app[" + key + "] should be equal to mozapp[" + key + "]");
   });
 
   Assert.ok(mozapp.principal, "app principal should exist");
   let expectedPrincipalOrigin = app.origin + "^appId=" + app.localId;
   Assert.equal(mozapp.principal.origin, expectedPrincipalOrigin,
                "app principal origin ok");
   Assert.equal(mozapp.principal.appId, app.localId, "app principal appId ok");
-  Assert.equal(mozapp.principal.isInBrowserElement, false,
-               "app principal isInBrowserElement ok");
+  Assert.equal(mozapp.principal.isInIsolatedMozBrowserElement, false,
+               "app principal isInIsolatedMozBrowserElement ok");
   run_next_test();
 });
 
 function run_test() {
   run_next_test();
 }
--- a/dom/base/ChromeUtils.cpp
+++ b/dom/base/ChromeUtils.cpp
@@ -103,15 +103,15 @@ ChromeUtils::CreateOriginAttributesFromD
 
 /* static */ bool
 ChromeUtils::IsOriginAttributesEqual(dom::GlobalObject& aGlobal,
                                      const dom::OriginAttributesDictionary& aA,
                                      const dom::OriginAttributesDictionary& aB)
 {
   return aA.mAddonId == aB.mAddonId &&
          aA.mAppId == aB.mAppId &&
-         aA.mInBrowser == aB.mInBrowser &&
+         aA.mInIsolatedMozBrowser == aB.mInIsolatedMozBrowser &&
          aA.mSignedPkg == aB.mSignedPkg &&
          aA.mUserContextId == aB.mUserContextId;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/PerformanceObserver.cpp
+++ b/dom/base/PerformanceObserver.cpp
@@ -130,38 +130,39 @@ PerformanceObserver::QueueEntry(Performa
   aEntry->GetEntryType(entryType);
   if (!mEntryTypes.Contains<nsString>(entryType)) {
     return;
   }
 
   mQueuedEntries.AppendElement(aEntry);
 }
 
-static nsString sValidTypeNames[7] = {
-  NS_LITERAL_STRING("composite"),
-  NS_LITERAL_STRING("mark"),
-  NS_LITERAL_STRING("measure"),
-  NS_LITERAL_STRING("navigation"),
-  NS_LITERAL_STRING("render"),
-  NS_LITERAL_STRING("resource"),
-  NS_LITERAL_STRING("server")
+static const char16_t* sValidTypeNames[7] = {
+  MOZ_UTF16("composite"),
+  MOZ_UTF16("mark"),
+  MOZ_UTF16("measure"),
+  MOZ_UTF16("navigation"),
+  MOZ_UTF16("render"),
+  MOZ_UTF16("resource"),
+  MOZ_UTF16("server")
 };
 
 void
 PerformanceObserver::Observe(const PerformanceObserverInit& aOptions,
                              ErrorResult& aRv)
 {
   if (aOptions.mEntryTypes.IsEmpty()) {
     aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
     return;
   }
 
   nsTArray<nsString> validEntryTypes;
 
-  for (const nsString& validTypeName : sValidTypeNames) {
+  for (const char16_t* name : sValidTypeNames) {
+    nsDependentString validTypeName(name);
     if (aOptions.mEntryTypes.Contains<nsString>(validTypeName) &&
         !validEntryTypes.Contains<nsString>(validTypeName)) {
       validEntryTypes.AppendElement(validTypeName);
     }
   }
 
   if (validEntryTypes.IsEmpty()) {
     aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
--- a/dom/base/ScriptSettings.cpp
+++ b/dom/base/ScriptSettings.cpp
@@ -344,19 +344,20 @@ AutoJSAPI::InitInternal(JSObject* aGloba
     // be necessary.
     JS::Rooted<JSObject*> global(JS_GetRuntime(aCx), aGlobal);
     mCxPusher.emplace(mCx);
     mAutoNullableCompartment.emplace(mCx, global);
   } else {
     mAutoNullableCompartment.emplace(mCx, aGlobal);
   }
 
+  JSRuntime* rt = JS_GetRuntime(aCx);
+  mOldErrorReporter.emplace(JS_GetErrorReporter(rt));
+
   if (aIsMainThread) {
-    JSRuntime* rt = JS_GetRuntime(aCx);
-    mOldErrorReporter.emplace(JS_GetErrorReporter(rt));
     JS_SetErrorReporter(rt, xpc::SystemErrorReporter);
   }
 }
 
 AutoJSAPI::AutoJSAPI(nsIGlobalObject* aGlobalObject,
                      bool aIsMainThread,
                      JSContext* aCx)
   : mOwnErrorReporting(false)
@@ -460,18 +461,31 @@ AutoJSAPI::InitWithLegacyErrorReporting(
 // reports to the JSErrorReporter as soon as they are generated. These go
 // directly to the console, so we can handle them easily here.
 //
 // Eventually, SpiderMonkey will have a special-purpose callback for warnings
 // only.
 void
 WarningOnlyErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aRep)
 {
-  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(JSREPORT_IS_WARNING(aRep->flags));
+  if (!NS_IsMainThread()) {
+    // Reporting a warning on workers is a bit complicated because we have to
+    // climb our parent chain until we get to the main thread.  So go ahead and
+    // just go through the worker ReportError codepath here.
+    //
+    // That said, it feels like we should be able to short-circuit things a bit
+    // here by posting an appropriate runnable to the main thread directly...
+    // Worth looking into sometime.
+    workers::WorkerPrivate* worker = workers::GetWorkerPrivateFromContext(aCx);
+    MOZ_ASSERT(worker);
+
+    worker->ReportError(aCx, aMessage, aRep);
+    return;
+  }
 
   RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
   nsGlobalWindow* win = xpc::CurrentWindowOrNull(aCx);
   xpcReport->Init(aRep, aMessage, nsContentUtils::IsCallerChrome(),
                   win ? win->AsInner()->WindowID() : 0);
   xpcReport->LogToConsole();
 }
 
@@ -479,23 +493,17 @@ void
 AutoJSAPI::TakeOwnershipOfErrorReporting()
 {
   MOZ_ASSERT(!mOwnErrorReporting);
   mOwnErrorReporting = true;
 
   JSRuntime *rt = JS_GetRuntime(cx());
   mOldAutoJSAPIOwnsErrorReporting = JS::ContextOptionsRef(cx()).autoJSAPIOwnsErrorReporting();
   JS::ContextOptionsRef(cx()).setAutoJSAPIOwnsErrorReporting(true);
-  // Workers have their own error reporting mechanism which deals with warnings
-  // as well, so don't change the worker error reporter for now.  Once we switch
-  // all of workers to TakeOwnershipOfErrorReporting(), we will just make the
-  // default worker error reporter assert that it only sees warnings.
-  if (mIsMainThread) {
-    JS_SetErrorReporter(rt, WarningOnlyErrorReporter);
-  }
+  JS_SetErrorReporter(rt, WarningOnlyErrorReporter);
 }
 
 void
 AutoJSAPI::ReportException()
 {
   MOZ_ASSERT(OwnsErrorReporting(), "This is not our exception to report!");
   if (!HasException()) {
     return;
@@ -543,16 +551,17 @@ AutoJSAPI::ReportException()
       // to get hold of it.  After we invoke ReportError, clear the exception on
       // cx(), just in case ReportError didn't.
       JS_SetPendingException(cx(), exn);
       worker->ReportError(cx(), jsReport.message(), jsReport.report());
       ClearException();
     }
   } else {
     NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");
+    ClearException();
   }
 }
 
 bool
 AutoJSAPI::PeekException(JS::MutableHandle<JS::Value> aVal)
 {
   MOZ_ASSERT_IF(mIsMainThread, CxPusherIsStackTop());
   MOZ_ASSERT(HasException());
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -417,17 +417,17 @@ nsFrameLoader::ReallyStartLoadingInterna
     }
   }
   loadInfo->SetReferrerPolicy(referrerPolicy);
 
   // Default flags:
   int32_t flags = nsIWebNavigation::LOAD_FLAGS_NONE;
 
   // Flags for browser frame:
-  if (OwnerIsBrowserFrame()) {
+  if (OwnerIsMozBrowserFrame()) {
     flags = nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
             nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
   }
 
   // Kick off the load...
   bool tmpState = mNeedsAsyncDestroy;
   mNeedsAsyncDestroy = true;
   nsCOMPtr<nsIURI> uriToLoad = mURIToLoad;
@@ -1195,18 +1195,18 @@ nsFrameLoader::SwapWithOtherLoader(nsFra
   NS_ASSERTION(otherDoc == otherParentDocument, "Unexpected parent document");
 
   nsIPresShell* ourShell = ourDoc->GetShell();
   nsIPresShell* otherShell = otherDoc->GetShell();
   if (!ourShell || !otherShell) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
-  if (ourDocshell->GetIsBrowserElement() !=
-      otherDocshell->GetIsBrowserElement() ||
+  if (ourDocshell->GetIsIsolatedMozBrowserElement() !=
+      otherDocshell->GetIsIsolatedMozBrowserElement() ||
       ourDocshell->GetIsApp() != otherDocshell->GetIsApp()) {
       return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   if (mInSwap || aOther->mInSwap) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
   AutoResetInFrameSwap autoFrameSwap(this, aOther, ourDocshell, otherDocshell,
@@ -1572,27 +1572,27 @@ nsFrameLoader::SetOwnerContent(Element* 
   if (RenderFrameParent* rfp = GetCurrentRenderFrame()) {
     rfp->OwnerContentChanged(aContent);
   }
 
   ResetPermissionManagerStatus();
 }
 
 bool
-nsFrameLoader::OwnerIsBrowserOrAppFrame()
+nsFrameLoader::OwnerIsMozBrowserOrAppFrame()
 {
   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
   return browserFrame ? browserFrame->GetReallyIsBrowserOrApp() : false;
 }
 
 // The xpcom getter version
 NS_IMETHODIMP
-nsFrameLoader::GetOwnerIsBrowserOrAppFrame(bool* aResult)
+nsFrameLoader::GetOwnerIsMozBrowserOrAppFrame(bool* aResult)
 {
-  *aResult = OwnerIsBrowserOrAppFrame();
+  *aResult = OwnerIsMozBrowserOrAppFrame();
   return NS_OK;
 }
 
 bool
 nsFrameLoader::OwnerIsWidget()
 {
   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
   return browserFrame ? browserFrame->GetReallyIsWidget() : false;
@@ -1610,19 +1610,76 @@ nsFrameLoader::GetOwnerIsWidget(bool* aR
 bool
 nsFrameLoader::OwnerIsAppFrame()
 {
   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
   return browserFrame ? browserFrame->GetReallyIsApp() : false;
 }
 
 bool
-nsFrameLoader::OwnerIsBrowserFrame()
+nsFrameLoader::OwnerIsMozBrowserFrame()
+{
+  return OwnerIsMozBrowserOrAppFrame() && !OwnerIsAppFrame();
+}
+
+bool
+nsFrameLoader::OwnerIsIsolatedMozBrowserFrame()
 {
-  return OwnerIsBrowserOrAppFrame() && !OwnerIsAppFrame();
+  nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
+  if (!browserFrame) {
+    return false;
+  }
+
+  if (!OwnerIsMozBrowserFrame()) {
+    return false;
+  }
+
+  bool isolated = browserFrame->GetIsolated();
+  if (isolated) {
+    return true;
+  }
+
+  // After bug 1238160, which allows isolation to be disabled on mozbrowser
+  // frames, we no longer have a way to tell from the principal alone if
+  // something "is a mozbrowser".  Instead, we now only know "is an isolated
+  // mozbrowser".  The following code paths would return invalid results if it
+  // were possible to have apps *and* isolation could be disabled:
+  //   * CheckPermission in AppProcessChecker.cpp
+  //   * nsScriptSecurityManager::AppStatusForPrincipal
+  //   * init() in SystemMessageManager.js
+  // Currently, desktop is the only platform where we intend to disable
+  // isolation on a browser frame, so non-desktop should be able to assume that
+  // inIsolatedMozBrowser is true for all mozbrowser frames.  To enforce these
+  // assumptions, we assert that there are no apps installed if we have tried
+  // to disable isolation.
+  nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
+  if (!appsService) {
+    // If the apps service is not present, we assume this means there can't be
+    // any apps at all, so there is no problem.
+    return false;
+  }
+  bool appsInstalled;
+  nsresult rv = appsService->AreAnyAppsInstalled(&appsInstalled);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    // The apps service exists, but it threw an error when checking if there are
+    // any apps, so we don't know if we have them or not.
+    return false;
+  }
+#ifdef MOZ_B2G
+  MOZ_RELEASE_ASSERT(!appsInstalled,
+                     "Disabling mozbrowser isolation is not currently "
+                     "allowed when apps are installed.");
+#else
+  if (appsInstalled) {
+    NS_WARNING("Disabling mozbrowser isolation is not currently allowed when "
+               "apps are installed.");
+  }
+#endif
+
+  return false;
 }
 
 void
 nsFrameLoader::GetOwnerAppManifestURL(nsAString& aOut)
 {
   aOut.Truncate();
   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
   if (browserFrame) {
@@ -1687,25 +1744,25 @@ nsFrameLoader::ShouldUseRemoteProcess()
   if (XRE_IsContentProcess() &&
       !(PR_GetEnv("MOZ_NESTED_OOP_TABS") ||
         Preferences::GetBool("dom.ipc.tabs.nested.enabled", false))) {
     return false;
   }
 
   // If we're an <iframe mozbrowser> and we don't have a "remote" attribute,
   // fall back to the default.
-  if (OwnerIsBrowserOrAppFrame() &&
+  if (OwnerIsMozBrowserOrAppFrame() &&
       !mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::Remote)) {
 
     return Preferences::GetBool("dom.ipc.browser_frames.oop_by_default", false);
   }
 
   // Otherwise, we're remote if we have "remote=true" and we're either a
   // browser frame or a XUL element.
-  return (OwnerIsBrowserOrAppFrame() ||
+  return (OwnerIsMozBrowserOrAppFrame() ||
           mOwnerContent->GetNameSpaceID() == kNameSpaceID_XUL) &&
          mOwnerContent->AttrValueIs(kNameSpaceID_None,
                                     nsGkAtoms::Remote,
                                     nsGkAtoms::_true,
                                     eCaseMatters);
 }
 
 bool
@@ -1878,42 +1935,43 @@ nsFrameLoader::MaybeCreateDocShell()
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
     webNav->SetSessionHistory(sessionHistory);
   }
 
   if (OwnerIsAppFrame()) {
     // You can't be both an app and a browser frame.
-    MOZ_ASSERT(!OwnerIsBrowserFrame());
+    MOZ_ASSERT(!OwnerIsMozBrowserFrame());
 
     nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
     MOZ_ASSERT(ownApp);
     uint32_t ownAppId = nsIScriptSecurityManager::NO_APP_ID;
     if (ownApp) {
       NS_ENSURE_SUCCESS(ownApp->GetLocalId(&ownAppId), NS_ERROR_FAILURE);
     }
 
     mDocShell->SetIsApp(ownAppId);
   }
 
-  if (OwnerIsBrowserFrame()) {
+  if (OwnerIsMozBrowserFrame()) {
     // You can't be both a browser and an app frame.
     MOZ_ASSERT(!OwnerIsAppFrame());
 
     nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
     uint32_t containingAppId = nsIScriptSecurityManager::NO_APP_ID;
     if (containingApp) {
       NS_ENSURE_SUCCESS(containingApp->GetLocalId(&containingAppId),
                         NS_ERROR_FAILURE);
     }
     mDocShell->SetIsBrowserInsideApp(containingAppId);
+    mDocShell->SetIsInIsolatedMozBrowserElement(OwnerIsIsolatedMozBrowserFrame());
   }
 
-  if (OwnerIsBrowserOrAppFrame()) {
+  if (OwnerIsMozBrowserOrAppFrame()) {
     // For inproc frames, set the docshell properties.
     nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(docShell);
     nsAutoString name;
     if (mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name)) {
       item->SetName(name);
     }
     mDocShell->SetFullscreenAllowed(
       mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) ||
@@ -2244,17 +2302,17 @@ nsFrameLoader::TryRemoteBrowser()
 
   if (openingTab &&
       openingTab->Manager() &&
       openingTab->Manager()->IsContentParent()) {
     openerContentParent = openingTab->Manager()->AsContentParent();
   }
 
   // <iframe mozbrowser> gets to skip these checks.
-  if (!OwnerIsBrowserOrAppFrame()) {
+  if (!OwnerIsMozBrowserOrAppFrame()) {
     if (parentDocShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
       return false;
     }
 
     if (!mOwnerContent->IsXULElement()) {
       return false;
     }
 
@@ -2561,17 +2619,17 @@ nsFrameLoader::EnsureMessageManager()
 {
   NS_ENSURE_STATE(mOwnerContent);
 
   if (mMessageManager) {
     return NS_OK;
   }
 
   if (!mIsTopLevelContent &&
-      !OwnerIsBrowserOrAppFrame() &&
+      !OwnerIsMozBrowserOrAppFrame() &&
       !IsRemoteFrame() &&
       !(mOwnerContent->IsXULElement() &&
         mOwnerContent->AttrValueIs(kNameSpaceID_None,
                                    nsGkAtoms::forcemessagemanager,
                                    nsGkAtoms::_true, eCaseMatters))) {
     return NS_OK;
   }
 
@@ -2667,17 +2725,17 @@ nsFrameLoader::SwapRemoteBrowser(nsITabP
   RefPtr<TabParent> newParent = TabParent::GetFrom(aTabParent);
   if (!newParent || !mRemoteBrowser) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
   if (!IsRemoteFrame()) {
     NS_WARNING("Switching from in-process to out-of-process is not supported.");
     return NS_ERROR_NOT_IMPLEMENTED;
   }
-  if (!OwnerIsBrowserOrAppFrame()) {
+  if (!OwnerIsMozBrowserOrAppFrame()) {
     NS_WARNING("Switching process for non-mozbrowser/app frame is not supported.");
     return NS_ERROR_NOT_IMPLEMENTED;
   }
   if (newParent == mRemoteBrowser) {
     return NS_OK;
   }
 
   MaybeUpdatePrimaryTabParent(eTabParentRemoved);
@@ -2818,27 +2876,27 @@ nsFrameLoader::ResetPermissionManagerSta
 
   // Finding the new app Id:
   // . first we check if the owner is an app frame
   // . second, we check if the owner is a browser frame
   // in both cases we populate the appId variable.
   uint32_t appId = nsIScriptSecurityManager::NO_APP_ID;
   if (OwnerIsAppFrame()) {
     // You can't be both an app and a browser frame.
-    MOZ_ASSERT(!OwnerIsBrowserFrame());
+    MOZ_ASSERT(!OwnerIsMozBrowserFrame());
 
     nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
     MOZ_ASSERT(ownApp);
     uint32_t ownAppId = nsIScriptSecurityManager::NO_APP_ID;
     if (ownApp && NS_SUCCEEDED(ownApp->GetLocalId(&ownAppId))) {
       appId = ownAppId;
     }
   }
 
-  if (OwnerIsBrowserFrame()) {
+  if (OwnerIsMozBrowserFrame()) {
     // You can't be both a browser and an app frame.
     MOZ_ASSERT(!OwnerIsAppFrame());
 
     nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
     uint32_t containingAppId = nsIScriptSecurityManager::NO_APP_ID;
     if (containingApp && NS_SUCCEEDED(containingApp->GetLocalId(&containingAppId))) {
       appId = containingAppId;
     }
@@ -2966,17 +3024,17 @@ nsFrameLoader::GetLoadContext(nsILoadCon
   }
   loadContext.forget(aLoadContext);
   return NS_OK;
 }
 
 void
 nsFrameLoader::InitializeBrowserAPI()
 {
-  if (OwnerIsBrowserOrAppFrame()) {
+  if (OwnerIsMozBrowserOrAppFrame()) {
     if (!IsRemoteFrame()) {
       nsresult rv = EnsureMessageManager();
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return;
       }
       if (mMessageManager) {
         mMessageManager->LoadFrameScript(
           NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js"),
@@ -3061,17 +3119,17 @@ nsFrameLoader::MaybeUpdatePrimaryTabPare
 nsresult
 nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext,
                                 nsIURI* aURI,
                                 const nsACString& aPackageId)
 {
   nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
   nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
   DocShellOriginAttributes attrs;
-  attrs.mInBrowser = OwnerIsBrowserFrame();
+  attrs.mInIsolatedMozBrowser = OwnerIsIsolatedMozBrowserFrame();
 
   nsCString signedPkgOrigin;
   if (!aPackageId.IsEmpty()) {
     // Only when aPackageId is not empty would signed package origin
     // be meaningful.
     nsPrincipal::GetOriginForURI(aURI, signedPkgOrigin);
   }
 
@@ -3102,13 +3160,17 @@ nsFrameLoader::GetNewTabContext(MutableT
   if (!userContextIdStr.IsEmpty()) {
     nsresult err;
     uint32_t userContextId = userContextIdStr.ToInteger(&err);
     NS_ENSURE_SUCCESS(err, err);
     attrs.mUserContextId = userContextId;
   }
 
   bool tabContextUpdated =
-    aTabContext->SetTabContext(ownApp, containingApp, attrs, signedPkgOrigin);
+    aTabContext->SetTabContext(OwnerIsMozBrowserFrame(),
+                               ownApp,
+                               containingApp,
+                               attrs,
+                               signedPkgOrigin);
   NS_ENSURE_STATE(tabContextUpdated);
 
   return NS_OK;
 }
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -138,17 +138,17 @@ public:
    * Return the primary frame for our owning content, or null if it
    * can't be found.
    */
   nsIFrame* GetPrimaryFrameOfOwningContent() const
   {
     return mOwnerContent ? mOwnerContent->GetPrimaryFrame() : nullptr;
   }
 
-  /** 
+  /**
    * Return the document that owns this, or null if we don't have
    * an owner.
    */
   nsIDocument* GetOwnerDoc() const
   { return mOwnerContent ? mOwnerContent->OwnerDoc() : nullptr; }
 
   PBrowserParent* GetRemoteBrowser() const;
 
@@ -189,17 +189,17 @@ public:
 
   /**
    * Stashes a detached view on the frame loader. We do this when we're
    * destroying the nsSubDocumentFrame. If the nsSubdocumentFrame is
    * being reframed we'll restore the detached view when it's recreated,
    * otherwise we'll discard the old presentation and set the detached
    * subdoc view to null. aContainerDoc is the document containing the
    * the subdoc frame. This enables us to detect when the containing
-   * document has changed during reframe, so we can discard the presentation 
+   * document has changed during reframe, so we can discard the presentation
    * in that case.
    */
   void SetDetachedSubdocView(nsView* aDetachedView,
                              nsIDocument* aContainerDoc);
 
   /**
    * Retrieves the detached view and the document containing the view,
    * as set by SetDetachedSubdocView().
@@ -237,35 +237,46 @@ private:
    * Return true if the frame is a remote frame. Return false otherwise
    */
   bool IsRemoteFrame();
 
   /**
    * Is this a frameloader for a bona fide <iframe mozbrowser> or
    * <iframe mozapp>?  (I.e., does the frame return true for
    * nsIMozBrowserFrame::GetReallyIsBrowserOrApp()?)
+   * <xul:browser> is not a mozbrowser or app, so this is false for that case.
    */
-  bool OwnerIsBrowserOrAppFrame();
+  bool OwnerIsMozBrowserOrAppFrame();
 
   /**
    * Is this a frameloader for a bona fide <iframe mozwidget>?  (I.e., does the
    * frame return true for nsIMozBrowserFrame::GetReallyIsWidget()?)
    */
   bool OwnerIsWidget();
 
   /**
    * Is this a frameloader for a bona fide <iframe mozapp>?  (I.e., does the
    * frame return true for nsIMozBrowserFrame::GetReallyIsApp()?)
    */
   bool OwnerIsAppFrame();
 
   /**
    * Is this a frame loader for a bona fide <iframe mozbrowser>?
+   * <xul:browser> is not a mozbrowser, so this is false for that case.
    */
-  bool OwnerIsBrowserFrame();
+  bool OwnerIsMozBrowserFrame();
+
+  /**
+   * Is this a frame loader for an isolated <iframe mozbrowser>?
+   *
+   * By default, mozbrowser frames are isolated.  Isolation can be disabled by
+   * setting the frame's noisolation attribute.  Disabling isolation is
+   * only allowed if the containing document is chrome.
+   */
+  bool OwnerIsIsolatedMozBrowserFrame();
 
   /**
    * Get our owning element's app manifest URL, or return the empty string if
    * our owning element doesn't have an app manifest URL.
    */
   void GetOwnerAppManifestURL(nsAString& aOut);
 
   /**
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -652,16 +652,17 @@ GK_ATOM(noautohide, "noautohide")
 GK_ATOM(norolluponanchor, "norolluponanchor")
 GK_ATOM(nobr, "nobr")
 GK_ATOM(node, "node")
 GK_ATOM(nodefaultsrc, "nodefaultsrc")
 GK_ATOM(nodeSet, "node-set")
 GK_ATOM(noembed, "noembed")
 GK_ATOM(noframes, "noframes")
 GK_ATOM(nohref, "nohref")
+GK_ATOM(noisolation, "noisolation")
 GK_ATOM(nonce, "nonce")
 GK_ATOM(none, "none")
 GK_ATOM(noresize, "noresize")
 GK_ATOM(normal, "normal")
 GK_ATOM(normalizeSpace, "normalize-space")
 GK_ATOM(noscript, "noscript")
 GK_ATOM(noshade, "noshade")
 GK_ATOM(novalidate, "novalidate")
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -452,18 +452,16 @@ nsGlobalWindow::DOMMinTimeoutValue() con
     }                                                                         \
     return GetCurrentInnerWindowInternal()->method args;                      \
   }                                                                           \
   PR_END_MACRO
 
 // CIDs
 static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
 
-static const char sPopStatePrefStr[] = "browser.history.allowPopState";
-
 #define NETWORK_UPLOAD_EVENT_NAME     NS_LITERAL_STRING("moznetworkupload")
 #define NETWORK_DOWNLOAD_EVENT_NAME   NS_LITERAL_STRING("moznetworkdownload")
 
 /**
  * An indirect observer object that means we don't have to implement nsIObserver
  * on nsGlobalWindow, where any script could see it.
  */
 class nsGlobalWindowObserver final : public nsIObserver,
@@ -1153,16 +1151,17 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
     mFullscreenMode(false),
     mIsClosed(false),
     mInClose(false),
     mHavePendingClose(false),
     mHadOriginalOpener(false),
     mIsPopupSpam(false),
     mBlockScriptedClosingFlag(false),
     mWasOffline(false),
+    mHasHadSlowScript(false),
     mNotifyIdleObserversIdleOnThaw(false),
     mNotifyIdleObserversActiveOnThaw(false),
     mCreatingInnerWindow(false),
     mIsChrome(false),
     mCleanMessageManager(false),
     mNeedsFocus(true),
     mHasFocus(false),
 #if defined(XP_MACOSX)
@@ -3796,17 +3795,17 @@ nsGlobalWindow::GetParentOuter()
 {
   MOZ_RELEASE_ASSERT(IsOuterWindow());
 
   if (!mDocShell) {
     return nullptr;
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> parent;
-  if (mDocShell->GetIsBrowserOrApp()) {
+  if (mDocShell->GetIsMozBrowserOrApp()) {
     parent = AsOuter();
   } else {
     parent = GetParent();
   }
 
   return parent.forget();
 }
 
@@ -3962,17 +3961,17 @@ nsGlobalWindow::GetContentInternal(Error
   nsCOMPtr<nsPIDOMWindowOuter> domWindow =
     GetChildWindow(NS_LITERAL_STRING("content"));
   if (domWindow) {
     return domWindow.forget();
   }
 
   // If we're contained in <iframe mozbrowser> or <iframe mozapp>, then
   // GetContent is the same as window.top.
-  if (mDocShell && mDocShell->GetIsInBrowserOrApp()) {
+  if (mDocShell && mDocShell->GetIsInMozBrowserOrApp()) {
     return GetTopOuter();
   }
 
   nsCOMPtr<nsIDocShellTreeItem> primaryContent;
   if (aUnprivilegedCaller) {
     // If we're called by non-chrome code, make sure we don't return
     // the primary content window if the calling tab is hidden. In
     // such a case we return the same-type root in the hidden tab,
@@ -7170,17 +7169,17 @@ void
 nsGlobalWindow::ResizeToOuter(int32_t aWidth, int32_t aHeight, ErrorResult& aError, bool aCallerIsChrome)
 {
   MOZ_RELEASE_ASSERT(IsOuterWindow());
 
   /*
    * If caller is a browser-element then dispatch a resize event to
    * the embedder.
    */
-  if (mDocShell && mDocShell->GetIsBrowserOrApp()) {
+  if (mDocShell && mDocShell->GetIsMozBrowserOrApp()) {
     CSSIntSize size(aWidth, aHeight);
     if (!DispatchResizeEvent(size)) {
       // The embedder chose to prevent the default action for this
       // event, so let's not resize this window after all...
       return;
     }
   }
 
@@ -7220,17 +7219,17 @@ nsGlobalWindow::ResizeByOuter(int32_t aW
                               ErrorResult& aError, bool aCallerIsChrome)
 {
   MOZ_RELEASE_ASSERT(IsOuterWindow());
 
   /*
    * If caller is a browser-element then dispatch a resize event to
    * parent.
    */
-  if (mDocShell && mDocShell->GetIsBrowserOrApp()) {
+  if (mDocShell && mDocShell->GetIsMozBrowserOrApp()) {
     CSSIntSize size;
     if (NS_FAILED(GetInnerSize(size))) {
       return;
     }
 
     size.width += aWidthDif;
     size.height += aHeightDif;
 
@@ -8169,17 +8168,17 @@ nsGlobalWindow::CanClose()
 }
 
 void
 nsGlobalWindow::CloseOuter(bool aTrustedCaller)
 {
   MOZ_RELEASE_ASSERT(IsOuterWindow());
 
   if (!mDocShell || IsInModalState() ||
-      (IsFrame() && !mDocShell->GetIsBrowserOrApp())) {
+      (IsFrame() && !mDocShell->GetIsMozBrowserOrApp())) {
     // window.close() is called on a frame in a frameset, on a window
     // that's already closed, or on a window for which there's
     // currently a modal dialog open. Ignore such calls.
     return;
   }
 
   if (mHavePendingClose) {
     // We're going to be closed anyway; do nothing since we don't want
@@ -8696,17 +8695,17 @@ nsGlobalWindow::CacheXBLPrototypeHandler
   mCachedXBLPrototypeHandlers->Put(aKey, aHandler);
 }
 
 Element*
 nsGlobalWindow::GetFrameElementOuter()
 {
   MOZ_RELEASE_ASSERT(IsOuterWindow());
 
-  if (!mDocShell || mDocShell->GetIsBrowserOrApp()) {
+  if (!mDocShell || mDocShell->GetIsMozBrowserOrApp()) {
     return nullptr;
   }
 
   // Per HTML5, the frameElement getter returns null in cross-origin situations.
   Element* element = GetRealFrameElementOuter();
   if (!element) {
     return nullptr;
   }
@@ -9911,21 +9910,16 @@ nsGlobalWindow::FireHashchange(const nsA
 
 nsresult
 nsGlobalWindow::DispatchSyncPopState()
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
                "Must be safe to run script here.");
 
-  // Check that PopState hasn't been pref'ed off.
-  if (!Preferences::GetBool(sPopStatePrefStr, false)) {
-    return NS_OK;
-  }
-
   nsresult rv = NS_OK;
 
   // Bail if the window is frozen.
   if (IsFrozen()) {
     return NS_OK;
   }
 
   // Get the document's pending state object -- it contains the data we're
@@ -10657,16 +10651,23 @@ nsGlobalWindow::ShowSlowScriptDialog()
     return KillSlowScript;
   }
 
   // Check if we should offer the option to debug
   JS::UniqueChars filename;
   unsigned lineno;
   bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, &lineno);
 
+  // Record the slow script event if we haven't done so already for this inner window
+  // (which represents a particular page to the user).
+  if (!mHasHadSlowScript) {
+    Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_PAGE_COUNT, 1);
+  }
+  mHasHadSlowScript = true;
+
   if (XRE_IsContentProcess() &&
       ProcessHangMonitor::Get()) {
     ProcessHangMonitor::SlowScriptAction action;
     RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
     nsCOMPtr<nsITabChild> child = do_GetInterface(GetDocShell());
     action = monitor->NotifySlowScript(child,
                                        filename.get(),
                                        lineno);
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -1686,16 +1686,21 @@ protected:
   bool                          mIsPopupSpam : 1;
 
   // Indicates whether scripts are allowed to close this window.
   bool                          mBlockScriptedClosingFlag : 1;
 
   // Window offline status. Checked to see if we need to fire offline event
   bool                          mWasOffline : 1;
 
+  // Represents whether the inner window's page has had a slow script notice.
+  // Only used by inner windows; will always be false for outer windows.
+  // This is used to implement Telemetry measures such as SLOW_SCRIPT_PAGE_COUNT.
+  bool                          mHasHadSlowScript : 1;
+
   // Track what sorts of events we need to fire when thawed
   bool                          mNotifyIdleObserversIdleOnThaw : 1;
   bool                          mNotifyIdleObserversActiveOnThaw : 1;
 
   // Indicates whether we're in the middle of creating an initializing
   // a new inner window object.
   bool                          mCreatingInnerWindow : 1;
 
--- a/dom/base/nsHistory.cpp
+++ b/dom/base/nsHistory.cpp
@@ -20,21 +20,16 @@
 #include "nsContentUtils.h"
 #include "nsISHistory.h"
 #include "nsISHistoryInternal.h"
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-static const char* sAllowPushStatePrefStr =
-  "browser.history.allowPushState";
-static const char* sAllowReplaceStatePrefStr =
-  "browser.history.allowReplaceState";
-
 //
 //  History class implementation
 //
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsHistory)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHistory)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHistory)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHistory)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
@@ -299,22 +294,16 @@ nsHistory::PushOrReplaceState(JSContext*
   }
 
   if (!win->HasActiveDocument()) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
 
     return;
   }
 
-  // Check that PushState hasn't been pref'ed off.
-  if (!Preferences::GetBool(aReplace ? sAllowReplaceStatePrefStr :
-                            sAllowPushStatePrefStr, false)) {
-    return;
-  }
-
   // AddState might run scripts, so we need to hold a strong reference to the
   // docShell here to keep it from going away.
   nsCOMPtr<nsIDocShell> docShell = win->GetDocShell();
 
   if (!docShell) {
     aRv.Throw(NS_ERROR_FAILURE);
 
     return;
--- a/dom/base/nsIFrameLoader.idl
+++ b/dom/base/nsIFrameLoader.idl
@@ -145,17 +145,17 @@ interface nsIFrameLoader : nsISupports
    * the child content process when these events are targeted to
    * the remote browser element.
    *
    * Used primarly for input events (mouse, keyboard)
    */
   const unsigned long EVENT_MODE_NORMAL_DISPATCH = 0x00000000;
 
   /**
-   * With this event mode, it's the application's responsability to 
+   * With this event mode, it's the application's responsability to
    * convert and forward events to the content process
    */
   const unsigned long EVENT_MODE_DONT_FORWARD_TO_CHILD = 0x00000001;
 
   attribute unsigned long eventMode;
 
   /**
    * If false, then the subdocument is not clipped to its CSS viewport, and the
@@ -191,24 +191,25 @@ interface nsIFrameLoader : nsISupports
    *
    * The notion of "visibility" here is separate from the notion of a
    * window/docshell's visibility.  This field is mostly here so that we can
    * have a notion of visibility in the parent process when frames are OOP.
    */
   [infallible] attribute boolean visible;
 
   /**
-   * Find out whether the owner content really is a browser or app frame
-   * Especially, a widget frame is regarded as an app frame.
+   * Find out whether the owner content really is a mozbrowser or app frame
+   * Especially, a widget frame is regarded as an app frame.  <xul:browser> is
+   * not considered to be a mozbrowser frame.
    */
-  readonly attribute boolean ownerIsBrowserOrAppFrame;
+  readonly attribute boolean ownerIsMozBrowserOrAppFrame;
 
   /**
    * Find out whether the owner content really is a widget. If this attribute
-   * returns true, |ownerIsBrowserOrAppFrame| must return true.
+   * returns true, |ownerIsMozBrowserOrAppFrame| must return true.
    */
   readonly attribute boolean ownerIsWidget;
 
 };
 
 %{C++
 class nsFrameLoader;
 %}
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1432,16 +1432,21 @@ TimeUntilNow(TimeStamp start)
   if (start.IsNull()) {
     return 0;
   }
   return TimeBetween(start, TimeStamp::Now());
 }
 
 struct CycleCollectorStats
 {
+  MOZ_CONSTEXPR CycleCollectorStats() :
+    mMaxGCDuration(0), mRanSyncForgetSkippable(false), mSuspected(0),
+    mMaxSkippableDuration(0), mMaxSliceTime(0), mMaxSliceTimeSinceClear(0),
+    mTotalSliceTime(0), mAnyLockedOut(false), mExtraForgetSkippableCalls(0) {}
+
   void Init()
   {
     Clear();
     mMaxSliceTimeSinceClear = 0;
   }
 
   void Clear()
   {
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -254,16 +254,17 @@ support-files =
   test_performance_observer.js
   performance_observer.html
   test_anonymousContent_style_csp.html^headers^
   file_explicit_user_agent.sjs
   referrer_change_server.sjs
   file_change_policy_redirect.html
   file_bug1198095.js
   file_bug1250148.sjs
+  mozbrowser_api_utils.js
 
 [test_anonymousContent_api.html]
 [test_anonymousContent_append_after_reflow.html]
 [test_anonymousContent_canvas.html]
 skip-if = buildapp == 'b2g' # Requires webgl support
 [test_anonymousContent_insert.html]
 [test_anonymousContent_manipulate_content.html]
 [test_anonymousContent_style_csp.html]
@@ -867,9 +868,11 @@ skip-if = e10s || os != 'linux' || build
 [test_explicit_user_agent.html]
 [test_change_policy.html]
 skip-if = buildapp == 'b2g' #no ssl support
 [test_document.all_iteration.html]
 [test_bug1198095.html]
 [test_bug1187157.html]
 [test_bug769117.html]
 [test_bug1250148.html]
-[test_bug1240471.html]
\ No newline at end of file
+[test_bug1240471.html]
+[test_mozbrowser_apis_allowed.html]
+[test_mozbrowser_apis_blocked.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/mozbrowser_api_utils.js
@@ -0,0 +1,72 @@
+const FRAME_URL = "http://example.org/";
+
+const METHODS = {
+  setVisible: {},
+  getVisible: {},
+  setActive: {},
+  getActive: {},
+  addNextPaintListener: {},
+  removeNextPaintListener: {},
+  sendMouseEvent: {},
+  sendTouchEvent: {},
+  goBack: {},
+  goForward: {},
+  reload: {},
+  stop: {},
+  download: {},
+  purgeHistory: {},
+  getScreenshot: {},
+  zoom: {},
+  getCanGoBack: {},
+  getCanGoForward: {},
+  getContentDimensions: {},
+  setInputMethodActive: { alwaysFails: true }, // needs input-manage
+  setNFCFocus: { alwaysFails: true }, // needs nfc-manager
+  findAll: {},
+  findNext: {},
+  clearMatch: {},
+  executeScript: { alwaysFails: true }, // needs browser:universalxss
+  getStructuredData: {},
+  getWebManifest: {},
+  mute: {},
+  unmute: {},
+  getMuted: {},
+  setVolume: {},
+  getVolume: {},
+};
+
+const ATTRIBUTES = [
+  "allowedAudioChannels",
+];
+
+function once(target, eventName, useCapture = false) {
+  info("Waiting for event: '" + eventName + "' on " + target + ".");
+
+  return new Promise(resolve => {
+    for (let [add, remove] of [
+      ["addEventListener", "removeEventListener"],
+      ["addMessageListener", "removeMessageListener"],
+    ]) {
+      if ((add in target) && (remove in target)) {
+        target[add](eventName, function onEvent(...aArgs) {
+          info("Got event: '" + eventName + "' on " + target + ".");
+          target[remove](eventName, onEvent, useCapture);
+          resolve(aArgs);
+        }, useCapture);
+        break;
+      }
+    }
+  });
+}
+
+function* loadFrame(attributes = {}) {
+  let iframe = document.createElement("iframe");
+  iframe.setAttribute("src", FRAME_URL);
+  for (let key in attributes) {
+    iframe.setAttribute(key, attributes[key]);
+  }
+  let loaded = once(iframe, "load");
+  document.body.appendChild(iframe);
+  yield loaded;
+  return iframe;
+}
--- a/dom/base/test/test_messagemanager_principal.html
+++ b/dom/base/test/test_messagemanager_principal.html
@@ -29,18 +29,18 @@
         sendAsyncMessage(message.name, "principal: " + (message.principal ? "OK" : "KO"));
 
         sendAsyncMessage(message.name, "principal.appId: " +
                          ("appId" in message.principal ? "OK" : "KO"));
 
         sendAsyncMessage(message.name, "principal.origin: " +
                          ("origin" in message.principal ? "OK" : "KO"));
 
-        sendAsyncMessage(message.name, "principal.isInBrowserElement: " +
-                         ("isInBrowserElement" in message.principal ? "OK" : "KO"));
+        sendAsyncMessage(message.name, "principal.isInIsolatedMozBrowserElement: " +
+                         ("isInIsolatedMozBrowserElement" in message.principal ? "OK" : "KO"));
 
         sendAsyncMessage(message.name, "DONE");
       });
     }
 
     function runTests() {
       ok("Browser prefs set.");
 
--- a/dom/base/test/test_messagemanager_send_principal.html
+++ b/dom/base/test/test_messagemanager_send_principal.html
@@ -33,18 +33,18 @@
                          (message.data instanceof Ci.nsIPrincipal ? "OK" : "KO"));
 
         sendAsyncMessage("test:result", "principal.appId: " +
                          ("appId" in message.data ? "OK" : "KO"));
 
         sendAsyncMessage("test:result", "principal.origin: " +
                          ("origin" in message.data ? "OK" : "KO"));
 
-        sendAsyncMessage("test:result", "principal.isInBrowserElement: " +
-                         ("isInBrowserElement" in message.data ? "OK" : "KO"));
+        sendAsyncMessage("test:result", "principal.isInIsolatedMozBrowserElement: " +
+                         ("isInIsolatedMozBrowserElement" in message.data ? "OK" : "KO"));
       });
 
       addMessageListener("test:system", function(message) {
         sendAsyncMessage("test:result", "isSystemPrincipal: " +
                          (secMan.isSystemPrincipal(message.data) ? "OK" : "KO"));
       });
 
       addMessageListener("test:ep", function(message) {
--- a/dom/base/test/test_messagemanager_targetchain.html
+++ b/dom/base/test/test_messagemanager_targetchain.html
@@ -105,17 +105,17 @@
       SpecialPowers.pushPermissions([
         { type: "browser", allow: 1, context: { url: principal.URI.spec,
                                                 originAttributes: {
                                                   appId: principal.appId
                                                 }}},
         { type: "browser", allow: 1, context: { url: principal.URI.spec,
                                                 originAttributes: {
                                                   appId: principal.appId,
-                                                  inBrowser: true }}}
+                                                  inIsolatedMozBrowser: true }}}
       ], () => {
         SpecialPowers.pushPrefEnv({
           set: [
             ["dom.mozBrowserFramesEnabled", true],
             ["dom.ipc.browser_frames.oop_by_default", false],
           ]
         }, runTests);
       });
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_mozbrowser_apis_allowed.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Verify mozbrowser APIs are allowed with browser permission</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+  <script type="text/javascript" src="mozbrowser_api_utils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+<script type="application/javascript;version=1.8">
+  add_task(function*() {
+    yield new Promise(resolve => {
+      SpecialPowers.pushPrefEnv(
+        { "set": [["dom.mozBrowserFramesEnabled", true]] },
+        resolve);
+    });
+  });
+
+  add_task(function*() {
+    yield new Promise(resolve => {
+      SpecialPowers.pushPermissions([
+        { "type": "browser", "allow": 1, "context": document }
+      ], resolve);
+    });
+  });
+
+  add_task(function*() {
+    // Create <iframe mozbrowser>
+    let frame = yield loadFrame({
+      mozbrowser: "true"
+    });
+
+    // Verify that mozbrowser APIs are accessible
+    for (let method in METHODS) {
+      let { alwaysFails } = METHODS[method];
+      if (alwaysFails) {
+        ok(!(method in frame), `frame does not have method ${method}, ` +
+                               `needs more permissions`);
+      } else {
+        ok(method in frame, `frame has method ${method}`);
+      }
+    }
+    for (let attribute of ATTRIBUTES) {
+      ok(attribute in frame, `frame has attribute ${attribute}`);
+    }
+  });
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_mozbrowser_apis_blocked.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Verify mozbrowser APIs are blocked without browser permission</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+  <script type="text/javascript" src="mozbrowser_api_utils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+<script type="application/javascript;version=1.8">
+  add_task(function*() {
+    yield new Promise(resolve => {
+      SpecialPowers.pushPrefEnv(
+        { "set": [["dom.mozBrowserFramesEnabled", true]] },
+        resolve);
+    });
+  });
+
+  add_task(function*() {
+    // Create <iframe mozbrowser>
+    let frame = yield loadFrame({
+      mozbrowser: "true"
+    });
+
+    // Verify that mozbrowser APIs are not accessible
+    for (let method in METHODS) {
+      ok(!(method in frame), `frame does not have method ${method}`);
+    }
+    for (let attribute of ATTRIBUTES) {
+      ok(!(attribute in frame), `frame does not have attribute ${attribute}`);
+    }
+  });
+</script>
+</body>
+</html>
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -12182,16 +12182,25 @@ class CGDictionary(CGThing):
         return self.structs.define()
 
     def base(self):
         if self.dictionary.parent:
             return self.makeClassName(self.dictionary.parent)
         return "DictionaryBase"
 
     def initMethod(self):
+        """
+        This function outputs the body of the Init() method for the dictionary.
+
+        For the most part, this is some bookkeeping for our atoms so
+        we can avoid atomizing strings all the time, then we just spit
+        out the getMemberConversion() output for each member,
+        separated by newlines.
+
+        """
         body = dedent("""
             // Passing a null JSContext is OK only if we're initing from null,
             // Since in that case we will not have to do any property gets
             MOZ_ASSERT_IF(!cx, val.isNull());
             """)
 
         if self.needToInitIds:
             body += fill(
@@ -12499,16 +12508,35 @@ class CGDictionary(CGThing):
         # We can't handle having a holderType here
         assert conversionInfo.holderType is None
         declType = conversionInfo.declType
         if conversionInfo.dealWithOptional:
             declType = CGTemplatedType("Optional", declType)
         return declType.define()
 
     def getMemberConversion(self, memberInfo):
+        """
+        A function that outputs the initialization of a single dictionary
+        member from the given dictionary value.
+
+        We start with our conversionInfo, which tells us how to
+        convert a JS::Value to whatever type this member is.  We
+        substiture the template from the conversionInfo with values
+        that point to our "temp" JS::Value and our member (which is
+        the C++ value we want to produce).  The output is a string of
+        code to do the conversion.  We store this string in
+        conversionReplacements["convert"].
+
+        Now we have three different ways we might use (or skip) this
+        string of code, depending on whether the value is required,
+        optional with default value, or optional without default
+        value.  We set up a template in the 'conversion' variable for
+        exactly how to do this, then substitute into it from the
+        conversionReplacements dictionary.
+        """
         member, conversionInfo = memberInfo
         replacements = {
             "val": "temp.ref()",
             "declName": self.makeMemberName(member.identifier.name),
             # We need a holder name for external interfaces, but
             # it's scoped down to the conversion so we can just use
             # anything we want.
             "holderName": "holder",
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -56,16 +56,17 @@ MSG_DEF(MSG_INVALID_READ_SIZE, 0, JSEXN_
 MSG_DEF(MSG_HEADERS_IMMUTABLE, 0, JSEXN_TYPEERR, "Headers are immutable and cannot be modified.")
 MSG_DEF(MSG_INVALID_HEADER_NAME, 1, JSEXN_TYPEERR, "{0} is an invalid header name.")
 MSG_DEF(MSG_INVALID_HEADER_VALUE, 1, JSEXN_TYPEERR, "{0} is an invalid header value.")
 MSG_DEF(MSG_INVALID_HEADER_SEQUENCE, 0, JSEXN_TYPEERR, "Headers require name/value tuples when being initialized by a sequence.")
 MSG_DEF(MSG_PERMISSION_DENIED_TO_PASS_ARG, 1, JSEXN_TYPEERR, "Permission denied to pass cross-origin object as {0}.")
 MSG_DEF(MSG_MISSING_REQUIRED_DICTIONARY_MEMBER, 1, JSEXN_TYPEERR, "Missing required {0}.")
 MSG_DEF(MSG_INVALID_REQUEST_METHOD, 1, JSEXN_TYPEERR, "Invalid request method {0}.")
 MSG_DEF(MSG_INVALID_REQUEST_MODE, 1, JSEXN_TYPEERR, "Invalid request mode {0}.")
+MSG_DEF(MSG_INVALID_REFERRER_URL, 1, JSEXN_TYPEERR, "Invalid referrer URL {0}.")
 MSG_DEF(MSG_FETCH_BODY_CONSUMED_ERROR, 0, JSEXN_TYPEERR, "Body has already been consumed.")
 MSG_DEF(MSG_RESPONSE_INVALID_STATUSTEXT_ERROR, 0, JSEXN_TYPEERR, "Response statusText may not contain newline or carriage return.")
 MSG_DEF(MSG_FETCH_FAILED, 0, JSEXN_TYPEERR, "NetworkError when attempting to fetch resource.")
 MSG_DEF(MSG_NO_BODY_ALLOWED_FOR_GET_AND_HEAD, 0, JSEXN_TYPEERR, "HEAD or GET Request cannot have a body.")
 MSG_DEF(MSG_RESPONSE_NULL_STATUS_WITH_BODY, 0, JSEXN_TYPEERR, "Response body is given with a null body status.")
 MSG_DEF(MSG_DEFINE_NON_CONFIGURABLE_PROP_ON_WINDOW, 0, JSEXN_TYPEERR, "Not allowed to define a non-configurable property on the WindowProxy object")
 MSG_DEF(MSG_INVALID_ZOOMANDPAN_VALUE_ERROR, 0, JSEXN_RANGEERR, "Invalid zoom and pan value.")
 MSG_DEF(MSG_INVALID_TRANSFORM_ANGLE_ERROR, 0, JSEXN_RANGEERR, "Invalid transform angle.")
--- a/dom/browser-element/BrowserElementChild.js
+++ b/dom/browser-element/BrowserElementChild.js
@@ -21,17 +21,17 @@ function parentDocShell(docshell) {
   }
   let treeitem = docshell.QueryInterface(Ci.nsIDocShellTreeItem);
   return treeitem.parent ? treeitem.parent.QueryInterface(Ci.nsIDocShell) : null;
 }
 
 function isTopBrowserElement(docShell) {
   while (docShell) {
     docShell = parentDocShell(docShell);
-    if (docShell && docShell.isBrowserOrApp) {
+    if (docShell && docShell.isMozBrowserOrApp) {
       return false;
     }
   }
   return true;
 }
 
 if (!('BrowserElementIsPreloaded' in this)) {
   if (isTopBrowserElement(docShell)) {
--- a/dom/browser-element/BrowserElementCopyPaste.js
+++ b/dom/browser-element/BrowserElementCopyPaste.js
@@ -84,17 +84,17 @@ var CopyPasteAssistent = {
       detail.rect.bottom += currentRect.top;
       detail.rect.left += currentRect.left;
       detail.rect.right += currentRect.left;
       currentWindow = currentWindow.realFrameElement.ownerDocument.defaultView;
 
       let targetDocShell = currentWindow
           .QueryInterface(Ci.nsIInterfaceRequestor)
           .getInterface(Ci.nsIWebNavigation);
-      if(targetDocShell.isBrowserOrApp) {
+      if(targetDocShell.isMozBrowserOrApp) {
         break;
       }
     }
 
     sendAsyncMsg('caretstatechanged', detail);
   },
 };
 
--- a/dom/browser-element/mochitest/browserElement_AllowEmbedAppsInNestedOOIframe.js
+++ b/dom/browser-element/mochitest/browserElement_AllowEmbedAppsInNestedOOIframe.js
@@ -18,17 +18,17 @@ function runTest() {
   iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
     is(e.detail.message == 'app', true, e.detail.message);
     SimpleTest.finish();
   });
 
   document.body.appendChild(iframe);
 
   var context = {url: 'http://example.org',
-                 originAttributes: {inBrowser: true}};
+                 originAttributes: {inIsolatedMozBrowser: true}};
   SpecialPowers.pushPermissions([
     {type: 'browser', allow: 1, context: context},
     {type: 'embed-apps', allow: 1, context: context}
   ], function() {
     iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_AllowEmbedAppsInNestedOOIframe.html';
   });
 }
 
--- a/dom/browser-element/mochitest/browserElement_AudioChannel_nested.js
+++ b/dom/browser-element/mochitest/browserElement_AudioChannel_nested.js
@@ -57,17 +57,17 @@ function runTests() {
   }
 
   iframe.addEventListener('mozbrowserloadend', audio_loadend);
   iframe.addEventListener('mozbrowsershowmodalprompt', listener, false);
   document.body.appendChild(iframe);
 
   var context = { 'url': 'http://example.org',
                   'appId': SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
-                  'isInBrowserElement': true };
+                  'isInIsolatedMozBrowserElement': true };
   SpecialPowers.pushPermissions([
     {'type': 'browser', 'allow': 1, 'context': context},
     {'type': 'embed-apps', 'allow': 1, 'context': context}
   ], function() {
     iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_AudioChannel_nested.html';
   });
 }
 
--- a/dom/browser-element/mochitest/browserElement_Auth.js
+++ b/dom/browser-element/mochitest/browserElement_Auth.js
@@ -167,17 +167,17 @@ function testAuthJarNoInterfere(e) {
 
   // Set a bunch of auth data that should not conflict with the correct auth data already
   // stored in the cache.
   var attrs = {appId: 1};
   var principal = secMan.createCodebasePrincipal(uri, attrs);
   authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
                           'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
                           '', 'httpuser', 'wrongpass', false, principal);
-  attrs = {appId: 1, inBrowser: true};
+  attrs = {appId: 1, inIsolatedMozBrowser: true};
   principal = secMan.createCodebasePrincipal(uri, attrs);
   authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
                           'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
                           '', 'httpuser', 'wrongpass', false, principal);
   principal = secMan.createCodebasePrincipal(uri, {});
   authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
                           'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
                           '', 'httpuser', 'wrongpass', false, principal);
@@ -202,17 +202,17 @@ function testAuthJarInterfere(e) {
     .getService(SpecialPowers.Ci.nsIHttpAuthManager);
   var secMan = SpecialPowers.Cc["@mozilla.org/scriptsecuritymanager;1"]
                .getService(SpecialPowers.Ci.nsIScriptSecurityManager);
   var ioService = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
                   .getService(SpecialPowers.Ci.nsIIOService);
   var uri = ioService.newURI("http://test/tests/dom/browser-element/mochitest/file_http_401_response.sjs", null, null);
 
   // Set some auth data that should overwrite the successful stored details.
-  var principal = secMan.createCodebasePrincipal(uri, {inBrowser: true});
+  var principal = secMan.createCodebasePrincipal(uri, {inIsolatedMozBrowser: true});
   authMgr.setAuthIdentity('http', 'test', -1, 'basic', 'http_realm',
                           'tests/dom/browser-element/mochitest/file_http_401_response.sjs',
                           '', 'httpuser', 'wrongpass', false, principal);
 
   // Will authenticate with correct password, prompt should not be
   // called again.
   var gotusernamepasswordrequired = false;
   function onUserNameAndPasswordRequired() {
--- a/dom/browser-element/mochitest/browserElement_CopyPaste.js
+++ b/dom/browser-element/mochitest/browserElement_CopyPaste.js
@@ -324,16 +324,16 @@ function testCut2(e) {
   mm.loadFrameScript(getScriptForGetContent(), false);
 }
 
 // Give our origin permission to open browsers, and remove it when the test is complete.
 var principal = SpecialPowers.wrap(document).nodePrincipal;
 var context = { url: SpecialPowers.wrap(principal.URI).spec,
                 originAttributes: {
                   appId: principal.appId,
-                  inBrowser: true }};
+                  inIsolatedMozBrowser: true }};
 
 addEventListener('testready', function() {
   SpecialPowers.pushPermissions([
     {type: 'browser', allow: 1, context: context}
   ], runTest);
 });
 
--- a/dom/browser-element/mochitest/browserElement_DisallowEmbedAppsInOOP.js
+++ b/dom/browser-element/mochitest/browserElement_DisallowEmbedAppsInOOP.js
@@ -24,17 +24,17 @@ function runTest() {
   iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
     is(e.detail.message == 'app', canEmbedApp, e.detail.message);
     SimpleTest.finish();
   });
 
   document.body.appendChild(iframe);
 
   var context = {url: 'http://example.org',
-                 originAttributes: {inBrowser: true}};
+                 originAttributes: {inIsolatedMozBrowser: true}};
   SpecialPowers.pushPermissions([
     {type: 'browser', allow: 1, context: context},
     {type: 'embed-apps', allow: 1, context: context}
   ], function() {
     iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_DisallowEmbedAppsInOOP.html';
   });
 }
 
--- a/dom/browser-element/mochitest/browserElement_Proxy.js
+++ b/dom/browser-element/mochitest/browserElement_Proxy.js
@@ -10,26 +10,26 @@ browserElementTestHelpers.addPermission(
 function runTest() {
   let frameUrl = SimpleTest.getTestFileURL('/file_empty.html');
   SpecialPowers.pushPermissions([{
     type: 'browser:embedded-system-app',
     allow: true,
     context: {
       url: frameUrl,
       originAttributes: {
-        inBrowser: true
+        inIsolatedMozBrowser: true
       }
     }
   },{
     type: 'browser',
     allow: true,
     context: {
       url: frameUrl,
       originAttributes: {
-        inBrowser: true
+        inIsolatedMozBrowser: true
       }
     }
   }], createFrame);
 }
 
 var frame;
 var mm;
 
--- a/dom/browser-element/mochitest/browserElement_SetInputMethodActive.js
+++ b/dom/browser-element/mochitest/browserElement_SetInputMethodActive.js
@@ -88,17 +88,17 @@ function createFrames() {
 function setPermissions() {
   let permissions = [{
     type: 'input',
     allow: true,
     context: {
       url: SimpleTest.getTestFileURL('/file_empty.html'),
       originAttributes: {
         appId: currentAppId,
-        inBrowser: true
+        inIsolatedMozBrowser: true
       }
     }
   }];
 
   if (inApp) {
     // The current document would also need to be given access for IPC to
     // recognize our permission (why)?
     permissions.push({
--- a/dom/browser-element/mochitest/browserElement_SetVisibleFrames.js
+++ b/dom/browser-element/mochitest/browserElement_SetVisibleFrames.js
@@ -16,17 +16,17 @@ browserElementTestHelpers.addPermission(
 
 var iframe;
 
 function runTest() {
   var principal = SpecialPowers.wrap(document).nodePrincipal;
   SpecialPowers.addPermission("browser", true, {url: SpecialPowers.wrap(principal.URI).spec,
                                                 originAttributes: {
                                                   appId: principal.appId,
-                                                  inBrowser: true
+                                                  inIsolatedMozBrowser: true
                                                 }});
 
   iframe = document.createElement('iframe');
   iframe.setAttribute('mozbrowser', 'true');
 
   // Our test involves three <iframe mozbrowser>'s, parent, child1, and child2.
   // child1 and child2 are contained inside parent.  child1 is visibile, and
   // child2 is not.
@@ -75,17 +75,17 @@ function finish() {
   // expected, but if we don't remove our listener, then we'll end up causing
   // the /next/ test to fail!
   iframe.removeEventListener('mozbrowsershowmodalprompt', checkMessage);
 
   var principal = SpecialPowers.wrap(document).nodePrincipal;
   SpecialPowers.removePermission("browser", {url: SpecialPowers.wrap(principal.URI).spec,
                                              originAttributes: {
                                                appId: principal.appId,
-                                               inBrowser: true
+                                               inIsolatedMozBrowser: true
                                              }});
   SimpleTest.finish();
 }
 
 var expectedMsg = null;
 var expectedMsgCallback = null;
 function expectMessage(msg, next) {
   expectedMsg = msg;
--- a/dom/browser-element/mochitest/browserElement_SetVisibleFrames2.js
+++ b/dom/browser-element/mochitest/browserElement_SetVisibleFrames2.js
@@ -10,17 +10,17 @@ SimpleTest.waitForExplicitFinish();
 browserElementTestHelpers.setEnabledPref(true);
 browserElementTestHelpers.addPermission();
 
 function runTest() {
   var principal = SpecialPowers.wrap(document).nodePrincipal;
   SpecialPowers.addPermission("browser", true, {url: SpecialPowers.wrap(principal.URI).spec,
                                                 originAttributes: {
                                                   appId: principal.appId,
-                                                  inBrowser: true
+                                                  inIsolatedMozBrowser: true
                                                 }});
 
   var iframe = document.createElement('iframe');
   iframe.setAttribute('mozbrowser', 'true');
 
   // We need remote = false here until bug 761935 is fixed; see
   // SetVisibleFrames.js for an explanation.
   iframe.remote = false;
@@ -56,15 +56,15 @@ function runTest() {
   document.body.appendChild(iframe);
 }
 
 function finish() {
   var principal = SpecialPowers.wrap(document).nodePrincipal;
   SpecialPowers.removePermission("browser", {url: SpecialPowers.wrap(principal.URI).spec,
                                              originAttributes: {
                                                appId: principal.appId,
-                                               inBrowser: true
+                                               inIsolatedMozBrowser: true
                                              }});
 
   SimpleTest.finish();
 }
 
 addEventListener('testready', runTest);
--- a/dom/browser-element/mochitest/priority/test_ExpectingSystemMessage2.html
+++ b/dom/browser-element/mochitest/priority/test_ExpectingSystemMessage2.html
@@ -20,25 +20,25 @@ browserElementTestHelpers.addPermission(
 browserElementTestHelpers.enableProcessPriorityManager();
 SpecialPowers.addPermission("embed-apps", true, document);
 
 // Give our origin permission to open browsers, and remove it when the test is complete.
 var principal = SpecialPowers.wrap(document).nodePrincipal;
 SpecialPowers.addPermission("browser", true, {url: SpecialPowers.wrap(principal.URI).spec,
                                               originAttributes: {
                                                 appId: principal.appId,
-                                                inBrowser: true
+                                                inIsolatedMozBrowser: true
                                               }});
 
 addEventListener('unload', function() {
   var principal = SpecialPowers.wrap(document).nodePrincipal;
   SpecialPowers.removePermission("browser", {url: SpecialPowers.wrap(principal.URI).spec,
                                              originAttributes: {
                                                appId: principal.appId,
-                                               inBrowser: true
+                                               inIsolatedMozBrowser: true
                                              }});
 });
 
 function runTest() {
   var iframe = document.createElement('iframe');
   iframe.setAttribute('mozbrowser', true);
   iframe.setAttribute('expecting-system-message', true);
   iframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
--- a/dom/browser-element/mochitest/priority/test_NestedFrames.html
+++ b/dom/browser-element/mochitest/priority/test_NestedFrames.html
@@ -19,25 +19,25 @@ browserElementTestHelpers.setEnabledPref
 browserElementTestHelpers.addPermission();
 browserElementTestHelpers.enableProcessPriorityManager();
 
 // Give our origin permission to open browsers, and remove it when the test is complete.
 var principal = SpecialPowers.wrap(document).nodePrincipal;
 SpecialPowers.addPermission("browser", true, {url: SpecialPowers.wrap(principal.URI).spec,
                                               originAttributes: {
                                                 appId: principal.appId,
-                                                inBrowser: true
+                                                inIsolatedMozBrowser: true
                                               }});
 
 addEventListener('unload', function() {
   var principal = SpecialPowers.wrap(document).nodePrincipal;
   SpecialPowers.removePermission("browser", {url: SpecialPowers.wrap(principal.URI).spec,
                                              originAttributes: {
                                                appId: principal.appId,
-                                               inBrowser: true
+                                               inIsolatedMozBrowser: true
                                              }});
 });
 
 function runTest() {
   // Set up the following hierarchy of frames:
   //
   //   <iframe mozbrowser remote=false src='file_NestedFramesOuter.html'>
   //     <iframe mozbrowser remote=true src='file_empty.html'>
--- a/dom/cache/DBSchema.cpp
+++ b/dom/cache/DBSchema.cpp
@@ -2394,17 +2394,17 @@ Validate(mozIStorageConnection* aConn)
 
 // -----
 // Schema migration code
 // -----
 
 typedef nsresult (*MigrationFunc)(mozIStorageConnection*);
 struct Migration
 {
-  Migration(int32_t aFromVersion, MigrationFunc aFunc)
+  MOZ_CONSTEXPR Migration(int32_t aFromVersion, MigrationFunc aFunc)
     : mFromVersion(aFromVersion)
     , mFunc(aFunc)
   { }
   int32_t mFromVersion;
   MigrationFunc mFunc;
 };
 
 // Declare migration functions here.  Each function should upgrade
--- a/dom/canvas/test/crossorigin/mochitest.ini
+++ b/dom/canvas/test/crossorigin/mochitest.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
+skip-if = e10s && debug && os == 'mac' # Bug 1252348
 support-files =
   image-allow-credentials.png
   image-allow-credentials.png^headers^
   image-allow-star.png
   image-allow-star.png^headers^
   image.png
   video.sjs
 
--- a/dom/canvas/test/mochitest.ini
+++ b/dom/canvas/test/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = e10s && debug && os == 'win' # Bug 1252677
+skip-if = e10s && debug && (os == 'win' || os == 'mac') # Bug 1252677 for Windows, Bug 1252348 for Mac
 support-files =
   android.json
   file_drawImage_document_domain.html
   image_anim-gr.gif
   image_anim-gr.png
   image_anim-poster-gr.png
   image_broken.png
   image_error-early.png
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -1505,17 +1505,17 @@ EventStateManager::FireContextClick()
           allowedToDispatch = false;
         }
       }
     }
     else if (mGestureDownContent->IsHTMLElement()) {
       nsCOMPtr<nsIFormControl> formCtrl(do_QueryInterface(mGestureDownContent));
 
       if (formCtrl) {
-        allowedToDispatch = formCtrl->IsTextControl(false) ||
+        allowedToDispatch = formCtrl->IsTextOrNumberControl(/*aExcludePassword*/ false) ||
                             formCtrl->GetType() == NS_FORM_INPUT_FILE;
       }
       else if (mGestureDownContent->IsAnyOfHTMLElements(nsGkAtoms::applet,
                                                         nsGkAtoms::embed,
                                                         nsGkAtoms::object)) {
         allowedToDispatch = false;
       }
     }
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -86,28 +86,38 @@ Request::RequestCacheEnabled(JSContext* 
 already_AddRefed<InternalRequest>
 Request::GetInternalRequest()
 {
   RefPtr<InternalRequest> r = mRequest;
   return r.forget();
 }
 
 namespace {
-void
-GetRequestURLFromDocument(nsIDocument* aDocument, const nsAString& aInput,
-                          nsAString& aRequestURL, ErrorResult& aRv)
+already_AddRefed<nsIURI>
+ParseURLFromDocument(nsIDocument* aDocument, const nsAString& aInput,
+                     ErrorResult& aRv)
 {
   MOZ_ASSERT(aDocument);
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIURI> baseURI = aDocument->GetBaseURI();
   nsCOMPtr<nsIURI> resolvedURI;
   aRv = NS_NewURI(getter_AddRefs(resolvedURI), aInput, nullptr, baseURI);
   if (NS_WARN_IF(aRv.Failed())) {
     aRv.ThrowTypeError<MSG_INVALID_URL>(aInput);
+  }
+  return resolvedURI.forget();
+}
+
+void
+GetRequestURLFromDocument(nsIDocument* aDocument, const nsAString& aInput,
+                          nsAString& aRequestURL, ErrorResult& aRv)
+{
+  nsCOMPtr<nsIURI> resolvedURI = ParseURLFromDocument(aDocument, aInput, aRv);
+  if (aRv.Failed()) {
     return;
   }
 
   // This fails with URIs with weird protocols, even when they are valid,
   // so we ignore the failure
   nsAutoCString credentials;
   Unused << resolvedURI->GetUserPass(credentials);
   if (!credentials.IsEmpty()) {
@@ -127,26 +137,35 @@ GetRequestURLFromDocument(nsIDocument* a
   aRv = resolvedURIClone->GetSpec(spec);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   CopyUTF8toUTF16(spec, aRequestURL);
 }
 
-void
-GetRequestURLFromChrome(const nsAString& aInput, nsAString& aRequestURL,
-                        ErrorResult& aRv)
+already_AddRefed<nsIURI>
+ParseURLFromChrome(const nsAString& aInput, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIURI> uri;
   aRv = NS_NewURI(getter_AddRefs(uri), aInput, nullptr, nullptr);
   if (NS_WARN_IF(aRv.Failed())) {
     aRv.ThrowTypeError<MSG_INVALID_URL>(aInput);
+  }
+  return uri.forget();
+}
+
+void
+GetRequestURLFromChrome(const nsAString& aInput, nsAString& aRequestURL,
+                        ErrorResult& aRv)
+{
+  nsCOMPtr<nsIURI> uri = ParseURLFromChrome(aInput, aRv);
+  if (aRv.Failed()) {
     return;
   }
 
   // This fails with URIs with weird protocols, even when they are valid,
   // so we ignore the failure
   nsAutoCString credentials;
   Unused << uri->GetUserPass(credentials);
   if (!credentials.IsEmpty()) {
@@ -166,29 +185,39 @@ GetRequestURLFromChrome(const nsAString&
   aRv = uriClone->GetSpec(spec);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   CopyUTF8toUTF16(spec, aRequestURL);
 }
 
-void
-GetRequestURLFromWorker(const GlobalObject& aGlobal, const nsAString& aInput,
-                        nsAString& aRequestURL, ErrorResult& aRv)
+already_AddRefed<workers::URL>
+ParseURLFromWorker(const GlobalObject& aGlobal, const nsAString& aInput,
+                   ErrorResult& aRv)
 {
   workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
   MOZ_ASSERT(worker);
   worker->AssertIsOnWorkerThread();
 
   NS_ConvertUTF8toUTF16 baseURL(worker->GetLocationInfo().mHref);
   RefPtr<workers::URL> url =
     workers::URL::Constructor(aGlobal, aInput, baseURL, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     aRv.ThrowTypeError<MSG_INVALID_URL>(aInput);
+  }
+  return url.forget();
+}
+
+void
+GetRequestURLFromWorker(const GlobalObject& aGlobal, const nsAString& aInput,
+                        nsAString& aRequestURL, ErrorResult& aRv)
+{
+  RefPtr<workers::URL> url = ParseURLFromWorker(aGlobal, aInput, aRv);
+  if (aRv.Failed()) {
     return;
   }
 
   nsString username;
   url->GetUsername(username, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
@@ -210,16 +239,48 @@ GetRequestURLFromWorker(const GlobalObje
   }
 
   url->Stringify(aRequestURL, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 }
 
+class ReferrerSameOriginChecker final : public workers::WorkerMainThreadRunnable
+{
+public:
+  ReferrerSameOriginChecker(workers::WorkerPrivate* aWorkerPrivate,
+                            const nsAString& aReferrerURL,
+                            nsresult& aResult)
+    : workers::WorkerMainThreadRunnable(aWorkerPrivate),
+      mReferrerURL(aReferrerURL),
+      mResult(aResult)
+  {
+    mWorkerPrivate->AssertIsOnWorkerThread();
+  }
+
+  bool
+  MainThreadRun() override
+  {
+    nsCOMPtr<nsIURI> uri;
+    if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), mReferrerURL))) {
+      nsCOMPtr<nsIPrincipal> principal = mWorkerPrivate->GetPrincipal();
+      if (principal) {
+        mResult = principal->CheckMayLoad(uri, /* report */ false,
+                                          /* allowIfInheritsPrincipal */ false);
+      }
+    }
+    return true;
+  }
+
+private:
+  const nsString mReferrerURL;
+  nsresult& mResult;
+};
+
 } // namespace
 
 /*static*/ already_AddRefed<Request>
 Request::Constructor(const GlobalObject& aGlobal,
                      const RequestOrUSVString& aInput,
                      const RequestInit& aInit, ErrorResult& aRv)
 {
   nsCOMPtr<nsIInputStream> temporaryBody;
@@ -285,16 +346,84 @@ Request::Constructor(const GlobalObject&
                                    : fallbackCredentials;
 
   if (mode == RequestMode::Navigate ||
       (aInit.IsAnyMemberPresent() && request->Mode() == RequestMode::Navigate)) {
     aRv.ThrowTypeError<MSG_INVALID_REQUEST_MODE>(NS_LITERAL_STRING("navigate"));
     return nullptr;
   }
 
+  if (aInit.IsAnyMemberPresent()) {
+    request->SetReferrer(NS_LITERAL_STRING(kFETCH_CLIENT_REFERRER_STR));
+  }
+  if (aInit.mReferrer.WasPassed()) {
+    const nsString& referrer = aInit.mReferrer.Value();
+    if (referrer.IsEmpty()) {
+      request->SetReferrer(NS_LITERAL_STRING(""));
+    } else {
+      nsAutoString referrerURL;
+      if (NS_IsMainThread()) {
+        nsIDocument* doc = GetEntryDocument();
+        nsCOMPtr<nsIURI> uri;
+        if (doc) {
+          uri = ParseURLFromDocument(doc, referrer, aRv);
+        } else {
+          // If we don't have a document, we must assume that this is a full URL.
+          uri = ParseURLFromChrome(referrer, aRv);
+        }
+        if (NS_WARN_IF(aRv.Failed())) {
+          aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
+          return nullptr;
+        }
+        nsAutoCString spec;
+        uri->GetSpec(spec);
+        CopyUTF8toUTF16(spec, referrerURL);
+        if (!referrerURL.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
+          nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull();
+          if (principal) {
+            nsresult rv = principal->CheckMayLoad(uri, /* report */ false,
+                                                  /* allowIfInheritsPrincipal */ false);
+            if (NS_FAILED(rv)) {
+              aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
+              return nullptr;
+            }
+          }
+        }
+      } else {
+        RefPtr<workers::URL> url = ParseURLFromWorker(aGlobal, referrer, aRv);
+        if (NS_WARN_IF(aRv.Failed())) {
+          aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
+          return nullptr;
+        }
+        url->Stringify(referrerURL, aRv);
+        if (NS_WARN_IF(aRv.Failed())) {
+          aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
+          return nullptr;
+        }
+        if (!referrerURL.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
+          workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
+          nsresult rv = NS_OK;
+          // ReferrerSameOriginChecker uses a sync loop to get the main thread
+          // to perform the same-origin check.  Overall, on Workers this method
+          // can create 3 sync loops (two for constructing URLs and one here) so
+          // in the future we may want to optimize it all by off-loading all of
+          // this work in a single sync loop.
+          RefPtr<ReferrerSameOriginChecker> checker =
+            new ReferrerSameOriginChecker(worker, referrerURL, rv);
+          checker->Dispatch(aRv);
+          if (aRv.Failed() || NS_FAILED(rv)) {
+            aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
+            return nullptr;
+          }
+        }
+      }
+      request->SetReferrer(referrerURL);
+    }
+  }
+
   if (mode != RequestMode::EndGuard_) {
     request->ClearCreatedByFetchEvent();
     request->SetMode(mode);
   }
 
   if (credentials != RequestCredentials::EndGuard_) {
     request->ClearCreatedByFetchEvent();
     request->SetCredentialsMode(credentials);
--- a/dom/html/nsBrowserElement.cpp
+++ b/dom/html/nsBrowserElement.cpp
@@ -49,25 +49,25 @@ nsBrowserElement::IsNotWidgetOrThrow(Err
   }
   aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
   return false;
 }
 
 void
 nsBrowserElement::InitBrowserElementAPI()
 {
-  bool isBrowserOrApp;
+  bool isMozBrowserOrApp;
   nsCOMPtr<nsIFrameLoader> frameLoader = GetFrameLoader();
   NS_ENSURE_TRUE_VOID(frameLoader);
-  nsresult rv = frameLoader->GetOwnerIsBrowserOrAppFrame(&isBrowserOrApp);
+  nsresult rv = frameLoader->GetOwnerIsMozBrowserOrAppFrame(&isMozBrowserOrApp);
   NS_ENSURE_SUCCESS_VOID(rv);
   rv = frameLoader->GetOwnerIsWidget(&mOwnerIsWidget);
   NS_ENSURE_SUCCESS_VOID(rv);
 
-  if (!isBrowserOrApp) {
+  if (!isMozBrowserOrApp) {
     return;
   }
 
   if (!mBrowserElementAPI) {
     mBrowserElementAPI = do_CreateInstance("@mozilla.org/dom/browser-element-api;1");
     if (NS_WARN_IF(!mBrowserElementAPI)) {
       return;
     }
@@ -505,23 +505,23 @@ nsBrowserElement::GetAllowedAudioChannel
 
   // If empty, it means that this is the first call of this method.
   if (mBrowserElementAudioChannels.IsEmpty()) {
     nsCOMPtr<nsIFrameLoader> frameLoader = GetFrameLoader();
     if (NS_WARN_IF(!frameLoader)) {
       return;
     }
 
-    bool isBrowserOrApp;
-    aRv = frameLoader->GetOwnerIsBrowserOrAppFrame(&isBrowserOrApp);
+    bool isMozBrowserOrApp;
+    aRv = frameLoader->GetOwnerIsMozBrowserOrAppFrame(&isMozBrowserOrApp);
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
 
-    if (!isBrowserOrApp) {
+    if (!isMozBrowserOrApp) {
       return;
     }
 
     nsCOMPtr<nsIDOMElement> frameElement;
     aRv = frameLoader->GetOwnerElement(getter_AddRefs(frameElement));
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -2366,17 +2366,17 @@ nsGenericHTMLFormElement::IntrinsicState
       NS_ASSERTION(IsSubmitControl(),
                    "Default submit element that isn't a submit control.");
       // We are the default submit element (:default)
       state |= NS_EVENT_STATE_DEFAULT;
   }
 
   // Make the text controls read-write
   if (!state.HasState(NS_EVENT_STATE_MOZ_READWRITE) &&
-      IsTextControl(false)) {
+      IsTextOrNumberControl(/*aExcludePassword*/ false)) {
     bool roState = GetBoolAttr(nsGkAtoms::readonly);
 
     if (!roState) {
       state |= NS_EVENT_STATE_MOZ_READWRITE;
       state &= ~NS_EVENT_STATE_MOZ_READONLY;
     }
   }
 
--- a/dom/html/nsGenericHTMLFrameElement.cpp
+++ b/dom/html/nsGenericHTMLFrameElement.cpp
@@ -546,16 +546,30 @@ nsGenericHTMLFrameElement::GetReallyIsWi
   GetManifestURLByType(nsGkAtoms::mozwidget, widgetManifestURL);
   bool isWidget = !widgetManifestURL.IsEmpty();
 
   *aOut = isWidget && !isApp;
   return NS_OK;
 }
 
 /* [infallible] */ NS_IMETHODIMP
+nsGenericHTMLFrameElement::GetIsolated(bool *aOut)
+{
+  *aOut = true;
+
+  if (!nsContentUtils::IsSystemPrincipal(NodePrincipal())) {
+    return NS_OK;
+  }
+
+  // Isolation is only disabled if the attribute is present
+  *aOut = !HasAttr(kNameSpaceID_None, nsGkAtoms::noisolation);
+  return NS_OK;
+}
+
+/* [infallible] */ NS_IMETHODIMP
 nsGenericHTMLFrameElement::GetIsExpectingSystemMessage(bool *aOut)
 {
   *aOut = false;
 
   if (!nsIMozBrowserFrame::GetReallyIsApp()) {
     return NS_OK;
   }
 
@@ -700,9 +714,8 @@ nsGenericHTMLFrameElement::InitializeBro
 }
 
 void
 nsGenericHTMLFrameElement::SwapFrameLoaders(nsXULElement& aOtherOwner,
                                             ErrorResult& aError)
 {
   aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
 }
-
--- a/dom/html/nsIFormControl.h
+++ b/dom/html/nsIFormControl.h
@@ -171,17 +171,24 @@ public:
    */
   inline bool IsSubmitControl() const;
 
   /**
    * Returns whether this is a text control.
    * @param  aExcludePassword  to have NS_FORM_INPUT_PASSWORD returning false.
    * @return whether this is a text control.
    */
-  inline bool IsTextControl(bool aExcludePassword) const ;
+  inline bool IsTextControl(bool aExcludePassword) const;
+
+  /**
+   * Returns true if this is a text control or a number control.
+   * @param  aExcludePassword  to have NS_FORM_INPUT_PASSWORD returning false.
+   * @return true if this is a text control or a number control.
+   */
+  inline bool IsTextOrNumberControl(bool aExcludePassword) const;
 
   /**
    * Returns whether this is a single line text control.
    * @param  aExcludePassword  to have NS_FORM_INPUT_PASSWORD returning false.
    * @return whether this is a single line text control.
    */
   inline bool IsSingleLineTextControl(bool aExcludePassword) const;
 
@@ -231,16 +238,22 @@ bool
 nsIFormControl::IsTextControl(bool aExcludePassword) const
 {
   uint32_t type = GetType();
   return type == NS_FORM_TEXTAREA ||
          IsSingleLineTextControl(aExcludePassword, type);
 }
 
 bool
+nsIFormControl::IsTextOrNumberControl(bool aExcludePassword) const
+{
+  return IsTextControl(aExcludePassword) || GetType() == NS_FORM_INPUT_NUMBER;
+}
+
+bool
 nsIFormControl::IsSingleLineTextControl(bool aExcludePassword) const
 {
   return IsSingleLineTextControl(aExcludePassword, GetType());
 }
 
 /*static*/
 bool
 nsIFormControl::IsSingleLineTextControl(bool aExcludePassword, uint32_t aType)
--- a/dom/indexedDB/test/unit/test_defaultStorageUpgrade.js
+++ b/dom/indexedDB/test/unit/test_defaultStorageUpgrade.js
@@ -42,21 +42,21 @@ function testSteps()
 
     // This one lives in storage/default/file++++c++Users+joe+index.html
     { url: "file:///c:/Users/joe/index.html", dbName: "dbK", dbVersion: 1 },
 
     // This one lives in storage/permanent/chrome
     { dbName: "dbL", dbVersion: 1 },
 
     // This one lives in storage/default/1007+f+app+++system.gaiamobile.org
-    { appId: 1007, inMozBrowser: false, url: "app://system.gaiamobile.org",
+    { appId: 1007, inIsolatedMozBrowser: false, url: "app://system.gaiamobile.org",
       dbName: "dbM", dbVersion: 1 },
 
     // This one lives in storage/default/1007+t+https+++developer.cdn.mozilla.net
-    { appId: 1007, inMozBrowser: true, url: "https://developer.cdn.mozilla.net",
+    { appId: 1007, inIsolatedMozBrowser: true, url: "https://developer.cdn.mozilla.net",
       dbName: "dbN", dbVersion: 1 },
 
     // This one lives in storage/default/http+++127.0.0.1
     { url: "http://127.0.0.1", dbName: "dbO", dbVersion: 1 },
 
     // This one lives in storage/default/file++++
     { url: "file:///", dbName: "dbP", dbVersion: 1 },
 
@@ -88,17 +88,17 @@ function testSteps()
 
   function openDatabase(params) {
     let request;
     if ("url" in params) {
       let uri = ios.newURI(params.url, null, null);
       let principal =
         ssm.createCodebasePrincipal(uri,
                                     {appId: params.appId || ssm.NO_APPID,
-                                     inBrowser: params.inMozBrowser});
+                                     inIsolatedMozBrowser: params.inIsolatedMozBrowser});
       if ("dbVersion" in params) {
         request = indexedDB.openForPrincipal(principal, params.dbName,
                                              params.dbVersion);
       } else {
         request = indexedDB.openForPrincipal(principal, params.dbName,
                                              params.dbOptions);
       }
     } else {
--- a/dom/inputmethod/Keyboard.jsm
+++ b/dom/inputmethod/Keyboard.jsm
@@ -146,17 +146,17 @@ this.Keyboard = {
           type: 'inputmethod-contextchange',
           inputType: 'blur'
         });
 
         this.formMM = null;
       }
     } else {
       // Ignore notifications that aren't from a BrowserOrApp
-      if (!frameLoader.ownerIsBrowserOrAppFrame) {
+      if (!frameLoader.ownerIsMozBrowserOrAppFrame) {
         return;
       }
       this.initFormsFrameScript(mm);
     }
   },
 
   initFormsFrameScript: function(mm) {
     mm.addMessageListener('Forms:Focus', this);
--- a/dom/inputmethod/mochitest/test_bug1043828.html
+++ b/dom/inputmethod/mochitest/test_bug1043828.html
@@ -87,17 +87,17 @@ function runTest() {
     let imeUrl = basePath + '/file_blank.html';
 
     SpecialPowers.pushPermissions([{
       type: 'input',
       allow: true,
       context: {
         url: imeUrl,
         originAttributes: {
-          inBrowser: true
+          inIsolatedMozBrowser: true
         }
       }
     }], function() {
       keyboardA.src = imeUrl;
       keyboardB.src = imeUrl;
 
       var handler = {
         handleEvent: function(){
--- a/dom/inputmethod/mochitest/test_bug944397.html
+++ b/dom/inputmethod/mochitest/test_bug944397.html
@@ -74,17 +74,17 @@ function runTest() {
     let imeUrl = basePath + '/file_inputmethod.html#data';
 
     SpecialPowers.pushPermissions([{
       type: 'input',
       allow: true,
       context: {
         url: imeUrl,
         originAttributes: {
-          inBrowser: true
+          inIsolatedMozBrowser: true
         }
       }
     }], function() {
       // STEP 2c: Tell Gecko to use this iframe as its keyboard app
       let req = keyboard.setInputMethodActive(true);
 
       req.onsuccess = function() {
         ok(true, 'setInputMethodActive succeeded.');
--- a/dom/inputmethod/mochitest/test_focus_blur_manage_events.html
+++ b/dom/inputmethod/mochitest/test_focus_blur_manage_events.html
@@ -137,17 +137,17 @@ function setupInputAppFrame() {
     document.body.appendChild(inputAppFrame);
 
     SpecialPowers.pushPermissions([{
       type: 'input',
       allow: true,
       context: {
         url: imeUrl,
         originAttributes: {
-          inBrowser: true
+          inIsolatedMozBrowser: true
         }
       }
     }], function() {
       let mm = SpecialPowers.getBrowserFrameMessageManager(inputAppFrame);
       inputAppFrame.addEventListener('mozbrowserloadend', function() {
         mm.addMessageListener('text:appEvent', function(msg) {
           ok(false, 'Input app should not receive ' + msg.data.type + ' event.');
         });
--- a/dom/inputmethod/mochitest/test_input_registry_events.html
+++ b/dom/inputmethod/mochitest/test_input_registry_events.html
@@ -66,17 +66,17 @@ function setupInputAppFrame() {
     document.body.appendChild(inputAppFrame);
 
     SpecialPowers.pushPermissions([{
       type: 'input',
       allow: true,
       context: {
         url: imeUrl,
         originAttributes: {
-          inBrowser: true
+          inIsolatedMozBrowser: true
         }
       }
     }], function() {
       let mm = appFrameMM =
         SpecialPowers.getBrowserFrameMessageManager(inputAppFrame);
 
       inputAppFrame.addEventListener('mozbrowserloadend', function() {
         mm.addMessageListener('test:appEvent', function(msg) {
--- a/dom/inputmethod/mochitest/test_simple_manage_events.html
+++ b/dom/inputmethod/mochitest/test_simple_manage_events.html
@@ -99,17 +99,17 @@ function setupInputAppFrame() {
     document.body.appendChild(inputAppFrame);
 
     SpecialPowers.pushPermissions([{
       type: 'input',
       allow: true,
       context: {
         url: imeUrl,
         originAttributes: {
-          inBrowser: true
+          inIsolatedMozBrowser: true
         }
       }
     }], function() {
       let mm = appFrameMM =
         SpecialPowers.getBrowserFrameMessageManager(inputAppFrame);
 
       inputAppFrame.addEventListener('mozbrowserloadend', function() {
         mm.addMessageListener('test:appEvent', function(msg) {
--- a/dom/interfaces/apps/nsIAppsService.idl
+++ b/dom/interfaces/apps/nsIAppsService.idl
@@ -61,16 +61,21 @@ interface nsIAppsService : nsISupports
    */
   DOMString getCoreAppsBasePath();
 
   /**
    * Returns the basepath for regular packaged apps
    */
   DOMString getWebAppsBasePath();
 
+  /**
+   * Returns true if at least one app is in the registry.
+   */
+  boolean areAnyAppsInstalled();
+
   jsval getAppInfo(in DOMString appId);
 
   /**
    * Returns a URI to redirect to when we get a redirection to 'uri'.
    * Returns null if no redirection is declared for this uri.
    */
   nsIURI getRedirect(in unsigned long localId, in nsIURI uri);
 
--- a/dom/interfaces/html/nsIMozBrowserFrame.idl
+++ b/dom/interfaces/html/nsIMozBrowserFrame.idl
@@ -39,16 +39,30 @@ interface nsIMozBrowserFrame : nsIDOMMoz
    * In order to really be a frame, this frame must really be a browser
    * frame (this requirement will go away eventually), the frame's mozwidget
    * attribute must point to the manifest of a valid app, and the src should
    * be in the |widgetPages| specified by the manifest.
    */
   [infallible] readonly attribute boolean reallyIsWidget;
 
   /**
+   * Gets whether this frame is an isolated frame.
+   *
+   * By default, browser frames are isolated, meaning they have a principal
+   * where OriginAttributes.mIsInIsolatedMozBrowser == true.  This isolates
+   * storage and other origin related items from non-browser apps, xul:browsers,
+   * etc.
+   *
+   * Isolation can be disabled by setting the frame's isolated attribute to
+   * false.  Disabling isolation is only allowed if the containing document has
+   * browser permission (or equivalent access).
+   */
+  [infallible] readonly attribute boolean isolated;
+
+  /**
    * This corresponds to the expecting-system-message attribute, which tells us
    * whether we should expect that this frame will receive a system message once
    * it starts up.
    *
    * It's the embedder's job to set this attribute on a frame.  Its presence
    * might cause us to increase the priority of the frame's process.
    */
   [infallible] readonly attribute boolean isExpectingSystemMessage;
--- a/dom/ipc/AppProcessChecker.cpp
+++ b/dom/ipc/AppProcessChecker.cpp
@@ -86,17 +86,17 @@ AssertAppProcess(PBrowserParent* aActor,
   if (!aActor) {
     NS_WARNING("Testing process capability for null actor");
     return false;
   }
 
   TabParent* tab = TabParent::GetFrom(aActor);
   nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp();
 
-  return CheckAppTypeHelper(app, aType, aCapability, tab->IsBrowserElement());
+  return CheckAppTypeHelper(app, aType, aCapability, tab->IsMozBrowserElement());
 }
 
 static bool
 CheckAppStatusHelper(mozIApplication* aApp,
                      unsigned short aStatus)
 {
   bool valid = false;
 
@@ -168,17 +168,17 @@ AssertAppProcess(TabContext& aContext,
   // Do a origin-based permission check if the TabContext owns a signed package.
   if (!aContext.SignedPkgOriginNoSuffix().IsEmpty() &&
       (ASSERT_APP_HAS_PERMISSION == aType || ASSERT_APP_PROCESS_PERMISSION == aType)) {
     nsCString origin = aContext.SignedPkgOriginNoSuffix() + suffix;
     return CheckOriginPermission(origin, aCapability);
   }
 
   nsCOMPtr<mozIApplication> app = aContext.GetOwnOrContainingApp();
-  return CheckAppTypeHelper(app, aType, aCapability, aContext.IsBrowserElement());
+  return CheckAppTypeHelper(app, aType, aCapability, aContext.IsMozBrowserElement());
 }
 
 bool
 AssertAppStatus(TabContext& aContext,
                 unsigned short aStatus)
 {
 
   nsCOMPtr<mozIApplication> app = aContext.GetOwnOrContainingApp();
@@ -244,26 +244,26 @@ AssertAppPrincipal(PContentParent* aActo
 {
   if (!aPrincipal) {
     NS_WARNING("Principal is invalid, killing app process");
     static_cast<ContentParent*>(aActor)->KillHard("AssertAppPrincipal");
     return false;
   }
 
   uint32_t principalAppId = aPrincipal->GetAppId();
-  bool inBrowserElement = aPrincipal->GetIsInBrowserElement();
+  bool inIsolatedBrowser = aPrincipal->GetIsInIsolatedMozBrowserElement();
 
   // Check if the permission's appId matches a child we manage.
   nsTArray<TabContext> contextArray =
     static_cast<ContentParent*>(aActor)->GetManagedTabContext();
   for (uint32_t i = 0; i < contextArray.Length(); ++i) {
     if (contextArray[i].OwnOrContainingAppId() == principalAppId) {
-      // If the child only runs inBrowserElement content and the principal claims
-      // it's not in a browser element, it's lying.
-      if (!contextArray[i].IsBrowserElement() || inBrowserElement) {
+      // If the child only runs isolated browser content and the principal
+      // claims it's not in an isolated browser element, it's lying.
+      if (!contextArray[i].IsIsolatedMozBrowserElement() || inIsolatedBrowser) {
         return true;
       }
       break;
     }
   }
 
   NS_WARNING("Principal is invalid, killing app process");
   static_cast<ContentParent*>(aActor)->KillHard("AssertAppPrincipal");
@@ -314,18 +314,27 @@ CheckPermission(PContentParent* aActor,
   NS_ENSURE_SUCCESS(rv, nsIPermissionManager::UNKNOWN_ACTION);
   if (permission == nsIPermissionManager::UNKNOWN_ACTION ||
       permission == nsIPermissionManager::DENY_ACTION) {
     return permission;
   }
 
   // For browser content (and if the app hasn't explicitly denied this),
   // consider the requesting origin, not the app.
+  // After bug 1238160, the principal no longer knows how to answer "is this a
+  // browser element", which is really what this code path wants. Currently,
+  // desktop is the only platform where we intend to disable isolation on a
+  // browser frame, so non-desktop should be able to assume that
+  // inIsolatedMozBrowser is true for all mozbrowser frames.  This code path is
+  // currently unused on desktop, since MOZ_CHILD_PERMISSIONS is only set for
+  // MOZ_B2G.  We use a release assertion in
+  // nsFrameLoader::OwnerIsIsolatedMozBrowserFrame so that platforms with apps
+  // can assume inIsolatedMozBrowser is true for all mozbrowser frames.
   if (appPerm == nsIPermissionManager::PROMPT_ACTION &&
-      aPrincipal->GetIsInBrowserElement()) {
+      aPrincipal->GetIsInIsolatedMozBrowserElement()) {
     return permission;
   }
 
   // Setting to "prompt" in the settings UI should prompt everywhere in
   // non-browser content.
   if (appPerm == nsIPermissionManager::PROMPT_ACTION ||
       permission == nsIPermissionManager::PROMPT_ACTION) {
     return nsIPermissionManager::PROMPT_ACTION;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -801,17 +801,17 @@ ContentChild::ProvideWindowCommon(TabChi
 
   nsAutoPtr<IPCTabContext> ipcContext;
   TabId openerTabId = TabId(0);
 
   if (aTabOpener) {
     PopupIPCTabContext context;
     openerTabId = aTabOpener->GetTabId();
     context.opener() = openerTabId;
-    context.isBrowserElement() = aTabOpener->IsBrowserElement();
+    context.isMozBrowserElement() = aTabOpener->IsMozBrowserElement();
     ipcContext = new IPCTabContext(context);
   } else {
     // It's possible to not have a TabChild opener in the case
     // of ServiceWorker::OpenWindow.
     UnsafeIPCTabContext unsafeTabContext;
     ipcContext = new IPCTabContext(unsafeTabContext);
   }
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -62,16 +62,17 @@
 #include "mozilla/dom/ServiceWorkerRegistrar.h"
 #include "mozilla/dom/bluetooth/PBluetoothParent.h"
 #include "mozilla/dom/cellbroadcast/CellBroadcastParent.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
 #include "mozilla/dom/icc/IccParent.h"
 #include "mozilla/dom/mobileconnection/MobileConnectionParent.h"
 #include "mozilla/dom/mobilemessage/SmsParent.h"
 #include "mozilla/dom/power/PowerManagerService.h"
+#include "mozilla/dom/Permissions.h"
 #include "mozilla/dom/PresentationParent.h"
 #include "mozilla/dom/PPresentationParent.h"
 #include "mozilla/dom/quota/QuotaManagerService.h"
 #include "mozilla/dom/telephony/TelephonyParent.h"
 #include "mozilla/dom/time/DateCacheCleaner.h"
 #include "mozilla/dom/voicemail/VoicemailParent.h"
 #include "mozilla/embedding/printingui/PrintingParent.h"
 #include "mozilla/hal_sandbox/PHalParent.h"
@@ -1049,16 +1050,24 @@ ContentParent::RecvUngrabPointer(const u
   return false;
 #else
   gdk_pointer_ungrab(aTime);
   return true;
 #endif
 }
 
 bool
+ContentParent::RecvRemovePermission(const IPC::Principal& aPrincipal,
+                                    const nsCString& aPermissionType,
+                                    nsresult* aRv) {
+  *aRv = Permissions::RemovePermission(aPrincipal, aPermissionType.get());
+  return true;
+}
+
+bool
 ContentParent::RecvConnectPluginBridge(const uint32_t& aPluginId, nsresult* aRv)
 {
   *aRv = NS_OK;
   // We don't need to get the run ID for the plugin, since we already got it
   // in the first call to SetupBridge in RecvLoadPlugin, so we pass in a dummy
   // pointer and just throw it away.
   uint32_t dummy = 0;
   return mozilla::plugins::SetupBridge(aPluginId, this, true, aRv, &dummy);
@@ -1117,29 +1126,29 @@ ContentParent::CreateBrowserOrApp(const 
   TabId tabId;
 
   nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement);
   TabId openerTabId;
   if (docShell) {
     openerTabId = TabParent::GetTabIdFrom(docShell);
   }
 
-  if (aContext.IsBrowserElement() || !aContext.HasOwnApp()) {
+  if (aContext.IsMozBrowserElement() || !aContext.HasOwnApp()) {
     RefPtr<TabParent> tp;
     RefPtr<nsIContentParent> constructorSender;
     if (isInContentProcess) {
-      MOZ_ASSERT(aContext.IsBrowserElement());
+      MOZ_ASSERT(aContext.IsMozBrowserElement());
       constructorSender = CreateContentBridgeParent(aContext, initialPriority,
                                                     openerTabId, &tabId);
     } else {
       if (aOpenerContentParent) {
         constructorSender = aOpenerContentParent;
       } else {
         constructorSender =
-          GetNewOrUsedBrowserProcess(aContext.IsBrowserElement(),
+          GetNewOrUsedBrowserProcess(aContext.IsMozBrowserElement(),
                                      initialPriority);
         if (!constructorSender) {
           return nullptr;
         }
       }
       tabId = AllocateTabId(openerTabId,
                             aContext.AsIPCTabContext(),
                            constructorSender->ChildID());
@@ -5329,17 +5338,17 @@ ContentParent::RecvCreateWindow(PBrowser
       return false;
   }
 
   TabParent* thisTabParent = nullptr;
   if (aThisTab) {
     thisTabParent = TabParent::GetFrom(aThisTab);
   }
 
-  if (NS_WARN_IF(thisTabParent && thisTabParent->IsBrowserOrApp())) {
+  if (NS_WARN_IF(thisTabParent && thisTabParent->IsMozBrowserOrApp())) {
     return false;
   }
 
   nsCOMPtr<nsPIWindowWatcher> pwwatch =
     do_GetService(NS_WINDOWWATCHER_CONTRACTID, aResult);
 
   if (NS_WARN_IF(NS_FAILED(*aResult))) {
     return true;
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -208,16 +208,20 @@ public:
 
   virtual bool RecvFindPlugins(const uint32_t& aPluginEpoch,
                                nsresult* aRv,
                                nsTArray<PluginTag>* aPlugins,
                                uint32_t* aNewPluginEpoch) override;
 
   virtual bool RecvUngrabPointer(const uint32_t& aTime) override;
 
+  virtual bool RecvRemovePermission(const IPC::Principal& aPrincipal,
+                                    const nsCString& aPermissionType,
+                                    nsresult* aRv) override;
+
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver)
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIDOMGEOPOSITIONCALLBACK
   NS_DECL_NSIDOMGEOPOSITIONERRORCALLBACK
 
   /**
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1185,15 +1185,17 @@ parent:
 
     /**
      * Tells the parent to ungrab the pointer on the default display.
      *
      * This is for GTK platforms where we have to ensure the pointer ungrab happens in the
      * chrome process as that's the process that receives the pointer event.
      */
     sync UngrabPointer(uint32_t time);
+
+    sync RemovePermission(Principal principal, nsCString permissionType) returns (nsresult rv);
 both:
      async AsyncMessage(nsString aMessage, ClonedMessageData aData,
                         CpowEntry[] aCpows, Principal aPrincipal);
 };
 
 }
 }
--- a/dom/ipc/PTabContext.ipdlh
+++ b/dom/ipc/PTabContext.ipdlh
@@ -8,45 +8,50 @@ include protocol PBrowser;
 include PBrowserOrId;
 
 namespace mozilla {
 namespace dom {
 
 // An IPCTabContext which corresponds to a PBrowser opened by a child when it
 // receives window.open().
 //
-// If isBrowserElement is false, this PopupIPCTabContext corresponds to an app
-// frame, and the frame's app-id and app-frame-owner-app-id will be equal to the
-// opener's values.
+// If isMozBrowserElement is false, this PopupIPCTabContext is either a
+// <xul:browser> or an app frame.  The frame's app-id and app-frame-owner-app-id
+// will be equal to the opener's values.  For a <xul:browser>, those app IDs
+// will be NO_APP_ID.
 //
-// If isBrowserElement is true, the frame's browserFrameOwnerAppId will be equal
-// to the opener's app-id.
+// If isMozBrowserElement is true, the frame's browserFrameOwnerAppId will be
+// equal to the opener's app-id.
 //
-// It's an error to set isBrowserElement == false if opener is a browser
+// It's an error to set isMozBrowserElement == false if opener is a mozbrowser
 // element.  Such a PopupIPCTabContext should be rejected by code which receives
 // it.
 struct PopupIPCTabContext
 {
   PBrowserOrId opener;
-  bool isBrowserElement;
+  bool isMozBrowserElement;
 };
 
 // An IPCTabContext which corresponds to an app, browser, or normal frame.
 struct FrameIPCTabContext
 {
   // The stringified originAttributes dictionary.
   nsCString originSuffix;
 
   // The ID of the app containing this app/browser frame, if applicable.
   uint32_t frameOwnerAppId;
 
   // The origin without originAttribute suffix for a signed package.
   // This value would be empty if the TabContext doesn't own a signed
   // package.
   nsCString signedPkgOriginNoSuffix;
+
+  // Whether this is a mozbrowser frame.  <iframe mozbrowser mozapp> and
+  // <xul:browser> are not considered to be mozbrowser frames.
+  bool isMozBrowserElement;
 };
 
 // XXXcatalinb: This is only used by ServiceWorkerClients::OpenWindow.
 // Because service workers don't have an associated TabChild
 // we can't satisfy the security constraints on b2g. As such, the parent
 // process will accept this tab context only on desktop.
 struct UnsafeIPCTabContext
 { };
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -864,19 +864,19 @@ ParticularProcessPriorityManager::OnRemo
   NS_ENSURE_TRUE_VOID(tp);
 
   MOZ_ASSERT(XRE_IsParentProcess());
   if (tp->Manager() != mContentParent) {
     return;
   }
 
   // Ignore notifications that aren't from a BrowserOrApp
-  bool isBrowserOrApp;
-  fl->GetOwnerIsBrowserOrAppFrame(&isBrowserOrApp);
-  if (isBrowserOrApp) {
+  bool isMozBrowserOrApp;
+  fl->GetOwnerIsMozBrowserOrAppFrame(&isMozBrowserOrApp);
+  if (isMozBrowserOrApp) {
     ResetPriority();
   }
 
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   if (os) {
     os->RemoveObserver(this, "remote-browser-shown");
   }
 }
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -544,17 +544,17 @@ TabChild::PreloadSlowThings()
 /*static*/ already_AddRefed<TabChild>
 TabChild::Create(nsIContentChild* aManager,
                  const TabId& aTabId,
                  const TabContext &aContext,
                  uint32_t aChromeFlags)
 {
     if (sPreallocatedTab &&
         sPreallocatedTab->mChromeFlags == aChromeFlags &&
-        aContext.IsBrowserOrApp()) {
+        aContext.IsMozBrowserOrApp()) {
 
         RefPtr<TabChild> child = sPreallocatedTab.get();
         sPreallocatedTab = nullptr;
 
         MOZ_ASSERT(!child->mTriedBrowserInit);
 
         child->mManager = aManager;
         child->SetTabId(aTabId);
@@ -860,18 +860,19 @@ void
 TabChild::NotifyTabContextUpdated()
 {
     nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
     MOZ_ASSERT(docShell);
 
     if (docShell) {
         // nsDocShell will do the right thing if we pass NO_APP_ID or
         // UNKNOWN_APP_ID for aOwnOrContainingAppId.
-        if (IsBrowserElement()) {
+        if (IsMozBrowserElement()) {
           docShell->SetIsBrowserInsideApp(BrowserOwnerAppId());
+          docShell->SetIsInIsolatedMozBrowserElement(IsIsolatedMozBrowserElement());
         } else {
           docShell->SetIsApp(OwnAppId());
         }
 
         OriginAttributes attrs = OriginAttributesRef();
         docShell->SetIsSignedPackage(attrs.mSignedPkg);
         docShell->SetUserContextId(attrs.mUserContextId);
     }
@@ -1105,17 +1106,17 @@ TabChild::ProvideWindow(mozIDOMWindowPro
                         mozIDOMWindowProxy** aReturn)
 {
     *aReturn = nullptr;
 
     // If aParent is inside an <iframe mozbrowser> or <iframe mozapp> and this
     // isn't a request to open a modal-type window, we're going to create a new
     // <iframe mozbrowser/mozapp> and return its window here.
     nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent);
-    bool iframeMoz = (docshell && docshell->GetIsInBrowserOrApp() &&
+    bool iframeMoz = (docshell && docshell->GetIsInMozBrowserOrApp() &&
                       !(aChromeFlags & (nsIWebBrowserChrome::CHROME_MODAL |
                                         nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
                                         nsIWebBrowserChrome::CHROME_OPENAS_CHROME)));
 
     if (!iframeMoz) {
       int32_t openLocation =
         nsWindowWatcher::GetWindowOpenLocation(nsPIDOMWindowOuter::From(aParent),
                                                aChromeFlags, aCalledFromJS,
@@ -1498,17 +1499,17 @@ TabChild::ApplyShowInfo(const ShowInfo& 
     // Once we've got one ShowInfo from parent, no need to update the values
     // anymore.
     mDidSetRealShowInfo = true;
   }
 
   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
   if (docShell) {
     nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(docShell);
-    if (IsBrowserOrApp()) {
+    if (IsMozBrowserOrApp()) {
       // B2G allows window.name to be set by changing the name attribute on the
       // <iframe mozbrowser> element. window.open calls cause this attribute to
       // be set to the correct value. A normal <xul:browser> element has no such
       // attribute. The data we get here comes from reading the attribute, so we
       // shouldn't trust it for <xul:browser> elements.
       item->SetName(aInfo.name());
     }
     docShell->SetFullscreenAllowed(aInfo.fullscreenAllowed());
@@ -1535,17 +1536,17 @@ TabChild::ApplyShowInfo(const ShowInfo& 
 }
 
 #ifdef MOZ_WIDGET_GONK
 void
 TabChild::MaybeRequestPreinitCamera()
 {
     // Check if this tab is an app (not a browser frame) and will use the
     // `camera` permission,
-    if (IsBrowserElement()) {
+    if (IsIsolatedMozBrowserElement()) {
       return;
     }
 
     nsCOMPtr<nsIAppsService> appsService = do_GetService("@mozilla.org/AppsService;1");
     if (NS_WARN_IF(!appsService)) {
       return;
     }
 
@@ -2520,17 +2521,17 @@ TabChild::InitTabChildGlobal(FrameScript
     NS_ENSURE_TRUE(root, false);
     root->SetParentTarget(scope);
   }
 
   if (aScriptLoading != DONT_LOAD_SCRIPTS && !mTriedBrowserInit) {
     mTriedBrowserInit = true;
     // Initialize the child side of the browser element machinery,
     // if appropriate.
-    if (IsBrowserOrApp()) {
+    if (IsMozBrowserOrApp()) {
       RecvLoadRemoteScript(BROWSER_ELEMENT_CHILD_SCRIPT, true);
     }
   }
 
   return true;
 }
 
 bool
--- a/dom/ipc/TabContext.cpp
+++ b/dom/ipc/TabContext.cpp
@@ -17,31 +17,38 @@
 using namespace mozilla::dom::ipc;
 using namespace mozilla::layout;
 
 namespace mozilla {
 namespace dom {
 
 TabContext::TabContext()
   : mInitialized(false)
+  , mIsMozBrowserElement(false)
   , mContainingAppId(NO_APP_ID)
   , mOriginAttributes()
 {
 }
 
 bool
-TabContext::IsBrowserElement() const
+TabContext::IsMozBrowserElement() const
 {
-  return mOriginAttributes.mInBrowser;
+  return mIsMozBrowserElement;
 }
 
 bool
-TabContext::IsBrowserOrApp() const
+TabContext::IsIsolatedMozBrowserElement() const
 {
-  return HasOwnApp() || IsBrowserElement();
+  return mOriginAttributes.mInIsolatedMozBrowser;
+}
+
+bool
+TabContext::IsMozBrowserOrApp() const
+{
+  return HasOwnApp() || IsMozBrowserElement();
 }
 
 uint32_t
 TabContext::OwnAppId() const
 {
   return mOriginAttributes.mAppId;
 }
 
@@ -57,27 +64,27 @@ TabContext::HasOwnApp() const
 {
   nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
   return !!ownApp;
 }
 
 uint32_t
 TabContext::BrowserOwnerAppId() const
 {
-  if (IsBrowserElement()) {
+  if (IsMozBrowserElement()) {
     return mContainingAppId;
   }
   return NO_APP_ID;
 }
 
 already_AddRefed<mozIApplication>
 TabContext::GetBrowserOwnerApp() const
 {
   nsCOMPtr<mozIApplication> ownerApp;
-  if (IsBrowserElement()) {
+  if (IsMozBrowserElement()) {
     ownerApp = mContainingApp;
   }
   return ownerApp.forget();
 }
 
 bool
 TabContext::HasBrowserOwnerApp() const
 {
@@ -160,17 +167,18 @@ TabContext::OriginAttributesRef() const
 
 const nsACString&
 TabContext::SignedPkgOriginNoSuffix() const
 {
   return mSignedPkgOriginNoSuffix;
 }
 
 bool
-TabContext::SetTabContext(mozIApplication* aOwnApp,
+TabContext::SetTabContext(bool aIsMozBrowserElement,
+                          mozIApplication* aOwnApp,
                           mozIApplication* aAppFrameOwnerApp,
                           const DocShellOriginAttributes& aOriginAttributes,
                           const nsACString& aSignedPkgOriginNoSuffix)
 {
   NS_ENSURE_FALSE(mInitialized, false);
 
   // Get ids for both apps and only write to our member variables after we've
   // verified that this worked.
@@ -189,32 +197,34 @@ TabContext::SetTabContext(mozIApplicatio
   }
 
   // Veryify that app id matches mAppId passed in originAttributes
   MOZ_RELEASE_ASSERT((aOwnApp && aOriginAttributes.mAppId == ownAppId) ||
                      (aAppFrameOwnerApp && aOriginAttributes.mAppId == containingAppId) ||
                      aOriginAttributes.mAppId == NO_APP_ID);
 
   mInitialized = true;
+  mIsMozBrowserElement = aIsMozBrowserElement;
   mOriginAttributes = aOriginAttributes;
   mContainingAppId = containingAppId;
   mOwnApp = aOwnApp;
   mContainingApp = aAppFrameOwnerApp;
   mSignedPkgOriginNoSuffix = aSignedPkgOriginNoSuffix;
   return true;
 }
 
 IPCTabContext
 TabContext::AsIPCTabContext() const
 {
   nsAutoCString originSuffix;
   mOriginAttributes.CreateSuffix(originSuffix);
   return IPCTabContext(FrameIPCTabContext(originSuffix,
                                           mContainingAppId,
-                                          mSignedPkgOriginNoSuffix));
+                                          mSignedPkgOriginNoSuffix,
+                                          mIsMozBrowserElement));
 }
 
 static already_AddRefed<mozIApplication>
 GetAppForId(uint32_t aAppId)
 {
   nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(appsService, nullptr);
 
@@ -222,29 +232,31 @@ GetAppForId(uint32_t aAppId)
   appsService->GetAppByLocalId(aAppId, getter_AddRefs(app));
 
   return app.forget();
 }
 
 MaybeInvalidTabContext::MaybeInvalidTabContext(const IPCTabContext& aParams)
   : mInvalidReason(nullptr)
 {
+  bool isMozBrowserElement = false;
   uint32_t containingAppId = NO_APP_ID;
   DocShellOriginAttributes originAttributes;
   nsAutoCString originSuffix;
   nsAutoCString signedPkgOriginNoSuffix;
 
   switch(aParams.type()) {
     case IPCTabContext::TPopupIPCTabContext: {
       const PopupIPCTabContext &ipcContext = aParams.get_PopupIPCTabContext();
 
       TabContext *context;
       if (ipcContext.opener().type() == PBrowserOrId::TPBrowserParent) {
         context = TabParent::GetFrom(ipcContext.opener().get_PBrowserParent());
-        if (context->IsBrowserElement() && !ipcContext.isBrowserElement()) {
+        if (context->IsMozBrowserElement() &&
+            !ipcContext.isMozBrowserElement()) {
           // If the TabParent corresponds to a browser element, then it can only
           // open other browser elements, for security reasons.  We should have
           // checked this before calling the TabContext constructor, so this is
           // a fatal error.
           mInvalidReason = "Child is-browser process tried to "
                            "open a non-browser tab.";
           return;
         }
@@ -264,28 +276,30 @@ MaybeInvalidTabContext::MaybeInvalidTabC
 
       // Browser elements can't nest other browser elements.  So if
       // our opener is browser element, we must be a new DOM window
       // opened by it.  In that case we inherit our containing app ID
       // (if any).
       //
       // Otherwise, we're a new app window and we inherit from our
       // opener app.
+      isMozBrowserElement = ipcContext.isMozBrowserElement();
       originAttributes = context->mOriginAttributes;
-      if (ipcContext.isBrowserElement()) {
+      if (isMozBrowserElement) {
         containingAppId = context->OwnOrContainingAppId();
       } else {
         containingAppId = context->mContainingAppId;
       }
       break;
     }
     case IPCTabContext::TFrameIPCTabContext: {
       const FrameIPCTabContext &ipcContext =
         aParams.get_FrameIPCTabContext();
 
+      isMozBrowserElement = ipcContext.isMozBrowserElement();
       containingAppId = ipcContext.frameOwnerAppId();
       signedPkgOriginNoSuffix = ipcContext.signedPkgOriginNoSuffix();
       originSuffix = ipcContext.originSuffix();
       originAttributes.PopulateFromSuffix(originSuffix);
       break;
     }
     case IPCTabContext::TUnsafeIPCTabContext: {
       // XXXcatalinb: This used *only* by ServiceWorkerClients::OpenWindow.
@@ -305,34 +319,35 @@ MaybeInvalidTabContext::MaybeInvalidTabC
       break;
     }
     default: {
       MOZ_CRASH();
     }
   }
 
   nsCOMPtr<mozIApplication> ownApp;
-  if (!originAttributes.mInBrowser) {
-    // mAppId corresponds to OwnOrContainingAppId; if mInBrowser is
+  if (!isMozBrowserElement) {
+    // mAppId corresponds to OwnOrContainingAppId; if isMozBrowserElement is
     // false then it's ownApp otherwise it's containingApp
     ownApp = GetAppForId(originAttributes.mAppId);
     if ((ownApp == nullptr) != (originAttributes.mAppId == NO_APP_ID)) {
       mInvalidReason = "Got an ownAppId that didn't correspond to an app.";
       return;
     }
   }
 
   nsCOMPtr<mozIApplication> containingApp = GetAppForId(containingAppId);
   if ((containingApp == nullptr) != (containingAppId == NO_APP_ID)) {
     mInvalidReason = "Got a containingAppId that didn't correspond to an app.";
     return;
   }
 
   bool rv;
-  rv = mTabContext.SetTabContext(ownApp,
+  rv = mTabContext.SetTabContext(isMozBrowserElement,
+                                 ownApp,
                                  containingApp,
                                  originAttributes,
                                  signedPkgOriginNoSuffix);
   if (!rv) {
     mInvalidReason = "Couldn't initialize TabContext.";
   }
 }
 
--- a/dom/ipc/TabContext.h
+++ b/dom/ipc/TabContext.h
@@ -37,47 +37,61 @@ public:
 
   /**
    * Generates IPCTabContext of type BrowserFrameIPCTabContext or
    * AppFrameIPCTabContext from this TabContext's information.
    */
   IPCTabContext AsIPCTabContext() const;
 
   /**
-   * Does this TabContext correspond to a mozbrowser?  (<iframe mozbrowser
-   * mozapp> is not a browser.)
+   * Does this TabContext correspond to a mozbrowser?
    *
-   * If IsBrowserElement() is true, HasOwnApp() and HasAppOwnerApp() are
+   * <iframe mozbrowser mozapp> and <xul:browser> are not considered to be
+   * mozbrowser elements.
+   *
+   * If IsMozBrowserElement() is true, HasOwnApp() and HasAppOwnerApp() are
    * guaranteed to be false.
    *
-   * If IsBrowserElement() is false, HasBrowserOwnerApp() is guaranteed to be
+   * If IsMozBrowserElement() is false, HasBrowserOwnerApp() is guaranteed to be
    * false.
    */
-  bool IsBrowserElement() const;
+  bool IsMozBrowserElement() const;
+
+  /**
+   * Does this TabContext correspond to an isolated mozbrowser?
+   *
+   * <iframe mozbrowser mozapp> and <xul:browser> are not considered to be
+   * mozbrowser elements.  <iframe mozbrowser noisolation> does not count as
+   * isolated since isolation is disabled.  Isolation can only be disabled by
+   * chrome pages.
+   */
+  bool IsIsolatedMozBrowserElement() const;
 
   /**
    * Does this TabContext correspond to a mozbrowser or mozapp?  This is
-   * equivalent to IsBrowserElement() || HasOwnApp().
+   * equivalent to IsMozBrowserElement() || HasOwnApp().  Returns false for
+   * <xul:browser>, which is neither a mozbrowser nor a mozapp.
    */
-  bool IsBrowserOrApp() const;
+  bool IsMozBrowserOrApp() const;
 
   /**
    * OwnAppId() returns the id of the app which directly corresponds to this
    * context's frame.  GetOwnApp() returns the corresponding app object, and
    * HasOwnApp() returns true iff GetOwnApp() would return a non-null value.
    *
-   * If HasOwnApp() is true, IsBrowserElement() is guaranteed to be false.
+   * If HasOwnApp() is true, IsMozBrowserElement() is guaranteed to be
+   * false.
    */
   uint32_t OwnAppId() const;
   already_AddRefed<mozIApplication> GetOwnApp() const;
   bool HasOwnApp() const;
 
   /**
    * BrowserOwnerAppId() gets the ID of the app which contains this browser
-   * frame.  If this is not a browser frame (i.e., if !IsBrowserElement()), then
+   * frame.  If this is not a mozbrowser frame (if !IsMozBrowserElement()), then
    * BrowserOwnerAppId() is guaranteed to return NO_APP_ID.
    *
    * Even if we are a browser frame, BrowserOwnerAppId() may still return
    * NO_APP_ID, if this browser frame is not contained inside an app.
    */
   uint32_t BrowserOwnerAppId() const;
   already_AddRefed<mozIApplication> GetBrowserOwnerApp() const;
   bool HasBrowserOwnerApp() const;
@@ -135,37 +149,46 @@ protected:
 
   /**
    * Set the TabContext for this frame. This can either be:
    *  - an app frame (with the given own app) inside the given owner app. Either
    *    apps can be null.
    *  - a browser frame inside the given owner app (which may be null).
    *  - a non-browser, non-app frame. Both own app and owner app should be null.
    */
-  bool SetTabContext(mozIApplication* aOwnApp,
+  bool SetTabContext(bool aIsMozBrowserElement,
+                     mozIApplication* aOwnApp,
                      mozIApplication* aAppFrameOwnerApp,
                      const DocShellOriginAttributes& aOriginAttributes,
                      const nsACString& aSignedPkgOriginNoSuffix);
 
 private:
   /**
    * Has this TabContext been initialized?  If so, mutator methods will fail.
    */
   bool mInitialized;
 
   /**
+   * Whether this TabContext corresponds to a mozbrowser.
+   *
+   * <iframe mozbrowser mozapp> and <xul:browser> are not considered to be
+   * mozbrowser elements.
+   */
+  bool mIsMozBrowserElement;
+
+  /**
    * This TabContext's own app.  If this is non-null, then this
-   * TabContext corresponds to an app, and mIsBrowser must be false.
+   * TabContext corresponds to an app, and mIsMozBrowserElement must be false.
    */
   nsCOMPtr<mozIApplication> mOwnApp;
 
   /**
-   * This TabContext's containing app.  If mIsBrowser, this corresponds to the
-   * app which contains the browser frame; otherwise, this corresponds to the
-   * app which contains the app frame.
+   * This TabContext's containing app.  If mIsMozBrowserElement, this
+   * corresponds to the app which contains the browser frame; otherwise, this
+   * corresponds to the app which contains the app frame.
    */
   nsCOMPtr<mozIApplication> mContainingApp;
 
   /*
    * Cache of mContainingApp->GetLocalId().
    */
   uint32_t mContainingAppId;
 
@@ -192,22 +215,24 @@ class MutableTabContext : public TabCont
 {
 public:
   bool SetTabContext(const TabContext& aContext)
   {
     return TabContext::SetTabContext(aContext);
   }
 
   bool
-  SetTabContext(mozIApplication* aOwnApp,
+  SetTabContext(bool aIsMozBrowserElement,
+                mozIApplication* aOwnApp,
                 mozIApplication* aAppFrameOwnerApp,
                 const DocShellOriginAttributes& aOriginAttributes,
                 const nsACString& aSignedPkgOriginNoSuffix = EmptyCString())
   {
-    return TabContext::SetTabContext(aOwnApp,
+    return TabContext::SetTabContext(aIsMozBrowserElement,
+                                     aOwnApp,
                                      aAppFrameOwnerApp,
                                      aOriginAttributes,
                                      aSignedPkgOriginNoSuffix);
   }
 };
 
 /**
  * MaybeInvalidTabContext is a simple class that lets you transform an
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -3098,17 +3098,17 @@ public:
     return NS_OK;
   }
   NS_IMETHOD GetNestedFrameId(uint64_t*) NO_IMPL
   NS_IMETHOD IsAppOfType(uint32_t, bool*) NO_IMPL
   NS_IMETHOD GetIsContent(bool*) NO_IMPL
   NS_IMETHOD GetUsePrivateBrowsing(bool*) NO_IMPL
   NS_IMETHOD SetUsePrivateBrowsing(bool) NO_IMPL
   NS_IMETHOD SetPrivateBrowsing(bool) NO_IMPL
-  NS_IMETHOD GetIsInBrowserElement(bool*) NO_IMPL
+  NS_IMETHOD GetIsInIsolatedMozBrowserElement(bool*) NO_IMPL
   NS_IMETHOD GetAppId(uint32_t*) NO_IMPL
   NS_IMETHOD GetOriginAttributes(JS::MutableHandleValue) NO_IMPL
   NS_IMETHOD GetUseRemoteTabs(bool*) NO_IMPL
   NS_IMETHOD SetRemoteTabs(bool) NO_IMPL
 #undef NO_IMPL
 
 protected:
   ~FakeChannel() {}
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -89,20 +89,20 @@ nsIContentParent::CanOpenBrowser(const I
     }
 
     auto opener = TabParent::GetFrom(popupContext.opener().get_PBrowserParent());
     if (!opener) {
       ASSERT_UNLESS_FUZZING("Got null opener from child; aborting AllocPBrowserParent.");
       return false;
     }
 
-    // Popup windows of isBrowser frames must be isBrowser if the parent
-    // isBrowser.  Allocating a !isBrowser frame with same app ID would allow
-    // the content to access data it's not supposed to.
-    if (!popupContext.isBrowserElement() && opener->IsBrowserElement()) {
+    // Popup windows of isMozBrowserElement frames must be isMozBrowserElement if
+    // the parent isMozBrowserElement.  Allocating a !isMozBrowserElement frame with
+    // same app ID would allow the content to access data it's not supposed to.
+    if (!popupContext.isMozBrowserElement() && opener->IsMozBrowserElement()) {
       ASSERT_UNLESS_FUZZING("Child trying to escalate privileges!  Aborting AllocPBrowserParent.");
       return false;
     }
   }
 
   MaybeInvalidTabContext tc(aContext);
   if (!tc.IsValid()) {
     NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext.  (%s)  "
--- a/dom/media/TextTrack.cpp
+++ b/dom/media/TextTrack.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 et tw=78: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/dom/TextTrack.h"
 #include "mozilla/dom/TextTrackBinding.h"
 #include "mozilla/dom/TextTrackList.h"
 #include "mozilla/dom/TextTrackCue.h"
 #include "mozilla/dom/TextTrackCueList.h"
 #include "mozilla/dom/TextTrackRegion.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/HTMLTrackElement.h"
@@ -143,41 +144,56 @@ TextTrack::UpdateActiveCueList()
     return;
   }
 
   HTMLMediaElement* mediaElement = mTextTrackList->GetMediaElement();
   if (!mediaElement) {
     return;
   }
 
+  // Flag that indicates whether or not this call of UpdateActiveCueList has
+  // changed the activeCueList.
+  bool hasChanged = false;
+
   // If we are dirty, i.e. an event happened that may cause the sorted mCueList
   // to have changed like a seek or an insert for a cue, than we need to rebuild
   // the active cue list from scratch.
   if (mDirty) {
     mCuePos = 0;
     mDirty = false;
     mActiveCueList->RemoveAll();
   }
 
   double playbackTime = mediaElement->CurrentTime();
   // Remove all the cues from the active cue list whose end times now occur
   // earlier then the current playback time.
   for (uint32_t i = mActiveCueList->Length(); i > 0; i--) {
     if ((*mActiveCueList)[i - 1]->EndTime() < playbackTime) {
       mActiveCueList->RemoveCueAt(i - 1);
+      hasChanged = true;
     }
   }
   // Add all the cues, starting from the position of the last cue that was
   // added, that have valid start and end times for the current playback time.
   // We can stop iterating safely once we encounter a cue that does not have
   // a valid start time as the cue list is sorted.
   for (; mCuePos < mCueList->Length() &&
          (*mCueList)[mCuePos]->StartTime() <= playbackTime; mCuePos++) {
     if ((*mCueList)[mCuePos]->EndTime() >= playbackTime) {
       mActiveCueList->AddCue(*(*mCueList)[mCuePos]);
+      hasChanged = true;
+      }
+    }
+
+    if (hasChanged) {
+      RefPtr<AsyncEventDispatcher> asyncDispatcher =
+        new AsyncEventDispatcher(this, NS_LITERAL_STRING("cuechange"), false);
+      asyncDispatcher->PostDOMEvent();
+      if (mTrackElement) {
+        mTrackElement->DispatchTrackRunnable(NS_LITERAL_STRING("cuechange"));
     }
   }
 }
 
 TextTrackCueList*
 TextTrack::GetActiveCues() {
   if (mMode != TextTrackMode::Disabled) {
     UpdateActiveCueList();
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -572,16 +572,22 @@ MediaKeySystemAccess::GetSupportedConfig
 
 
 /* static */
 void
 MediaKeySystemAccess::NotifyObservers(nsPIDOMWindowInner* aWindow,
                                       const nsAString& aKeySystem,
                                       MediaKeySystemStatus aStatus)
 {
+  if (aStatus == MediaKeySystemStatus::Cdm_not_supported) {
+    // Ignore, since there's nothing the user can do to rectify this, and we
+    // don't want the prompt to confuse them.
+    // TODO: Remove places that call with this entirely.
+    return;
+  }
   RequestMediaKeySystemAccessNotification data;
   data.mKeySystem = aKeySystem;
   data.mStatus = aStatus;
   nsAutoString json;
   data.ToJSON(json);
   EME_LOG("MediaKeySystemAccess::NotifyObservers() %s", NS_ConvertUTF16toUTF8(json).get());
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (obs) {
--- a/dom/media/platforms/wmf/WMFDecoderModule.cpp
+++ b/dom/media/platforms/wmf/WMFDecoderModule.cpp
@@ -12,16 +12,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Services.h"
 #include "WMFMediaDataDecoder.h"
 #include "nsIWindowsRegKey.h"
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIGfxInfo.h"
+#include "nsWindowsHelpers.h"
 #include "GfxDriverInfo.h"
 #include "gfxWindowsPlatform.h"
 #include "MediaInfo.h"
 #include "prsystem.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/StaticMutex.h"
 
 namespace mozilla {
@@ -158,19 +159,55 @@ CanCreateWMFDecoder()
   StaticMutexAutoLock lock(sMutex);
   static Maybe<bool> result;
   if (result.isNothing()) {
     result.emplace(CanCreateMFTDecoder(aGuid));
   }
   return result.value();
 }
 
+static bool
+IsH264DecoderBlacklisted()
+{
+#ifdef _WIN64
+  WCHAR systemPath[MAX_PATH + 1];
+  if (!ConstructSystem32Path(L"msmpeg2vdec.dll", systemPath, MAX_PATH + 1)) {
+    // Cannot build path -> Assume it's not the blacklisted DLL.
+    return false;
+  }
+
+  DWORD zero;
+  DWORD infoSize = GetFileVersionInfoSizeW(systemPath, &zero);
+  if (infoSize == 0) {
+    // Can't get file info -> Assume we don't have the blacklisted DLL.
+    return false;
+  }
+  auto infoData = MakeUnique<unsigned char[]>(infoSize);
+  VS_FIXEDFILEINFO *vInfo;
+  UINT vInfoLen;
+  if (GetFileVersionInfoW(systemPath, 0, infoSize, infoData.get()) &&
+    VerQueryValueW(infoData.get(), L"\\", (LPVOID*)&vInfo, &vInfoLen))
+  {
+    if ((vInfo->dwFileVersionMS == ((12u << 16) | 0u))
+        && ((vInfo->dwFileVersionLS == ((9200u << 16) | 16426u))
+            || (vInfo->dwFileVersionLS == ((9200u << 16) | 17037u)))) {
+      // 12.0.9200.16426 & .17037 are blacklisted on Win64, see bug 1242343.
+      return true;
+    }
+  }
+#endif // _WIN64
+  return false;
+}
+
 /* static */ bool
 WMFDecoderModule::HasH264()
 {
+  if (IsH264DecoderBlacklisted()) {
+    return false;
+  }
   return CanCreateWMFDecoder<CLSID_CMSH264DecoderMFT>();
 }
 
 /* static */ bool
 WMFDecoderModule::HasAAC()
 {
   return CanCreateWMFDecoder<CLSID_CMSAACDecMFT>();
 }
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -483,16 +483,17 @@ support-files =
   seek.ogv
   seek.ogv^headers^
   seek.webm
   seek.webm^headers^
   seek.yuv
   seek_support.js
   seekLies.sjs
   seek_with_sound.ogg^headers^
+  sequential.vtt
   short-cenc.mp4
   sine.webm
   sine.webm^headers^
   short.mp4
   short.mp4^headers^
   short-video.ogv
   short-video.ogv^headers^
   small-shot-mp3.mp4
@@ -836,16 +837,17 @@ tags=msg capturestream
 [test_streams_individual_pause.html]
 tags=msg
 [test_streams_srcObject.html]
 tags=msg capturestream
 [test_streams_tracks.html]
 tags=msg capturestream
 [test_texttrack.html]
 [test_texttrackcue.html]
+[test_texttrackevents_video.html]
 [test_texttracklist.html]
 [test_texttrackregion.html]
 [test_timeupdate_small_files.html]
 skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
 [test_trackelementevent.html]
 [test_trackevent.html]
 [test_unseekable.html]
 skip-if = toolkit == 'gonk' || (toolkit == 'android' && processor == 'x86') #x86 only and bug 1128845 on gonk
new file mode 100644
--- /dev/null
+++ b/dom/media/test/sequential.vtt
@@ -0,0 +1,10 @@
+WEBVTT
+
+00:01.000 --> 00:02.000
+This
+
+00:03.000 --> 00:04.000
+Is
+
+00:05.000 --> 00:06.000
+A Test
--- a/dom/media/test/test_eme_request_notifications.html
+++ b/dom/media/test/test_eme_request_notifications.html
@@ -70,21 +70,16 @@ var tests = [
   },
   {
     keySystem: CLEARKEY_ID,
     shouldPass: false,
     expectedStatus: 'cdm-disabled',
     prefs: [["media.eme.enabled", true], ["media.eme.clearkey.enabled", false]]
   },
   {
-    keySystem: 'unsupported-keysystem',
-    shouldPass: false,
-    expectedStatus: 'cdm-not-supported'
-  },
-  {
     keySystem: CLEARKEY_ID + '.10000' , // A stupendously high min CDM version, presumably not installed.
     shouldPass: false,
     expectedStatus: 'cdm-insufficient-version',
     prefs: [["media.eme.enabled", true], ["media.eme.clearkey.enabled", true]]
   },
   {
     keySystem: CLEARKEY_ID,
     shouldPass: true,
new file mode 100644
--- /dev/null
+++ b/dom/media/test/test_texttrackevents_video.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Tests for TextTrack DOM Events</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true]]},
+  function() {
+    var video = document.createElement("video");
+    video.src = "vp9cake.webm";
+    video.preload = "auto";
+    video.controls = true;
+    var trackElement = document.createElement("track");
+    trackElement.src = "sequential.vtt";
+    trackElement.kind = "subtitles";
+    trackElement.default = true;
+    document.getElementById("content").appendChild(video);
+    video.appendChild(trackElement);
+
+    var trackElementCueChangeCount = 0;
+    var trackCueChangeCount = 0;
+
+    video.addEventListener("loadedmetadata", function run_tests() {
+      // Re-queue run_tests() at the end of the event loop until the track
+      // element has loaded its data.
+      if (trackElement.readyState == 1) {
+        return setTimeout(run_tests, 0);
+      }
+      is(trackElement.readyState, 2, "Track::ReadyState should be set to LOADED.");
+      ok('oncuechange' in trackElement.track, "Track::OnCueChange should exist.");
+
+      trackElement.track.oncuechange = function() {
+        ++trackElementCueChangeCount;
+      };
+
+      trackElement.addEventListener("cuechange", function() {
+        ++trackCueChangeCount;
+      });
+
+      video.play();
+    });
+
+    video.addEventListener('ended', function() {
+      // Should be fired 6 times, as there are 3 cues, with a change event
+      // for when it is activated/deactivated (6 events total)
+      is(trackElementCueChangeCount, 6, "TrackElement should fire cue change 6 times.");
+      is(trackCueChangeCount, 6, "TrackElement.track should fire cue change 6 times.");
+      SimpleTest.finish()
+    })
+  }
+);
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/tests/mochitest/test_peerConnection_scaleResolution.html
+++ b/dom/media/tests/mochitest/test_peerConnection_scaleResolution.html
@@ -7,63 +7,77 @@
 <pre id="test">
 <script type="application/javascript;version=1.8">
   createHTML({
     bug: "1244913",
     title: "Scale resolution down on a PeerConnection",
     visible: true
   });
 
-  var pc1 = new RTCPeerConnection();
-  var pc2 = new RTCPeerConnection();
-
-  var add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed);
-  pc1.onicecandidate = e => add(pc2, e.candidate, generateErrorCallback());
-  pc2.onicecandidate = e => add(pc1, e.candidate, generateErrorCallback());
-
-  pc1.onnegotiationneeded = e =>
-    pc1.createOffer().then(d => pc1.setLocalDescription(d))
-    .then(() => pc2.setRemoteDescription(pc1.localDescription))
-    .then(() => pc2.createAnswer()).then(d => pc2.setLocalDescription(d))
-    .then(() => pc1.setRemoteDescription(pc2.localDescription))
-    .catch(generateErrorCallback());
-
   var mustRejectWith = (msg, reason, f) =>
     f().then(() => ok(false, msg),
              e => is(e.name, reason, msg));
-  var v1, v2;
+
+  var removeVP8 = d => (d.sdp = d.sdp.replace("a=rtpmap:120 VP8/90000\r\n", ""), d);
+
+  function testScale(codec) {
+    var pc1 = new RTCPeerConnection();
+    var pc2 = new RTCPeerConnection();
+
+    var add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed);
+    pc1.onicecandidate = e => add(pc2, e.candidate, generateErrorCallback());
+    pc2.onicecandidate = e => add(pc1, e.candidate, generateErrorCallback());
+
+    info("testing scaling with " + codec);
 
-  runNetworkTest(function() {
-    v1 = createMediaElement('video', 'v1');
-    v2 = createMediaElement('video', 'v2');
+    pc1.onnegotiationneeded = e =>
+      pc1.createOffer()
+      .then(d => pc1.setLocalDescription(codec == "VP8" ? d : removeVP8(d)))
+      .then(() => pc2.setRemoteDescription(pc1.localDescription))
+      .then(() => pc2.createAnswer()).then(d => pc2.setLocalDescription(d))
+      .then(() => pc1.setRemoteDescription(pc2.localDescription))
+      .catch(generateErrorCallback());
 
-    is(v2.currentTime, 0, "v2.currentTime is zero at outset");
+    return navigator.mediaDevices.getUserMedia({ video: true })
+    .then(stream => {
+      var v1 = createMediaElement('video', 'v1');
+      var v2 = createMediaElement('video', 'v2');
 
-    navigator.mediaDevices.getUserMedia({ video: true })
-    .then(stream => {
+      is(v2.currentTime, 0, "v2.currentTime is zero at outset");
+
       v1.srcObject = stream;
       var sender = pc1.addTrack(stream.getVideoTracks()[0], stream);
 
       return mustRejectWith("Invalid scaleResolutionDownBy must reject", "RangeError",
                             () => sender.setParameters({ encodings:
                                                        [{ scaleResolutionDownBy: 0.5 } ] }))
       .then(() => sender.setParameters({ encodings: [{ maxBitrate: 60000,
-                                                     scaleResolutionDownBy: 2 }] }))
+                                                       scaleResolutionDownBy: 2 }] }))
+      .then(() => new Promise(resolve => pc2.ontrack = e => resolve(e)))
+      .then(e => v2.srcObject = e.streams[0])
+      .then(() => new Promise(resolve => v2.onloadedmetadata = resolve))
+      .then(() => waitUntil(() => v2.currentTime > 0 && v2.srcObject.currentTime > 0))
+      .then(() => ok(v2.currentTime > 0, "v2.currentTime is moving (" + v2.currentTime + ")"))
+      .then(() => wait(3000)) // TODO: Bug 1248154
+      .then(() => {
+        ok(v1.videoWidth > 0, "source width is positive");
+        ok(v1.videoHeight > 0, "source height is positive");
+        if (v2.videoWidth == 640 && v2.videoHeight == 480) { // TODO: Bug 1248154
+          info("Skipping test due to Bug 1248154");
+        } else {
+          is(v2.videoWidth, v1.videoWidth / 2, "sink is half the width of source");
+          is(v2.videoHeight, v1.videoHeight / 2, "sink is half the height of source");
+        }
+      })
+      .then(() => {
+        stream.getTracks().forEach(track => track.stop());
+        v1.srcObject = v2.srcObject = null;
+      })
     })
-    .then(() => new Promise(resolve => pc2.ontrack = e => resolve(e)))
-    .then(e => v2.srcObject = e.streams[0])
-    .then(() => new Promise(resolve => v2.onloadedmetadata = resolve))
-    .then(() => waitUntil(() => v2.currentTime > 0 && v2.srcObject.currentTime > 0))
-    .then(() => ok(v2.currentTime > 0, "v2.currentTime is moving (" + v2.currentTime + ")"))
-    .then(() => wait(1000)) // TODO: Bug 1248154
-    .then(() => {
-      ok(v1.videoWidth > 0, "source width is positive");
-      ok(v1.videoHeight > 0, "source height is positive");
-      is(v2.videoWidth, v1.videoWidth / 2, "sink is half the width of source");
-      is(v2.videoHeight, v1.videoHeight / 2, "sink is half the height of source");
-    })
-    .catch(generateErrorCallback())
-    .then(networkTestFinished);
-  });
+    .catch(generateErrorCallback());
+  }
+
+  runNetworkTest(() => testScale("VP8").then(() => testScale("H264"))
+                 .then(networkTestFinished));
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/webaudio/FFTBlock.h
+++ b/dom/media/webaudio/FFTBlock.h
@@ -116,20 +116,17 @@ public:
       AudioBufferCopyWithScale(mOutputBuffer.Elements()->f, 2.0f,
                                aDataOut, mFFTSize);
       aDataOut[1] = 2.0f * mOutputBuffer[mFFTSize/2].r; // Packed Nyquist
       av_rdft_calc(mAvIRDFT, aDataOut);
     }
 #else
 #ifdef BUILD_ARM_NEON
     if (mozilla::supports_neon()) {
-      omxSP_FFTInv_CCSToR_F32_Sfs(mOutputBuffer.Elements()->f, aDataOut, mOmxIFFT);
-      // There is no function that computes de inverse FFT without scaling, so
-      // we have to scale back up here. Bug 1158741.
-      AudioBufferInPlaceScale(aDataOut, mFFTSize, mFFTSize);
+      omxSP_FFTInv_CCSToR_F32_Sfs_unscaled(mOutputBuffer.Elements()->f, aDataOut, mOmxIFFT);
     } else
 #endif
     {
       kiss_fftri(mKissIFFT, &(mOutputBuffer.Elements()->c), aDataOut);
     }
 #endif
   }
 
--- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp
@@ -2,16 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaEngineTabVideoSource.h"
 
 #include "mozilla/gfx/2D.h"
 #include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtrExtensions.h"
 #include "nsGlobalWindow.h"
 #include "nsIDOMClientRect.h"
 #include "nsIDocShell.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "gfxContext.h"
 #include "gfx2DGlue.h"
 #include "ImageContainer.h"
@@ -242,17 +243,17 @@ MediaEngineTabVideoSource::Draw() {
     }
   }
 
   gfxImageFormat format = SurfaceFormat::X8R8G8B8_UINT32;
   uint32_t stride = gfxASurface::FormatStrideForWidth(format, size.width);
 
   if (mDataSize < static_cast<size_t>(stride * size.height)) {
     mDataSize = stride * size.height;
-    mData = static_cast<unsigned char*>(malloc(mDataSize));
+    mData = MakeUniqueFallible<unsigned char[]>(mDataSize);
   }
   if (!mData) {
     return;
   }
 
   nsCOMPtr<nsIPresShell> presShell;
   {
     RefPtr<nsPresContext> presContext;
@@ -273,17 +274,17 @@ MediaEngineTabVideoSource::Draw() {
   nsRect r(nsPresContext::CSSPixelsToAppUnits((float)mViewportOffsetX),
            nsPresContext::CSSPixelsToAppUnits((float)mViewportOffsetY),
            nsPresContext::CSSPixelsToAppUnits((float)mViewportWidth),
            nsPresContext::CSSPixelsToAppUnits((float)mViewportHeight));
 
   RefPtr<layers::ImageContainer> container = layers::LayerManager::CreateImageContainer();
   RefPtr<DrawTarget> dt =
     Factory::CreateDrawTargetForData(BackendType::CAIRO,
-                                     mData.rwget(),
+                                     mData.get(),
                                      size,
                                      stride,
                                      SurfaceFormat::B8G8R8X8);
   if (!dt) {
     return;
   }
   RefPtr<gfxContext> context = new gfxContext(dt);
   context->SetMatrix(context->CurrentMatrix().Scale((((float) size.width)/mViewportWidth),
--- a/dom/media/webrtc/MediaEngineTabVideoSource.h
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.h
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIDOMEventListener.h"
 #include "MediaEngine.h"
 #include "ImageContainer.h"
 #include "nsITimer.h"
 #include "mozilla/Monitor.h"
+#include "mozilla/UniquePtr.h"
 #include "nsITabSource.h"
 
 namespace mozilla {
 
 class MediaEngineTabVideoSource : public MediaEngineVideoSource, nsIDOMEventListener, nsITimerCallback {
   public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIDOMEVENTLISTENER
@@ -80,17 +81,17 @@ private:
     int32_t mBufHeightMax;
     int64_t mWindowId;
     bool mScrollWithPage;
     int32_t mViewportOffsetX;
     int32_t mViewportOffsetY;
     int32_t mViewportWidth;
     int32_t mViewportHeight;
     int32_t mTimePerFrame;
-    ScopedFreePtr<unsigned char> mData;
+    UniquePtr<unsigned char[]> mData;
     size_t mDataSize;
     nsCOMPtr<nsPIDOMWindowOuter> mWindow;
     RefPtr<layers::SourceSurfaceImage> mImage;
     nsCOMPtr<nsITimer> mTimer;
     Monitor mMonitor;
     nsCOMPtr<nsITabSource> mTabSource;
   };
 }
--- a/dom/messages/SystemMessageManager.js
+++ b/dom/messages/SystemMessageManager.js
@@ -327,17 +327,27 @@ SystemMessageManager.prototype = {
   // nsIDOMGlobalPropertyInitializer implementation.
   init: function(aWindow) {
     debug("init");
     this.initDOMRequestHelper(aWindow,
                               ["SystemMessageManager:Message",
                                "SystemMessageManager:GetPendingMessages:Return"]);
 
     let principal = aWindow.document.nodePrincipal;
-    this._isInBrowserElement = principal.isInBrowserElement;
+
+    // After bug 1238160, the principal no longer knows how to answer "is this a
+    // browser element", which is really what this code path wants. Currently,
+    // desktop is the only platform where we intend to disable isolation on a
+    // browser frame, so non-desktop should be able to assume that
+    // inIsolatedMozBrowser is true for all mozbrowser frames.  Additionally,
+    // this system message API is disabled on desktop behind the pref
+    // "dom.sysmsg.enabled".   We use a release assertion in
+    // nsFrameLoader::OwnerIsIsolatedMozBrowserFrame so that platforms with apps
+    // can assume inIsolatedMozBrowser is true for all mozbrowser frames.
+    this._isInBrowserElement = principal.isInIsolatedMozBrowserElement;
     this._pageURL = principal.URI.spec;
 
     let appsService = Cc["@mozilla.org/AppsService;1"]
                         .getService(Ci.nsIAppsService);
     this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
 
     // Two cases are valid to register the manifest URL for the current process:
     // 1. This is asked by a child process (parent process must be ready).
--- a/dom/network/NetworkStatsService.jsm
+++ b/dom/network/NetworkStatsService.jsm
@@ -733,19 +733,19 @@ this.NetworkStatsService = {
         aCallback(true, "OK");
       }
     });
   },
 
   /*
    * Function responsible for receiving stats which are not from netd.
    */
-  saveStats: function saveStats(aAppId, aIsInBrowser, aServiceType, aNetworkInfo,
-                                aTimeStamp, aRxBytes, aTxBytes, aIsAccumulative,
-                                aCallback) {
+  saveStats: function saveStats(aAppId, aIsInIsolatedMozBrowser, aServiceType,
+                                aNetworkInfo, aTimeStamp, aRxBytes, aTxBytes,
+                                aIsAccumulative, aCallback) {
     let netId = this.convertNetworkInfo(aNetworkInfo);
     if (!netId) {
       if (aCallback) {
         aCallback(false, "Invalid network type");
       }
       return;
     }
 
@@ -756,17 +756,17 @@ this.NetworkStatsService = {
     // b. Both |aAppId| is zero and |aServiceType| is empty.
     if (!this._networks[netId] || (aAppId && aServiceType) ||
         (!aAppId && !aServiceType)) {
       debug("Invalid network interface, appId or serviceType");
       return;
     }
 
     let stats = { appId:          aAppId,
-                  isInBrowser:    aIsInBrowser,
+                  isInBrowser:    aIsInIsolatedMozBrowser,
                   serviceType:    aServiceType,
                   networkId:      this._networks[netId].network.id,
                   networkType:    this._networks[netId].network.type,
                   date:           new Date(aTimeStamp),
                   rxBytes:        aRxBytes,
                   txBytes:        aTxBytes,
                   isAccumulative: aIsAccumulative };
 
--- a/dom/network/NetworkStatsServiceProxy.js
+++ b/dom/network/NetworkStatsServiceProxy.js
@@ -24,37 +24,37 @@ function NetworkStatsServiceProxy() {
   }
 }
 
 NetworkStatsServiceProxy.prototype = {
   /*
    * Function called in the protocol layer (HTTP, FTP, WebSocket ...etc)
    * to pass the per-app stats to NetworkStatsService.
    */
-  saveAppStats: function saveAppStats(aAppId, aIsInBrowser, aNetworkInfo, aTimeStamp,
+  saveAppStats: function saveAppStats(aAppId, aIsInIsolatedMozBrowser, aNetworkInfo, aTimeStamp,
                                       aRxBytes, aTxBytes, aIsAccumulative,
                                       aCallback) {
     if (!aNetworkInfo) {
       if (DEBUG) {
         debug("|aNetworkInfo| is not specified. Failed to save stats. Returning.");
       }
       return;
     }
 
     if (DEBUG) {
-      debug("saveAppStats: " + aAppId + " " + aIsInBrowser + " " +
+      debug("saveAppStats: " + aAppId + " " + aIsInIsolatedMozBrowser + " " +
             aNetworkInfo.type + " " + aTimeStamp + " " +
             aRxBytes + " " + aTxBytes + " " + aIsAccumulative);
     }
 
     if (aCallback) {
       aCallback = aCallback.notify;
     }
 
-    NetworkStatsService.saveStats(aAppId, aIsInBrowser, "", aNetworkInfo,
+    NetworkStatsService.saveStats(aAppId, aIsInIsolatedMozBrowser, "", aNetworkInfo,
                                   aTimeStamp, aRxBytes, aTxBytes,
                                   aIsAccumulative, aCallback);
   },
 
   /*
    * Function called in the points of different system services
    * to pass the per-service stats to NetworkStatsService.
    */
--- a/dom/network/TCPServerSocket.cpp
+++ b/dom/network/TCPServerSocket.cpp
@@ -143,17 +143,17 @@ TCPServerSocket::FireEvent(const nsAStri
 
 NS_IMETHODIMP
 TCPServerSocket::OnSocketAccepted(nsIServerSocket* aServer, nsISocketTransport* aTransport)
 {
   nsCOMPtr<nsIGlobalObject> global = GetOwnerGlobal();
   RefPtr<TCPSocket> socket = TCPSocket::CreateAcceptedSocket(global, aTransport, mUseArrayBuffers);
   if (mServerBridgeParent) {
     socket->SetAppIdAndBrowser(mServerBridgeParent->GetAppId(),
-                               mServerBridgeParent->GetInBrowser());
+                               mServerBridgeParent->GetInIsolatedMozBrowser());
   }
   FireEvent(NS_LITERAL_STRING("connect"), socket);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TCPServerSocket::OnStopListening(nsIServerSocket* aServer, nsresult aStatus)
 {
--- a/dom/network/TCPServerSocketParent.cpp
+++ b/dom/network/TCPServerSocketParent.cpp
@@ -70,22 +70,22 @@ TCPServerSocketParent::GetAppId()
     TabParent *tab = TabParent::GetFrom(browser);
     return tab->OwnAppId();
   } else {
     return nsIScriptSecurityManager::UNKNOWN_APP_ID;
   }
 }
 
 bool
-TCPServerSocketParent::GetInBrowser()
+TCPServerSocketParent::GetInIsolatedMozBrowser()
 {
   const PContentParent *content = Manager()->Manager();
   if (PBrowserParent* browser = SingleManagedOrNull(content->ManagedPBrowserParent())) {
     TabParent *tab = TabParent::GetFrom(browser);
-    return tab->IsBrowserElement();
+    return tab->IsIsolatedMozBrowserElement();
   } else {
     return false;
   }
 }
 
 nsresult
 TCPServerSocketParent::SendCallbackAccept(TCPSocketParent *socket)
 {
@@ -145,17 +145,17 @@ TCPServerSocketParent::RecvRequestDelete
   mozilla::Unused << Send__delete__(this);
   return true;
 }
 
 void
 TCPServerSocketParent::OnConnect(TCPServerSocketEvent* event)
 {
   RefPtr<TCPSocket> socket = event->Socket();
-  socket->SetAppIdAndBrowser(GetAppId(), GetInBrowser());
+  socket->SetAppIdAndBrowser(GetAppId(), GetInIsolatedMozBrowser());
 
   RefPtr<TCPSocketParent> socketParent = new TCPSocketParent();
   socketParent->SetSocket(socket);
 
   socket->SetSocketBridgeParent(socketParent);
 
   SendCallbackAccept(socketParent);
 }
--- a/dom/network/TCPServerSocketParent.h
+++ b/dom/network/TCPServerSocketParent.h
@@ -30,17 +30,17 @@ public:
                         uint16_t aBacklog, bool aUseArrayBuffers);
 
   void Init();
 
   virtual bool RecvClose() override;
   virtual bool RecvRequestDelete() override;
 
   uint32_t GetAppId();
-  bool GetInBrowser();
+  bool GetInIsolatedMozBrowser();
 
   void AddIPDLReference();
   void ReleaseIPDLReference();
 
   void OnConnect(TCPServerSocketEvent* event);
 
 private:
   ~TCPServerSocketParent();
--- a/dom/network/TCPSocket.cpp
+++ b/dom/network/TCPSocket.cpp
@@ -161,17 +161,17 @@ TCPSocket::TCPSocket(nsIGlobalObject* aG
   , mBufferedAmount(0)
   , mSuspendCount(0)
   , mTrackingNumber(0)
   , mWaitingForStartTLS(false)
 #ifdef MOZ_WIDGET_GONK
   , mTxBytes(0)
   , mRxBytes(0)
   , mAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID)
-  , mInBrowser(false)
+  , mInIsolatedMozBrowser(false)
 #endif
 {
   if (aGlobal) {
     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
     if (window) {
       mInnerWindowID = window->WindowID();
     }
   }
@@ -1095,21 +1095,21 @@ TCPSocket::OnStopRequest(nsIRequest* aRe
 
 void
 TCPSocket::SetSocketBridgeParent(TCPSocketParent* aBridgeParent)
 {
   mSocketBridgeParent = aBridgeParent;
 }
 
 void
-TCPSocket::SetAppIdAndBrowser(uint32_t aAppId, bool aInBrowser)
+TCPSocket::SetAppIdAndBrowser(uint32_t aAppId, bool aInIsolatedMozBrowser)
 {
 #ifdef MOZ_WIDGET_GONK
   mAppId = aAppId;
-  mInBrowser = aInBrowser;
+  mInIsolatedMozBrowser = aInIsolatedMozBrowser;
 #endif
 }
 
 NS_IMETHODIMP
 TCPSocket::UpdateReadyState(uint32_t aReadyState)
 {
   MOZ_ASSERT(mSocketBridgeChild);
   mReadyState = static_cast<TCPReadyState>(aReadyState);
@@ -1150,18 +1150,18 @@ TCPSocket::SaveNetworkStats(bool aEnforc
   }
 
   nsCOMPtr<nsINetworkStatsServiceProxy> nssProxy =
     do_GetService("@mozilla.org/networkstatsServiceProxy;1");
   if (!nssProxy) {
     return;
   }
 
-  nssProxy->SaveAppStats(mAppId, mInBrowser, mActiveNetworkInfo, PR_Now(),
-                         mRxBytes, mTxBytes, false, nullptr);
+  nssProxy->SaveAppStats(mAppId, mInIsolatedMozBrowser, mActiveNetworkInfo,
+                         PR_Now(), mRxBytes, mTxBytes, false, nullptr);
 
   // Reset the counters once the statistics is saved to NetworkStatsServiceProxy.
   mTxBytes = mRxBytes = 0;
 }
 #endif
 
 NS_IMETHODIMP
 TCPSocket::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
--- a/dom/network/TCPSocket.h
+++ b/dom/network/TCPSocket.h
@@ -237,18 +237,18 @@ private:
 
 #ifdef MOZ_WIDGET_GONK
   // Number of bytes sent.
   uint32_t mTxBytes;
   // Number of bytes received.
   uint32_t mRxBytes;
   // The app that owns this socket.
   uint32_t mAppId;
-  // Was this socket created inside of a mozbrowser frame?
-  bool mInBrowser;
+  // Was this socket created inside of an isolated browser frame?
+  bool mInIsolatedMozBrowser;
   // The name of the active network used by this socket.
   nsCOMPtr<nsINetworkInfo> mActiveNetworkInfo;
 #endif
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/network/TCPSocketParent.cpp
+++ b/dom/network/TCPSocketParent.cpp
@@ -72,22 +72,22 @@ TCPSocketParent::GetAppId()
     TabParent *tab = TabParent::GetFrom(browser);
     return tab->OwnAppId();
   } else {
     return nsIScriptSecurityManager::UNKNOWN_APP_ID;
   }
 };
 
 bool
-TCPSocketParent::GetInBrowser()
+TCPSocketParent::GetInIsolatedMozBrowser()
 {
   const PContentParent *content = Manager()->Manager();
   if (PBrowserParent* browser = SingleManagedOrNull(content->ManagedPBrowserParent())) {
     TabParent *tab = TabParent::GetFrom(browser);
-    return tab->IsBrowserElement();
+    return tab->IsIsolatedMozBrowserElement();
   } else {
     return false;
   }
 }
 
 nsresult
 TCPSocketParent::OfflineNotification(nsISupports *aSubject)
 {
@@ -150,26 +150,26 @@ TCPSocketParent::RecvOpen(const nsString
   if (net::UsingNeckoIPCSecurity() &&
       !AssertAppProcessPermission(Manager()->Manager(), "tcp-socket")) {
     FireInteralError(this, __LINE__);
     return true;
   }
 
   // Obtain App ID
   uint32_t appId = GetAppId();
-  bool     inBrowser = GetInBrowser();
+  bool     inIsolatedMozBrowser = GetInIsolatedMozBrowser();
 
   if (NS_IsAppOffline(appId)) {
     NS_ERROR("Can't open socket because app is offline");
     FireInteralError(this, __LINE__);
     return true;
   }
 
   mSocket = new TCPSocket(nullptr, aHost, aPort, aUseSSL, aUseArrayBuffers);
-  mSocket->SetAppIdAndBrowser(appId, inBrowser);
+  mSocket->SetAppIdAndBrowser(appId, inIsolatedMozBrowser);
   mSocket->SetSocketBridgeParent(this);
   NS_ENSURE_SUCCESS(mSocket->Init(), true);
   return true;
 }
 
 bool
 TCPSocketParent::RecvOpenBind(const nsCString& aRemoteHost,
                               const uint16_t& aRemotePort,
@@ -216,28 +216,28 @@ TCPSocketParent::RecvOpenBind(const nsCS
   rv = socketTransport->Bind(&addr);
   if (NS_FAILED(rv)) {
     FireInteralError(this, __LINE__);
     return true;
   }
 
   // Obtain App ID
   uint32_t appId = nsIScriptSecurityManager::NO_APP_ID;
-  bool     inBrowser = false;
+  bool     inIsolatedMozBrowser = false;
   const PContentParent *content = Manager()->Manager();
   if (PBrowserParent* browser = SingleManagedOrNull(content->ManagedPBrowserParent())) {
     // appId's are for B2G only currently, where managees.Count() == 1
     // This is not guaranteed currently in Desktop, so skip this there.
     TabParent *tab = TabParent::GetFrom(browser);
     appId = tab->OwnAppId();
-    inBrowser = tab->IsBrowserElement();
+    inIsolatedMozBrowser = tab->IsIsolatedMozBrowserElement();
   }
 
   mSocket = new TCPSocket(nullptr, NS_ConvertUTF8toUTF16(aRemoteHost), aRemotePort, aUseSSL, aUseArrayBuffers);
-  mSocket->SetAppIdAndBrowser(appId, inBrowser);
+  mSocket->SetAppIdAndBrowser(appId, inIsolatedMozBrowser);
   mSocket->SetSocketBridgeParent(this);
   rv = mSocket->InitWithUnconnectedTransport(socketTransport);
   NS_ENSURE_SUCCESS(rv, true);
   return true;
 }
 
 bool
 TCPSocketParent::RecvStartTLS()
--- a/dom/network/TCPSocketParent.h
+++ b/dom/network/TCPSocketParent.h
@@ -63,17 +63,17 @@ public:
   virtual bool RecvSuspend() override;
   virtual bool RecvResume() override;
   virtual bool RecvClose() override;
   virtual bool RecvData(const SendableData& aData,
                         const uint32_t& aTrackingNumber) override;
   virtual bool RecvRequestDelete() override;
   virtual nsresult OfflineNotification(nsISupports *) override;
   virtual uint32_t GetAppId() override;
-  bool GetInBrowser();
+  bool GetInIsolatedMozBrowser();
 
   void FireErrorEvent(const nsAString& aName, const nsAString& aType, TCPReadyState aReadyState);
   void FireEvent(const nsAString& aType, TCPReadyState aReadyState);
   void FireArrayBufferDataEvent(nsTArray<uint8_t>& aBuffer, TCPReadyState aReadyState);
   void FireStringDataEvent(const nsACString& aData, TCPReadyState aReadyState);
 
   void SetSocket(TCPSocket *socket);
   nsresult GetHost(nsAString& aHost);
--- a/dom/network/interfaces/nsINetworkStatsServiceProxy.idl
+++ b/dom/network/interfaces/nsINetworkStatsServiceProxy.idl
@@ -17,26 +17,31 @@ interface nsINetworkStatsServiceProxyCal
 };
 
 [scriptable, uuid(f4f3e901-e102-499d-9d37-dc9951f52df7)]
 interface nsINetworkStatsServiceProxy : nsISupports
 {
   /*
    * An interface used to record per-app traffic data.
    * @param aAppId app id
-   * @param aIsInBrowser true if the iframe element is mozbrowser
+   * @param aIsInIsolatedMozBrowser
+   *        true if the frame is an isolated mozbrowser element. <iframe
+   *        mozbrowser mozapp> and <xul:browser> are not considered to be
+   *        mozbrowser elements.  <iframe mozbrowser noisolation> does not count
+   *        as isolated since isolation is disabled.  Isolation can only be
+   *        disabled if the containing document is chrome.
    * @param aNetworkInterface network
    * @param aTimeStamp time stamp
    * @param aRxBytes received data amount
    * @param aTxBytes transmitted data amount
    * @param aIsAccumulative is stats accumulative
    * @param aCallback an optional callback
    */
   void saveAppStats(in unsigned long aAppId,
-                    in boolean aIsInBrowser,
+                    in boolean aIsInIsolatedMozBrowser,
                     in nsINetworkInfo aNetworkInfo,
                     in unsigned long long aTimeStamp,
                     in unsigned long long aRxBytes,
                     in unsigned long long aTxBytes,
                     in boolean aIsAccumulative,
          [optional] in nsINetworkStatsServiceProxyCallback aCallback);
 
   /*
--- a/dom/payment/Payment.jsm
+++ b/dom/payment/Payment.jsm
@@ -231,17 +231,17 @@ var PaymentManager =  {
         };
 
 #ifdef MOZ_B2G
         // Let this payment provider access the firefox-accounts API when
         // it's loaded in the trusted UI.
         if (systemAppId != Ci.nsIScriptSecurityManager.NO_APP_ID) {
           this.LOG("Granting firefox-accounts permission to " + provider.uri);
           let uri = Services.io.newURI(provider.uri, null, null);
-          let attrs = {appId: systemAppId, inBrowser: true};
+          let attrs = {appId: systemAppId, inIsolatedMozBrowser: true};
           let principal =
             Services.scriptSecurityManager.createCodebasePrincipal(uri, attrs);
 
           Services.perms.addFromPrincipal(principal, "firefox-accounts",
                                           Ci.nsIPermissionManager.ALLOW_ACTION,
                                           Ci.nsIPermissionManager.EXPIRE_SESSION);
         }
 #endif
--- a/dom/permission/PermissionSettings.js
+++ b/dom/permission/PermissionSettings.js
@@ -37,17 +37,17 @@ PermissionSettings.prototype = {
   get: function get(aPermName, aManifestURL, aOrigin, aBrowserFlag) {
     // TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.js
     debug("Get called with: " + aPermName + ", " + aManifestURL + ", " + aOrigin + ", " + aBrowserFlag);
     let uri = Services.io.newURI(aOrigin, null, null);
     let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
     let principal =
       Services.scriptSecurityManager.createCodebasePrincipal(uri,
                                                              {appId: appID,
-                                                              inBrowser: aBrowserFlag});
+                                                              inIsolatedMozBrowser: aBrowserFlag});
     let result = Services.perms.testExactPermanentPermission(principal, aPermName);
 
     switch (result)
     {
       case Ci.nsIPermissionManager.UNKNOWN_ACTION:
         return "unknown";
       case Ci.nsIPermissionManager.ALLOW_ACTION:
         return "allow";
@@ -63,17 +63,17 @@ PermissionSettings.prototype = {
 
   isExplicit: function isExplicit(aPermName, aManifestURL, aOrigin,
                                   aBrowserFlag) {
     // TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.js
     debug("isExplicit: " + aPermName + ", " + aManifestURL + ", " + aOrigin);
     let uri = Services.io.newURI(aOrigin, null, null);
     let app = appsService.getAppByManifestURL(aManifestURL);
     let principal = Services.scriptSecurityManager
-      .createCodebasePrincipal(uri, {appId: app.localId, inBrowser: aBrowserFlag});
+      .createCodebasePrincipal(uri, {appId: app.localId, inIsolatedMozBrowser: aBrowserFlag});
 
     return isExplicitInPermissionsTable(aPermName,
                                         principal.appStatus);
   },
 
   set: function set(aPermName, aPermValue, aManifestURL, aOrigin,
                     aBrowserFlag) {
     debug("Set called with: " + aPermName + ", " + aManifestURL + ", " +
@@ -104,17 +104,17 @@ PermissionSettings.prototype = {
 
   remove: function remove(aPermName, aManifestURL, aOrigin) {
     // TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.js
     let uri = Services.io.newURI(aOrigin, null, null);
     let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
     let principal =
       Services.scriptSecurityManager.createCodebasePrincipal(uri,
                                                              {appId: appID,
-                                                              inBrowser: true});
+                                                              inIsolatedMozBrowser: true});
 
     if (principal.appStatus !== Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED) {
       let errorMsg = "PermissionSettings.js: '" + aOrigin + "'" +
                      " is installed or permission is implicit, cannot remove '" +
                      aPermName + "'.";
       Cu.reportError(errorMsg);
       throw new Components.Exception(errorMsg);
     }
--- a/dom/permission/PermissionSettings.jsm
+++ b/dom/permission/PermissionSettings.jsm
@@ -77,17 +77,17 @@ this.PermissionSettingsModule = {
         Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(aData.origin);
       app = {localId: principal.appId};
     } else {
       app = appsService.getAppByManifestURL(aData.manifestURL);
       let uri = Services.io.newURI(aData.origin, null, null);
       principal =
         Services.scriptSecurityManager.createCodebasePrincipal(uri,
                                                                {appId: app.localId,
-                                                                inBrowser: aData.browserFlag});
+                                                                inIsolatedMozBrowser: aData.browserFlag});
     }
 
     let action;
     switch (aData.value)
     {
       case "unknown":
         action = Ci.nsIPermissionManager.UNKNOWN_ACTION;
         break;
@@ -126,17 +126,17 @@ this.PermissionSettingsModule = {
       principal =
         Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(aOrigin);
     } else {
       let uri = Services.io.newURI(aOrigin, null, null);
       let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
       principal =
         Services.scriptSecurityManager.createCodebasePrincipal(uri,
                                                                {appId: appID,
-                                                                inBrowser: aBrowserFlag});
+                                                                inIsolatedMozBrowser: aBrowserFlag});
     }
     let result = Services.perms.testExactPermissionFromPrincipal(principal, aPermName);
     switch (result)
     {
       case Ci.nsIPermissionManager.UNKNOWN_ACTION:
         return "unknown";
       case Ci.nsIPermissionManager.ALLOW_ACTION:
         return "allow";
--- a/dom/permission/Permissions.cpp
+++ b/dom/permission/Permissions.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/Permissions.h"
 
+#include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/PermissionsBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/Services.h"
 #include "nsIPermissionManager.h"
 #include "PermissionUtils.h"
 
 namespace mozilla {
 namespace dom {
@@ -116,10 +117,88 @@ Permissions::Query(JSContext* aCx,
     promise->MaybeReject(aRv);
   } else {
     MOZ_ASSERT(status);
     promise->MaybeResolve(status);
   }
   return promise.forget();
 }
 
+/* static */ nsresult
+Permissions::RemovePermission(nsIPrincipal* aPrincipal, const char* aPermissionType)
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
+  if (NS_WARN_IF(!permMgr)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return permMgr->RemoveFromPrincipal(aPrincipal, aPermissionType);
+}
+
+already_AddRefed<Promise>
+Permissions::Revoke(JSContext* aCx,
+                    JS::Handle<JSObject*> aPermission,
+                    ErrorResult& aRv)
+{
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
+  if (!global) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
+  PermissionDescriptor permission;
+  JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aPermission));
+  if (NS_WARN_IF(!permission.Init(aCx, value))) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
+  RefPtr<Promise> promise = Promise::Create(global, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIDocument> document = mWindow->GetExtantDoc();
+  if (!document) {
+    promise->MaybeReject(NS_ERROR_UNEXPECTED);
+    return promise.forget();
+  }
+
+  nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
+  if (NS_WARN_IF(!permMgr)) {
+    promise->MaybeReject(NS_ERROR_FAILURE);
+    return promise.forget();
+  }
+
+  const char* permissionType = PermissionNameToType(permission.mName);
+
+  nsresult rv;
+  if (XRE_IsParentProcess()) {
+    rv = RemovePermission(document->NodePrincipal(), permissionType);
+  } else {
+    // Permissions can't be removed from the content process. Send a message
+    // to the parent; `ContentParent::RecvRemovePermission` will call
+    // `RemovePermission`.
+    ContentChild::GetSingleton()->SendRemovePermission(
+      IPC::Principal(document->NodePrincipal()), nsDependentCString(permissionType), &rv);
+  }
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    promise->MaybeReject(rv);
+    return promise.forget();
+  }
+
+  RefPtr<PermissionStatus> status =
+    CreatePermissionStatus(aCx, aPermission, mWindow, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    MOZ_ASSERT(!status);
+    promise->MaybeReject(aRv);
+  } else {
+    MOZ_ASSERT(status);
+    promise->MaybeResolve(status);
+  }
+  return promise.forget();
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/permission/Permissions.h
+++ b/dom/permission/Permissions.h
@@ -33,16 +33,22 @@ public:
 
   JSObject* WrapObject(JSContext* aCx,
                        JS::Handle<JSObject*> aGivenProto) override;
 
   already_AddRefed<Promise> Query(JSContext* aCx,
                                   JS::Handle<JSObject*> aPermission,
                                   ErrorResult& aRv);
 
+  static nsresult RemovePermission(nsIPrincipal* aPrincipal, const char* aPermissionType);
+
+  already_AddRefed<Promise> Revoke(JSContext* aCx,
+                                   JS::Handle<JSObject*> aPermission,
+                                   ErrorResult& aRv);
+
 private:
   ~Permissions();
 
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/permission/moz.build
+++ b/dom/permission/moz.build
@@ -45,8 +45,10 @@ if CONFIG['MOZ_WEBSMS_BACKEND']:
 
 if CONFIG['MOZ_TIME_MANAGER']:
     MOCHITEST_MANIFESTS += ['tests/mochitest-time.ini']
 
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wshadow']
+
+include('/ipc/chromium/chromium-config.mozbuild')
--- a/dom/permission/tests/test_permissions_api.html
+++ b/dom/permission/tests/test_permissions_api.html
@@ -37,27 +37,49 @@ function setPermissions(action) {
   });
   return new Promise((resolve, reject) => {
     SpecialPowers.popPermissions(() => {
       SpecialPowers.pushPermissions(permissions, resolve);
     });
   });
 }
 
+function revokePermissions(action) {
+  return Promise.all(PERMISSIONS.map(x =>
+    navigator.permissions.revoke({ name: x.name }).then(
+      result => is(result.state, "prompt", `correct state for '${x.name}'`),
+      error => ok(false, `revoke should not have rejected for '${x.name}'`))
+  ));
+}
+
+function revokeUnsupportedPermissions() {
+  return Promise.all(UNSUPPORTED_PERMISSIONS.map(name =>
+    navigator.permissions.revoke({ name: name }).then(
+      result => ok(false, `revoke should not have resolved for '${name}'`),
+      error => is(error.name, 'TypeError', `revoke should have thrown TypeError for '${name}'`))
+  ));
+}
+
+function revokeUserVisiblePushPermission() {
+  return navigator.permissions.revoke({ name: 'push', userVisible: true }).then(
+    result => ok(false, `revoke should not have resolved for userVisible push`),
+    error => ok(true, `revoke should have rejected for userVisible push`));
+}
+
 function checkPermissions(state) {
   return Promise.all(PERMISSIONS.map(x => {
     return navigator.permissions.query({ name: x.name }).then(
       result => is(result.state, state, `correct state for '${x.name}'`),
       error => ok(false, `query should not have rejected for '${x.name}'`));
   }));
 }
 
 function checkUnsupportedPermissions() {
   return Promise.all(UNSUPPORTED_PERMISSIONS.map(name => {
-    return navigator.permissions.query({ name }).then(
+    return navigator.permissions.query({ name: name }).then(
       result => ok(false, `query should not have resolved for '${name}'`),
       error => {
         is(error.name, 'TypeError',
            `query should have thrown TypeError for '${name}'`);
       });
   }));
 }
 
@@ -97,29 +119,40 @@ function testStatusOnChange() {
 }
 
 function testInvalidQuery() {
   navigator.permissions.query({ name: 'invalid' }).then(
     result => ok(false, 'invalid query should not have resolved'),
     error => ok(true, 'invalid query should have rejected'));
 }
 
+function testInvalidRevoke() {
+  navigator.permissions.revoke({ name: 'invalid' }).then(
+    result => ok(false, 'invalid revoke should not have resolved'),
+    error => ok(true, 'invalid revoke should have rejected'));
+}
+
 function runTests() {
   checkUnsupportedPermissions()
     .then(checkUserVisiblePushPermission)
     .then(() => setPermissions(UNKNOWN_ACTION))
     .then(() => checkPermissions('prompt'))
     .then(() => setPermissions(PROMPT_ACTION))
     .then(() => checkPermissions('prompt'))
     .then(() => setPermissions(ALLOW_ACTION))
     .then(() => checkPermissions('granted'))
     .then(() => setPermissions(DENY_ACTION))
     .then(() => checkPermissions('denied'))
     .then(testStatusOnChange)
     .then(testInvalidQuery)
+    .then(revokeUnsupportedPermissions)
+    .then(revokeUserVisiblePushPermission)
+    .then(revokePermissions)
+    .then(() => checkPermissions('prompt'))
+    .then(testInvalidRevoke)
     .then(SimpleTest.finish)
     .catch ((e) => {
       ok(false, 'Unexpected error ' + e);
       SimpleTest.finish();
     });
 }
 </script>
 </pre>
--- a/dom/push/test/xpcshell/head.js
+++ b/dom/push/test/xpcshell/head.js
@@ -502,16 +502,16 @@ var tearDownServiceInParent = Task.async
     originAttributes: '',
   });
   ok(record.pushEndpoint.startsWith('https://example.org/push'),
     'Wrong push endpoint in subscription record');
 
   record = yield db.getByIdentifiers({
     scope: 'https://example.net/scope/1',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: 1, inBrowser: true }),
+      { appId: 1, inIsolatedMozBrowser: true }),
   });
   ok(record.pushEndpoint.startsWith('https://example.org/push'),
     'Wrong push endpoint in app record');
 
   record = yield db.getByKeyID('3a414737-2fd0-44c0-af05-7efc172475fc');
   ok(!record, 'Unsubscribed record should not exist');
 });
--- a/dom/push/test/xpcshell/test_clear_origin_data.js
+++ b/dom/push/test/xpcshell/test_clear_origin_data.js
@@ -46,41 +46,41 @@ function run_test() {
 
 add_task(function* test_webapps_cleardata() {
   let db = PushServiceWebSocket.newPushDB();
   do_register_cleanup(() => {return db.drop().then(_ => db.close());});
 
   let testRecords = [{
     scope: 'https://example.org/1',
     originAttributes: { appId: 1 },
-    clearIf: { appId: 1, inBrowser: false },
+    clearIf: { appId: 1, inIsolatedMozBrowser: false },
   }, {
     scope: 'https://example.org/1',
-    originAttributes: { appId: 1, inBrowser: true },
+    originAttributes: { appId: 1, inIsolatedMozBrowser: true },
     clearIf: { appId: 1 },
   }, {
     scope: 'https://example.org/1',
-    originAttributes: { appId: 2, inBrowser: true },
-    clearIf: { appId: 2, inBrowser: true },
+    originAttributes: { appId: 2, inIsolatedMozBrowser: true },
+    clearIf: { appId: 2, inIsolatedMozBrowser: true },
   }, {
     scope: 'https://example.org/2',
     originAttributes: { appId: 1 },
-    clearIf: { appId: 1, inBrowser: false },
+    clearIf: { appId: 1, inIsolatedMozBrowser: false },
   }, {
     scope: 'https://example.org/2',
-    originAttributes: { appId: 2, inBrowser: true },
-    clearIf: { appId: 2, inBrowser: true },
+    originAttributes: { appId: 2, inIsolatedMozBrowser: true },
+    clearIf: { appId: 2, inIsolatedMozBrowser: true },
   }, {
     scope: 'https://example.org/3',
-    originAttributes: { appId: 3, inBrowser: true },
-    clearIf: { inBrowser: true },
+    originAttributes: { appId: 3, inIsolatedMozBrowser: true },
+    clearIf: { inIsolatedMozBrowser: true },
   }, {
     scope: 'https://example.org/3',
-    originAttributes: { appId: 4, inBrowser: true },
-    clearIf: { inBrowser: true },
+    originAttributes: { appId: 4, inIsolatedMozBrowser: true },
+    clearIf: { inIsolatedMozBrowser: true },
   }];
 
   let unregisterDone;
   let unregisterPromise = new Promise(resolve =>
     unregisterDone = after(testRecords.length, resolve));
 
   PushService.init({
     serverURI: "wss://push.example.org",
@@ -118,25 +118,25 @@ add_task(function* test_webapps_cleardat
     PushService.register({
       scope: test.scope,
       originAttributes: ChromeUtils.originAttributesToSuffix(
         test.originAttributes),
     })
   ));
 
   // Removes records for all scopes with the same app ID. Excludes records
-  // where `inBrowser` is true.
-  yield clearForPattern(testRecords, { appId: 1, inBrowser: false });
+  // where `inIsolatedMozBrowser` is true.
+  yield clearForPattern(testRecords, { appId: 1, inIsolatedMozBrowser: false });
 
-  // Removes the remaining record for app ID 1, where `inBrowser` is true.
+  // Removes the remaining record for app ID 1, where `inIsolatedMozBrowser` is true.
   yield clearForPattern(testRecords, { appId: 1 });
 
   // Removes all records for all scopes with the same app ID, where
-  // `inBrowser` is true.
-  yield clearForPattern(testRecords, { appId: 2, inBrowser: true });
+  // `inIsolatedMozBrowser` is true.
+  yield clearForPattern(testRecords, { appId: 2, inIsolatedMozBrowser: true });
 
-  // Removes all records where `inBrowser` is true.
-  yield clearForPattern(testRecords, { inBrowser: true });
+  // Removes all records where `inIsolatedMozBrowser` is true.
+  yield clearForPattern(testRecords, { inIsolatedMozBrowser: true });
 
   equal(testRecords.length, 0, 'Should remove all test records');
   yield waitForPromise(unregisterPromise, DEFAULT_TIMEOUT,
     'Timed out waiting for unregister');
 });
--- a/dom/push/test/xpcshell/test_notification_http2.js
+++ b/dom/push/test/xpcshell/test_notification_http2.js
@@ -75,17 +75,17 @@ add_task(function* test_pushNotification
       d: '1jUPhzVsRkzV0vIzwL4ZEsOlKdNOWm7TmaTfzitJkgM',
       ext: true,
       key_ops: ["deriveBits"],
       kty: "EC",
       x: '8J3iA1CSPBFqHrUul0At3NkosudTlQDAPO1Dn-HRCxM',
       y: '26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA'
     },
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     quota: Infinity,
     systemRecord: true,
   }, {
     subscriptionUri: serverURL + '/pushNotifications/subscription2',
     pushEndpoint: serverURL + '/pushEndpoint2',
     pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint2',
     scope: 'https://example.com/page/2',
     p256dhPublicKey: 'BPnWyUo7yMnuMlyKtERuLfWE8a09dtdjHSW2lpC9_BqR5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E',
@@ -94,17 +94,17 @@ add_task(function* test_pushNotification
       d: 'lFm4nPsUKYgNGBJb5nXXKxl8bspCSp0bAhCYxbveqT4',
       ext: true,
       key_ops: ["deriveBits"],
       kty: 'EC',
       x: '-dbJSjvIye4yXIq0RG4t9YTxrT1212MdJbaWkL38GpE',
       y: '5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E'
     },
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     quota: Infinity,
     systemRecord: true,
   }, {
     subscriptionUri: serverURL + '/pushNotifications/subscription3',
     pushEndpoint: serverURL + '/pushEndpoint3',
     pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint3',
     scope: 'https://example.com/page/3',
     p256dhPublicKey: 'BDhUHITSeVrWYybFnb7ylVTCDDLPdQWMpf8gXhcWwvaaJa6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI',
@@ -113,17 +113,17 @@ add_task(function* test_pushNotification
       d: 'Q1_SE1NySTYzjbqgWwPgrYh7XRg3adqZLkQPsy319G8',
       ext: true,
       key_ops: ["deriveBits"],
       kty: 'EC',
       x: 'OFQchNJ5WtZjJsWdvvKVVMIMMs91BYyl_yBeFxbC9po',
       y: 'Ja6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI'
     },
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     quota: Infinity,
     systemRecord: true,
   }];
 
   for (let record of records) {
     yield db.put(record);
   }
 
--- a/dom/push/test/xpcshell/test_reconnect_retry.js
+++ b/dom/push/test/xpcshell/test_reconnect_retry.js
@@ -53,22 +53,22 @@ add_task(function* test_reconnect_retry(
         }
       });
     }
   });
 
   let registration = yield PushService.register({
     scope: 'https://example.com/page/1',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
   });
   let retryEndpoint = 'https://example.org/push/' + channelID;
   equal(registration.endpoint, retryEndpoint, 'Wrong endpoint for retried request');
 
   registration = yield PushService.register({
     scope: 'https://example.com/page/2',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
   });
   notEqual(registration.endpoint, retryEndpoint, 'Wrong endpoint for new request')
 
   equal(registers, 3, 'Wrong registration count');
 });
--- a/dom/push/test/xpcshell/test_register_5xxCode_http2.js
+++ b/dom/push/test/xpcshell/test_register_5xxCode_http2.js
@@ -76,17 +76,17 @@ add_task(function* test1() {
 
   PushService.init({
     serverURI: serverURL + "/subscribe5xxCode",
     db
   });
 
   let originAttributes = ChromeUtils.originAttributesToSuffix({
     appId: Ci.nsIScriptSecurityManager.NO_APP_ID,
-    inBrowser: false,
+    inIsolatedMozBrowser: false,
   });
   let newRecord = yield PushService.register({
     scope: 'https://example.com/retry5xxCode',
     originAttributes: originAttributes,
   });
 
   var subscriptionUri = serverURL + '/subscription';
   var pushEndpoint = serverURL + '/pushEndpoint';
--- a/dom/push/test/xpcshell/test_register_case.js
+++ b/dom/push/test/xpcshell/test_register_case.js
@@ -42,17 +42,17 @@ add_task(function* test_register_case() 
       });
     }
   });
 
   let newRecord = yield waitForPromise(
     PushService.register({
       scope: 'https://example.net/case',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     DEFAULT_TIMEOUT,
     'Mixed-case register response timed out'
   );
   equal(newRecord.endpoint, 'https://example.com/update/case',
     'Wrong push endpoint in registration record');
 
   let record = yield db.getByPushEndpoint('https://example.com/update/case');
--- a/dom/push/test/xpcshell/test_register_error_http2.js
+++ b/dom/push/test/xpcshell/test_register_error_http2.js
@@ -40,17 +40,17 @@ add_task(function* test_pushSubscription
     serverURI: serverURL + "/pushSubscriptionNoConnection/subscribe",
     db
   });
 
   yield rejects(
     PushService.register({
       scope: 'https://example.net/page/invalid-response',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     'Expected error for not being able to establish connecion.'
   );
 
   let record = yield db.getAllKeyIDs();
   ok(record.length === 0, "Should not store records when connection couldn't be established.");
   PushService.uninit();
 });
@@ -80,17 +80,17 @@ add_task(function* test_pushSubscription
     serverURI: serverURL + "/pushSubscriptionMissingLocation/subscribe",
     db
   });
 
   yield rejects(
     PushService.register({
       scope: 'https://example.net/page/invalid-response',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     'Expected error for the missing location header.'
   );
 
   let record = yield db.getAllKeyIDs();
   ok(record.length === 0, 'Should not store records when the location header is missing.');
   PushService.uninit();
 });
@@ -106,17 +106,17 @@ add_task(function* test_pushSubscription
     serverURI: serverURL + "/pushSubscriptionMissingLink/subscribe",
     db
   });
 
   yield rejects(
     PushService.register({
       scope: 'https://example.net/page/invalid-response',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     'Expected error for the missing link header.'
   );
 
   let record = yield db.getAllKeyIDs();
   ok(record.length === 0, 'Should not store records when a link header is missing.');
   PushService.uninit();
 });
@@ -132,17 +132,17 @@ add_task(function* test_pushSubscription
     serverURI: serverURL + "/pushSubscriptionMissingLink1/subscribe",
     db
   });
 
   yield rejects(
     PushService.register({
       scope: 'https://example.net/page/invalid-response',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     'Expected error for the missing push endpoint.'
   );
 
   let record = yield db.getAllKeyIDs();
   ok(record.length === 0, 'Should not store records when the push endpoint is missing.');
   PushService.uninit();
 });
@@ -158,17 +158,17 @@ add_task(function* test_pushSubscription
     serverURI: serverURL + "/pushSubscriptionLocationBogus/subscribe",
     db
   });
 
   yield rejects(
     PushService.register({
       scope: 'https://example.net/page/invalid-response',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     'Expected error for the bogus location'
   );
 
   let record = yield db.getAllKeyIDs();
   ok(record.length === 0, 'Should not store records when location header is bogus.');
   PushService.uninit();
 });
@@ -184,17 +184,17 @@ add_task(function* test_pushSubscription
     serverURI: serverURL + "/pushSubscriptionNot201Code/subscribe",
     db
   });
 
   yield rejects(
     PushService.register({
       scope: 'https://example.net/page/invalid-response',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     'Expected error for not 201 responce code.'
   );
 
   let record = yield db.getAllKeyIDs();
   ok(record.length === 0, 'Should not store records when respons code is not 201.');
 });
 
--- a/dom/push/test/xpcshell/test_register_invalid_channel.js
+++ b/dom/push/test/xpcshell/test_register_invalid_channel.js
@@ -43,16 +43,16 @@ add_task(function* test_register_invalid
       });
     }
   });
 
   yield rejects(
     PushService.register({
       scope: 'https://example.com/invalid-channel',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     'Expected error for invalid channel ID'
   );
 
   let record = yield db.getByKeyID(channelID);
   ok(!record, 'Should not store records for error responses');
 });
--- a/dom/push/test/xpcshell/test_register_invalid_endpoint.js
+++ b/dom/push/test/xpcshell/test_register_invalid_endpoint.js
@@ -44,16 +44,16 @@ add_task(function* test_register_invalid
       });
     }
   });
 
   yield rejects(
     PushService.register({
       scope: 'https://example.net/page/invalid-endpoint',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     'Expected error for invalid endpoint'
   );
 
   let record = yield db.getByKeyID(channelID);
   ok(!record, 'Should not store records with invalid endpoints');
 });
--- a/dom/push/test/xpcshell/test_register_invalid_json.js
+++ b/dom/push/test/xpcshell/test_register_invalid_json.js
@@ -44,17 +44,17 @@ add_task(function* test_register_invalid
       });
     }
   });
 
   yield rejects(
     PushService.register({
       scope: 'https://example.net/page/invalid-json',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     'Expected error for invalid JSON response'
   );
 
   yield waitForPromise(helloPromise, DEFAULT_TIMEOUT,
     'Reconnect after invalid JSON response timed out');
   equal(registers, 1, 'Wrong register count');
 });
--- a/dom/push/test/xpcshell/test_register_no_id.js
+++ b/dom/push/test/xpcshell/test_register_no_id.js
@@ -48,17 +48,17 @@ add_task(function* test_register_no_id()
       });
     }
   });
 
   yield rejects(
     PushService.register({
       scope: 'https://example.com/incomplete',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     'Expected error for incomplete register response'
   );
 
   yield waitForPromise(helloPromise, DEFAULT_TIMEOUT,
     'Reconnect after incomplete register response timed out');
   equal(registers, 1, 'Wrong register count');
 });
--- a/dom/push/test/xpcshell/test_register_request_queue.js
+++ b/dom/push/test/xpcshell/test_register_request_queue.js
@@ -40,22 +40,22 @@ add_task(function* test_register_request
         }
       });
     }
   });
 
   let firstRegister = PushService.register({
     scope: 'https://example.com/page/1',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
   });
   let secondRegister = PushService.register({
     scope: 'https://example.com/page/1',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
   });
 
   yield waitForPromise(Promise.all([
     rejects(firstRegister, 'Should time out the first request'),
     rejects(secondRegister, 'Should time out the second request')
   ]), DEFAULT_TIMEOUT, 'Queued requests did not time out');
 
   yield waitForPromise(helloPromise, DEFAULT_TIMEOUT,
--- a/dom/push/test/xpcshell/test_register_rollback.js
+++ b/dom/push/test/xpcshell/test_register_rollback.js
@@ -70,17 +70,17 @@ add_task(function* test_register_rollbac
     }
   });
 
   // Should return a rejected promise if storage fails.
   yield rejects(
     PushService.register({
       scope: 'https://example.com/storage-error',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     'Expected error for unregister database failure'
   );
 
   // Should send an out-of-band unregister request.
   yield waitForPromise(unregisterPromise, DEFAULT_TIMEOUT,
     'Unregister request timed out');
   equal(handshakes, 1, 'Wrong handshake count');
--- a/dom/push/test/xpcshell/test_register_success.js
+++ b/dom/push/test/xpcshell/test_register_success.js
@@ -51,17 +51,17 @@ add_task(function* test_register_success
         }
       });
     }
   });
 
   let newRecord = yield PushService.register({
     scope: 'https://example.org/1',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
   });
   equal(newRecord.endpoint, 'https://example.com/update/1',
     'Wrong push endpoint in registration record');
 
   let record = yield db.getByKeyID(channelID);
   equal(record.channelID, channelID,
     'Wrong channel ID in database record');
   equal(record.pushEndpoint, 'https://example.com/update/1',
--- a/dom/push/test/xpcshell/test_register_success_http2.js
+++ b/dom/push/test/xpcshell/test_register_success_http2.js
@@ -60,17 +60,17 @@ add_task(function* test_pushSubscription
   PushService.init({
     serverURI: serverURL + "/pushSubscriptionSuccess/subscribe",
     db
   });
 
   let newRecord = yield PushService.register({
     scope: 'https://example.org/1',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
   });
 
   var subscriptionUri = serverURL + '/pushSubscriptionSuccesss';
   var pushEndpoint = serverURL + '/pushEndpointSuccess';
   var pushReceiptEndpoint = serverURL + '/receiptPushEndpointSuccess';
   equal(newRecord.endpoint, pushEndpoint,
     'Wrong push endpoint in registration record');
 
@@ -95,17 +95,17 @@ add_task(function* test_pushSubscription
   PushService.init({
     serverURI: serverURL + "/pushSubscriptionMissingLink2/subscribe",
     db
   });
 
   let newRecord = yield PushService.register({
     scope: 'https://example.org/no_receiptEndpoint',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
   });
 
   var subscriptionUri = serverURL + '/subscriptionMissingLink2';
   var pushEndpoint = serverURL + '/pushEndpointMissingLink2';
   var pushReceiptEndpoint = '';
   equal(newRecord.endpoint, pushEndpoint,
     'Wrong push endpoint in registration record');
 
--- a/dom/push/test/xpcshell/test_register_timeout.js
+++ b/dom/push/test/xpcshell/test_register_timeout.js
@@ -70,17 +70,17 @@ add_task(function* test_register_timeout
       });
     }
   });
 
   yield rejects(
     PushService.register({
       scope: 'https://example.net/page/timeout',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     'Expected error for request timeout'
   );
 
   let record = yield db.getByKeyID(channelID);
   ok(!record, 'Should not store records for timed-out responses');
 
   yield waitForPromise(
--- a/dom/push/test/xpcshell/test_register_wrong_id.js
+++ b/dom/push/test/xpcshell/test_register_wrong_id.js
@@ -54,17 +54,17 @@ add_task(function* test_register_wrong_i
       });
     }
   });
 
   yield rejects(
     PushService.register({
       scope: 'https://example.com/mismatched',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     'Expected error for mismatched register reply'
   );
 
   yield waitForPromise(helloPromise, DEFAULT_TIMEOUT,
     'Reconnect after mismatched register reply timed out');
   equal(registers, 1, 'Wrong register count');
 });
--- a/dom/push/test/xpcshell/test_register_wrong_type.js
+++ b/dom/push/test/xpcshell/test_register_wrong_type.js
@@ -48,17 +48,17 @@ add_task(function* test_register_wrong_t
       });
     }
   });
 
   yield rejects(
     PushService.register({
       scope: 'https://example.com/mistyped',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     'Expected error for non-string channel ID'
   );
 
   yield waitForPromise(helloPromise, DEFAULT_TIMEOUT,
     'Reconnect after sending non-string channel ID timed out');
   equal(registers, 1, 'Wrong register count');
 });
--- a/dom/push/test/xpcshell/test_registration_error.js
+++ b/dom/push/test/xpcshell/test_registration_error.js
@@ -29,16 +29,16 @@ add_task(function* test_registrations_er
       return new MockWebSocket(uri);
     }
   });
 
   yield rejects(
     PushService.registration({
       scope: 'https://example.net/1',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     function(error) {
       return error == 'Database error';
     },
     'Wrong message'
   );
 });
--- a/dom/push/test/xpcshell/test_registration_error_http2.js
+++ b/dom/push/test/xpcshell/test_registration_error_http2.js
@@ -23,16 +23,16 @@ add_task(function* test_registrations_er
       }
     }),
   });
 
   yield rejects(
     PushService.registration({
       scope: 'https://example.net/1',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     function(error) {
       return error == 'Database error';
     },
     'Wrong message'
   );
 });
--- a/dom/push/test/xpcshell/test_registration_none.js
+++ b/dom/push/test/xpcshell/test_registration_none.js
@@ -21,12 +21,12 @@ add_task(function* test_registration_non
     makeWebSocket(uri) {
       return new MockWebSocket(uri);
     }
   });
 
   let registration = yield PushService.registration({
     scope: 'https://example.net/1',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
   });
   ok(!registration, 'Should not open a connection without registration');
 });
--- a/dom/push/test/xpcshell/test_registration_success.js
+++ b/dom/push/test/xpcshell/test_registration_success.js
@@ -31,17 +31,17 @@ add_task(function* test_registration_suc
       { appId: 42 }),
     version: 10,
     quota: Infinity,
   }, {
     channelID: 'b1cf38c9-6836-4d29-8a30-a3e98d59b728',
     pushEndpoint: 'https://example.org/update/different-manifest',
     scope: 'https://example.org/c',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: 42, inBrowser: true }),
+      { appId: 42, inIsolatedMozBrowser: true }),
     version: 15,
     quota: Infinity,
   }];
   for (let record of records) {
     yield db.put(record);
   }
 
   let handshakeDone;
--- a/dom/push/test/xpcshell/test_registration_success_http2.js
+++ b/dom/push/test/xpcshell/test_registration_success_http2.js
@@ -41,48 +41,48 @@ add_task(function* test_pushNotification
   var serverURL = "https://localhost:" + serverPort;
 
   let records = [{
     subscriptionUri: serverURL + '/subscriptionA',
     pushEndpoint: serverURL + '/pushEndpointA',
     pushReceiptEndpoint: serverURL + '/pushReceiptEndpointA',
     scope: 'https://example.net/a',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     quota: Infinity,
   }, {
     subscriptionUri: serverURL + '/subscriptionB',
     pushEndpoint: serverURL + '/pushEndpointB',
     pushReceiptEndpoint: serverURL + '/pushReceiptEndpointB',
     scope: 'https://example.net/b',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     quota: Infinity,
   }, {
     subscriptionUri: serverURL + '/subscriptionC',
     pushEndpoint: serverURL + '/pushEndpointC',
     pushReceiptEndpoint: serverURL + '/pushReceiptEndpointC',
     scope: 'https://example.net/c',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     quota: Infinity,
   }];
 
   for (let record of records) {
     yield db.put(record);
   }
 
   PushService.init({
     serverURI: serverURL,
     db
   });
 
   let registration = yield PushService.registration({
     scope: 'https://example.net/a',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
   });
   equal(
     registration.endpoint,
     serverURL + '/pushEndpointA',
     'Wrong push endpoint for scope'
   );
 });
--- a/dom/push/test/xpcshell/test_unregister_empty_scope.js
+++ b/dom/push/test/xpcshell/test_unregister_empty_scope.js
@@ -27,13 +27,13 @@ add_task(function* test_unregister_empty
       });
     }
   });
 
   yield rejects(
     PushService.unregister({
       scope: '',
       originAttributes: ChromeUtils.originAttributesToSuffix(
-        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+        { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     }),
     'Expected error for empty endpoint'
   );
 });
--- a/dom/push/test/xpcshell/test_unregister_invalid_json.js
+++ b/dom/push/test/xpcshell/test_unregister_invalid_json.js
@@ -70,17 +70,17 @@ add_task(function* test_unregister_inval
   });
   let record = yield db.getByKeyID(
     '87902e90-c57e-4d18-8354-013f4a556559');
   ok(!record, 'Failed to delete unregistered record');
 
   yield PushService.unregister({
     scope: 'https://example.net/page/1',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
   });
   record = yield db.getByKeyID(
     '057caa8f-9b99-47ff-891c-adad18ce603e');
   ok(!record,
     'Failed to delete unregistered record after receiving invalid JSON');
 
   yield waitForPromise(unregisterPromise, DEFAULT_TIMEOUT,
     'Timed out waiting for unregister');
--- a/dom/push/test/xpcshell/test_unregister_not_found.js
+++ b/dom/push/test/xpcshell/test_unregister_not_found.js
@@ -26,12 +26,12 @@ add_task(function* test_unregister_not_f
         }
       });
     }
   });
 
   let result = yield PushService.unregister({
     scope: 'https://example.net/nonexistent',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
   });
   ok(result === false, "unregister should resolve with false for nonexistent scope");
 });
--- a/dom/push/test/xpcshell/test_unregister_success_http2.js
+++ b/dom/push/test/xpcshell/test_unregister_success_http2.js
@@ -61,29 +61,29 @@ add_task(function* test_pushUnsubscripti
   var serverURL = "https://localhost:" + serverPort;
 
   yield db.put({
     subscriptionUri: serverURL + '/subscriptionUnsubscriptionSuccess',
     pushEndpoint: serverURL + '/pushEndpointUnsubscriptionSuccess',
     pushReceiptEndpoint: serverURL + '/receiptPushEndpointUnsubscriptionSuccess',
     scope: 'https://example.com/page/unregister-success',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
     quota: Infinity,
   });
 
   PushService.init({
     serverURI: serverURL,
     db
   });
 
   yield PushService.unregister({
     scope: 'https://example.com/page/unregister-success',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
   });
   let record = yield db.getByKeyID(serverURL + '/subscriptionUnsubscriptionSuccess');
   ok(!record, 'Unregister did not remove record');
 
 });
 
 add_task(function* test_complete() {
   prefs.setBoolPref("network.http.spdy.enforce-tls-profile", tlsProfile);
--- a/dom/push/test/xpcshell/test_updateRecordNoEncryptionKeys_ws.js
+++ b/dom/push/test/xpcshell/test_updateRecordNoEncryptionKeys_ws.js
@@ -66,17 +66,17 @@ add_task(function* test_with_data_enable
         }
       });
     },
   });
 
   let newRecord = yield PushService.register({
     scope: 'https://example.com/page/3',
     originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
+      { appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inIsolatedMozBrowser: false }),
   });
   ok(newRecord.p256dhKey, 'Should generate public keys for new records');
 
   let record = yield db.getByKeyID('eb18f12a-cc42-4f14-accb-3bfc1227f1aa');
   ok(record.p256dhPublicKey, 'Should add public key to partial record');
   ok(record.p256dhPrivateKey, 'Should add private key to partial record');
 
   record = yield db.getByKeyID('0d8886b9-8da1-4778-8f5d-1cf93a877ed6');
--- a/dom/quota/ActorsParent.cpp
+++ b/dom/quota/ActorsParent.cpp
@@ -1350,29 +1350,29 @@ class MOZ_STACK_CLASS OriginParser final
   nsCString mSchema;
   nsCString mHost;
   Nullable<uint32_t> mPort;
   nsTArray<nsCString> mPathnameComponents;
   nsCString mHandledTokens;
 
   SchemaType mSchemaType;
   State mState;
-  bool mInMozBrowser;
+  bool mInIsolatedMozBrowser;
   bool mMaybeDriveLetter;
   bool mError;
 
 public:
   explicit OriginParser(const nsACString& aOrigin)
     : mOrigin(aOrigin)
     , mTokenizer(aOrigin, '+')
     , mAppId(kNoAppId)
     , mPort()
     , mSchemaType(eNone)
     , mState(eExpectingAppIdOrSchema)
-    , mInMozBrowser(false)
+    , mInIsolatedMozBrowser(false)
     , mMaybeDriveLetter(false)
     , mError(false)
   { }
 
   static bool
   ParseOrigin(const nsACString& aOrigin,
               nsCString& aSpec,
               PrincipalOriginAttributes* aAttrs);
@@ -5708,17 +5708,17 @@ OriginClearOp::DoInitOnMainThread()
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   const mozilla::PrincipalOriginAttributes& attrs =
     mozilla::BasePrincipal::Cast(principal)->OriginAttributesRef();
 
   nsAutoCString pattern;
-  QuotaManager::GetOriginPatternString(attrs.mAppId, attrs.mInBrowser, origin,
+  QuotaManager::GetOriginPatternString(attrs.mAppId, attrs.mInIsolatedMozBrowser, origin,
                                        pattern);
 
   mOriginScope.SetFromPattern(pattern);
 
   return NS_OK;
 }
 
 void
@@ -6261,17 +6261,17 @@ OriginParser::Parse(nsACString& aSpec, P
     QM_WARNING("Origin '%s' failed to parse, handled tokens: %s", mOrigin.get(),
                mHandledTokens.get());
 
     return false;
   }
 
   MOZ_ASSERT(mState == eComplete || mState == eHandledTrailingSeparator);
 
-  *aAttrs = PrincipalOriginAttributes(mAppId, mInMozBrowser);
+  *aAttrs = PrincipalOriginAttributes(mAppId, mInIsolatedMozBrowser);
 
   nsAutoCString spec(mSchema);
 
   if (mSchemaType == eFile) {
     spec.AppendLiteral("://");
 
     for (uint32_t count = mPathnameComponents.Length(), index = 0;
          index < count;
@@ -6386,19 +6386,19 @@ OriginParser::HandleToken(const nsDepend
         QM_WARNING("'%d' is not a valid length for the inMozBrowser flag!",
                    aToken.Length());
 
         mError = true;
         return;
       }
 
       if (aToken.First() == 't') {
-        mInMozBrowser = true;
+        mInIsolatedMozBrowser = true;
       } else if (aToken.First() == 'f') {
-        mInMozBrowser = false;
+        mInIsolatedMozBrowser = false;
       } else {
         QM_WARNING("'%s' is not a valid value for the inMozBrowser flag!",
                    nsCString(aToken).get());
 
         mError = true;
         return;
       }
 
--- a/dom/requestsync/RequestSyncManager.js
+++ b/dom/requestsync/RequestSyncManager.js
@@ -53,37 +53,37 @@ RequestSyncManager.prototype = {
     });
   },
 
   registrations: function() {
     debug('registrations');
     return this.sendMessage("RequestSyncManager:Registrations", {});
   },
 
-  setPolicy: function(aTask, aOrigin, aManifestURL, aIsInBrowserElement,
+  setPolicy: function(aTask, aOrigin, aManifestURL, aIsInIsolatedMozBrowserElement,
                       aState, aOverwrittenMinInterval) {
     debug('setPolicy');
 
     return this.sendMessage("RequestSyncManager:SetPolicy",
       { task: aTask,
         origin: aOrigin,
         manifestURL: aManifestURL,
-        isInBrowserElement: aIsInBrowserElement,
+        isInBrowserElement: aIsInIsolatedMozBrowserElement,
         state: aState,
         overwrittenMinInterval: aOverwrittenMinInterval });
   },
 
-  runTask: function(aTask, aOrigin, aManifestURL, aIsInBrowserElement) {
+  runTask: function(aTask, aOrigin, aManifestURL, aIsInIsolatedMozBrowserElement) {
     debug('runTask');
 
     return this.sendMessage("RequestSyncManager:RunTask",
       { task: aTask,
         origin: aOrigin,
         manifestURL: aManifestURL,
-        isInBrowserElement: aIsInBrowserElement });
+        isInBrowserElement: aIsInIsolatedMozBrowserElement });
   },
 
   registrationsResult: function(aData) {
     debug("registrationsResult");
 
     let results = new this._window.Array();
     for (let i = 0; i < aData.length; ++i) {
       if (!("app" in aData[i])) {
--- a/dom/requestsync/RequestSyncService.jsm
+++ b/dom/requestsync/RequestSyncService.jsm
@@ -518,17 +518,17 @@ this.RequestSyncService = {
 
     let toSave = null;
     let self = this;
     this.forEachRegistration(function(aObj) {
       if (aObj.data.task != aData.task) {
         return;
       }
 
-      if (aObj.principal.isInBrowserElement != aData.isInBrowserElement ||
+      if (aObj.principal.isInIsolatedMozBrowserElement != aData.isInBrowserElement ||
           aObj.principal.originNoSuffix != aData.origin) {
         return;
       }
 
       let app = appsService.getAppByLocalId(aObj.principal.appId);
       if (app && app.manifestURL != aData.manifestURL ||
           (!app && aData.manifestURL != "")) {
         return;
@@ -567,17 +567,17 @@ this.RequestSyncService = {
     debug("runTask");
 
     let task = null;
     this.forEachRegistration(function(aObj) {
       if (aObj.data.task != aData.task) {
         return;
       }
 
-      if (aObj.principal.isInBrowserElement != aData.isInBrowserElement ||
+      if (aObj.principal.isInIsolatedMozBrowserElement != aData.isInBrowserElement ||
           aObj.principal.originNoSuffix != aData.origin) {
         return;
       }
 
       let app = appsService.getAppByLocalId(aObj.principal.appId);
       if (app && app.manifestURL != aData.manifestURL ||
           (!app && aData.manifestURL != "")) {
         return;
@@ -614,17 +614,17 @@ this.RequestSyncService = {
              data: aObj.data };
   },
 
   createFullTaskObject: function(aObj) {
     let obj = this.createPartialTaskObject(aObj);
 
     obj.app = { manifestURL: '',
                 origin: aObj.principal.originNoSuffix,
-                isInBrowserElement: aObj.principal.isInBrowserElement };
+                isInBrowserElement: aObj.principal.isInIsolatedMozBrowserElement };
 
     let app = appsService.getAppByLocalId(aObj.principal.appId);
     if (app) {
       obj.app.manifestURL = app.manifestURL;
     }
 
     obj.state = aObj.state;
     obj.overwrittenMinInterval = aObj.overwrittenMinInterval;
--- a/dom/storage/DOMStorageDBThread.cpp
+++ b/dom/storage/DOMStorageDBThread.cpp
@@ -53,31 +53,31 @@ Scheme0Scope(DOMStorageCacheBridge* aCac
 
   nsCString suffix = aCache->OriginSuffix();
 
   PrincipalOriginAttributes oa;
   if (!suffix.IsEmpty()) {
     oa.PopulateFromSuffix(suffix);
   }
 
-  if (oa.mAppId != nsIScriptSecurityManager::NO_APP_ID || oa.mInBrowser) {
+  if (oa.mAppId != nsIScriptSecurityManager::NO_APP_ID || oa.mInIsolatedMozBrowser) {
     result.AppendInt(oa.mAppId);
     result.Append(':');
-    result.Append(oa.mInBrowser ? 't' : 'f');
+    result.Append(oa.mInIsolatedMozBrowser ? 't' : 'f');
     result.Append(':');
   }
 
   // If there is more than just appid and/or inbrowser stored in origin
   // attributes, put it to the schema 0 scope as well.  We must do that
   // to keep the scope column unique (same resolution as schema 1 has
   // with originAttributes and originKey columns) so that switch between
   // schema 1 and 0 always works in both ways.
   nsAutoCString remaining;
   oa.mAppId = 0;
-  oa.mInBrowser = false;
+  oa.mInIsolatedMozBrowser = false;
   oa.CreateSuffix(remaining);
   if (!remaining.IsEmpty()) {
     MOZ_ASSERT(!suffix.IsEmpty());
 
     if (result.IsEmpty()) {
       // Must contain the old prefix, otherwise we won't search for the whole
       // origin attributes suffix.
       result.Append(NS_LITERAL_CSTRING("0:f:"));
--- a/dom/storage/DOMStorageDBUpdater.cpp
+++ b/dom/storage/DOMStorageDBUpdater.cpp
@@ -62,83 +62,83 @@ nsReverseStringSQLFunction::OnFunctionCa
 class ExtractOriginData : protected mozilla::Tokenizer
 {
 public:
   ExtractOriginData(const nsACString& scope, nsACString& suffix, nsACString& origin)
     : mozilla::Tokenizer(scope)
   {
     using mozilla::OriginAttributes;
 
-    // Parse optional appId:isInBrowserElement: string, in case
+    // Parse optional appId:isInIsolatedMozBrowserElement: string, in case
     // we don't find it, the scope is our new origin key and suffix
     // is empty.
     suffix.Truncate();
     origin.Assign(scope);
 
     // Bail out if it isn't appId.
     uint32_t appId;
     if (!ReadInteger(&appId)) {
       return;
     }
 
     // Should be followed by a colon.
     if (!CheckChar(':')) {
       return;
     }
 
-    // Bail out if it isn't 'browserFlag'.
-    nsDependentCSubstring browserFlag;
-    if (!ReadWord(browserFlag)) {
+    // Bail out if it isn't 'isolatedBrowserFlag'.
+    nsDependentCSubstring isolatedBrowserFlag;
+    if (!ReadWord(isolatedBrowserFlag)) {
       return;
     }
 
-    bool inBrowser = browserFlag == "t";
-    bool notInBrowser = browserFlag == "f";
-    if (!inBrowser && !notInBrowser) {
+    bool inIsolatedMozBrowser = isolatedBrowserFlag == "t";
+    bool notInIsolatedBrowser = isolatedBrowserFlag == "f";
+    if (!inIsolatedMozBrowser && !notInIsolatedBrowser) {
       return;
     }
 
     // Should be followed by a colon.
     if (!CheckChar(':')) {
       return;
     }
 
-    // OK, we have found appId and inBrowser flag, create the suffix from it
-    // and take the rest as the origin key.
+    // OK, we have found appId and inIsolatedMozBrowser flag, create the suffix
+    // from it and take the rest as the origin key.
 
     // If the profile went through schema 1 -> schema 0 -> schema 1 switching
     // we may have stored the full attributes origin suffix when there were
-    // more than just appid and inbrowser set on storage principal's
+    // more than just appId and inIsolatedMozBrowser set on storage principal's
     // OriginAttributes.
     //
     // To preserve full uniqueness we store this suffix to the scope key.
     // Schema 0 code will just ignore it while keeping the scoping unique.
     //
     // The whole scope string is in one of the following forms (when we are here):
     //
     // "1001:f:^appId=1001&inBrowser=false&addonId=101:gro.allizom.rxd.:https:443"
     // "1001:f:gro.allizom.rxd.:https:443"
     //         |
     //         +- the parser cursor position.
     //
     // If there is '^', the full origin attributes suffix follows.  We search
     // for ':' since it is the delimiter used in the scope string and is never
-    // contained in the origin attributes suffix.  Remaning string after
+    // contained in the origin attributes suffix.  Remaining string after
     // the comma is the reversed-domain+schema+port tuple.
     Record();
     if (CheckChar('^')) {
       Token t;
       while (Next(t)) {
         if (t.Equals(Token::Char(':'))) {
           Claim(suffix);
           break;
         }
       }
     } else {
-      PrincipalOriginAttributes attrs(appId, inBrowser);
+      PrincipalOriginAttributes attrs(appId, inIsolatedMozBrowser);
       attrs.CreateSuffix(suffix);
     }
 
     // Consume the rest of the input as "origin".
     origin.Assign(Substring(mCursor, mEnd));
   }
 };
 
--- a/dom/webidl/ChromeUtils.webidl
+++ b/dom/webidl/ChromeUtils.webidl
@@ -82,19 +82,19 @@ interface ChromeUtils : ThreadSafeChrome
  * (1) Add them to both dictionaries.
  * (2) Update the methods on mozilla::OriginAttributes, including equality,
  *     serialization, deserialization, and inheritance.
  * (3) Update the methods on mozilla::OriginAttributesPattern, including matching.
  */
 dictionary OriginAttributesDictionary {
   unsigned long appId = 0;
   unsigned long userContextId = 0;
-  boolean inBrowser = false;
+  boolean inIsolatedMozBrowser = false;
   DOMString addonId = "";
   DOMString signedPkg = "";
 };
 dictionary OriginAttributesPatternDictionary {
   unsigned long appId;
   unsigned long userContextId;
-  boolean inBrowser;
+  boolean inIsolatedMozBrowser;
   DOMString addonId;
   DOMString signedPkg;
 };
--- a/dom/webidl/Permissions.webidl
+++ b/dom/webidl/Permissions.webidl
@@ -21,9 +21,11 @@ dictionary PermissionDescriptor {
 dictionary PushPermissionDescriptor : PermissionDescriptor {
   boolean userVisible = false;
 };
 
 [Exposed=(Window)]
 interface Permissions {
   [Throws]
   Promise<PermissionStatus> query(object permission);
+  [Throws]
+  Promise<PermissionStatus> revoke(object permission);
 };
--- a/dom/webidl/Request.webidl
+++ b/dom/webidl/Request.webidl
@@ -34,16 +34,17 @@ interface Request {
   void setContentPolicyType(nsContentPolicyType context);
 };
 Request implements Body;
 
 dictionary RequestInit {
   ByteString method;
   HeadersInit headers;
   BodyInit? body;
+  USVString referrer;
   RequestMode mode;
   RequestCredentials credentials;
   RequestCache cache;
   RequestRedirect redirect;
 };
 
 // Gecko currently does not ship RequestContext, so please don't use it in IDL
 // that is exposed to script.
--- a/dom/webidl/TextTrack.webidl
+++ b/dom/webidl/TextTrack.webidl
@@ -34,16 +34,16 @@ interface TextTrack : EventTarget {
 
   readonly attribute TextTrackCueList? cues;
   readonly attribute TextTrackCueList? activeCues;
 
   void addCue(VTTCue cue);
   [Throws]
   void removeCue(VTTCue cue);
 
-           //(Not implemented)attribute EventHandler oncuechange;
+           attribute EventHandler oncuechange;
 };
 
 // Mozilla Extensions
 partial interface TextTrack {
   [ChromeOnly]
   readonly attribute TextTrackList? textTrackList;
 };
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -554,25 +554,16 @@ LoadJSGCMemoryOptions(const char* aPrefN
     nsAutoCString message("Workers don't support the 'mem.");
     message.Append(memPrefName);
     message.AppendLiteral("' preference!");
     NS_WARNING(message.get());
 #endif
   }
 }
 
-void
-ErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aReport)
-{
-  WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
-  MOZ_ASSERT(worker);
-
-  return worker->ReportError(aCx, aMessage, aReport);
-}
-
 bool
 InterruptCallback(JSContext* aCx)
 {
   WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
   MOZ_ASSERT(worker);
 
   // Now is a good time to turn on profiling if it's pending.
   profiler_js_operation_callback();
@@ -807,18 +798,16 @@ CreateJSContextForWorker(WorkerPrivate* 
   JS::SetAsmJSCacheOps(aRuntime, &asmJSCacheOps);
 
   JSContext* workerCx = JS_NewContext(aRuntime, 0);
   if (!workerCx) {
     NS_WARNING("Could not create new context!");
     return nullptr;
   }
 
-  JS_SetErrorReporter(aRuntime, ErrorReporter);
-
   JS_SetInterruptCallback(aRuntime, InterruptCallback);
 
   js::SetCTypesActivityCallback(aRuntime, CTypesActivityCallback);
 
   JS::ContextOptionsRef(workerCx) = kRequiredContextOptions;
 
 #ifdef JS_GC_ZEAL
   JS_SetGCZeal(workerCx, settings.gcZeal, settings.gcZealFrequency);
@@ -1661,16 +1650,19 @@ RuntimeService::UnregisterWorker(JSConte
 
     if (windowArray->IsEmpty()) {
       mWindowMap.Remove(window);
     }
   }
 
   if (queuedWorker && !ScheduleWorker(aCx, queuedWorker)) {
     UnregisterWorker(aCx, queuedWorker);
+    // There's nowhere sane to report the exception from ScheduleWorker, if any,
+    // here.
+    JS_ClearPendingException(aCx);
   }
 }
 
 bool
 RuntimeService::ScheduleWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
 {
   if (!aWorkerPrivate->Start()) {
     // This is ok, means that we didn't need to make a thread for this worker.
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -302,16 +302,19 @@ public:
 private:
   ~ScriptExecutorRunnable()
   { }
 
   virtual bool
   IsDebuggerRunnable() const override;
 
   virtual bool
+  PreRun(WorkerPrivate* aWorkerPrivate) override;
+
+  virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
 
   virtual void
   PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult)
           override;
 
   NS_DECL_NSICANCELABLERUNNABLE
 
@@ -1719,16 +1722,51 @@ ScriptExecutorRunnable::IsDebuggerRunnab
 {
   // ScriptExecutorRunnable is used to execute both worker and debugger scripts.
   // In the latter case, the runnable needs to be dispatched to the debugger
   // queue.
   return mScriptLoader.mWorkerScriptType == DebuggerScript;
 }
 
 bool
+ScriptExecutorRunnable::PreRun(WorkerPrivate* aWorkerPrivate)
+{
+  aWorkerPrivate->AssertIsOnWorkerThread();
+
+  if (!mIsWorkerScript) {
+    return true;
+  }
+
+  if (!aWorkerPrivate->GetJSContext()) {
+    return false;
+  }
+
+  MOZ_ASSERT(mFirstIndex == 0);
+  MOZ_ASSERT(!mScriptLoader.mRv.Failed());
+
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  jsapi.TakeOwnershipOfErrorReporting();
+
+  WorkerGlobalScope* globalScope =
+    aWorkerPrivate->GetOrCreateGlobalScope(jsapi.cx());
+  if (NS_WARN_IF(!globalScope)) {
+    NS_WARNING("Failed to make global!");
+    // There's no way to report the exception on jsapi right now, because there
+    // is no way to even enter a compartment on this thread anymore.  Just clear
+    // the exception.  We'll report some sort of error to our caller thread in
+    // ShutdownScriptLoader.
+    jsapi.ClearException();
+    return false;
+  }
+
+  return true;
+}
+
+bool
 ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
 {
   aWorkerPrivate->AssertIsOnWorkerThread();
 
   nsTArray<ScriptLoadInfo>& loadInfos = mScriptLoader.mLoadInfos;
 
   // Don't run if something else has already failed.
   for (uint32_t index = 0; index < mFirstIndex; index++) {
@@ -1740,42 +1778,21 @@ ScriptExecutorRunnable::WorkerRun(JSCont
     if (!loadInfo.mExecutionResult) {
       return true;
     }
   }
 
   // If nothing else has failed, our ErrorResult better not be a failure either.
   MOZ_ASSERT(!mScriptLoader.mRv.Failed(), "Who failed it and why?");
 
-  JS::Rooted<JSObject*> global(aCx);
-
-  if (mIsWorkerScript) {
-    WorkerGlobalScope* globalScope =
-      aWorkerPrivate->GetOrCreateGlobalScope(aCx);
-    if (NS_WARN_IF(!globalScope)) {
-      NS_WARNING("Failed to make global!");
-      // There's no way to report the exception on aCx right now, because there
-      // is no way to even enter a compartment on this thread anymore.  Just
-      // clear the exception.  We'll report some sort of error to our caller
-      // thread in ShutdownScriptLoader.
-      JS_ClearPendingException(aCx);
-      return false;
-    }
-
-    global.set(globalScope->GetWrapper());
-  } else {
-    // XXXbz Icky action at a distance...  Would be better to capture this state
-    // in mScriptLoader!
-    global.set(JS::CurrentGlobalOrNull(aCx));
-  }
-
+  // Slightly icky action at a distance, but there's no better place to stash
+  // this value, really.
+  JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
   MOZ_ASSERT(global);
 
-  JSAutoCompartment ac(aCx, global);
-
   for (uint32_t index = mFirstIndex; index <= mLastIndex; index++) {
     ScriptLoadInfo& loadInfo = loadInfos.ElementAt(index);
 
     NS_ASSERTION(!loadInfo.mChannel, "Should no longer have a channel!");
     NS_ASSERTION(loadInfo.mExecutionScheduled, "Should be scheduled!");
     NS_ASSERTION(!loadInfo.mExecutionResult, "Should not have executed yet!");
 
     MOZ_ASSERT(!mScriptLoader.mRv.Failed(), "Who failed it and why?");
--- a/dom/workers/ServiceWorkerManagerService.cpp
+++ b/dom/workers/ServiceWorkerManagerService.cpp
@@ -58,22 +58,22 @@ public:
     if (NS_IsMainThread()) {
       for (uint32_t i = 0; i < mData->Length(); ++i) {
         NotifySoftUpdateData& data = mData->ElementAt(i);
         nsTArray<TabContext> contextArray =
           data.mContentParent->GetManagedTabContext();
         // mContentParent needs to be released in the main thread.
         data.mContentParent = nullptr;
         // We only send the notification about the soft update to the
-        // tabs/apps with the same appId and inBrowser values.
+        // tabs/apps with the same appId and inIsolatedMozBrowser values.
         // Sending a notification to the wrong process will make the process
         // to be killed.
         for (uint32_t j = 0; j < contextArray.Length(); ++j) {
           if ((contextArray[j].OwnOrContainingAppId() == mOriginAttributes.mAppId) &&
-              (contextArray[j].IsBrowserElement() == mOriginAttributes.mInBrowser)) {
+              (contextArray[j].IsIsolatedMozBrowserElement() == mOriginAttributes.mInIsolatedMozBrowser)) {
             continue;
           }
           // Array entries with no mParent won't receive any notification.
           data.mParent = nullptr;
         }
       }
       nsresult rv = mBackgroundThread->Dispatch(this, NS_DISPATCH_NORMAL);
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -271,20 +271,17 @@ public:
       result.SuppressException();
       return;
     }
 
     RefPtr<Promise> waitUntilPromise = aEvent->GetPromise();
     if (!waitUntilPromise) {
       waitUntilPromise =
         Promise::Resolve(sgo, aCx, JS::UndefinedHandleValue, result);
-      if (NS_WARN_IF(result.Failed())) {
-        result.SuppressException();
-        return;
-      }
+      MOZ_RELEASE_ASSERT(!result.Failed());
     }
 
     MOZ_ASSERT(waitUntilPromise);
     RefPtr<KeepAliveHandler> keepAliveHandler =
       new KeepAliveHandler(mKeepAliveToken);
     waitUntilPromise->AppendNativeHandler(keepAliveHandler);
 
     if (aWaitUntilPromise) {
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -493,35 +493,39 @@ class CompileScriptRunnable final : publ
 public:
   explicit CompileScriptRunnable(WorkerPrivate* aWorkerPrivate,
                                  const nsAString& aScriptURL)
   : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
     mScriptURL(aScriptURL)
   { }
 
 private:
+  // We can't implement PreRun effectively, because at the point when that would
+  // run we have not yet done our load so don't know things like our final
+  // principal and whatnot.
+
   virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
     aWorkerPrivate->AssertIsOnWorkerThread();
 
     ErrorResult rv;
     scriptloader::LoadMainScript(aWorkerPrivate, mScriptURL, WorkerScript, rv);
     rv.WouldReportJSException();
     // Explicitly ignore NS_BINDING_ABORTED on rv.  Or more precisely, still
     // return false and don't SetWorkerScriptExecutedSuccessfully() in that
     // case, but don't throw anything on aCx.  The idea is to not dispatch error
     // events if our load is canceled with that error code.
     if (rv.ErrorCodeIs(NS_BINDING_ABORTED)) {
       rv.SuppressException();
       return false;
     }
-    // Make sure to propagate exceptions from rv onto aCx, so that our PostRun
-    // can report it.  We do this for all failures on rv, because now we're
-    // using rv to track all the state we care about.
+    // Make sure to propagate exceptions from rv onto aCx, so that they will get
+    // reported after we return.  We do this for all failures on rv, because now
+    // we're using rv to track all the state we care about.
     //
     // This is a little dumb, but aCx is in the null compartment here because we
     // set it up that way in our Run(), since we had not created the global at
     // that point yet.  So we need to enter the compartment of our global,
     // because setting a pending exception on aCx involves wrapping into its
     // current compartment.  Luckily we have a global now (else how would we
     // have a JS exception?) so we can just enter its compartment.
     JSAutoCompartment ac(aCx,
@@ -569,19 +573,19 @@ private:
     // Explicitly ignore NS_BINDING_ABORTED on rv.  Or more precisely, still
     // return false and don't SetWorkerScriptExecutedSuccessfully() in that
     // case, but don't throw anything on aCx.  The idea is to not dispatch error
     // events if our load is canceled with that error code.
     if (rv.ErrorCodeIs(NS_BINDING_ABORTED)) {
       rv.SuppressException();
       return false;
     }
-    // Make sure to propagate exceptions from rv onto aCx, so that our PostRun
-    // can report it.  We do this for all failures on rv, because now we're
-    // using rv to track all the state we care about.
+    // Make sure to propagate exceptions from rv onto aCx, so that they will get
+    // reported after we return.  We do this for all failures on rv, because now
+    // we're using rv to track all the state we care about.
     if (rv.MaybeSetPendingException(aCx)) {
       return false;
     }
 
     return true;
   }
 };
 
@@ -1226,18 +1230,18 @@ private:
 
   virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
     JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
     JS::Rooted<JS::Value> callable(aCx, JS::ObjectValue(*mHandler->Callable()));
     JS::HandleValueArray args = JS::HandleValueArray::empty();
     JS::Rooted<JS::Value> rval(aCx);
-    if (!JS_CallFunctionValue(aCx, global, callable, args, &rval) &&
-        !JS_ReportPendingException(aCx)) {
+    if (!JS_CallFunctionValue(aCx, global, callable, args, &rval)) {
+      // Just return false; WorkerRunnable::Run will report the exception.
       return false;
     }
 
     return true;
   }
 };
 
 void
@@ -3139,16 +3143,24 @@ WorkerPrivateParent<Derived>::BroadcastE
                                                     const nsAString& aFilename,
                                                     const nsAString& aLine,
                                                     uint32_t aLineNumber,
                                                     uint32_t aColumnNumber,
                                                     uint32_t aFlags)
 {
   AssertIsOnMainThread();
 
+  if (JSREPORT_IS_WARNING(aFlags)) {
+    // Don't fire any events anywhere.  Just log to console.
+    // XXXbz should we log to all the consoles of all the relevant windows?
+    LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber,
+                      aFlags, 0);
+    return;
+  }
+
   AutoTArray<RefPtr<SharedWorker>, 10> sharedWorkers;
   GetAllSharedWorkers(sharedWorkers);
 
   if (sharedWorkers.IsEmpty()) {
     return;
   }
 
   AutoTArray<WindowAction, 10> windowActions;
@@ -4665,16 +4677,18 @@ WorkerPrivate::ShutdownGCTimers()
   mIdleGCTimerRunning = false;
 }
 
 bool
 WorkerPrivate::InterruptCallback(JSContext* aCx)
 {
   AssertIsOnWorkerThread();
 
+  MOZ_ASSERT(!JS_IsExceptionPending(aCx));
+
   bool mayContinue = true;
   bool scheduledIdleGC = false;
 
   for (;;) {
     // Run all control events now.
     mayContinue = ProcessAllControlRunnables();
 
     bool mayFreeze = mFrozen;
--- a/dom/workers/WorkerRunnable.cpp
+++ b/dom/workers/WorkerRunnable.cpp
@@ -150,16 +150,22 @@ WorkerRunnable::PostDispatch(WorkerPriva
 
   if (!aDispatchResult) {
     if (mBehavior == WorkerThreadModifyBusyCount) {
       aWorkerPrivate->ModifyBusyCount(false);
     }
   }
 }
 
+bool
+WorkerRunnable::PreRun(WorkerPrivate* aWorkerPrivate)
+{
+  return true;
+}
+
 void
 WorkerRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
                         bool aRunResult)
 {
   MOZ_ASSERT(aCx);
   MOZ_ASSERT(aWorkerPrivate);
 
 #ifdef DEBUG
@@ -179,20 +185,16 @@ WorkerRunnable::PostRun(JSContext* aCx, 
     default:
       MOZ_ASSERT_UNREACHABLE("Unknown behavior!");
   }
 #endif
 
   if (mBehavior == WorkerThreadModifyBusyCount) {
     aWorkerPrivate->ModifyBusyCountFromWorker(false);
   }
-
-  if (!aRunResult) {
-    JS_ReportPendingException(aCx);
-  }
 }
 
 // static
 WorkerRunnable*
 WorkerRunnable::FromRunnable(nsIRunnable* aRunnable)
 {
   MOZ_ASSERT(aRunnable);
 
@@ -255,62 +257,83 @@ WorkerRunnable::Run()
     MOZ_ASSERT(mCallingCancelWithinRun);
     mCallingCancelWithinRun = false;
 
     MOZ_ASSERT(IsCanceled(), "Subclass Cancel() didn't set IsCanceled()!");
 
     return NS_OK;
   }
 
-  // Track down the appropriate global to use for the AutoJSAPI/AutoEntryScript.
+  bool result = PreRun(mWorkerPrivate);
+  if (!result) {
+    MOZ_ASSERT(targetIsWorkerThread,
+               "The only PreRun implementation that can fail is "
+               "ScriptExecutorRunnable");
+    mWorkerPrivate->AssertIsOnWorkerThread();
+    MOZ_ASSERT(!JS_IsExceptionPending(mWorkerPrivate->GetJSContext()));
+    // We can't enter a useful compartment on the JSContext here; just pass it
+    // in as-is.
+    PostRun(mWorkerPrivate->GetJSContext(), mWorkerPrivate, false);
+    return NS_ERROR_FAILURE;
+  }
+
+  // Track down the appropriate global, if any, to use for the AutoEntryScript.
   nsCOMPtr<nsIGlobalObject> globalObject;
   bool isMainThread = !targetIsWorkerThread && !mWorkerPrivate->GetParent();
   MOZ_ASSERT(isMainThread == NS_IsMainThread());
   RefPtr<WorkerPrivate> kungFuDeathGrip;
   if (targetIsWorkerThread) {
     JSContext* cx = GetCurrentThreadJSContext();
     if (NS_WARN_IF(!cx)) {
       return NS_ERROR_FAILURE;
     }
 
     JSObject* global = JS::CurrentGlobalOrNull(cx);
     if (global) {
       globalObject = GetGlobalObjectForGlobal(global);
     } else {
       globalObject = DefaultGlobalObject();
     }
+
+    // We may still not have a globalObject here: in the case of
+    // CompileScriptRunnable, we don't actually create the global object until
+    // we have the script data, which happens in a syncloop under
+    // CompileScriptRunnable::WorkerRun, so we can't assert that it got created
+    // in the PreRun call above.
   } else {
     kungFuDeathGrip = mWorkerPrivate;
     if (isMainThread) {
       globalObject = nsGlobalWindow::Cast(mWorkerPrivate->GetWindow());
     } else {
       globalObject = mWorkerPrivate->GetParent()->GlobalScope();
     }
   }
 
   // We might run script as part of WorkerRun, so we need an AutoEntryScript.
   // This is part of the HTML spec for workers at:
   // http://www.whatwg.org/specs/web-apps/current-work/#run-a-worker
   // If we don't have a globalObject we have to use an AutoJSAPI instead, but
   // this is OK as we won't be running script in these circumstances.
-  // It's important that aes is declared after jsapi, because if WorkerRun
-  // creates a global then we construct aes before PostRun and we need them to
-  // be destroyed in the correct order.
-  mozilla::dom::AutoJSAPI jsapi;
+  Maybe<mozilla::dom::AutoJSAPI> maybeJSAPI;
   Maybe<mozilla::dom::AutoEntryScript> aes;
   JSContext* cx;
+  AutoJSAPI* jsapi;
   if (globalObject) {
     aes.emplace(globalObject, "Worker runnable",
                 isMainThread,
                 isMainThread ? nullptr : GetCurrentThreadJSContext());
+    jsapi = aes.ptr();
     cx = aes->cx();
   } else {
-    jsapi.Init();
-    cx = jsapi.cx();
+    maybeJSAPI.emplace();
+    maybeJSAPI->Init();
+    jsapi = maybeJSAPI.ptr();
+    cx = jsapi->cx();
   }
+  jsapi->TakeOwnershipOfErrorReporting();
 
   // Note that we can't assert anything about mWorkerPrivate->GetWrapper()
   // existing, since it may in fact have been GCed (and we may be one of the
   // runnables cleaning up the worker as a result).
 
   // If we are on the parent thread and that thread is not the main thread,
   // then we must be a dedicated worker (because there are no
   // Shared/ServiceWorkers whose parent is itself a worker) and then we
@@ -343,27 +366,44 @@ WorkerRunnable::Run()
                js::GetObjectCompartment(mWorkerPrivate->GetWrapper()) ==
                  js::GetContextCompartment(cx),
                "Must either be in the null compartment or in our reflector "
                "compartment");
 
     ac.emplace(cx, mWorkerPrivate->GetWrapper());
   }
 
-  bool result = WorkerRun(cx, mWorkerPrivate);
+  MOZ_ASSERT(!jsapi->HasException());
+  result = WorkerRun(cx, mWorkerPrivate);
+  MOZ_ASSERT_IF(result, !jsapi->HasException());
+  jsapi->ReportException();
+
+  // We can't even assert that this didn't create our global, since in the case
+  // of CompileScriptRunnable it _does_.
 
-  // In the case of CompileScriptRunnnable, WorkerRun above can cause us to
-  // lazily create a global, so we construct aes here before calling PostRun.
-  if (targetIsWorkerThread && !aes && DefaultGlobalObject()) {
-    aes.emplace(DefaultGlobalObject(), "worker runnable",
-                false, GetCurrentThreadJSContext());
-    cx = aes->cx();
-  }
-
+  // It would be nice to avoid passing a JSContext to PostRun, but in the case
+  // of ScriptExecutorRunnable we need to know the current compartment on the
+  // JSContext (the one we set up based on the global returned from PreRun) so
+  // that we can sanely do exception reporting.  In particular, we want to make
+  // sure that we do our JS_SetPendingException while still in that compartment,
+  // because otherwise we might end up trying to create a cross-compartment
+  // wrapper when we try to move the JS exception from our runnable's
+  // ErrorResult to the JSContext, and that's not desirable in this case.
+  //
+  // We _could_ skip passing a JSContext here and then in
+  // ScriptExecutorRunnable::PostRun end up grabbing it from the WorkerPrivate
+  // and looking at its current compartment.  But that seems like slightly weird
+  // action-at-a-distance...
+  //
+  // In any case, we do NOT try to change the compartment on the JSContext at
+  // this point; in the one case in which we could do that
+  // (CompileScriptRunnable) it actually doesn't matter which compartment we're
+  // in for PostRun.
   PostRun(cx, mWorkerPrivate, result);
+  MOZ_ASSERT(!jsapi->HasException());
 
   return result ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 WorkerRunnable::Cancel()
 {
   uint32_t canceledCount = ++mCanceled;
--- a/dom/workers/WorkerRunnable.h
+++ b/dom/workers/WorkerRunnable.h
@@ -117,41 +117,57 @@ protected:
   virtual bool
   PreDispatch(WorkerPrivate* aWorkerPrivate);
 
   // By default asserts that Dispatch() is being called on the right thread
   // (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
   virtual void
   PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult);
 
+  // May be implemented by subclasses if desired if they need to do some sort of
+  // setup before we try to set up our JSContext and compartment for real.
+  // Typically the only thing that should go in here is creation of the worker's
+  // global.
+  //
+  // If false is returned, WorkerRun will not be called at all.  PostRun will
+  // still be called, with false passed for aRunResult.
+  virtual bool
+  PreRun(WorkerPrivate* aWorkerPrivate);
+
   // Must be implemented by subclasses. Called on the target thread.  The return
   // value will be passed to PostRun().  The JSContext passed in here comes from
   // an AutoJSAPI (or AutoEntryScript) that we set up on the stack.  If
   // mBehavior is ParentThreadUnchangedBusyCount, it is in the compartment of
   // mWorkerPrivate's reflector (i.e. the worker object in the parent thread),
   // unless that reflector is null, in which case it's in the compartment of the
   // parent global (which is the compartment reflector would have been in), or
   // in the null compartment if there is no parent global.  For other mBehavior
   // values, we're running on the worker thread and aCx is in whatever
   // compartment GetCurrentThreadJSContext() was in when nsIRunnable::Run() got
-  // called (XXXbz: Why is this a sane thing to be doing now that we have
-  // multiple globals per worker???).  If it wasn't in a compartment, aCx will
-  // be in either the debugger global's compartment or the worker's global's
-  // compartment depending on whether IsDebuggerRunnable() is true.
+  // called.  This is actually important for cases when a runnable spins a
+  // syncloop and wants everything that happens during the syncloop to happen in
+  // the compartment that runnable set up (which may, for example, be a debugger
+  // sandbox compartment!).  If aCx wasn't in a compartment to start with, aCx
+  // will be in either the debugger global's compartment or the worker's
+  // global's compartment depending on whether IsDebuggerRunnable() is true.
+  //
+  // Immediately after WorkerRun returns, the caller will assert that either it
+  // returns false or there is no exception pending on aCx.  Then it will report
+  // any pending exceptions on aCx.
   virtual bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0;
 
   // By default asserts that Run() (and WorkerRun()) were called on the correct
   // thread.  Also sends an asynchronous message to the ParentThread if the
   // busy count was previously modified in PreDispatch().
   //
   // The aCx passed here is the same one as was passed to WorkerRun and is
-  // still in the same compartment.  If aRunResult is false, any failures on
-  // aCx are reported.  Otherwise failures are left to linger on the JSContext
-  // and maim later code (XXXbz: Aiming to fix that in bug 1072144).
+  // still in the same compartment.  PostRun implementations must NOT leave an
+  // exception on the JSContext and must not run script, because the incoming
+  // JSContext may be in the null compartment.
   virtual void
   PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult);
 
   virtual bool
   DispatchInternal();
 
   // Calling Run() directly is not supported. Just call Dispatch() and
   // WorkerRun() will be called on the correct thread automatically.
--- a/dom/workers/test/sharedWorker_sharedWorker.js
+++ b/dom/workers/test/sharedWorker_sharedWorker.js
@@ -67,16 +67,21 @@ onconnect = function(event) {
   }
   if (!(event.ports[0] == event.source)) {
     throw new Error("'connect' event source property is incorrect!");
   }
   if (event.data) {
     throw new Error("'connect' event has data: " + event.data);
   }
 
+  // "".contains("") should trigger a warning in debug builds, but NOT fire
+  // error events at us.  If we ever actually remove contains() we'll need
+  // something else to test this case.
+  "".contains("");
+
   event.ports[0].onmessage = function(event) {
     if (!(event instanceof MessageEvent)) {
       throw new Error("'message' event is not a MessageEvent!");
     }
     if (!("ports" in event)) {
       throw new Error("'message' event doesn't have a 'ports' property!");
     }
     if (event.ports === null) {
--- a/dom/workers/test/test_sharedWorker.html
+++ b/dom/workers/test/test_sharedWorker.html
@@ -17,17 +17,17 @@
       <script class="testbody">
         "use strict";
 
         const href = window.location.href;
         const filename = "sharedWorker_sharedWorker.js";
         const sentMessage = "ping";
         const errorFilename = href.substring(0, href.lastIndexOf("/") + 1) +
                               filename;
-        const errorLine = 86;
+        const errorLine = 91;
         const errorColumn = 0;
 
         var worker = new SharedWorker(filename);
 
         ok(worker instanceof SharedWorker, "Got SharedWorker instance");
         ok(!("postMessage" in worker), "SharedWorker has no 'postMessage'");
         ok(worker.port instanceof MessagePort,
           "Shared worker has MessagePort");
--- a/editor/libeditor/nsHTMLEditRules.cpp
+++ b/editor/libeditor/nsHTMLEditRules.cpp
@@ -6470,17 +6470,20 @@ nsHTMLEditRules::ReturnInParagraph(Selec
 
   int32_t offset;
   nsCOMPtr<nsIDOMNode> parent = nsEditor::GetNodeLocation(aNode, &offset);
 
   NS_ENSURE_STATE(mHTMLEditor);
   bool doesCRCreateNewP = mHTMLEditor->GetReturnInParagraphCreatesNewParagraph();
 
   bool newBRneeded = false;
+  bool newSelNode = false;
   nsCOMPtr<nsIDOMNode> sibling;
+  nsCOMPtr<nsIDOMNode> selNode = aNode;
+  int32_t selOffset = aOffset;
 
   NS_ENSURE_STATE(mHTMLEditor);
   if (aNode == aPara && doesCRCreateNewP) {
     // we are at the edges of the block, newBRneeded not needed!
     sibling = aNode;
   } else if (mHTMLEditor->IsTextNode(aNode)) {
     nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(aNode);
     uint32_t strLength;
@@ -6508,58 +6511,65 @@ nsHTMLEditRules::ReturnInParagraph(Selec
         newBRneeded = true;
         offset++;
       }
     } else {
       if (doesCRCreateNewP) {
         nsCOMPtr<nsIDOMNode> tmp;
         res = mEditor->SplitNode(aNode, aOffset, getter_AddRefs(tmp));
         NS_ENSURE_SUCCESS(res, res);
-        aNode = tmp;
+        selNode = tmp;
       }
 
       newBRneeded = true;
       offset++;
     }
   } else {
     // not in a text node.
     // is there a BR prior to it?
-    nsCOMPtr<nsIDOMNode> nearNode, selNode = aNode;
+    nsCOMPtr<nsIDOMNode> nearNode;
     NS_ENSURE_STATE(mHTMLEditor);
     res = mHTMLEditor->GetPriorHTMLNode(aNode, aOffset, address_of(nearNode));
     NS_ENSURE_SUCCESS(res, res);
     NS_ENSURE_STATE(mHTMLEditor);
     if (!nearNode || !mHTMLEditor->IsVisBreak(nearNode) ||
         nsTextEditUtils::HasMozAttr(nearNode)) {
       // is there a BR after it?
       NS_ENSURE_STATE(mHTMLEditor);
       res = mHTMLEditor->GetNextHTMLNode(aNode, aOffset, address_of(nearNode));
       NS_ENSURE_SUCCESS(res, res);
       NS_ENSURE_STATE(mHTMLEditor);
       if (!nearNode || !mHTMLEditor->IsVisBreak(nearNode) ||
           nsTextEditUtils::HasMozAttr(nearNode)) {
         newBRneeded = true;
+        parent = aNode;
+        offset = 0;
+        newSelNode = true;
       }
     }
     if (!newBRneeded) {
       sibling = nearNode;
     }
   }
   if (newBRneeded) {
     // if CR does not create a new P, default to BR creation
     NS_ENSURE_TRUE(doesCRCreateNewP, NS_OK);
 
     nsCOMPtr<nsIDOMNode> brNode;
     NS_ENSURE_STATE(mHTMLEditor);
     res =  mHTMLEditor->CreateBR(parent, offset, address_of(brNode));
     sibling = brNode;
-  }
-  nsCOMPtr<nsIDOMNode> selNode = aNode;
+    if (newSelNode) {
+      // We split the parent after the br we've just inserted.
+      selNode = parent;
+      selOffset = 1;
+    }
+  }
   *aHandled = true;
-  return SplitParagraph(aPara, sibling, aSelection, address_of(selNode), &aOffset);
+  return SplitParagraph(aPara, sibling, aSelection, address_of(selNode), &selOffset);
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // SplitParagraph: split a paragraph at selection point, possibly deleting a br
 //
 nsresult
 nsHTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
                                 nsIDOMNode *aBRNode,
--- a/editor/libeditor/tests/chrome.ini
+++ b/editor/libeditor/tests/chrome.ini
@@ -25,16 +25,17 @@ skip-if = buildapp == 'mulet'
 [test_bug1102906.html]
 [test_bug1101392.html]
 [test_bug1140105.html]
 [test_bug1140617.xul]
 [test_bug1153237.html]
 [test_bug1154791.html]
 [test_bug1248128.html]
 [test_bug1248185.html]
+[test_bug1250010.html]
 [test_composition_event_created_in_chrome.html]
 [test_contenteditable_text_input_handling.html]
 [test_dragdrop.html]
 skip-if = buildapp == 'mulet'
 [test_htmleditor_keyevent_handling.html]
 [test_selection_move_commands.xul]
 [test_texteditor_keyevent_handling.html]
 skip-if = (debug && os=='win') || (os == 'linux') # Bug 1116205, leaks on windows debug, fails delete key on linux
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/test_bug1250010.html
@@ -0,0 +1,53 @@
+<!DOCTYPE>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1250010
+-->
+<head>
+  <title>Test for Bug 1250010</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+</head>
+<body>
+<div id="display">
+</div>
+
+<div id="content" contenteditable><p><b><font color="red">1234567890</font></b></p></div>
+
+<pre id="test">
+</pre>
+
+<script class="testbody" type="application/javascript">
+
+/** Test for Bug 1250010 **/
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+  var div = document.getElementById("content");
+  div.focus();
+  synthesizeMouseAtCenter(div, {});
+
+  var sel = window.getSelection();
+  var selRange = sel.getRangeAt(0);
+  is(selRange.endContainer.nodeName, "#text", "selection should be at the end of text node");
+  is(selRange.endOffset, 10, "offset should be 10");
+
+  synthesizeKey("VK_RETURN", {});
+  synthesizeKey("VK_RETURN", {});
+  synthesizeKey("b", {});
+  synthesizeKey("VK_UP", {});
+  synthesizeKey("a", {});
+
+  is(div.innerHTML, "<p><b><font color=\"red\">1234567890</font></b></p>" +
+                    "<p><b><font color=\"red\">a<br></font></b></p>" +
+                    "<p><b><font color=\"red\">b<br></font></b></p>",
+                    "unexpected HTML");
+
+  SimpleTest.finish();
+
+});
+
+</script>
+</body>
+
+</html>
--- a/embedding/browser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/nsDocShellTreeOwner.cpp
@@ -568,20 +568,23 @@ nsDocShellTreeOwner::GetDevicePixelsPerD
 
   *aScale = 1.0;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShellTreeOwner::SetPositionDesktopPix(int32_t aX, int32_t aY)
 {
-  // Added to nsIBaseWindow in bug 1247335;
-  // implement if a use-case is found.
-  NS_ASSERTION(false, "implement me!");
-  return NS_ERROR_NOT_IMPLEMENTED;
+  if (mWebBrowser) {
+    return mWebBrowser->SetPositionDesktopPix(aX, aY);
+  }
+
+  double scale = 1.0;
+  GetDevicePixelsPerDesktopPixel(&scale);
+  return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale));
 }
 
 NS_IMETHODIMP
 nsDocShellTreeOwner::SetPosition(int32_t aX, int32_t aY)
 {
   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   if (ownerWin) {
     return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION,
--- a/embedding/browser/nsWebBrowser.cpp
+++ b/embedding/browser/nsWebBrowser.cpp
@@ -1300,20 +1300,26 @@ nsWebBrowser::GetDevicePixelsPerDesktopP
   *aScale = mParentWidget ? mParentWidget->GetDesktopToDeviceScale().scale
                           : 1.0;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWebBrowser::SetPositionDesktopPix(int32_t aX, int32_t aY)
 {
-  // Added to nsIBaseWindow in bug 1247335;
-  // implement if a use-case is found.
-  NS_ASSERTION(false, "implement me!");
-  return NS_ERROR_NOT_IMPLEMENTED;
+  // XXX jfkthame
+  // It's not clear to me whether this will be fully correct across
+  // potential multi-screen, mixed-DPI configurations for all platforms;
+  // we might need to add code paths that make it possible to pass the
+  // desktop-pix parameters all the way through to the native widget,
+  // to avoid the risk of device-pixel coords mapping to the wrong
+  // display on OS X with mixed retina/non-retina screens.
+  double scale = 1.0;
+  GetDevicePixelsPerDesktopPixel(&scale);
+  return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale));
 }
 
 NS_IMETHODIMP
 nsWebBrowser::SetPosition(int32_t aX, int32_t aY)
 {
   int32_t cx = 0;
   int32_t cy = 0;
 
--- a/embedding/components/windowwatcher/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/nsWindowWatcher.cpp
@@ -1694,17 +1694,17 @@ nsWindowWatcher::CalculateChromeFlags(mo
   if (!(chromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME)) {
     // Remove the dependent flag if we're not opening as chrome
     chromeFlags &= ~nsIWebBrowserChrome::CHROME_DEPENDENT;
   }
 
   // Disable CHROME_OPENAS_DIALOG if the window is inside <iframe mozbrowser>.
   // It's up to the embedder to interpret what dialog=1 means.
   nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent);
-  if (docshell && docshell->GetIsInBrowserOrApp()) {
+  if (docshell && docshell->GetIsInMozBrowserOrApp()) {
     chromeFlags &= ~nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
   }
 
   return chromeFlags;
 }
 
 // static
 int32_t
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -118,20 +118,20 @@ GetPrincipalFromOrigin(const nsACString&
 
   nsCOMPtr<nsIPrincipal> principal = mozilla::BasePrincipal::CreateCodebasePrincipal(uri, attrs);
   principal.forget(aPrincipal);
   return NS_OK;
 }
 
 
 nsresult
-GetPrincipal(nsIURI* aURI, uint32_t aAppId, bool aIsInBrowserElement, nsIPrincipal** aPrincipal)
+GetPrincipal(nsIURI* aURI, uint32_t aAppId, bool aIsInIsolatedMozBrowserElement, nsIPrincipal** aPrincipal)
 {
   // TODO: Bug 1165267 - Use OriginAttributes for nsCookieService
-  mozilla::PrincipalOriginAttributes attrs(aAppId, aIsInBrowserElement);
+  mozilla::PrincipalOriginAttributes attrs(aAppId, aIsInIsolatedMozBrowserElement);
   nsCOMPtr<nsIPrincipal> principal = mozilla::BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
   NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
 
   principal.forget(aPrincipal);
   return NS_OK;
 }
 
 nsresult
@@ -358,17 +358,17 @@ private:
   nsCOMPtr<mozIStorageConnection> mDBConn;
   int64_t* mID;
 };
 
 
 nsresult
 UpgradeHostToOriginAndInsert(const nsACString& aHost, const nsAFlatCString& aType,
                              uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime,
-                             int64_t aModificationTime, uint32_t aAppId, bool aIsInBrowserElement,
+                             int64_t aModificationTime, uint32_t aAppId, bool aIsInIsolatedMozBrowserElement,
                              UpgradeHostToOriginHelper* aHelper)
 {
   if (aHost.EqualsLiteral("<file>")) {
     // We no longer support the magic host <file>
     NS_WARNING("The magic host <file> is no longer supported. "
                "It is being removed from the permissions database.");
     return NS_OK;
   }
@@ -382,17 +382,17 @@ UpgradeHostToOriginAndInsert(const nsACS
     // these useless database entries
     bool nullpScheme = false;
     if (NS_SUCCEEDED(uri->SchemeIs("moz-nullprincipal", &nullpScheme)) && nullpScheme) {
       NS_WARNING("A moz-nullprincipal: permission is being discarded.");
       return NS_OK;
     }
 
     nsCOMPtr<nsIPrincipal> principal;
-    rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal));
+    rv = GetPrincipal(uri, aAppId, aIsInIsolatedMozBrowserElement, getter_AddRefs(principal));
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoCString origin;
     rv = principal->GetOrigin(origin);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return aHelper->Insert(origin, aType, aPermission,
                            aExpireType, aExpireTime, aModificationTime);
@@ -490,17 +490,17 @@ UpgradeHostToOriginAndInsert(const nsACS
       if (NS_WARN_IF(NS_FAILED(rv))) continue;
 
       // Use the provided host - this URI may be for a subdomain, rather than the host we care about.
       rv = uri->SetHost(aHost);
       if (NS_WARN_IF(NS_FAILED(rv))) continue;
 
       // We now have a URI which we can make a nsIPrincipal out of
       nsCOMPtr<nsIPrincipal> principal;
-      rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal));
+      rv = GetPrincipal(uri, aAppId, aIsInIsolatedMozBrowserElement, getter_AddRefs(principal));
       if (NS_WARN_IF(NS_FAILED(rv))) continue;
 
       nsAutoCString origin;
       rv = principal->GetOrigin(origin);
       if (NS_WARN_IF(NS_FAILED(rv))) continue;
 
       // Ensure that we don't insert the same origin repeatedly
       if (insertedOrigins.Contains(origin)) {
@@ -536,30 +536,30 @@ UpgradeHostToOriginAndInsert(const nsACS
     } else {
       hostSegment.Assign(aHost);
     }
 
     // http:// URI default
     rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + hostSegment);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal));
+    rv = GetPrincipal(uri, aAppId, aIsInIsolatedMozBrowserElement, getter_AddRefs(principal));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = principal->GetOrigin(origin);
     NS_ENSURE_SUCCESS(rv, rv);
 
     aHelper->Insert(origin, aType, aPermission,
                     aExpireType, aExpireTime, aModificationTime);
 
     // https:// URI default
     rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("https://") + hostSegment);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = GetPrincipal(uri, aAppId, aIsInBrowserElement, getter_AddRefs(principal));
+    rv = GetPrincipal(uri, aAppId, aIsInIsolatedMozBrowserElement, getter_AddRefs(principal));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = principal->GetOrigin(origin);
     NS_ENSURE_SUCCESS(rv, rv);
 
     aHelper->Insert(origin, aType, aPermission,
                     aExpireType, aExpireTime, aModificationTime);
   }
--- a/extensions/cookie/test/channel_utils.js
+++ b/extensions/cookie/test/channel_utils.js
@@ -161,24 +161,24 @@ ChannelListener.prototype = {
     }
   }
 };
 
 /**
  * Class that implements nsILoadContext.  Use it as callbacks for channel when
  * test needs it.
  */
-function LoadContextCallback(appId, inBrowserElement, isPrivate, isContent) {
+function LoadContextCallback(appId, inIsolatedMozBrowser, isPrivate, isContent) {
   this.appId = appId;
-  this.isInBrowserElement = inBrowserElement;
+  this.isInIsolatedMozBrowserElement = inIsolatedMozBrowser;
   this.usePrivateBrowsing = isPrivate;
   this.isContent = isContent;
   this.originAttributes = {
     appId: appId,
-    inBrowser: inBrowserElement
+    inIsolatedMozBrowser: inIsolatedMozBrowser
   };
 }
 
 LoadContextCallback.prototype = {
   associatedWindow: null,
   topWindow : null,
   isAppOfType: function(appType) {
     throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
--- a/extensions/cookie/test/test_app_uninstall_permissions.html
+++ b/extensions/cookie/test/test_app_uninstall_permissions.html
@@ -75,17 +75,17 @@ function onInstall() {
   var attrs = {appId: testAppId};
   var principal = secMan.createCodebasePrincipal(ioService.newURI("http://www.example.com", null, null),
                                                  attrs);
 
   permManager.addFromPrincipal(principal, "foobar", Ci.nsIPermissionManager.ALLOW_ACTION);
   permManager.addFromPrincipal(principal, "foo", Ci.nsIPermissionManager.DENY_ACTION);
   permManager.addFromPrincipal(principal, "bar", Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION, 0);
 
-  attrs = {appId: testAppId, inBrowser: true};
+  attrs = {appId: testAppId, inIsolatedMozBrowser: true};
   principal = secMan.createCodebasePrincipal(ioService.newURI("http://www.example.com", null, null),
                                              attrs);
   permManager.addFromPrincipal(principal, "foobar", Ci.nsIPermissionManager.ALLOW_ACTION);
 
   attrs = {appId: testAppId};
   principal = secMan.createCodebasePrincipal(ioService.newURI("http://www.example.org", null, null),
                                              attrs);
   permManager.addFromPrincipal(principal, "foobar", Ci.nsIPermissionManager.ALLOW_ACTION);
--- a/extensions/cookie/test/unit/test_permmanager_cleardata.js
+++ b/extensions/cookie/test/unit/test_permmanager_cleardata.js
@@ -49,20 +49,20 @@ function run_test()
 {
   do_get_profile();
 
   pm = Cc["@mozilla.org/permissionmanager;1"]
          .getService(Ci.nsIPermissionManager);
 
   let entries = [
     { origin: 'http://example.com', originAttributes: { appId: 1 } },
-    { origin: 'http://example.com', originAttributes: { appId: 1, inBrowser: true } },
+    { origin: 'http://example.com', originAttributes: { appId: 1, inIsolatedMozBrowser: true } },
     { origin: 'http://example.com', originAttributes: {} },
     { origin: 'http://example.com', originAttributes: { appId: 2 } },
   ];
 
   // In that case, all permissions from app 1 should be removed but not the other ones.
   test(entries, getData({appId: 1}), [ pm.UNKNOWN_ACTION, pm.UNKNOWN_ACTION, pm.ALLOW_ACTION, pm.ALLOW_ACTION ]);
 
   // In that case, only the permissions of app 1 related to a browserElement should be removed.
   // All the other permissions should stay.
-  test(entries, getData({appId: 1, inBrowser: true}), [ pm.ALLOW_ACTION, pm.UNKNOWN_ACTION, pm.ALLOW_ACTION, pm.ALLOW_ACTION ]);
+  test(entries, getData({appId: 1, inIsolatedMozBrowser: true}), [ pm.ALLOW_ACTION, pm.UNKNOWN_ACTION, pm.ALLOW_ACTION, pm.ALLOW_ACTION ]);
 }
--- a/extensions/cookie/test/unit/test_permmanager_defaults.js
+++ b/extensions/cookie/test/unit/test_permmanager_defaults.js
@@ -51,17 +51,17 @@ add_task(function* do_test() {
            getService(Ci.nsIPermissionManager);
 
   // test the default permission was applied.
   let principal = Services.scriptSecurityManager.createCodebasePrincipal(TEST_ORIGIN, {});
   let principalHttps = Services.scriptSecurityManager.createCodebasePrincipal(TEST_ORIGIN_HTTPS, {});
   let principal2 = Services.scriptSecurityManager.createCodebasePrincipal(TEST_ORIGIN_2, {});
   let principal3 = Services.scriptSecurityManager.createCodebasePrincipal(TEST_ORIGIN_3, {});
 
-  let attrs = {appId: 1000, inBrowser: true};
+  let attrs = {appId: 1000, inIsolatedMozBrowser: true};
   let principal4 = Services.scriptSecurityManager.createCodebasePrincipal(TEST_ORIGIN, attrs);
   let principal5 = Services.scriptSecurityManager.createCodebasePrincipal(TEST_ORIGIN_3, attrs);
 
   do_check_eq(Ci.nsIPermissionManager.ALLOW_ACTION,
               pm.testPermissionFromPrincipal(principal, TEST_PERMISSION));
   do_check_eq(Ci.nsIPermissionManager.ALLOW_ACTION,
               pm.testPermissionFromPrincipal(principalHttps, TEST_PERMISSION));
   do_check_eq(Ci.nsIPermissionManager.ALLOW_ACTION,
--- a/extensions/cookie/test/unit/test_permmanager_matches.js
+++ b/extensions/cookie/test/unit/test_permmanager_matches.js
@@ -48,33 +48,33 @@ function run_test() {
   let attrs = {appId: 1000};
   let uri0_1000_n = secMan.createCodebasePrincipal(uri0, attrs);
   let uri1_1000_n = secMan.createCodebasePrincipal(uri1, attrs);
   let uri2_1000_n = secMan.createCodebasePrincipal(uri2, attrs);
   let uri3_1000_n = secMan.createCodebasePrincipal(uri3, attrs);
   let uri4_1000_n = secMan.createCodebasePrincipal(uri4, attrs);
   let uri5_1000_n = secMan.createCodebasePrincipal(uri5, attrs);
 
-  attrs = {appId: 1000, inBrowser: true};
+  attrs = {appId: 1000, inIsolatedMozBrowser: true};
   let uri0_1000_y = secMan.createCodebasePrincipal(uri0, attrs);
   let uri1_1000_y = secMan.createCodebasePrincipal(uri1, attrs);
   let uri2_1000_y = secMan.createCodebasePrincipal(uri2, attrs);
   let uri3_1000_y = secMan.createCodebasePrincipal(uri3, attrs);
   let uri4_1000_y = secMan.createCodebasePrincipal(uri4, attrs);
   let uri5_1000_y = secMan.createCodebasePrincipal(uri5, attrs);
 
   attrs = {appId: 2000};
   let uri0_2000_n = secMan.createCodebasePrincipal(uri0, attrs);
   let uri1_2000_n = secMan.createCodebasePrincipal(uri1, attrs);
   let uri2_2000_n = secMan.createCodebasePrincipal(uri2, attrs);
   let uri3_2000_n = secMan.createCodebasePrincipal(uri3, attrs);
   let uri4_2000_n = secMan.createCodebasePrincipal(uri4, attrs);
   let uri5_2000_n = secMan.createCodebasePrincipal(uri5, attrs);
 
-  attrs = {appId: 2000, inBrowser: true};
+  attrs = {appId: 2000, inIsolatedMozBrowser: true};
   let uri0_2000_y = secMan.createCodebasePrincipal(uri0, attrs);
   let uri1_2000_y = secMan.createCodebasePrincipal(uri1, attrs);
   let uri2_2000_y = secMan.createCodebasePrincipal(uri2, attrs);
   let uri3_2000_y = secMan.createCodebasePrincipal(uri3, attrs);
   let uri4_2000_y = secMan.createCodebasePrincipal(uri4, attrs);
   let uri5_2000_y = secMan.createCodebasePrincipal(uri5, attrs);
 
   pm.addFromPrincipal(uri0_n_n, "test/matches", pm.ALLOW_ACTION);
--- a/extensions/cookie/test/unit/test_permmanager_removeforapp.js
+++ b/extensions/cookie/test/unit/test_permmanager_removeforapp.js
@@ -1,19 +1,19 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function run_test() {
   // initialize the permission manager service
   let ssm = Services.scriptSecurityManager;
   let pm = Services.perms;
 
-  function mkPrin(uri, appId, inBrowser) {
+  function mkPrin(uri, appId, inIsolatedMozBrowser) {
     return ssm.createCodebasePrincipal(Services.io.newURI(uri, null, null),
-                                       {appId: appId, inBrowser: inBrowser});
+                                       {appId: appId, inIsolatedMozBrowser: inIsolatedMozBrowser});
   }
 
   function checkPerms(perms) {
     perms.forEach((perm) => {
       // Look up the expected permission
       do_check_eq(pm.getPermissionObject(mkPrin(perm[0],  perm[1], perm[2]),
                                          perm[3], true).capability,
                   perm[4], "Permission is expected in the permission database");
@@ -88,12 +88,12 @@ function run_test() {
 
     ['http://google.com',  1011, false, 'a', 1],
     ['http://google.com',  1011, false, 'b', 1],
     ['http://mozilla.com', 1011, false, 'b', 1],
     ['http://mozilla.com', 1011, false, 'a', 1],
   ];
 
   attrs = { appId: 1001,
-            inBrowser: true };
+            inIsolatedMozBrowser: true };
   pm.removePermissionsWithAttributes(JSON.stringify(attrs));
   checkPerms(remove_true_perms);
 }
--- a/gfx/layers/apz/test/reftest/reftest.list
+++ b/gfx/layers/apz/test/reftest/reftest.list
@@ -1,16 +1,16 @@
 # The following tests test the async positioning of the scrollbars.
 # Basic root-frame scrollbar with async scrolling
-skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-v.html async-scrollbar-1-v-ref.html
-skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-h.html async-scrollbar-1-h-ref.html
-skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-vh.html async-scrollbar-1-vh-ref.html
-skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-v-rtl.html async-scrollbar-1-v-rtl-ref.html
-skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-h-rtl.html async-scrollbar-1-h-rtl-ref.html
-skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-vh-rtl.html async-scrollbar-1-vh-rtl-ref.html
+fuzzy-if(Android,6,8) == async-scrollbar-1-v.html async-scrollbar-1-v-ref.html
+fuzzy-if(Android,6,8) == async-scrollbar-1-h.html async-scrollbar-1-h-ref.html
+fuzzy-if(Android,6,8) == async-scrollbar-1-vh.html async-scrollbar-1-vh-ref.html
+fuzzy-if(Android,6,8) == async-scrollbar-1-v-rtl.html async-scrollbar-1-v-rtl-ref.html
+fuzzy-if(Android,6,8) == async-scrollbar-1-h-rtl.html async-scrollbar-1-h-rtl-ref.html
+fuzzy-if(Android,6,8) == async-scrollbar-1-vh-rtl.html async-scrollbar-1-vh-rtl-ref.html
 
 # Different async zoom levels. Since the scrollthumb gets async-scaled in the
 # compositor, the border-radius ends of the scrollthumb are going to be a little
 # off, hence the fuzzy-if clauses.
 skip-if(!asyncZoom) fuzzy-if(B2G,98,82) == async-scrollbar-zoom-1.html async-scrollbar-zoom-1-ref.html
 skip-if(!asyncZoom) fuzzy-if(B2G,94,146) == async-scrollbar-zoom-2.html async-scrollbar-zoom-2-ref.html
 
 # Meta-viewport tag support
--- a/image/SVGDocumentWrapper.cpp
+++ b/image/SVGDocumentWrapper.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SVGDocumentWrapper.h"
 
+#include "mozilla/dom/DocumentTimeline.h"
 #include "mozilla/dom/Element.h"
 #include "nsICategoryManager.h"
 #include "nsIChannel.h"
 #include "nsIContentViewer.h"
 #include "nsIDocument.h"
 #include "nsIDocumentLoaderFactory.h"
 #include "nsIDOMSVGLength.h"
 #include "nsIHttpChannel.h"
@@ -110,18 +111,31 @@ SVGDocumentWrapper::FlushImageTransformI
   FlushLayout();
   mIgnoreInvalidation = false;
 }
 
 bool
 SVGDocumentWrapper::IsAnimated()
 {
   nsIDocument* doc = mViewer->GetDocument();
-  return doc && doc->HasAnimationController() &&
-    doc->GetAnimationController()->HasRegisteredAnimations();
+  if (!doc) {
+    return false;
+  }
+  if (doc->Timeline()->HasAnimations()) {
+    // CSS animations (technically HasAnimations() also checks for CSS
+    // transitions and Web animations but since SVG-as-an-image doesn't run
+    // script they will never run in the document that we wrap).
+    return true;
+  }
+  if (doc->HasAnimationController() &&
+      doc->GetAnimationController()->HasRegisteredAnimations()) {
+    // SMIL animations
+    return true;
+  }
+  return false;
 }
 
 void
 SVGDocumentWrapper::StartAnimation()
 {
   // Can be called for animated images during shutdown, after we've
   // already Observe()'d XPCOM shutdown and cleared out our mViewer pointer.
   if (!mViewer) {
--- a/ipc/glue/CrossProcessMutex.h
+++ b/ipc/glue/CrossProcessMutex.h
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_CrossProcessMutex_h
 #define mozilla_CrossProcessMutex_h
 
 #include "base/process.h"
 #include "mozilla/Mutex.h"
 
-#if defined(OS_LINUX) || defined(XP_DARWIN)
+#if !defined(OS_WIN) && !defined(OS_NETBSD) && !defined(OS_OPENBSD)
 #include <pthread.h>
 #include "SharedMemoryBasic.h"
 #include "mozilla/Atomics.h"
 #include "nsAutoPtr.h"
 #endif
 
 namespace IPC {
 template<typename T>
@@ -29,17 +29,17 @@ struct ParamTraits;
 //    properly locked and unlocked
 //
 // Using CrossProcessMutexAutoLock/CrossProcessMutexAutoUnlock is MUCH
 // preferred to making bare calls to CrossProcessMutex.Lock and Unlock.
 //
 namespace mozilla {
 #if defined(OS_WIN)
 typedef HANDLE CrossProcessMutexHandle;
-#elif defined(OS_LINUX) || defined(OS_MACOSX)
+#elif !defined(OS_NETBSD) && !defined(OS_OPENBSD)
 typedef mozilla::ipc::SharedMemoryBasic::Handle CrossProcessMutexHandle;
 #else
 // Stub for other platforms. We can't use uintptr_t here since different
 // processes could disagree on its size.
 typedef uintptr_t CrossProcessMutexHandle;
 #endif
 
 class CrossProcessMutex
@@ -95,17 +95,17 @@ private:
   friend struct IPC::ParamTraits<CrossProcessMutex>;
 
   CrossProcessMutex();
   CrossProcessMutex(const CrossProcessMutex&);
   CrossProcessMutex &operator=(const CrossProcessMutex&);
 
 #if defined(OS_WIN)
   HANDLE mMutex;
-#elif defined(OS_LINUX) || defined(OS_MACOSX)
+#elif !defined(OS_NETBSD) && !defined(OS_OPENBSD)
   RefPtr<mozilla::ipc::SharedMemoryBasic> mSharedBuffer;
   pthread_mutex_t* mMutex;
   mozilla::Atomic<int32_t>* mCount;
 #endif
 };
 
 typedef BaseAutoLock<CrossProcessMutex> CrossProcessMutexAutoLock;
 typedef BaseAutoUnlock<CrossProcessMutex> CrossProcessMutexAutoUnlock;
--- a/ipc/glue/moz.build
+++ b/ipc/glue/moz.build
@@ -56,17 +56,17 @@ else:
         'SharedMemory_posix.cpp',
         'Transport_posix.cpp',
     ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     SOURCES += [
         'CrossProcessMutex_windows.cpp',
     ]
-elif CONFIG['OS_ARCH'] in ('Linux', 'Darwin'):
+elif not CONFIG['OS_ARCH'] in ('NetBSD', 'OpenBSD'):
     UNIFIED_SOURCES += [
         'CrossProcessMutex_posix.cpp',
     ]
 else:
     UNIFIED_SOURCES += [
         'CrossProcessMutex_unimplemented.cpp',
     ]
 
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -7470,20 +7470,16 @@ Parser<ParseHandler>::expr(InHandling in
         return null();
     if (!matched)
         return pn;
 
     Node seq = handler.newCommaExpressionList(pn);
     if (!seq)
         return null();
     while (true) {
-        if (handler.isUnparenthesizedYieldExpression(pn)) {
-            report(ParseError, false, pn, JSMSG_BAD_YIELD_SYNTAX);
-            return null();
-        }
 
         pn = assignExpr(inHandling, yieldHandling, tripledotHandling);
         if (!pn)
             return null();
         handler.addList(seq, pn);
 
         if (!tokenStream.matchToken(&matched, TOK_COMMA))
             return null();
@@ -8452,26 +8448,16 @@ Parser<ParseHandler>::argumentList(Yield
         if (!argNode)
             return false;
         if (spread) {
             argNode = handler.newUnary(PNK_SPREAD, JSOP_NOP, begin, argNode);
             if (!argNode)
                 return false;
         }
 
-        if (handler.isUnparenthesizedYieldExpression(argNode)) {
-            TokenKind tt;
-            if (!tokenStream.peekToken(&tt))
-                return false;
-            if (tt == TOK_COMMA) {
-                report(ParseError, false, argNode, JSMSG_BAD_YIELD_SYNTAX);
-                return false;
-            }
-        }
-
         handler.addList(listNode, argNode);
 
         bool matched;
         if (!tokenStream.matchToken(&matched, TOK_COMMA))
             return false;
         if (!matched)
             break;
     }
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -112,24 +112,16 @@ class SyntaxParseHandler
         // Legacy generator expressions of the form |(expr for (...))| and
         // array comprehensions of the form |[expr for (...)]|) don't permit
         // |expr| to be a comma expression.  Thus we need this to treat
         // |(a(), b for (x in []))| as a syntax error and
         // |((a(), b) for (x in []))| as a generator that calls |a| and then
         // yields |b| each time it's resumed.
         NodeUnparenthesizedCommaExpr,
 
-        // Yield expressions currently (but not in ES6 -- a SpiderMonkey bug to
-        // fix) must generally be parenthesized.  (See the uses of
-        // isUnparenthesizedYieldExpression in Parser.cpp for the rare
-        // exceptions.)  Thus we need this to treat |yield 1, 2;| as a syntax
-        // error and |(yield 1), 2;| as a comma expression that will yield 1,
-        // then evaluate to 2.
-        NodeUnparenthesizedYieldExpr,
-
         // Assignment expressions in condition contexts could be typos for
         // equality checks.  (Think |if (x = y)| versus |if (x == y)|.)  Thus
         // we need this to treat |if (x = y)| as a possible typo and
         // |if ((x = y))| as a deliberate assignment within a condition.
         //
         // (Technically this isn't needed, as these are *only* extraWarnings
         // warnings, and parsing with that option disables syntax parsing.  But
         // it seems best to be consistent, and perhaps the syntax parser will
@@ -283,17 +275,17 @@ class SyntaxParseHandler
     Node newPosHolder(const TokenPos& pos) { return NodeGeneric; }
     Node newSuperBase(Node thisName, const TokenPos& pos) { return NodeSuperBase; }
 
     bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; }
     bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; }
     bool addShorthand(Node literal, Node name, Node expr) { return true; }
     bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
     bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; }
-    Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeUnparenthesizedYieldExpr; }
+    Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
     Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
 
     // Statements
 
     Node newStatementList(unsigned blockid, const TokenPos& pos) { return NodeGeneric; }
     void addStatementToList(Node list, Node stmt, ParseContext<SyntaxParseHandler>* pc) {}
     void addCaseStatementToList(Node list, Node stmt, ParseContext<SyntaxParseHandler>* pc) {}
     bool prependInitialYield(Node stmtList, Node gen) { return true; }
@@ -478,20 +470,16 @@ class SyntaxParseHandler
     Node newAssignment(ParseNodeKind kind, Node lhs, Node rhs,
                        ParseContext<SyntaxParseHandler>* pc, JSOp op)
     {
         if (kind == PNK_ASSIGN)
             return NodeUnparenthesizedAssignment;
         return newBinary(kind, lhs, rhs, op);
     }
 
-    bool isUnparenthesizedYieldExpression(Node node) {
-        return node == NodeUnparenthesizedYieldExpr;
-    }
-
     bool isUnparenthesizedCommaExpression(Node node) {
         return node == NodeUnparenthesizedCommaExpr;
     }
 
     bool isUnparenthesizedAssignment(Node node) {
         return node == NodeUnparenthesizedAssignment;
     }
 
@@ -529,17 +517,16 @@ class SyntaxParseHandler
             return NodeParenthesizedArray;
         if (node == NodeUnparenthesizedObject)
             return NodeParenthesizedObject;
 
         // Other nodes need not be recognizable after parenthesization; convert
         // them to a generic node.
         if (node == NodeUnparenthesizedString ||
             node == NodeUnparenthesizedCommaExpr ||
-            node == NodeUnparenthesizedYieldExpr ||
             node == NodeUnparenthesizedAssignment)
         {
             return NodeGeneric;
         }
 
         // In all other cases, the parenthesized form of |node| is equivalent
         // to the unparenthesized form: return |node| unchanged.
         return node;
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -2105,16 +2105,17 @@ js::TenuringTracer::insertIntoFixupList(
     tail = &entry->nextRef();
     *tail = nullptr;
 }
 
 JSObject*
 js::TenuringTracer::moveToTenured(JSObject* src)
 {
     MOZ_ASSERT(IsInsideNursery(src));
+    MOZ_ASSERT(!src->zone()->usedByExclusiveThread);
 
     AllocKind dstKind = src->allocKindForTenure(nursery());
     Zone* zone = src->zone();
 
     TenuredCell* t = zone->arenas.allocateFromFreeList(dstKind, Arena::thingSize(dstKind));
     if (!t) {
         zone->arenas.checkEmptyFreeList(dstKind);
         AutoMaybeStartBackgroundAllocation maybeStartBackgroundAllocation;
--- a/js/src/jit/MacroAssembler-inl.h
+++ b/js/src/jit/MacroAssembler-inl.h
@@ -505,16 +505,24 @@ void
 MacroAssembler::branchTestNeedsIncrementalBarrier(Condition cond, Label* label)
 {
     MOZ_ASSERT(cond == Zero || cond == NonZero);
     CompileZone* zone = GetJitContext()->compartment->zone();
     AbsoluteAddress needsBarrierAddr(zone->addressOfNeedsIncrementalBarrier());
     branchTest32(cond, needsBarrierAddr, Imm32(0x1), label);
 }
 
+void
+MacroAssembler::branchTestMagicValue(Condition cond, const ValueOperand& val, JSWhyMagic why,
+                                     Label* label)
+{
+    MOZ_ASSERT(cond == Equal || cond == NotEqual);
+    branchTestValue(cond, val, MagicValue(why), label);
+}
+
 //}}} check_macroassembler_style
 // ===============================================================
 
 #ifndef JS_CODEGEN_ARM64
 
 template <typename T>
 void
 MacroAssembler::branchTestStackPtr(Condition cond, T t, Label* label)
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -916,27 +916,148 @@ class MacroAssembler : public MacroAssem
     // might actually be that type.
     void branchEqualTypeIfNeeded(MIRType type, MDefinition* maybeDef, Register tag, Label* label);
 
     template <typename T>
     inline void branchKey(Condition cond, const T& length, const Int32Key& key, Label* label);
 
     inline void branchTestNeedsIncrementalBarrier(Condition cond, Label* label);
 
-    inline void branchTestInt32(Condition cond, Register tag, Label* label)
-        DEFINED_ON(arm, arm64, mips_shared, x86, x64);
-    inline void branchTestInt32(Condition cond, const Address& address, Label* label)
-        DEFINED_ON(arm, arm64, mips_shared, x86, x64);
-    inline void branchTestInt32(Condition cond, const BaseIndex& address, Label* label)
-        DEFINED_ON(arm, arm64, mips_shared, x86, x64);
-    inline void branchTestInt32(Condition cond, const ValueOperand& src, Label* label) PER_ARCH;
+    // Perform a type-test on a tag of a Value (32bits boxing), or the tagged
+    // value (64bits boxing).
+    inline void branchTestUndefined(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
+    inline void branchTestInt32(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
+    inline void branchTestDouble(Condition cond, Register tag, Label* label)
+        DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
+    inline void branchTestNumber(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
+    inline void branchTestBoolean(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
+    inline void branchTestString(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
+    inline void branchTestSymbol(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
+    inline void branchTestNull(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
+    inline void branchTestObject(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
+    inline void branchTestPrimitive(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
+    inline void branchTestMagic(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
+
+    // Perform a type-test on a Value, addressed by Address or BaseIndex, or
+    // loaded into ValueOperand.
+    // BaseIndex and ValueOperand variants clobber the ScratchReg on x64.
+    // All Variants clobber the ScratchReg on arm64.
+    inline void branchTestUndefined(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestUndefined(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestUndefined(Condition cond, const ValueOperand& value, Label* label)
+        DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
+
+    inline void branchTestInt32(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestInt32(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestInt32(Condition cond, const ValueOperand& value, Label* label)
+        DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
+
+    inline void branchTestDouble(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestDouble(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestDouble(Condition cond, const ValueOperand& value, Label* label)
+        DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
+
+    inline void branchTestNumber(Condition cond, const ValueOperand& value, Label* label)
+        DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
+
+    inline void branchTestBoolean(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestBoolean(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestBoolean(Condition cond, const ValueOperand& value, Label* label)
+        DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
+
+    inline void branchTestString(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestString(Condition cond, const ValueOperand& value, Label* label)
+        DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
+
+    inline void branchTestSymbol(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestSymbol(Condition cond, const ValueOperand& value, Label* label)
+        DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
+
+    inline void branchTestNull(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestNull(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestNull(Condition cond, const ValueOperand& value, Label* label)
+        DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
+
+    // Clobbers the ScratchReg on x64.
+    inline void branchTestObject(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestObject(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestObject(Condition cond, const ValueOperand& value, Label* label)
+        DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
+
+    inline void branchTestGCThing(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestGCThing(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
 
-    inline void branchTestInt32Truthy(bool truthy, const ValueOperand& operand, Label* label)
+    inline void branchTestPrimitive(Condition cond, const ValueOperand& value, Label* label)
+        DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
+
+    inline void branchTestMagic(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
+    inline void branchTestMagic(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
+    template <class L>
+    inline void branchTestMagic(Condition cond, const ValueOperand& value, L label)
+        DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
+
+    inline void branchTestMagicValue(Condition cond, const ValueOperand& val, JSWhyMagic why,
+                                     Label* label);
+
+    void branchTestValue(Condition cond, const ValueOperand& lhs,
+                         const Value& rhs, Label* label) PER_ARCH;
+
+    // Checks if given Value is evaluated to true or false in a condition.
+    // The type of the value should match the type of the method.
+    inline void branchTestInt32Truthy(bool truthy, const ValueOperand& value, Label* label)
+        DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
+    inline void branchTestDoubleTruthy(bool truthy, FloatRegister reg, Label* label) PER_SHARED_ARCH;
+    inline void branchTestBooleanTruthy(bool truthy, const ValueOperand& value, Label* label) PER_ARCH;
+    inline void branchTestStringTruthy(bool truthy, const ValueOperand& value, Label* label)
         DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
 
+  private:
+
+    // Implementation for branch* methods.
+    template <typename T, typename S>
+    inline void branchPtrImpl(Condition cond, const T& lhs, const S& rhs, Label* label)
+        DEFINED_ON(x86_shared);
+
+    template <typename T>
+    inline void branchTestUndefinedImpl(Condition cond, const T& t, Label* label)
+        DEFINED_ON(arm, arm64, x86_shared);
+    template <typename T>
+    inline void branchTestInt32Impl(Condition cond, const T& t, Label* label)
+        DEFINED_ON(arm, arm64, x86_shared);
+    template <typename T>
+    inline void branchTestDoubleImpl(Condition cond, const T& t, Label* label)
+        DEFINED_ON(arm, arm64, x86_shared);
+    template <typename T>
+    inline void branchTestNumberImpl(Condition cond, const T& t, Label* label)
+        DEFINED_ON(arm, arm64, x86_shared);
+    template <typename T>
+    inline void branchTestBooleanImpl(Condition cond, const T& t, Label* label)
+        DEFINED_ON(arm, arm64, x86_shared);
+    template <typename T>
+    inline void branchTestStringImpl(Condition cond, const T& t, Label* label)
+        DEFINED_ON(arm, arm64, x86_shared);
+    template <typename T>
+    inline void branchTestSymbolImpl(Condition cond, const T& t, Label* label)
+        DEFINED_ON(arm, arm64, x86_shared);
+    template <typename T>
+    inline void branchTestNullImpl(Condition cond, const T& t, Label* label)
+        DEFINED_ON(arm, arm64, x86_shared);
+    template <typename T>
+    inline void branchTestObjectImpl(Condition cond, const T& t, Label* label)
+        DEFINED_ON(arm, arm64, x86_shared);
+    template <typename T>
+    inline void branchTestGCThingImpl(Condition cond, const T& t, Label* label)
+        DEFINED_ON(arm, arm64, x86_shared);
+    template <typename T>
+    inline void branchTestPrimitiveImpl(Condition cond, const T& t, Label* label)
+        DEFINED_ON(arm, arm64, x86_shared);
+    template <typename T, class L>
+    inline void branchTestMagicImpl(Condition cond, const T& t, L label)
+        DEFINED_ON(arm, arm64, x86_shared);
+
     //}}} check_macroassembler_style
   public:
 
     // Emits a test of a value against all types in a TypeSet. A scratch
     // register is required.
     template <typename Source>
     void guardTypeSet(const Source& address, const TypeSet* types, BarrierKind kind, Register scratch, Label* miss);
 
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -795,16 +795,48 @@ MacroAssembler::branchTest64(Condition c
         ma_orr(lhs.low, lhs.high, ScratchRegister);
         branchTestPtr(cond, ScratchRegister, ScratchRegister, label);
     } else {
         MOZ_CRASH("Unsupported condition");
     }
 }
 
 void
+MacroAssembler::branchTestUndefined(Condition cond, Register tag, Label* label)
+{
+    branchTestUndefinedImpl(cond, tag, label);
+}
+
+void
+MacroAssembler::branchTestUndefined(Condition cond, const Address& address, Label* label)
+{
+    branchTestUndefinedImpl(cond, address, label);
+}
+
+void
+MacroAssembler::branchTestUndefined(Condition cond, const BaseIndex& address, Label* label)
+{
+    branchTestUndefinedImpl(cond, address, label);
+}
+
+void
+MacroAssembler::branchTestUndefined(Condition cond, const ValueOperand& value, Label* label)
+{
+    branchTestUndefinedImpl(cond, value, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branchTestUndefinedImpl(Condition cond, const T& t, Label* label)
+{
+    Condition c = testUndefined(cond, t);
+    ma_b(label, c);
+}
+
+void
 MacroAssembler::branchTestInt32(Condition cond, Register tag, Label* label)
 {
     branchTestInt32Impl(cond, tag, label);
 }
 
 void
 MacroAssembler::branchTestInt32(Condition cond, const Address& address, Label* label)
 {
@@ -813,28 +845,330 @@ MacroAssembler::branchTestInt32(Conditio
 
 void
 MacroAssembler::branchTestInt32(Condition cond, const BaseIndex& address, Label* label)
 {
     branchTestInt32Impl(cond, address, label);
 }
 
 void
-MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& src, Label* label)
+MacroAssembler::branchTestInt32(Condition cond, const ValueOperand& value, Label* label)
+{
+    branchTestInt32Impl(cond, value, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branchTestInt32Impl(Condition cond, const T& t, Label* label)
+{
+    Condition c = testInt32(cond, t);
+    ma_b(label, c);
+}
+
+void
+MacroAssembler::branchTestInt32Truthy(bool truthy, const ValueOperand& value, Label* label)
+{
+    Condition c = testInt32Truthy(truthy, value);
+    ma_b(label, c);
+}
+
+void
+MacroAssembler::branchTestDouble(Condition cond, Register tag, Label* label)
+{
+    branchTestDoubleImpl(cond, tag, label);
+}
+
+void
+MacroAssembler::branchTestDouble(Condition cond, const Address& address, Label* label)
+{
+    branchTestDoubleImpl(cond, address, label);
+}
+
+void
+MacroAssembler::branchTestDouble(Condition cond, const BaseIndex& address, Label* label)
+{
+    branchTestDoubleImpl(cond, address, label);
+}
+
+void
+MacroAssembler::branchTestDouble(Condition cond, const ValueOperand& value, Label* label)
+{
+    branchTestDoubleImpl(cond, value, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branchTestDoubleImpl(Condition cond, const T& t, Label* label)
+{
+    Condition c = testDouble(cond, t);
+    ma_b(label, c);
+}
+
+void
+MacroAssembler::branchTestDoubleTruthy(bool truthy, FloatRegister reg, Label* label)
+{
+    Condition c = testDoubleTruthy(truthy, reg);
+    ma_b(label, c);
+}
+
+void
+MacroAssembler::branchTestNumber(Condition cond, Register tag, Label* label)
+{
+    branchTestNumberImpl(cond, tag, label);
+}
+
+void
+MacroAssembler::branchTestNumber(Condition cond, const ValueOperand& value, Label* label)
+{
+    branchTestNumberImpl(cond, value, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branchTestNumberImpl(Condition cond, const T& t, Label* label)
 {
-    branchTestInt32Impl(cond, src, label);
+    cond = testNumber(cond, t);
+    ma_b(label, cond);
+}
+
+void
+MacroAssembler::branchTestBoolean(Condition cond, Register tag, Label* label)
+{
+    branchTestBooleanImpl(cond, tag, label);
+}
+
+void
+MacroAssembler::branchTestBoolean(Condition cond, const Address& address, Label* label)
+{
+    branchTestBooleanImpl(cond, address, label);
+}
+
+void
+MacroAssembler::branchTestBoolean(Condition cond, const BaseIndex& address, Label* label)
+{
+    branchTestBooleanImpl(cond, address, label);
+}
+
+void
+MacroAssembler::branchTestBoolean(Condition cond, const ValueOperand& value, Label* label)
+{
+    branchTestBooleanImpl(cond, value, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branchTestBooleanImpl(Condition cond, const T& t, Label* label)
+{
+    Condition c = testBoolean(cond, t);
+    ma_b(label, c);
+}
+
+void
+MacroAssembler::branchTestBooleanTruthy(bool truthy, const ValueOperand& value, Label* label)
+{
+    Condition c = testBooleanTruthy(truthy, value);
+    ma_b(label, c);
+}
+
+void
+MacroAssembler::branchTestString(Condition cond, Register tag, Label* label)
+{
+    branchTestStringImpl(cond, tag, label);
+}
+
+void
+MacroAssembler::branchTestString(Condition cond, const BaseIndex& address, Label* label)
+{
+    branchTestStringImpl(cond, address, label);
+}
+
+void
+MacroAssembler::branchTestString(Condition cond, const ValueOperand& value, Label* label)
+{
+    branchTestStringImpl(cond, value, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branchTestStringImpl(Condition cond, const T& t, Label* label)
+{
+    Condition c = testString(cond, t);
+    ma_b(label, c);
+}
+
+void
+MacroAssembler::branchTestStringTruthy(bool truthy, const ValueOperand& value, Label* label)
+{
+    Condition c = testStringTruthy(truthy, value);
+    ma_b(label, c);
 }
 
 void
-MacroAssembler::branchTestInt32Truthy(bool truthy, const ValueOperand& operand, Label* label)
+MacroAssembler::branchTestSymbol(Condition cond, Register tag, Label* label)
+{
+    branchTestSymbolImpl(cond, tag, label);
+}
+
+void
+MacroAssembler::branchTestSymbol(Condition cond, const BaseIndex& address, Label* label)
+{
+    branchTestSymbolImpl(cond, address, label);
+}
+
+void
+MacroAssembler::branchTestSymbol(Condition cond, const ValueOperand& value, Label* label)
+{
+    branchTestSymbolImpl(cond, value, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branchTestSymbolImpl(Condition cond, const T& t, Label* label)
+{
+    Condition c = testSymbol(cond, t);
+    ma_b(label, c);
+}
+
+void
+MacroAssembler::branchTestNull(Condition cond, Register tag, Label* label)
+{
+    branchTestNullImpl(cond, tag, label);
+}
+
+void
+MacroAssembler::branchTestNull(Condition cond, const Address& address, Label* label)
+{
+    branchTestNullImpl(cond, address, label);
+}
+
+void
+MacroAssembler::branchTestNull(Condition cond, const BaseIndex& address, Label* label)
+{
+    branchTestNullImpl(cond, address, label);
+}
+
+void
+MacroAssembler::branchTestNull(Condition cond, const ValueOperand& value, Label* label)
+{
+    branchTestNullImpl(cond, value, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branchTestNullImpl(Condition cond, const T& t, Label* label)
+{
+    Condition c = testNull(cond, t);
+    ma_b(label, c);
+}
+
+void
+MacroAssembler::branchTestObject(Condition cond, Register tag, Label* label)
+{
+    branchTestObjectImpl(cond, tag, label);
+}
+
+void
+MacroAssembler::branchTestObject(Condition cond, const Address& address, Label* label)
+{
+    branchTestObjectImpl(cond, address, label);
+}
+
+void
+MacroAssembler::branchTestObject(Condition cond, const BaseIndex& address, Label* label)
+{
+    branchTestObjectImpl(cond, address, label);
+}
+
+void
+MacroAssembler::branchTestObject(Condition cond, const ValueOperand& value, Label* label)
 {
-    Condition c = testInt32Truthy(truthy, operand);
+    branchTestObjectImpl(cond, value, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branchTestObjectImpl(Condition cond, const T& t, Label* label)
+{
+    Condition c = testObject(cond, t);
+    ma_b(label, c);
+}
+
+void
+MacroAssembler::branchTestGCThing(Condition cond, const Address& address, Label* label)
+{
+    branchTestGCThingImpl(cond, address, label);
+}
+
+void
+MacroAssembler::branchTestGCThing(Condition cond, const BaseIndex& address, Label* label)
+{
+    branchTestGCThingImpl(cond, address, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branchTestGCThingImpl(Condition cond, const T& t, Label* label)
+{
+    Condition c = testGCThing(cond, t);
     ma_b(label, c);
 }
 
+void
+MacroAssembler::branchTestPrimitive(Condition cond, Register tag, Label* label)
+{
+    branchTestPrimitiveImpl(cond, tag, label);
+}
+
+void
+MacroAssembler::branchTestPrimitive(Condition cond, const ValueOperand& value, Label* label)
+{
+    branchTestPrimitiveImpl(cond, value, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branchTestPrimitiveImpl(Condition cond, const T& t, Label* label)
+{
+    Condition c = testPrimitive(cond, t);
+    ma_b(label, c);
+}
+
+void
+MacroAssembler::branchTestMagic(Condition cond, Register tag, Label* label)
+{
+    branchTestMagicImpl(cond, tag, label);
+}
+
+void
+MacroAssembler::branchTestMagic(Condition cond, const Address& address, Label* label)
+{
+    branchTestMagicImpl(cond, address, label);
+}
+
+void
+MacroAssembler::branchTestMagic(Condition cond, const BaseIndex& address, Label* label)
+{
+    branchTestMagicImpl(cond, address, label);
+}
+
+template <class L>
+void
+MacroAssembler::branchTestMagic(Condition cond, const ValueOperand& value, L label)
+{
+    branchTestMagicImpl(cond, value, label);
+}
+
+template <typename T, class L>
+void
+MacroAssembler::branchTestMagicImpl(Condition cond, const T& t, L label)
+{
+    cond = testMagic(cond, t);
+    ma_b(label, cond);
+}
+
 //}}} check_macroassembler_style
 // ===============================================================
 
 void
 MacroAssemblerARMCompat::incrementInt32Value(const Address& addr)
 {
     asMasm().add32(Imm32(1), ToPayload(addr));
 }
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -2848,63 +2848,16 @@ MacroAssemblerARMCompat::testGCThing(Con
 {
     MOZ_ASSERT(cond == Equal || cond == NotEqual);
     ScratchRegisterScope scratch(asMasm());
     extractTag(address, scratch);
     ma_cmp(scratch, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
     return cond == Equal ? AboveOrEqual : Below;
 }
 
-void
-MacroAssemblerARMCompat::branchTestValue(Condition cond, const ValueOperand& value,
-                                         const Value& v, Label* label)
-{
-    // If cond == NotEqual, branch when a.payload != b.payload || a.tag !=
-    // b.tag. If the payloads are equal, compare the tags. If the payloads are
-    // not equal, short circuit true (NotEqual).
-    //
-    // If cand == Equal, branch when a.payload == b.payload && a.tag == b.tag.
-    // If the payloads are equal, compare the tags. If the payloads are not