Backed out changeset a6a847452dbf (bug 802366)
authorJustin Lebar <justin.lebar@gmail.com>
Tue, 30 Oct 2012 21:36:29 -0400
changeset 111982 ea03279161147d8204df22990e25a477fdf58fa4
parent 111981 9c357f7836b4115fce80bb9e55c75a54dfff2af4
child 111983 039573154dcf70dfcfe4caca559a0846cff04cd4
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
bugs802366
milestone19.0a1
backs outa6a847452dbff26ab4dc366102e5af67522cc09e
Backed out changeset a6a847452dbf (bug 802366)
content/base/src/nsDocument.cpp
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameLoader.h
content/base/src/nsInProcessTabChildGlobal.cpp
content/base/src/nsInProcessTabChildGlobal.h
content/events/src/nsEventStateManager.cpp
content/html/content/src/nsGenericHTMLFrameElement.cpp
docshell/base/nsDSURIContentListener.cpp
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsIDocShell.idl
dom/base/nsGlobalWindow.cpp
dom/interfaces/html/nsIMozBrowserFrame.idl
dom/ipc/AppProcessPermissions.cpp
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
embedding/components/windowwatcher/src/nsWindowWatcher.cpp
xpfe/appshell/src/nsContentTreeOwner.cpp
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -8354,17 +8354,17 @@ HasCrossProcessParent(nsIDocument* aDocu
   nsPIDOMWindow* win = aDocument->GetWindow();
   if (!win) {
     return false;
   }
   nsCOMPtr<nsIDocShell> docShell = win->GetDocShell();
   if (!docShell) {
     return false;
   }
-  return docShell->GetIsBrowserOrApp();
+  return docShell->GetIsContentBoundary();
 }
 
 static bool
 ResetFullScreen(nsIDocument* aDocument, void* aData)
 {
   if (aDocument->IsFullScreenDoc()) {
     static_cast<nsDocument*>(aDocument)->CleanupFullscreenState();
     NS_ASSERTION(!aDocument->IsFullScreenDoc(), "Should reset full-screen");
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -939,17 +939,17 @@ nsFrameLoader::ShowRemoteFrame(const nsI
     }
 
     mRemoteBrowser->Show(size);
     mRemoteBrowserShown = true;
 
     EnsureMessageManager();
 
     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
-    if (OwnerIsBrowserOrAppFrame() && os && !mRemoteBrowserInitialized) {
+    if (OwnerIsBrowserFrame() && os && !mRemoteBrowserInitialized) {
       os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
                           "remote-browser-frame-shown", NULL);
       mRemoteBrowserInitialized = true;
     }
   } else {
     nsRect dimensions;
     NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), false);
     mRemoteBrowser->UpdateDimensions(dimensions, size);
@@ -1388,119 +1388,72 @@ nsFrameLoader::SetOwnerContent(Element* 
   }
   mOwnerContent = aContent;
   if (RenderFrameParent* rfp = GetCurrentRemoteFrame()) {
     rfp->OwnerContentChanged(aContent);
   }
 }
 
 bool
-nsFrameLoader::OwnerIsBrowserOrAppFrame()
+nsFrameLoader::OwnerIsBrowserFrame()
 {
   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
-  return browserFrame ? browserFrame->GetReallyIsBrowserOrApp() : false;
+  bool isBrowser = false;
+  if (browserFrame) {
+    browserFrame->GetReallyIsBrowser(&isBrowser);
+  }
+  return isBrowser;
 }
 
 bool
 nsFrameLoader::OwnerIsAppFrame()
 {
   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
-  return browserFrame ? browserFrame->GetReallyIsApp() : false;
-}
-
-bool
-nsFrameLoader::OwnerIsBrowserFrame()
-{
-  return OwnerIsBrowserOrAppFrame() && !OwnerIsAppFrame();
+  bool isApp = false;
+  if (browserFrame) {
+    browserFrame->GetReallyIsApp(&isApp);
+  }
+  return isApp;
 }
 
 void
 nsFrameLoader::GetOwnerAppManifestURL(nsAString& aOut)
 {
   aOut.Truncate();
   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
   if (browserFrame) {
     browserFrame->GetAppManifestURL(aOut);
   }
 }
 
-already_AddRefed<mozIApplication>
-nsFrameLoader::GetOwnApp()
-{
-  nsAutoString manifest;
-  GetOwnerAppManifestURL(manifest);
-  if (manifest.IsEmpty()) {
-    return nullptr;
-  }
-
-  nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(appsService, nullptr);
-
-  nsCOMPtr<mozIDOMApplication> domApp;
-  appsService->GetAppByManifestURL(manifest, getter_AddRefs(domApp));
-
-  nsCOMPtr<mozIApplication> app = do_QueryInterface(domApp);
-  MOZ_ASSERT_IF(domApp, app);
-  return app.forget();
-}
-
-already_AddRefed<mozIApplication>
-nsFrameLoader::GetOwnOrContainingApp()
-{
-  nsCOMPtr<mozIApplication> app = GetOwnApp();
-  if (app) {
-    return app.forget();
-  }
-
-  // See if our owner content's principal has an associated app.
-  uint32_t appId = mOwnerContent->NodePrincipal()->GetAppId();
-  MOZ_ASSERT(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
-
-  if (appId == nsIScriptSecurityManager::NO_APP_ID ||
-      appId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
-    return nullptr;
-  }
-
-  nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(appsService, nullptr);
-
-  nsCOMPtr<mozIDOMApplication> domApp;
-  appsService->GetAppByLocalId(appId, getter_AddRefs(domApp));
-  MOZ_ASSERT(domApp);
-
-  app = do_QueryInterface(domApp);
-  MOZ_ASSERT_IF(domApp, app);
-  return app.forget();
-}
-
 bool
 nsFrameLoader::ShouldUseRemoteProcess()
 {
   if (PR_GetEnv("MOZ_DISABLE_OOP_TABS") ||
       Preferences::GetBool("dom.ipc.tabs.disabled", false)) {
     return false;
   }
 
   // If we're inside a content process, don't use a remote process for this
   // frame; it won't work properly until bug 761935 is fixed.
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     return false;
   }
 
   // If we're an <iframe mozbrowser> and we don't have a "remote" attribute,
   // fall back to the default.
-  if (OwnerIsBrowserOrAppFrame() &&
+  if (OwnerIsBrowserFrame() &&
       !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 (OwnerIsBrowserFrame() ||
           mOwnerContent->GetNameSpaceID() == kNameSpaceID_XUL) &&
          mOwnerContent->AttrValueIs(kNameSpaceID_None,
                                     nsGkAtoms::Remote,
                                     nsGkAtoms::_true,
                                     eCaseMatters);
 }
 
 nsresult
@@ -1537,16 +1490,34 @@ nsFrameLoader::MaybeCreateDocShell()
     doc->GetContainer();
   nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_QueryInterface(container);
   NS_ENSURE_STATE(parentAsWebNav);
 
   // Create the docshell...
   mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
 
+  if (OwnerIsBrowserFrame()) {
+    nsAutoString manifest;
+    GetOwnerAppManifestURL(manifest);
+    if (!manifest.IsEmpty()) {
+      nsCOMPtr<nsIAppsService> appsService =
+        do_GetService(APPS_SERVICE_CONTRACTID);
+      if (!appsService) {
+        NS_ERROR("Apps Service is not available!");
+        return NS_ERROR_FAILURE;
+      }
+
+      uint32_t appId;
+      appsService->GetAppLocalIdByManifestURL(manifest, &appId);
+
+      mDocShell->SetAppId(appId);
+    }
+  }
+
   if (!mNetworkCreated) {
     nsCOMPtr<nsIDocShellHistory> history = do_QueryInterface(mDocShell);
     if (history) {
       history->SetCreatedDynamically(true);
     }
   }
 
   // Get the frame name and tell the docshell about it.
@@ -1638,44 +1609,19 @@ nsFrameLoader::MaybeCreateDocShell()
   if (NS_FAILED(base_win->Create()) || !win_private) {
     // Do not call Destroy() here. See bug 472312.
     NS_WARNING("Something wrong when creating the docshell for a frameloader!");
     return NS_ERROR_FAILURE;
   }
 
   EnsureMessageManager();
 
-  if (OwnerIsAppFrame()) {
-    // You can't be both an app and a browser frame.
-    MOZ_ASSERT(!OwnerIsBrowserFrame());
-
-    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()) {
+    mDocShell->SetIsBrowserElement();
 
-  if (OwnerIsBrowserFrame()) {
-    // You can't be both a browser and an app frame.
-    MOZ_ASSERT(!OwnerIsAppFrame());
-
-    nsCOMPtr<mozIApplication> containingApp = GetOwnOrContainingApp();
-    uint32_t containingAppId = nsIScriptSecurityManager::NO_APP_ID;
-    if (containingApp) {
-      NS_ENSURE_SUCCESS(containingApp->GetLocalId(&containingAppId),
-                        NS_ERROR_FAILURE);
-    }
-    mDocShell->SetIsBrowserInsideApp(containingAppId);
-  }
-
-  if (OwnerIsBrowserOrAppFrame()) {
     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
     if (os) {
       os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
                           "in-process-browser-or-app-frame-shown", NULL);
     }
 
     if (mMessageManager) {
       mMessageManager->LoadFrameScript(
@@ -1997,17 +1943,17 @@ nsFrameLoader::TryRemoteBrowser()
 
   if (!parentAsWebNav) {
     return false;
   }
 
   nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsWebNav));
 
   // <iframe mozbrowser> gets to skip these checks.
-  if (!OwnerIsBrowserOrAppFrame()) {
+  if (!OwnerIsBrowserFrame()) {
     int32_t parentType;
     parentAsItem->GetItemType(&parentType);
 
     if (parentType != nsIDocShellTreeItem::typeChrome) {
       return false;
     }
 
     if (!mOwnerContent->IsXUL()) {
@@ -2033,28 +1979,45 @@ nsFrameLoader::TryRemoteBrowser()
   nsCOMPtr<nsIXULWindow> window(do_GetInterface(parentOwner));
   if (!window) {
     return false;
   }
   if (NS_FAILED(window->GetChromeFlags(&chromeFlags))) {
     return false;
   }
 
-  // Get our own or containing app only if we're a browser or app frame.  We
-  // want to avoid the situation where, if we're a remote frame that's neither
-  // a browser nor an app frame, we pass our containing app to
-  // ContentParent::CreateBrowserOrApp below, because that would effectively
-  // give this non-browser-or-app frame app privileges.
+  bool isBrowserElement = false;
   nsCOMPtr<mozIApplication> app;
-  if (OwnerIsBrowserOrAppFrame()) {
-    app = GetOwnOrContainingApp();
+  if (OwnerIsBrowserFrame()) {
+    isBrowserElement = true;
+
+    nsAutoString manifest;
+    GetOwnerAppManifestURL(manifest);
+    if (!manifest.IsEmpty()) {
+      nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
+      if (!appsService) {
+        NS_ERROR("Apps Service is not available!");
+        return false;
+      }
+
+      nsCOMPtr<mozIDOMApplication> domApp;
+      appsService->GetAppByManifestURL(manifest, getter_AddRefs(domApp));
+      // If the frame is actually an app, we should not mark it as a
+      // browser.  This is to identify the data store: since <app>s
+      // and <browser>s-within-<app>s have different stores, we want
+      // to ensure the <app> uses its store, not the one for its
+      // <browser>s.
+      app = do_QueryInterface(domApp);
+      if (app) {
+        isBrowserElement = false;
+      }
+    }
   }
 
-  mRemoteBrowser = ContentParent::CreateBrowserOrApp(app, OwnerIsBrowserFrame());
-  if (mRemoteBrowser) {
+  if ((mRemoteBrowser = ContentParent::CreateBrowser(app, isBrowserElement))) {
     nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mOwnerContent);
     mRemoteBrowser->SetOwnerElement(element);
 
     nsCOMPtr<nsIDocShellTreeItem> rootItem;
     parentAsItem->GetRootTreeItem(getter_AddRefs(rootItem));
     nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
     nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin);
     NS_ABORT_IF_FALSE(rootChromeWin, "How did we not get a chrome window here?");
@@ -2354,17 +2317,17 @@ nsFrameLoader::EnsureMessageManager()
 {
   NS_ENSURE_STATE(mOwnerContent);
 
   nsresult rv = MaybeCreateDocShell();
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  if (!mIsTopLevelContent && !OwnerIsBrowserOrAppFrame() && !mRemoteFrame) {
+  if (!mIsTopLevelContent && !OwnerIsBrowserFrame() && !mRemoteFrame) {
     return NS_OK;
   }
 
   if (mMessageManager) {
     if (ShouldUseRemoteProcess()) {
       mMessageManager->SetCallback(mRemoteBrowserShown ? this : nullptr);
     }
     return NS_OK;
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -28,17 +28,16 @@ class nsIURI;
 class nsSubDocumentFrame;
 class nsIView;
 class nsIInProcessContentFrameMessageManager;
 class AutoResetInShow;
 class nsITabParent;
 class nsIDocShellTreeItem;
 class nsIDocShellTreeOwner;
 class nsIDocShellTreeNode;
-class mozIApplication;
 
 namespace mozilla {
 namespace dom {
 class PBrowserParent;
 class TabParent;
 struct StructuredCloneData;
 }
 
@@ -309,52 +308,33 @@ private:
 
   void SetOwnerContent(mozilla::dom::Element* aContent);
 
   bool ShouldUseRemoteProcess();
 
   /**
    * Is this a frameloader for a bona fide <iframe mozbrowser> or
    * <iframe mozapp>?  (I.e., does the frame return true for
-   * nsIMozBrowserFrame::GetReallyIsBrowserOrApp()?)
+   * nsIMozBrowserFrame::GetReallyIsBrowser()?)
    */
-  bool OwnerIsBrowserOrAppFrame();
+  bool OwnerIsBrowserFrame();
 
   /**
    * 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>?
-   */
-  bool OwnerIsBrowserFrame();
-
-  /**
    * 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);
 
   /**
-   * Get the app for our frame.  This is the app whose manifest is returned by
-   * GetOwnerAppManifestURL.
-   */
-  already_AddRefed<mozIApplication> GetOwnApp();
-
-  /**
-   * Get the closest app to our frame.  This is either the frame returned by
-   * GetOwnApp() or the app associated with our owner element's principal.
-   *
-   * That is, this method returns the app that our owner content is inside.
-   */
-  already_AddRefed<mozIApplication> GetOwnOrContainingApp();
-
-  /**
    * If we are an IPC frame, set mRemoteFrame. Otherwise, create and
    * initialize mDocShell.
    */
   nsresult MaybeCreateDocShell();
   nsresult EnsureMessageManager();
   NS_HIDDEN_(void) GetURL(nsString& aURL);
 
   // Properly retrieves documentSize of any subdocument type.
--- a/content/base/src/nsInProcessTabChildGlobal.cpp
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -92,25 +92,24 @@ nsInProcessTabChildGlobal::DoSendAsyncMe
 
 nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
                                                      nsIContent* aOwner,
                                                      nsFrameMessageManager* aChrome)
 : mDocShell(aShell), mInitialized(false), mLoadingScript(false),
   mDelayedDisconnect(false), mOwner(aOwner), mChromeMessageManager(aChrome)
 {
 
-  // If owner corresponds to an <iframe mozbrowser> or <iframe mozapp>, we'll
-  // have to tweak our PreHandleEvent implementation.
+  // If owner corresponds to an <iframe mozbrowser>, we'll have to tweak our
+  // PreHandleEvent implementation.
   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwner);
+  bool isBrowser = false;
   if (browserFrame) {
-    mIsBrowserOrAppFrame = browserFrame->GetReallyIsBrowserOrApp();
+    browserFrame->GetReallyIsBrowser(&isBrowser);
   }
-  else {
-    mIsBrowserOrAppFrame = false;
-  }
+  mIsBrowserFrame = isBrowser;
 }
 
 nsInProcessTabChildGlobal::~nsInProcessTabChildGlobal()
 {
   NS_ASSERTION(!mCx, "Couldn't release JSContext?!?");
 }
 
 /* [notxpcom] boolean markForCC (); */
@@ -264,17 +263,17 @@ nsInProcessTabChildGlobal::GetOwnerConte
   return mOwner;
 }
 
 nsresult
 nsInProcessTabChildGlobal::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = true;
 
-  if (mIsBrowserOrAppFrame &&
+  if (mIsBrowserFrame &&
       (!mOwner || !nsContentUtils::IsInChromeDocshell(mOwner->OwnerDoc()))) {
     if (mOwner) {
       nsPIDOMWindow* innerWindow = mOwner->OwnerDoc()->GetInnerWindow();
       if (innerWindow) {
         aVisitor.mParentTarget = innerWindow->GetParentTarget();
       }
     }
   } else {
--- a/content/base/src/nsInProcessTabChildGlobal.h
+++ b/content/base/src/nsInProcessTabChildGlobal.h
@@ -117,19 +117,18 @@ protected:
   nsresult Init();
   nsresult InitTabChildGlobal();
   nsCOMPtr<nsIContentFrameMessageManager> mMessageManager;
   nsCOMPtr<nsIDocShell> mDocShell;
   bool mInitialized;
   bool mLoadingScript;
   bool mDelayedDisconnect;
 
-  // Is this the message manager for an in-process <iframe mozbrowser> or
-  // <iframe mozapp>?  This affects where events get sent, so it affects
-  // PreHandleEvent.
-  bool mIsBrowserOrAppFrame;
+  // Is this the message manager for an in-process <iframe mozbrowser>?  This
+  // affects where events get sent, so it affects PreHandleEvent.
+  bool mIsBrowserFrame;
 public:
   nsIContent* mOwner;
   nsFrameMessageManager* mChromeMessageManager;
   nsTArray<nsCOMPtr<nsIRunnable> > mASyncMessages;
 };
 
 #endif
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -1565,20 +1565,24 @@ nsEventStateManager::IsRemoteTarget(nsIC
   if ((target->Tag() == nsGkAtoms::browser ||
        target->Tag() == nsGkAtoms::iframe) &&
       target->IsXUL() &&
       target->AttrValueIs(kNameSpaceID_None, nsGkAtoms::Remote,
                           nsGkAtoms::_true, eIgnoreCase)) {
     return true;
   }
 
-  // <frame/iframe mozbrowser/mozapp>
+  // <frame/iframe mozbrowser>
   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(target);
-  if (browserFrame && browserFrame->GetReallyIsBrowserOrApp()) {
-    return !!TabParent::GetFrom(target);
+  if (browserFrame) {
+    bool isBrowser = false;
+    browserFrame->GetReallyIsBrowser(&isBrowser);
+    if (isBrowser) {
+      return !!TabParent::GetFrom(target);
+    }
   }
 
   return false;
 }
 
 /*static*/ void
 nsEventStateManager::MapEventCoordinatesForChildProcess(nsFrameLoader* aFrameLoader,
                                                         nsEvent* aEvent)
--- a/content/html/content/src/nsGenericHTMLFrameElement.cpp
+++ b/content/html/content/src/nsGenericHTMLFrameElement.cpp
@@ -273,71 +273,73 @@ nsGenericHTMLFrameElement::IsHTMLFocusab
   return false;
 }
 
 /**
  * Return true if this frame element really is a mozbrowser or mozapp.  (It
  * needs to have the right attributes, and its creator must have the right
  * permissions.)
  */
-/* [infallible] */ nsresult
-nsGenericHTMLFrameElement::GetReallyIsBrowserOrApp(bool *aOut)
+nsresult
+nsGenericHTMLFrameElement::GetReallyIsBrowser(bool *aOut)
 {
   *aOut = false;
 
   // Fail if browser frames are globally disabled.
   if (!Preferences::GetBool("dom.mozBrowserFramesEnabled")) {
     return NS_OK;
   }
 
   // Fail if this frame doesn't have the mozbrowser attribute.
-  bool hasMozbrowser = false;
-  GetMozbrowser(&hasMozbrowser);
-  if (!hasMozbrowser) {
+  bool isBrowser = false;
+  GetMozbrowser(&isBrowser);
+  if (!isBrowser) {
     return NS_OK;
   }
 
   // Fail if the node principal isn't trusted.
   nsIPrincipal *principal = NodePrincipal();
   nsCOMPtr<nsIPermissionManager> permMgr =
     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
-  NS_ENSURE_TRUE(permMgr, NS_OK);
+  NS_ENSURE_STATE(permMgr);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
   nsresult rv = permMgr->TestPermissionFromPrincipal(principal, "browser", &permission);
   NS_ENSURE_SUCCESS(rv, NS_OK);
   *aOut = permission == nsIPermissionManager::ALLOW_ACTION;
   return NS_OK;
 }
 
-/* [infallible] */ NS_IMETHODIMP
+NS_IMETHODIMP
 nsGenericHTMLFrameElement::GetReallyIsApp(bool *aOut)
 {
   nsAutoString manifestURL;
   GetAppManifestURL(manifestURL);
 
   *aOut = !manifestURL.IsEmpty();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGenericHTMLFrameElement::GetAppManifestURL(nsAString& aOut)
 {
   aOut.Truncate();
 
   // At the moment, you can't be an app without being a browser.
-  if (!nsIMozBrowserFrame::GetReallyIsBrowserOrApp()) {
+  bool isBrowser = false;
+  GetReallyIsBrowser(&isBrowser);
+  if (!isBrowser) {
     return NS_OK;
   }
 
   // Check permission.
   nsIPrincipal *principal = NodePrincipal();
   nsCOMPtr<nsIPermissionManager> permMgr =
     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
-  NS_ENSURE_TRUE(permMgr, NS_OK);
+  NS_ENSURE_STATE(permMgr);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
   nsresult rv = permMgr->TestPermissionFromPrincipal(principal,
                                                      "embed-apps",
                                                      &permission);
   NS_ENSURE_SUCCESS(rv, NS_OK);
   if (permission != nsIPermissionManager::ALLOW_ACTION) {
     return NS_OK;
@@ -345,20 +347,21 @@ nsGenericHTMLFrameElement::GetAppManifes
 
   nsAutoString manifestURL;
   GetAttr(kNameSpaceID_None, nsGkAtoms::mozapp, manifestURL);
   if (manifestURL.IsEmpty()) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(appsService, NS_OK);
+  NS_ENSURE_STATE(appsService);
 
   nsCOMPtr<mozIDOMApplication> app;
   appsService->GetAppByManifestURL(manifestURL, getter_AddRefs(app));
+
   if (app) {
     aOut.Assign(manifestURL);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/docshell/base/nsDSURIContentListener.cpp
+++ b/docshell/base/nsDSURIContentListener.cpp
@@ -321,17 +321,17 @@ bool nsDSURIContentListener::CheckOneFra
 
     // 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->GetIsContentBoundary()) {
           break;
         }
 
         bool system = false;
         topDoc = do_GetInterface(parentDocShellItem);
         if (topDoc) {
             if (NS_SUCCEEDED(ssm->IsSystemPrincipal(topDoc->NodePrincipal(),
                                                     &system)) && system) {
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -724,17 +724,16 @@ static uint64_t gDocshellIDCounter = 0;
 nsDocShell::nsDocShell():
     nsDocLoader(),
     mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto),
     mTreeOwner(nullptr),
     mChromeEventHandler(nullptr),
     mCharsetReloadState(eCharsetReloadInit),
     mChildOffset(0),
     mBusyFlags(BUSY_FLAGS_NONE),
-    mFrameType(eFrameTypeRegular),
     mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
     mLoadType(0),
     mMarginWidth(-1),
     mMarginHeight(-1),
     mItemType(typeContent),
     mPreviousTransIndex(-1),
     mLoadedTransIndex(-1),
     mSandboxFlags(0),
@@ -762,17 +761,17 @@ nsDocShell::nsDocShell():
     mURIResultedInDocument(false),
     mIsBeingDestroyed(false),
     mIsExecutingOnLoadHandler(false),
     mIsPrintingOrPP(false),
     mSavingOldViewer(false),
 #ifdef DEBUG
     mInEnsureScriptEnv(false),
 #endif
-    mOwnOrContainingAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID),
+    mAppId(nsIScriptSecurityManager::NO_APP_ID),
     mParentCharsetSource(0)
 {
     mHistoryID = ++gDocshellIDCounter;
     if (gDocShellCount++ == 0) {
         NS_ASSERTION(sURIFixup == nullptr,
                      "Huh, sURIFixup not null in first nsDocShell ctor!");
 
         CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup);
@@ -2131,29 +2130,29 @@ NS_IMETHODIMP nsDocShell::SetAllowWindow
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed)
 {
     NS_ENSURE_ARG_POINTER(aFullscreenAllowed);
 
-    // Browsers and apps have their mFullscreenAllowed retrieved from their
+    // Content boundaries have their mFullscreenAllowed retrieved from their
     // corresponding iframe in their parent upon creation.
     if (mFullscreenAllowed != CHECK_ATTRIBUTES) {
         *aFullscreenAllowed = (mFullscreenAllowed == PARENT_ALLOWS);
         return NS_OK;
     }
 
     // Assume false until we determine otherwise...
     *aFullscreenAllowed = false;
 
-    // For non-browsers/apps, check that the enclosing iframe element
+    // For non-content boundaries, check that the enclosing iframe element
     // has the allowfullscreen attribute set to true. If any ancestor
-    // iframe does not have mozallowfullscreen=true, then fullscreen is
+    // iframe does not have allowfullscreen=true, then fullscreen is
     // prohibited.
     nsCOMPtr<nsPIDOMWindow> win = do_GetInterface(GetAsSupports(this));
     if (!win) {
         return NS_OK;
     }
     nsCOMPtr<nsIContent> frameElement = do_QueryInterface(win->GetFrameElementInternal());
     if (frameElement &&
         frameElement->IsHTML(nsGkAtoms::iframe) &&
@@ -2180,17 +2179,17 @@ nsDocShell::GetFullscreenAllowed(bool* a
     NS_ENSURE_TRUE(parent, NS_OK);
     
     return parent->GetFullscreenAllowed(aFullscreenAllowed);
 }
 
 NS_IMETHODIMP
 nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed)
 {
-    if (!nsIDocShell::GetIsBrowserOrApp()) {
+    if (!nsIDocShell::GetIsContentBoundary()) {
         // 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;
     }
@@ -2792,17 +2791,17 @@ nsDocShell::SetDocLoaderParent(nsDocLoad
 }
 
 NS_IMETHODIMP
 nsDocShell::GetSameTypeParent(nsIDocShellTreeItem ** aParent)
 {
     NS_ENSURE_ARG_POINTER(aParent);
     *aParent = nullptr;
 
-    if (nsIDocShell::GetIsBrowserOrApp()) {
+    if (mIsBrowserFrame) {
         return NS_OK;
     }
 
     nsCOMPtr<nsIDocShellTreeItem> parent =
         do_QueryInterface(GetAsSupports(mParent));
     if (!parent)
         return NS_OK;
 
@@ -2914,21 +2913,29 @@ 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 or neither to nsIDocShell.
         return false;
     }
 
-    if (targetDS && accessingDS &&
-        (targetDS->GetIsInBrowserElement() !=
-           accessingDS->GetIsInBrowserElement() ||
-         targetDS->GetAppId() != accessingDS->GetAppId())) {
-        return false;
+    if (targetDS && accessingDS) {
+        bool targetInBrowser = false, accessingInBrowser = false;
+        targetDS->GetIsInBrowserElement(&targetInBrowser);
+        accessingDS->GetIsInBrowserElement(&accessingInBrowser);
+
+        uint32_t targetAppId = 0, accessingAppId = 0;
+        targetDS->GetAppId(&targetAppId);
+        accessingDS->GetAppId(&accessingAppId);
+
+        if (targetInBrowser != accessingInBrowser ||
+            targetAppId != accessingAppId) {
+            return false;
+        }
     }
 
     nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
     aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot));
 
     if (aTargetItem == accessingRoot) {
         // A frame can navigate its root.
         return true;
@@ -5202,17 +5209,17 @@ nsDocShell::SetIsActive(bool aIsActive)
   // children; they handle their state separately.
   int32_t n = mChildList.Count();
   for (int32_t i = 0; i < n; ++i) {
       nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(ChildAt(i));
       if (!docshell) {
           continue;
       }
 
-      if (!docshell->GetIsBrowserOrApp()) {
+      if (!docshell->GetIsContentBoundary()) {
           docshell->SetIsActive(aIsActive);
       }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -12278,116 +12285,146 @@ nsDocShell::GetCanExecuteScripts(bool *a
 #endif // DEBUG
       } while (treeItem && docshell);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocShell::SetIsApp(uint32_t aOwnAppId)
-{
-    mOwnOrContainingAppId = aOwnAppId;
-    if (aOwnAppId != nsIScriptSecurityManager::NO_APP_ID &&
-        aOwnAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
-        mFrameType = eFrameTypeApp;
-    } else {
-        mFrameType = eFrameTypeRegular;
-    }
-
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDocShell::SetIsBrowserInsideApp(uint32_t aContainingAppId)
-{
-    mOwnOrContainingAppId = aContainingAppId;
-    mFrameType = eFrameTypeBrowser;
-    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)
-{
-    switch (mFrameType) {
-        case eFrameTypeRegular:
-            *aIsBrowserOrApp = false;
-            break;
-        case eFrameTypeBrowser:
-        case eFrameTypeApp:
-            *aIsBrowserOrApp = true;
-            break;
+nsDocShell::SetIsBrowserElement()
+{
+    if (mIsBrowserFrame) {
+        NS_ERROR("You should not call SetIsBrowserElement() more than once.");
+        return NS_OK;
+    }
+
+    mIsBrowserFrame = true;
+
+    nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+    if (os) {
+        os->NotifyObservers(GetAsSupports(this),
+                            "docshell-marked-as-browser-frame", NULL);
     }
 
     return NS_OK;
 }
 
 nsDocShell::FrameType
 nsDocShell::GetInheritedFrameType()
 {
-    if (mFrameType != eFrameTypeRegular) {
-        return mFrameType;
+    FrameType type = GetFrameType();
+
+    if (type != eFrameTypeRegular) {
+        return type;
     }
 
     nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
     GetSameTypeParent(getter_AddRefs(parentAsItem));
 
     nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentAsItem);
     if (!parent) {
         return eFrameTypeRegular;
     }
 
     return static_cast<nsDocShell*>(parent.get())->GetInheritedFrameType();
 }
 
+nsDocShell::FrameType
+nsDocShell::GetFrameType()
+{
+    if (mAppId != nsIScriptSecurityManager::NO_APP_ID) {
+        return eFrameTypeApp;
+    }
+
+    return mIsBrowserFrame ? eFrameTypeBrowser : eFrameTypeRegular;
+}
+
+/* [infallible] */ NS_IMETHODIMP
+nsDocShell::GetIsBrowserElement(bool* aIsBrowser)
+{
+    *aIsBrowser = (GetFrameType() == eFrameTypeBrowser);
+    return NS_OK;
+}
+
+/* [infallible] */ NS_IMETHODIMP
+nsDocShell::GetIsApp(bool* aIsApp)
+{
+    *aIsApp = (GetFrameType() == eFrameTypeApp);
+    return NS_OK;
+}
+
+/* [infallible] */ NS_IMETHODIMP
+nsDocShell::GetIsContentBoundary(bool* aIsContentBoundary)
+{
+    switch (GetFrameType()) {
+        case eFrameTypeRegular:
+            *aIsContentBoundary = false;
+            break;
+        case eFrameTypeBrowser:
+        case eFrameTypeApp:
+            *aIsContentBoundary = true;
+            break;
+    }
+
+    return NS_OK;
+}
+
 /* [infallible] */ NS_IMETHODIMP
 nsDocShell::GetIsInBrowserElement(bool* aIsInBrowserElement)
 {
     *aIsInBrowserElement = (GetInheritedFrameType() == eFrameTypeBrowser);
     return NS_OK;
 }
 
 /* [infallible] */ NS_IMETHODIMP
-nsDocShell::GetIsInBrowserOrApp(bool* aIsInBrowserOrApp)
+nsDocShell::GetIsInApp(bool* aIsInApp)
+{
+    *aIsInApp = (GetInheritedFrameType() == eFrameTypeApp);
+    return NS_OK;
+}
+
+/* [infallible] */ NS_IMETHODIMP
+nsDocShell::GetIsBelowContentBoundary(bool* aIsInContentBoundary)
 {
     switch (GetInheritedFrameType()) {
         case eFrameTypeRegular:
-            *aIsInBrowserOrApp = false;
+            *aIsInContentBoundary = false;
             break;
         case eFrameTypeBrowser:
         case eFrameTypeApp:
-            *aIsInBrowserOrApp = true;
+            *aIsInContentBoundary = true;
             break;
     }
 
     return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDocShell::SetAppId(uint32_t aAppId)
+{
+    MOZ_ASSERT(mAppId == nsIScriptSecurityManager::NO_APP_ID);
+    MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
+
+    mAppId = aAppId;
+    return NS_OK;
+}
+
 /* [infallible] */ NS_IMETHODIMP
 nsDocShell::GetAppId(uint32_t* aAppId)
 {
-    if (mOwnOrContainingAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
-        *aAppId = mOwnOrContainingAppId;
+    if (mAppId != nsIScriptSecurityManager::NO_APP_ID) {
+        MOZ_ASSERT(GetFrameType() == eFrameTypeApp);
+
+        *aAppId = mAppId;
         return NS_OK;
     }
 
+    MOZ_ASSERT(GetFrameType() != eFrameTypeApp);
+
     nsCOMPtr<nsIDocShell> parent;
     GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent));
 
     if (!parent) {
         *aAppId = nsIScriptSecurityManager::NO_APP_ID;
         return NS_OK;
     }
 
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -659,22 +659,23 @@ protected:
         void Revoke() { mDocShell = nullptr; }
     private:
         nsRefPtr<nsDocShell> mDocShell;
     };
 
     bool JustStartedNetworkLoad();
 
     enum FrameType {
-        eFrameTypeRegular,
-        eFrameTypeBrowser,
-        eFrameTypeApp
+        eFrameTypeRegular  = 0x0, // 0000
+        eFrameTypeBrowser  = 0x1, // 0001
+        eFrameTypeApp      = 0x2  // 0010
     };
 
     FrameType GetInheritedFrameType();
+    FrameType GetFrameType();
 
     // hash of session storages, keyed by domain
     nsInterfaceHashtable<nsCStringHashKey, nsIDOMStorage> mStorages;
 
     // Dimensions of the docshell
     nsIntRect                  mBounds;
     nsString                   mName;
     nsString                   mTitle;
@@ -801,16 +802,17 @@ protected:
     bool                       mObserveErrorPages;
     bool                       mAllowAuth;
     bool                       mAllowKeywordFixup;
     bool                       mIsOffScreenBrowser;
     bool                       mIsActive;
     bool                       mIsAppTab;
     bool                       mUseGlobalHistory;
     bool                       mInPrivateBrowsing;
+    bool                       mIsBrowserFrame;
 
     // This boolean is set to true right before we fire pagehide and generally
     // unset when we embed a new content viewer.  While it's true no navigation
     // is allowed in this docshell.
     bool                       mFiredUnloadEvent;
 
     // this flag is for bug #21358. a docshell may load many urls
     // which don't result in new documents being created (i.e. a new
@@ -837,28 +839,17 @@ protected:
     bool                       mInEnsureScriptEnv;
 #endif
     uint64_t                   mHistoryID;
 
     static nsIURIFixup *sURIFixup;
 
     nsRefPtr<nsDOMNavigationTiming> mTiming;
 
-    // Are we a regular frame, a browser frame, or an app frame?
-    FrameType mFrameType;
-
-    // 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.)
-    uint32_t mOwnOrContainingAppId;
+    uint32_t mAppId;
 
 private:
     nsCOMPtr<nsIAtom> mForcedCharset;
     nsCOMPtr<nsIAtom> mParentCharset;
     nsTObserverArray<nsWeakPtr> mPrivacyObservers;
     int32_t           mParentCharsetSource;
     nsCString         mOriginalUriString;
 
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -34,17 +34,17 @@ interface nsISHEntry;
 interface nsILayoutHistoryState;
 interface nsISecureBrowserUI;
 interface nsIDOMStorage;
 interface nsIPrincipal;
 interface nsIWebBrowserPrint;
 interface nsIVariant;
 interface nsIPrivacyTransitionObserver;
 
-[scriptable, builtinclass, uuid(318CE516-3F7A-41F6-8F3D-3661650F7A46)]
+[scriptable, builtinclass, uuid(0132C0BE-ACB5-4D61-9B19-01C005E030DA)]
 interface nsIDocShell : nsISupports
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -574,98 +574,82 @@ interface nsIDocShell : nsISupports
 
   /**
    * Add an observer to the list of parties to be notified when this docshell's
    * private browsing status is changed. |obs| must support weak references.
    */
   void addWeakPrivacyTransitionObserver(in nsIPrivacyTransitionObserver obs);
 
   /**
-   * Returns true if this docshell corresponds to an <iframe mozbrowser>.
-   * (<iframe mozapp mozbrowser> is not considered a browser.)
+   * Mark the docshell as a browser frame.
+   * This should be used for <iframe mozbrowser> but not for <iframe mozapp>.
+   *
+   * This method should not be called more than once.
+   */
+  void setIsBrowserElement();
+
+  /**
+   * Returns true iff the docshell is marked as a browser frame.
    */
   [infallible] readonly attribute boolean isBrowserElement;
 
   /**
-   * Returns true iff the docshell corresponds to an <iframe mozapp>.
+   * Returns true iif the docshell is marked as an app frame.
    */
   [infallible] readonly attribute boolean isApp;
 
   /**
-   * Returns isBrowserElement || isApp.
+   * Returns true iif the docshell is marked as a type that behaves like a
+   * content boundary.
    */
-  [infallible] readonly attribute boolean isBrowserOrApp;
+  [infallible] readonly attribute boolean isContentBoundary;
 
   /**
-   * 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.)
-   *
-   * 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.
+   * Returns true iif the docshell is inside a browser element.
    */
   [infallible] readonly attribute boolean isInBrowserElement;
 
   /**
-   * Returns true if this docshell corresponds to an <iframe mozbrowser> or
-   * <iframe mozap>, or if this docshell is contained in an <iframe mozbrowser>
-   * or <iframe mozapp>.
+   * Returns true iif the docshell is inside an application.  However, it will
+   * return false if the docshell is inside a browser element that is inside
+   * an application.
    *
-   * 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.
+   * Note: Do not use this method for permissions checks!  An app may contain
+   * an <iframe> pointing at arbitrary web code.  This iframe's docshell will
+   * have isInApp() == true, but the iframe's content is not "app code", and
+   * so should not be granted more trust than vanilla web content.
+   *
+   * (For example, suppose when web content calls API method X, we show a
+   * permission prompt, but when "app code" calls method X, we don't.  In this
+   * case, it would be /incorrect/ to show the permission prompt if
+   * !isInApp().)
+   *
+   * If you're doing a security check, use the content's principal instead of
+   * this method.
    */
-  [infallible] readonly attribute boolean isInBrowserOrApp;
-
-   /**
-    * 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.
-    *
-    * You can call this method more than once, but there's no guarantee that
-    * other components will update their view of the world if you change a
-    * docshell's app id, so tread lightly.
-    *
-    * If you call this method after calling setIsBrowserInsideApp, this
-    * docshell will forget the fact that it was a browser.
-    */
-   void setIsApp(in unsigned long ownAppId);
-
-   /**
-    * Indicate that this docshell corresponds to a browser inside an app with
-    * the given ID.  As with setIsApp, you may pass NO_APP_ID or
-    * UNKNOWN_APP_ID.
-    *
-    * As with setIsApp, you may call this more than once, but it's kind of a
-    * hack, so be careful.
-    */
-   void setIsBrowserInsideApp(in unsigned long containingAppId);
+  [infallible] readonly attribute boolean isInApp;
 
   /**
-   * Returns the id of the app associated with this docshell.  If this docshell
-   * is an <iframe mozbrowser> inside an <iframe mozapp>, we return the app's
-   * appId.
+   * Returns if the docshell has a docshell that behaves as a content boundary
+   * in his parent hierarchy.
+   */
+  [infallible] readonly attribute boolean isBelowContentBoundary;
+
+  /**
+   * Set the app id this docshell is associated with. The id has to be a valid
+   * app id. If the docshell isn't associated with any app, the value should be
+   * nsIScriptSecurityManager::NO_APP_ID. However, this is the default value if
+   * nothing is et.
    *
-   * We compute this value by walking up the docshell hierarchy until we find a
-   * docshell on which setIsApp(x) or setIsBrowserInsideApp(x) was called
-   * (ignoring those docshells where x == UNKNOWN_APP_ID).  We return the app
-   * id x.
+   * This method is [noscript] to reduce the scope. It should be used at very
+   * specific moments.
    *
-   * If we don't find a docshell with an associated app id in our hierarchy, we
-   * return NO_APP_ID.  We never return UNKNOWN_APP_ID.
-   *
-   * Notice that a docshell may have an associated app even if it returns true
-   * for isBrowserElement!
+   * Calling setAppId() will mark the frame as an app frame.
    */
-  [infallible] readonly attribute unsigned long appId;
+  [noscript] void setAppId(in unsigned long appId);
 
   /**
    * Like nsIDocShellTreeItem::GetSameTypeParent, except this ignores <iframe
    * mozbrowser> and <iframe mozapp> boundaries.
    */
   nsIDocShell getSameTypeParentIgnoreBrowserAndAppBoundaries();
 
   /** 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -3003,17 +3003,17 @@ nsGlobalWindow::GetScriptableParent(nsID
 {
   FORWARD_TO_OUTER(GetScriptableParent, (aParent), NS_ERROR_NOT_INITIALIZED);
 
   *aParent = NULL;
   if (!mDocShell) {
     return NS_OK;
   }
 
-  if (mDocShell->GetIsBrowserOrApp()) {
+  if (mDocShell->GetIsContentBoundary()) {
     nsCOMPtr<nsIDOMWindow> parent = static_cast<nsIDOMWindow*>(this);
     parent.swap(*aParent);
     return NS_OK;
   }
 
   return GetRealParent(aParent);
 }
 
@@ -3108,19 +3108,19 @@ nsGlobalWindow::GetTopImpl(nsIDOMWindow*
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::GetContent(nsIDOMWindow** aContent)
 {
   FORWARD_TO_OUTER(GetContent, (aContent), NS_ERROR_NOT_INITIALIZED);
   *aContent = nullptr;
 
-  // If we're contained in <iframe mozbrowser> or <iframe mozapp>, then
-  // GetContent is the same as window.top.
-  if (mDocShell && mDocShell->GetIsInBrowserOrApp()) {
+  // If we're contained in <iframe mozbrowser>, then GetContent is the same as
+  // window.top.
+  if (mDocShell && mDocShell->GetIsBelowContentBoundary()) {
     return GetScriptableTop(aContent);
   }
 
   nsCOMPtr<nsIDocShellTreeItem> primaryContent;
   if (!nsContentUtils::IsCallerChrome()) {
     // 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,
@@ -6556,17 +6556,17 @@ nsGlobalWindow::CanClose()
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::Close()
 {
   FORWARD_TO_OUTER(Close, (), NS_ERROR_NOT_INITIALIZED);
 
   if (!mDocShell || IsInModalState() ||
-      (IsFrame() && !mDocShell->GetIsBrowserOrApp())) {
+      (IsFrame() && !mDocShell->GetIsContentBoundary())) {
     // 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 NS_OK;
   }
 
   if (mHavePendingClose) {
@@ -7075,27 +7075,26 @@ nsGlobalWindow::CacheXBLPrototypeHandler
   mCachedXBLPrototypeHandlers.Put(aKey, aHandler.get());
 }
 
 /**
  * GetScriptableFrameElement is called when script reads
  * nsIGlobalWindow::frameElement.
  *
  * In contrast to GetRealFrameElement, GetScriptableFrameElement says that the
- * window contained by an <iframe mozbrowser> or <iframe mozapp> has no frame
- * element (effectively treating a mozbrowser the same as a content/chrome
- * boundary).
+ * window contained by an <iframe mozbrowser> has no frame element
+ * (effectively treating a mozbrowser the same as a content/chrome boundary).
  */
 NS_IMETHODIMP
 nsGlobalWindow::GetScriptableFrameElement(nsIDOMElement** aFrameElement)
 {
   FORWARD_TO_OUTER(GetScriptableFrameElement, (aFrameElement), NS_ERROR_NOT_INITIALIZED);
   *aFrameElement = NULL;
 
-  if (!mDocShell || mDocShell->GetIsBrowserOrApp()) {
+  if (!mDocShell || mDocShell->GetIsContentBoundary()) {
     return NS_OK;
   }
 
   return GetFrameElement(aFrameElement);
 }
 
 /**
  * nsIGlobalWindow::GetFrameElement (when called from C++) is just a wrapper
--- a/dom/interfaces/html/nsIMozBrowserFrame.idl
+++ b/dom/interfaces/html/nsIMozBrowserFrame.idl
@@ -4,42 +4,40 @@
 /* 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 "nsIDOMMozBrowserFrame.idl"
 
 interface nsITabParent;
 
-[scriptable, builtinclass, uuid(929AED00-3E15-49B7-8CA2-75003715B7E7)]
+[scriptable, uuid(6f043e42-02c9-4e8f-8f8d-1b83c6102827)]
 interface nsIMozBrowserFrame : nsIDOMMozBrowserFrame
 {
   /**
    * Gets whether this frame really is a browser or app frame.
    *
    * In order to really be a browser frame, this frame's
    * nsIDOMMozBrowserFrame::mozbrowser attribute must be true, and the frame
    * may have to pass various security checks.
    */
-  [infallible] readonly attribute boolean reallyIsBrowserOrApp;
+  readonly attribute boolean reallyIsBrowser;
 
   /**
    * Gets whether this frame really is an app frame.
    *
    * In order to really be an app frame, this frame must really be a browser
    * frame (this requirement will go away eventually), and the frame's mozapp
    * attribute must point to the manifest of a valid app.
    */
-  [infallible] readonly attribute boolean reallyIsApp;
+  readonly attribute boolean reallyIsApp;
 
   /**
    * Gets this frame's app manifest URL, if the frame really is an app frame.
    * Otherwise, returns the empty string.
-   *
-   * This method is guaranteed not to fail.
    */
   readonly attribute AString appManifestURL;
 
   /**
    * Normally, a frame tries to create its frame loader when its src is
    * modified, or its contentWindow is accessed.
    *
    * disallowCreateFrameLoader prevents the frame element from creating its
--- a/dom/ipc/AppProcessPermissions.cpp
+++ b/dom/ipc/AppProcessPermissions.cpp
@@ -22,17 +22,17 @@ bool
 AssertAppProcessPermission(PBrowserParent* aActor, const char* aPermission)
 {
   if (!aActor) {
     NS_WARNING("Testing permissions for null actor");
     return false;
   }
 
   TabParent* tab = static_cast<TabParent*>(aActor);
-  nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp();
+  nsCOMPtr<mozIApplication> app = tab->GetApp();
   bool hasPermission = false;
 
   // isBrowser frames inherit their app descriptor to identify their
   // data storage, but they don't inherit the permissions associated
   // with that descriptor.
   if (app && !tab->IsBrowserElement()) {
     if (!NS_SUCCEEDED(app->HasPermission(aPermission, &hasPermission))) {
       hasPermission = false;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -482,30 +482,26 @@ ContentChild::AllocPImageBridge(mozilla:
 
 static void FirstIdle(void)
 {
     ContentChild::GetSingleton()->SendFirstIdle();
 }
 
 PBrowserChild*
 ContentChild::AllocPBrowser(const uint32_t& aChromeFlags,
-                            const AppToken& aOwnOrContainingAppToken,
-                            const bool& aIsBrowserElement)
+                            const bool& aIsBrowserElement, const AppId& aApp)
 {
     static bool firstIdleTaskPosted = false;
     if (!firstIdleTaskPosted) {
         MessageLoop::current()->PostIdleTask(FROM_HERE, NewRunnableFunction(FirstIdle));
         firstIdleTaskPosted = true;
     }
 
-    nsRefPtr<TabChild> child = TabChild::Create(
-        aChromeFlags,
-        aOwnOrContainingAppToken.get_uint32_t(),
-        aIsBrowserElement);
-
+    nsRefPtr<TabChild> child =
+        TabChild::Create(aChromeFlags, aIsBrowserElement, aApp.get_uint32_t());
     // The ref here is released below.
     return child.forget().get();
 }
 
 bool
 ContentChild::DeallocPBrowser(PBrowserChild* iframe)
 {
     TabChild* child = static_cast<TabChild*>(iframe);
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -74,18 +74,18 @@ public:
     PCompositorChild*
     AllocPCompositor(mozilla::ipc::Transport* aTransport,
                      base::ProcessId aOtherProcess) MOZ_OVERRIDE;
     PImageBridgeChild*
     AllocPImageBridge(mozilla::ipc::Transport* aTransport,
                       base::ProcessId aOtherProcess) MOZ_OVERRIDE;
 
     virtual PBrowserChild* AllocPBrowser(const uint32_t& aChromeFlags,
-                                         const AppToken& aOwnOrContainingAppToken,
-                                         const bool& aIsBrowserElement);
+                                         const bool& aIsBrowserElement,
+                                         const AppId& aAppId);
     virtual bool DeallocPBrowser(PBrowserChild*);
 
     virtual PDeviceStorageRequestChild* AllocPDeviceStorageRequest(const DeviceStorageParams&);
     virtual bool DeallocPDeviceStorageRequest(PDeviceStorageRequestChild*);
 
     virtual PBlobChild* AllocPBlob(const BlobConstructorParams& aParams);
     virtual bool DeallocPBlob(PBlobChild*);
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -49,16 +49,17 @@
 #include "nsConsoleMessage.h"
 #include "nsDebugImpl.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsDOMFile.h"
 #include "nsExternalHelperAppService.h"
 #include "nsFrameMessageManager.h"
 #include "nsHashPropertyBag.h"
 #include "nsIAlertsService.h"
+#include "nsIAppsService.h"
 #include "nsIClipboard.h"
 #include "nsIConsoleService.h"
 #include "nsIDOMApplicationRegistry.h"
 #include "nsIDOMGeoGeolocation.h"
 #include "nsIDOMWindow.h"
 #include "nsIFilePicker.h"
 #include "nsIMemoryReporter.h"
 #include "nsIObserverService.h"
@@ -312,85 +313,90 @@ AppNeedsInheritedOSPrivileges(mozIApplic
         } else if (needsInherit) {
             return true;
         }
     }
     return false;
 }
 
 /*static*/ TabParent*
-ContentParent::CreateBrowserOrApp(mozIApplication* aOwnOrContainingApp,
-                                  bool aIsBrowserElement)
+ContentParent::CreateBrowser(mozIApplication* aApp, bool aIsBrowserElement)
 {
-    uint32_t ownOrContainingAppId = nsIScriptSecurityManager::NO_APP_ID;
-    if (aOwnOrContainingApp) {
-        NS_ENSURE_SUCCESS(aOwnOrContainingApp->GetLocalId(&ownOrContainingAppId),
-                          nullptr);
-    }
+    // We currently don't set the <app> ancestor for <browser> content
+    // correctly.  This assertion is to notify the person who fixes
+    // this code that they need to reevaluate places here where we may
+    // make bad assumptions based on that bug.
+    MOZ_ASSERT(!aApp || !aIsBrowserElement);
 
-    if (aIsBrowserElement || !aOwnOrContainingApp) {
+    if (!aApp) {
         if (ContentParent* cp = GetNewOrUsed(aIsBrowserElement)) {
-            nsRefPtr<TabParent> tp(new TabParent(aOwnOrContainingApp, aIsBrowserElement));
+            nsRefPtr<TabParent> tp(new TabParent(aApp, aIsBrowserElement));
             return static_cast<TabParent*>(
                 cp->SendPBrowserConstructor(
                     // DeallocPBrowserParent() releases the ref we take here
                     tp.forget().get(),
                     /*chromeFlags*/0,
-                    ownOrContainingAppId, aIsBrowserElement));
+                    aIsBrowserElement, nsIScriptSecurityManager::NO_APP_ID));
         }
         return nullptr;
     }
 
-    // If we got here, we have an app and we're not a browser element.  In this
-    // case, we assume the app is our own app, not a containing one.  That is,
-    // if you're a remote iframe inside an app, you must either be a browser or
-    // a new app; you can't be a non-browser non-app iframe.
-    nsCOMPtr<mozIApplication> ownApp = aOwnOrContainingApp;
-    uint32_t ownAppId = ownOrContainingAppId;
-
     if (!gAppContentParents) {
         gAppContentParents =
             new nsDataHashtable<nsStringHashKey, ContentParent*>();
         gAppContentParents->Init();
     }
 
     // Each app gets its own ContentParent instance.
     nsAutoString manifestURL;
-    if (NS_FAILED(ownApp->GetManifestURL(manifestURL))) {
+    if (NS_FAILED(aApp->GetManifestURL(manifestURL))) {
         NS_ERROR("Failed to get manifest URL");
         return nullptr;
     }
 
+    nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
+    if (!appsService) {
+        NS_ERROR("Failed to get apps service");
+        return nullptr;
+    }
+
+    // Send the local app ID to the new TabChild so it knows what app
+    // it is.
+    uint32_t appId;
+    if (NS_FAILED(appsService->GetAppLocalIdByManifestURL(manifestURL, &appId))) {
+        NS_ERROR("Failed to get local app ID");
+        return nullptr;
+    }
+
     nsRefPtr<ContentParent> p = gAppContentParents->Get(manifestURL);
     if (!p) {
-        if (AppNeedsInheritedOSPrivileges(ownApp)) {
-            p = new ContentParent(manifestURL, /* isBrowserElement = */ false,
+        if (AppNeedsInheritedOSPrivileges(aApp)) {
+            p = new ContentParent(manifestURL, aIsBrowserElement,
                                   base::PRIVILEGES_INHERIT);
             p->Init();
         } else {
             p = MaybeTakePreallocatedAppProcess();
             if (p) {
                 p->SetManifestFromPreallocated(manifestURL);
             } else {
                 NS_WARNING("Unable to use pre-allocated app process");
-                p = new ContentParent(manifestURL, /* isBrowserElement = */ false,
+                p = new ContentParent(manifestURL, aIsBrowserElement,
                                       base::PRIVILEGES_DEFAULT);
                 p->Init();
             }
         }
         gAppContentParents->Put(manifestURL, p);
     }
 
-    nsRefPtr<TabParent> tp(new TabParent(ownApp, /* isBrowserElement = */ false));
+    nsRefPtr<TabParent> tp(new TabParent(aApp, aIsBrowserElement));
     return static_cast<TabParent*>(
         // DeallocPBrowserParent() releases the ref we take here
         p->SendPBrowserConstructor(tp.forget().get(),
-                                   /* chromeFlags = */ 0,
-                                   ownAppId,
-                                   /* isBrowserElement = */ false));
+                                   /*chromeFlags*/0,
+                                   aIsBrowserElement, appId));
 }
 
 static PLDHashOperator
 AppendToTArray(const nsAString& aKey, ContentParent* aValue, void* aArray)
 {
     nsTArray<ContentParent*> *array =
         static_cast<nsTArray<ContentParent*>*>(aArray);
     array->AppendElement(aValue);
@@ -1139,42 +1145,39 @@ ContentParent::RecvGetProcessAttributes(
         (mAppManifestURL == MAGIC_PREALLOCATED_APP_MANIFEST_URL);
     *aIsForApp = IsForApp();
     *aIsForBrowser = mIsForBrowser;
     return true;
 }
 
 PBrowserParent*
 ContentParent::AllocPBrowser(const uint32_t& aChromeFlags,
-                             const AppToken& aOwnOrContainingAppToken,
-                             const bool& aIsBrowserElement)
+                             const bool& aIsBrowserElement, const AppId& aApp)
 {
     // We only use this Alloc() method when the content processes asks
     // us to open a window.  In that case, we're expecting to see the
     // opening PBrowser as its app descriptor, and we can trust the data
     // associated with that PBrowser since it's fully owned by this
     // process.
-    if (AppToken::TPBrowserParent != aOwnOrContainingAppToken.type()) {
+    if (AppId::TPBrowserParent != aApp.type()) {
         NS_ERROR("Content process attempting to forge app ID");
         return nullptr;
     }
-    TabParent* opener = static_cast<TabParent*>(
-      aOwnOrContainingAppToken.get_PBrowserParent());
+    TabParent* opener = static_cast<TabParent*>(aApp.get_PBrowserParent());
 
     // Popup windows of isBrowser frames are 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 (opener && opener->IsBrowserElement() && !aIsBrowserElement) {
         NS_ERROR("Content process attempting to escalate data access privileges");
         return nullptr;
     }
 
-    nsCOMPtr<mozIApplication> app = opener ? opener->GetOwnOrContainingApp() : nullptr;
-    TabParent* parent = new TabParent(app, aIsBrowserElement);
-
+    TabParent* parent = new TabParent(opener ? opener->GetApp() : nullptr,
+                                      aIsBrowserElement);
     // We release this ref in DeallocPBrowser()
     NS_ADDREF(parent);
     return parent;
 }
 
 bool
 ContentParent::DeallocPBrowser(PBrowserParent* frame)
 {
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -68,25 +68,25 @@ public:
      */
     static void StartUp();
     /** Shut down the content-process machinery. */
     static void ShutDown();
 
     static ContentParent* GetNewOrUsed(bool aForBrowserElement = false);
 
     /**
-     * Get or create a content process for the given (app, is-browser)
-     * descriptor.
+     * Get or create a content process for the given app descriptor,
+     * which may be null.  This function will assign processes to app
+     * or non-app browsers by internal heuristics.
      *
-     * The app here is inherited -- that is, <iframe mozbrowser> inside <iframe
-     * mozapp> must pass a non-null app.  aIsBrowserElement should be true
-     * only for <iframe mozbrowser> frames that are not app frames.
+     * Currently apps are given their own process, and browser tabs
+     * share processes.
      */
-    static TabParent* CreateBrowserOrApp(mozIApplication* aOwnOrContainingApp,
-                                         bool aIsBrowserElement);
+    static TabParent* CreateBrowser(mozIApplication* aApp,
+                                    bool aIsBrowserFrame);
 
     static void GetAll(nsTArray<ContentParent*>& aArray);
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOBSERVER
     NS_DECL_NSITHREADOBSERVER
     NS_DECL_NSIDOMGEOPOSITIONCALLBACK
 
@@ -183,18 +183,18 @@ private:
                       base::ProcessId aOtherProcess) MOZ_OVERRIDE;
 
     virtual bool RecvGetProcessAttributes(uint64_t* aId,
                                           bool* aStartBackground,
                                           bool* aIsForApp,
                                           bool* aIsForBrowser) MOZ_OVERRIDE;
 
     virtual PBrowserParent* AllocPBrowser(const uint32_t& aChromeFlags,
-                                          const AppToken& aOwnOrContainingAppToken,
-                                          const bool& aIsBrowserElement);
+                                          const bool& aIsBrowserElement,
+                                          const AppId& aApp);
     virtual bool DeallocPBrowser(PBrowserParent* frame);
 
     virtual PDeviceStorageRequestParent* AllocPDeviceStorageRequest(const DeviceStorageParams&);
     virtual bool DeallocPDeviceStorageRequest(PDeviceStorageRequestParent*);
 
     virtual PBlobParent* AllocPBlob(const BlobConstructorParams& aParams);
     virtual bool DeallocPBlob(PBlobParent*);
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -130,19 +130,17 @@ struct MysteryBlobConstructorParams
 union BlobConstructorParams
 {
   NormalBlobConstructorParams;
   FileBlobConstructorParams;
   SlicedBlobConstructorParams;
   MysteryBlobConstructorParams;
 };
 
-// This struct identifies an app, by providing either a uint32_t (an appID) or a
-// pointer to a PBrowser (whose appID we use to identify the app).
-union AppToken {
+union AppId {
   uint32_t;
   nullable PBrowser;
 };
 
 union PrefValue {
   nsCString;
   int32_t;
   bool;
@@ -182,23 +180,23 @@ rpc protocol PContent
 both:
     // Depending on exactly how the new browser is being created, it might be
     // created from either the child or parent process!
     //
     // The child creates the PBrowser as part of
     // TabChild::BrowserFrameProvideWindow, and the parent creates the
     // PBrowser as part of ContentParent::CreateTab.
     //
-    // When the parent constructs a PBrowser, the app token handed to the child
-    // side is trusted.  In that case, |ownOrContainingApp| is a uint32_t.
-    // However, when the child side constructs a PBrowser, for window.open(),
-    // the parent must validate the app ID used on the parent side.  To do so,
-    // the child process must pass a valid PBrowser as its |ownOrContainingApp|.
-    async PBrowser(uint32_t chromeFlags, AppToken ownOrContainingApp,
-                   bool isBrowserFrame);
+    // When the parent constructs a PBrowser, the app ID handed to the
+    // child side is trusted.  In that case, |appId| is uint32_t.
+    // However, when the child side constructs a PBrowser, for
+    // window.open(), the parent must validate the app ID used on the
+    // parent side.  To do so, the child process must pass a valid
+    // PBrowser as its |AppId|.
+    async PBrowser(uint32_t chromeFlags, bool isBrowserElement, AppId appId);
 
     async PBlob(BlobConstructorParams params);
 
 child:
     PMemoryReportRequest();
 
     /**
      * Dump the contents of about:memory to a file in our temp directory.
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -129,52 +129,50 @@ TabChild::PreloadSlowThings()
     tab->TryCacheLoadAndCompileScript(BROWSER_ELEMENT_CHILD_SCRIPT);
 
     sPreallocatedTab = tab;
     ClearOnShutdown(&sPreallocatedTab);
 }
 
 /*static*/ already_AddRefed<TabChild>
 TabChild::Create(uint32_t aChromeFlags,
-                 uint32_t aOwnOrContainingAppId,
-                 bool aIsBrowserElement)
+                 bool aIsBrowserElement, uint32_t aAppId)
 {
     if (sPreallocatedTab &&
         sPreallocatedTab->mChromeFlags == aChromeFlags &&
-        (aIsBrowserElement ||
-         aOwnOrContainingAppId != nsIScriptSecurityManager::NO_APP_ID)) {
+        (aIsBrowserElement || 
+         aAppId != nsIScriptSecurityManager::NO_APP_ID)) {
         nsRefPtr<TabChild> child = sPreallocatedTab.get();
         sPreallocatedTab = nullptr;
 
         MOZ_ASSERT(!child->mTriedBrowserInit);
 
-        child->SetAppBrowserConfig(aOwnOrContainingAppId, aIsBrowserElement);
+        child->SetAppBrowserConfig(aIsBrowserElement, aAppId);
 
         return child.forget();
     }
 
-    nsRefPtr<TabChild> iframe =
-        new TabChild(aChromeFlags, aOwnOrContainingAppId, aIsBrowserElement);
+    nsRefPtr<TabChild> iframe = new TabChild(aChromeFlags, aIsBrowserElement,
+                                             aAppId);
     return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr;
 }
 
 
-TabChild::TabChild(uint32_t aChromeFlags,
-                   uint32_t aOwnOrContainingAppId,
-                   bool aIsBrowserElement)
+TabChild::TabChild(uint32_t aChromeFlags, bool aIsBrowserElement,
+                   uint32_t aAppId)
   : mRemoteFrame(nullptr)
   , mTabChildGlobal(nullptr)
   , mChromeFlags(aChromeFlags)
   , mOuterRect(0, 0, 0, 0)
   , mInnerSize(0, 0)
   , mOldViewportWidth(0.0f)
   , mLastBackgroundColor(NS_RGB(255, 255, 255))
-  , mOwnOrContainingAppId(aOwnOrContainingAppId)
+  , mAppId(aAppId)
+  , mDidFakeShow(false)
   , mIsBrowserElement(aIsBrowserElement)
-  , mDidFakeShow(false)
   , mNotified(false)
   , mContentDocumentIsDisplayed(false)
   , mTriedBrowserInit(false)
 {
     printf("creating %d!\n", NS_IsMainThread());
 }
 
 NS_IMETHODIMP
@@ -527,17 +525,17 @@ TabChild::Init()
     nsIntRect(nsIntPoint(0, 0), nsIntSize(0, 0)),
     nullptr,                 // HandleWidgetEvent
     nullptr                  // nsDeviceContext
   );
 
   baseWindow->InitWindow(0, mWidget, 0, 0, 0, 0);
   baseWindow->Create();
 
-  SetAppBrowserConfig(mOwnOrContainingAppId, mIsBrowserElement);
+  SetAppBrowserConfig(mIsBrowserElement, mAppId);
 
   // IPC uses a WebBrowser object for which DNS prefetching is turned off
   // by default. But here we really want it, so enable it explicitly
   nsCOMPtr<nsIWebBrowserSetup> webBrowserSetup =
     do_QueryInterface(baseWindow);
   if (webBrowserSetup) {
     webBrowserSetup->SetProperty(nsIWebBrowserSetup::SETUP_ALLOW_DNS_PREFETCH,
                                  true);
@@ -551,37 +549,28 @@ TabChild::Init()
   nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
   NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE);
   webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_LOCATION);
 
   return NS_OK;
 }
 
 void
-TabChild::SetAppBrowserConfig(uint32_t aOwnOrContainingAppId, bool aIsBrowserElement)
+TabChild::SetAppBrowserConfig(bool aIsBrowserElement, uint32_t aAppId)
 {
-    mOwnOrContainingAppId = aOwnOrContainingAppId;
     mIsBrowserElement = aIsBrowserElement;
+    mAppId = aAppId;
 
     nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mWebNav);
     MOZ_ASSERT(docShell);
 
-    // We assume here that if !aIsBrowserElement and aOwnOrContainingAppId is
-    // not NO_APP_ID or UNKNOWN_APP_ID then the app id is our own app id, and
-    // not the id of a containing app.  That is, a TabChild that's contained
-    // inside an app must itself be an app or a browser.  Put another way, you
-    // can't have a remote non-app non-browser iframe contained inside an app.
-
     if (docShell) {
-        // nsDocShell will do the right thing if we pass NO_APP_ID or
-        // UNKNOWN_APP_ID for aOwnOrContainingAppId.
-        if (aIsBrowserElement) {
-          docShell->SetIsBrowserInsideApp(aOwnOrContainingAppId);
-        } else {
-          docShell->SetIsApp(aOwnOrContainingAppId);
+        docShell->SetAppId(mAppId);
+        if (mIsBrowserElement) {
+            docShell->SetIsBrowserElement();
         }
     }
 }
 
 NS_INTERFACE_MAP_BEGIN(TabChild)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
@@ -795,21 +784,21 @@ TabChild::ProvideWindow(nsIDOMWindow* aP
                         bool aCalledFromJS,
                         bool aPositionSpecified, bool aSizeSpecified,
                         nsIURI* aURI, const nsAString& aName,
                         const nsACString& aFeatures, bool* aWindowIsNew,
                         nsIDOMWindow** aReturn)
 {
     *aReturn = nullptr;
 
-    // If aParent is inside an <iframe mozbrowser> or <iframe mozapp> and this
-    // isn't a request to open a modal-type window, we're going to create a new
-    // <iframe mozbrowser/mozapp> and return its window here.
+    // If aParent is inside an <iframe mozbrowser> and this isn't a request to
+    // open a modal-type window, we're going to create a new <iframe mozbrowser>
+    // and return its window here.
     nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent);
-    if (docshell && docshell->GetIsInBrowserOrApp() &&
+    if (docshell && docshell->GetIsBelowContentBoundary() &&
         !(aChromeFlags & (nsIWebBrowserChrome::CHROME_MODAL |
                           nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
                           nsIWebBrowserChrome::CHROME_OPENAS_CHROME))) {
 
       // Note that BrowserFrameProvideWindow may return NS_ERROR_ABORT if the
       // open window call was canceled.  It's important that we pass this error
       // code back to our caller.
       return BrowserFrameProvideWindow(aParent, aURI, aName, aFeatures,
@@ -835,25 +824,25 @@ TabChild::BrowserFrameProvideWindow(nsID
                                     const nsAString& aName,
                                     const nsACString& aFeatures,
                                     bool* aWindowIsNew,
                                     nsIDOMWindow** aReturn)
 {
   *aReturn = nullptr;
 
   uint32_t chromeFlags = 0;
-  nsRefPtr<TabChild> newChild =
-      new TabChild(chromeFlags, mOwnOrContainingAppId, mIsBrowserElement);
+  nsRefPtr<TabChild> newChild = new TabChild(chromeFlags,
+                                             mIsBrowserElement, mAppId);
   if (!NS_SUCCEEDED(newChild->Init())) {
       return NS_ERROR_ABORT;
   }
   unused << Manager()->SendPBrowserConstructor(
       // We release this ref in DeallocPBrowserChild
       nsRefPtr<TabChild>(newChild).forget().get(),
-      chromeFlags, this, mIsBrowserElement);
+      chromeFlags, mIsBrowserElement, this);
   nsAutoCString spec;
   if (aURI) {
     aURI->GetSpec(spec);
   }
 
   NS_ConvertUTF8toUTF16 url(spec);
   nsString name(aName);
   NS_ConvertUTF8toUTF16 features(aFeatures);
@@ -1004,29 +993,28 @@ TabChild::~TabChild()
       }
       mTabChildGlobal->mTabChild = nullptr;
     }
 }
 
 void
 TabChild::SetProcessNameToAppName()
 {
-  if (IsBrowserOrApp()) {
+  if (mIsBrowserElement || (mAppId == nsIScriptSecurityManager::NO_APP_ID)) {
     return;
   }
-
   nsCOMPtr<nsIAppsService> appsService =
     do_GetService(APPS_SERVICE_CONTRACTID);
   if (!appsService) {
     NS_WARNING("No AppsService");
     return;
   }
   nsresult rv;
   nsCOMPtr<mozIDOMApplication> domApp;
-  rv = appsService->GetAppByLocalId(mOwnOrContainingAppId, getter_AddRefs(domApp));
+  rv = appsService->GetAppByLocalId(mAppId, getter_AddRefs(domApp));
   if (NS_FAILED(rv) || !domApp) {
     NS_WARNING("GetAppByLocalId failed");
     return;
   }
   nsCOMPtr<mozIApplication> app = do_QueryInterface(domApp);
   if (!app) {
     NS_WARNING("app isn't a mozIApplication");
     return;
@@ -1037,28 +1025,21 @@ TabChild::SetProcessNameToAppName()
     NS_WARNING("Failed to retrieve app name");
     return;
   }
 
   ContentChild::GetSingleton()->SetProcessName(appName);
 }
 
 bool
-TabChild::IsBrowserOrApp()
-{
-    return mIsBrowserElement ||
-           mOwnOrContainingAppId != nsIScriptSecurityManager::NO_APP_ID;
-}
-
-bool
 TabChild::IsRootContentDocument()
 {
-    if (IsBrowserOrApp()) {
-        // The child side of a browser or app element always behaves like a root
-        // content document.
+    if (mIsBrowserElement || mAppId == nsIScriptSecurityManager::NO_APP_ID) {
+        // We're the child side of a browser element.  This always
+        // behaves like a root content document.
         return true;
     }
 
     // Otherwise, we're the child side of an <html:app remote=true>
     // embedded in an outer <html:app>.  These don't behave like root
     // content documents in nested contexts.  Because of bug 761935,
     // <html:browser remote> and <html:app remote> can't nest, so we
     // assume this isn't the root.  When that bug is fixed, we need to
@@ -1701,17 +1682,17 @@ TabChild::InitTabChildGlobal(FrameScript
 
     chromeHandler->AddEventListener(NS_LITERAL_STRING("DOMMetaAdded"), this, false);
   }
 
   if (aScriptLoading != DONT_LOAD_SCRIPTS && !mTriedBrowserInit) {
     mTriedBrowserInit = true;
     // Initialize the child side of the browser element machinery,
     // if appropriate.
-    if (IsBrowserOrApp()) {
+    if (mIsBrowserElement || mAppId != nsIScriptSecurityManager::NO_APP_ID) {
       RecvLoadRemoteScript(BROWSER_ELEMENT_CHILD_SCRIPT);
     }
   }
 
   return true;
 }
 
 bool
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -159,25 +159,21 @@ public:
      * This is expected to be called off the critical path to content
      * startup.  This is an opportunity to load things that are slow
      * on the critical path.
      */
     static void PreloadSlowThings();
 
     /** Return a TabChild with the given attributes. */
     static already_AddRefed<TabChild> 
-    Create(uint32_t aChromeFlags, uint32_t aOwnOrContainingAppId, bool aIsBrowserElement);
+    Create(uint32_t aChromeFlags, bool aIsBrowserElement, uint32_t aAppId);
 
     virtual ~TabChild();
 
-    uint32_t GetOwnOrContainingAppId() { return mOwnOrContainingAppId; }
-
-    // Does this TabChild correspond to a browser or app frame?
-    // Equivalent to mIsBrowserElement || GetOwnOrContainingAppId() != NO_APP_ID.
-    bool IsBrowserOrApp();
+    uint32_t GetAppId() { return mAppId; }
 
     bool IsRootContentDocument();
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBBROWSERCHROME
     NS_DECL_NSIWEBBROWSERCHROME2
     NS_DECL_NSIEMBEDDINGSITEWINDOW
     NS_DECL_NSIWEBBROWSERCHROMEFOCUS
@@ -310,26 +306,25 @@ protected:
                                              bool* /* aAllowed */);
 
     virtual bool DeallocPIndexedDB(PIndexedDBChild* aActor);
 
 private:
     /**
      * Create a new TabChild object.
      *
-     * |aOwnOrContainingAppId| is the app-id of our frame or of the closest app
-     * frame in the hierarchy which contains us.
-     *
-     * |aIsBrowserElement| indicates whether we're a browser (but not an app).
+     * |aIsBrowserElement| indicates whether the tab is inside an <iframe mozbrowser>.
+     * |aAppId| is the app id of the app containing this tab. If the tab isn't
+     * contained in an app, aAppId will be nsIScriptSecurityManager::NO_APP_ID.
      */
-    TabChild(uint32_t aChromeFlags, uint32_t aOwnOrContainingAppId, bool aIsBrowserElement);
+    TabChild(uint32_t aChromeFlags, bool aIsBrowserElement, uint32_t aAppId);
 
     nsresult Init();
 
-    void SetAppBrowserConfig(uint32_t aOwnOrContainingAppId, bool aIsBrowserElement);
+    void SetAppBrowserConfig(bool aIsBrowserElement, uint32_t aAppId);
 
     bool UseDirectCompositor();
 
     void ActorDestroy(ActorDestroyReason why);
 
     enum FrameScriptLoading { DONT_LOAD_SCRIPTS, DEFAULT_LOAD_SCRIPTS };
     bool InitTabChildGlobal(FrameScriptLoading aScriptLoading = DEFAULT_LOAD_SCRIPTS);
     bool InitRenderingState();
@@ -383,19 +378,19 @@ private:
     RenderFrameChild* mRemoteFrame;
     nsRefPtr<TabChildGlobal> mTabChildGlobal;
     uint32_t mChromeFlags;
     nsIntRect mOuterRect;
     nsIntSize mInnerSize;
     float mOldViewportWidth;
     nscolor mLastBackgroundColor;
     ScrollingBehavior mScrolling;
-    uint32_t mOwnOrContainingAppId;
+    uint32_t mAppId;
+    bool mDidFakeShow;
     bool mIsBrowserElement;
-    bool mDidFakeShow;
     bool mNotified;
     bool mContentDocumentIsDisplayed;
     bool mTriedBrowserInit;
 
     DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 inline TabChild*
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -68,29 +68,29 @@ namespace mozilla {
 namespace dom {
 
 TabParent* sEventCapturer;
 
 TabParent *TabParent::mIMETabParent = nullptr;
 
 NS_IMPL_ISUPPORTS3(TabParent, nsITabParent, nsIAuthPromptProvider, nsISecureBrowserUI)
 
-TabParent::TabParent(mozIApplication* aOwnOrContainingApp, bool aIsBrowserElement)
+TabParent::TabParent(mozIApplication* aApp, bool aIsBrowserElement)
   : mFrameElement(NULL)
-  , mOwnOrContainingApp(aOwnOrContainingApp)
-  , mIsBrowserElement(aIsBrowserElement)
+  , mApp(aApp)
   , mIMESelectionAnchor(0)
   , mIMESelectionFocus(0)
   , mIMEComposing(false)
   , mIMECompositionEnding(false)
   , mIMECompositionStart(0)
   , mIMESeqno(0)
   , mEventCaptureDepth(0)
   , mDimensions(0, 0)
   , mDPI(0)
+  , mIsBrowserElement(aIsBrowserElement)
   , mShown(false)
 {
 }
 
 TabParent::~TabParent()
 {
 }
 
@@ -183,17 +183,17 @@ TabParent::RecvEvent(const RemoteDOMEven
 bool
 TabParent::AnswerCreateWindow(PBrowserParent** retval)
 {
     if (!mBrowserDOMWindow) {
         return false;
     }
 
     // Only non-app, non-browser processes may call CreateWindow.
-    if (IsBrowserOrApp()) {
+    if (GetApp() || IsBrowserElement()) {
         return false;
     }
 
     // Get a new rendering area from the browserDOMWin.  We don't want
     // to be starting any loads here, so get it with a null URI.
     nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner;
     mBrowserDOMWindow->OpenURIInFrame(nullptr, nullptr,
                                       nsIBrowserDOMWindow::OPEN_NEWTAB,
@@ -887,19 +887,19 @@ TabParent::RecvPIndexedDBConstructor(PIn
     NS_RUNTIMEABORT("Not supported yet!");
   }
 
   nsresult rv;
 
   // XXXbent Need to make sure we have a whitelist for chrome databases!
 
   // Verify the appID in the origin first.
-  if (mOwnOrContainingApp && !aASCIIOrigin.EqualsLiteral("chrome")) {
+  if (mApp && !aASCIIOrigin.EqualsLiteral("chrome")) {
     uint32_t appId;
-    rv = mOwnOrContainingApp->GetLocalId(&appId);
+    rv = mApp->GetLocalId(&appId);
     NS_ENSURE_SUCCESS(rv, false);
 
     if (!IndexedDatabaseManager::OriginMatchesApp(aASCIIOrigin, appId)) {
       NS_WARNING("App attempted to open databases that it does not have "
                  "permission to access!");
       return false;
     }
   }
@@ -1154,31 +1154,37 @@ TabParent::GetWidget() const
   if (!frame)
     return nullptr;
 
   nsCOMPtr<nsIWidget> widget = frame->GetNearestWidget();
   return widget.forget();
 }
 
 bool
-TabParent::IsForBrowserOrApp()
+TabParent::IsForMozBrowser()
 {
-  nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mFrameElement);
-  return browserFrame ? browserFrame->GetReallyIsBrowserOrApp() : false;
+  nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement);
+  nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(content);
+  if (browserFrame) {
+    bool isBrowser = false;
+    browserFrame->GetReallyIsBrowser(&isBrowser);
+    return isBrowser;
+  }
+  return false;
 }
 
 bool
 TabParent::UseAsyncPanZoom()
 {
   bool usingOffMainThreadCompositing = !!CompositorParent::CompositorLoop();
   bool asyncPanZoomEnabled =
     Preferences::GetBool("layers.async-pan-zoom.enabled", false);
   ContentParent* cp = static_cast<ContentParent*>(Manager());
   return (usingOffMainThreadCompositing &&
-          !cp->IsForApp() && IsForBrowserOrApp() &&
+          !cp->IsForApp() && IsForMozBrowser() &&
           asyncPanZoomEnabled);
 }
 
 void
 TabParent::MaybeForwardEventToRenderFrame(const nsInputEvent& aEvent,
                                           nsInputEvent* aOutEvent)
 {
   if (RenderFrameParent* rfp = GetRenderFrame()) {
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -49,28 +49,27 @@ class ContentDialogParent : public PCont
 class TabParent : public PBrowserParent 
                 , public nsITabParent 
                 , public nsIAuthPromptProvider
                 , public nsISecureBrowserUI
 {
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
 
 public:
-    TabParent(mozIApplication* aOwnOrContainingApp, bool aIsBrowserElement);
+    TabParent(mozIApplication* aApp, bool aIsBrowserElement);
     virtual ~TabParent();
     nsIDOMElement* GetOwnerElement() { return mFrameElement; }
     void SetOwnerElement(nsIDOMElement* aElement);
     nsIBrowserDOMWindow *GetBrowserDOMWindow() { return mBrowserDOMWindow; }
     void SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserDOMWindow) {
         mBrowserDOMWindow = aBrowserDOMWindow;
     }
  
-    mozIApplication* GetOwnOrContainingApp() { return mOwnOrContainingApp; }
+    mozIApplication* GetApp() { return mApp; }
     bool IsBrowserElement() { return mIsBrowserElement; }
-    bool IsBrowserOrApp() { return GetOwnOrContainingApp() || IsBrowserElement(); }
 
     /**
      * Return the TabParent that has decided it wants to capture an
      * event series for fast-path dispatch to its subprocess, if one
      * has.
      *
      * DOM event dispatch and widget are free to ignore capture
      * requests from TabParents; the end result wrt remote content is
@@ -257,19 +256,17 @@ protected:
     bool AllowContentIME();
 
     virtual PRenderFrameParent* AllocPRenderFrame(ScrollingBehavior* aScrolling,
                                                   LayersBackend* aBackend,
                                                   int32_t* aMaxTextureSize,
                                                   uint64_t* aLayersId) MOZ_OVERRIDE;
     virtual bool DeallocPRenderFrame(PRenderFrameParent* aFrame) MOZ_OVERRIDE;
 
-    nsCOMPtr<mozIApplication> mOwnOrContainingApp;
-    bool mIsBrowserElement;
-
+    nsCOMPtr<mozIApplication> mApp;
     // IME
     static TabParent *mIMETabParent;
     nsString mIMECacheText;
     uint32_t mIMESelectionAnchor;
     uint32_t mIMESelectionFocus;
     bool mIMEComposing;
     bool mIMECompositionEnding;
     // Buffer to store composition text during ResetInputState
@@ -278,26 +275,27 @@ protected:
     uint32_t mIMECompositionStart;
     uint32_t mIMESeqno;
 
     // The number of event series we're currently capturing.
     int32_t mEventCaptureDepth;
 
     nsIntSize mDimensions;
     float mDPI;
+    bool mIsBrowserElement;
     bool mShown;
 
 private:
     already_AddRefed<nsFrameLoader> GetFrameLoader() const;
     already_AddRefed<nsIWidget> GetWidget() const;
     layout::RenderFrameParent* GetRenderFrame();
     void TryCacheDPI();
-    // Return true iff this TabParent was created for a mozbrowser or mozapp
+    // Return true iff this TabParent was created for a mozbrowser
     // frame.
-    bool IsForBrowserOrApp();
+    bool IsForMozBrowser();
     // When true, we create a pan/zoom controller for our frame and
     // notify it of input events targeting us.
     bool UseAsyncPanZoom();
     // If we have a render frame currently, notify it that we're about
     // to dispatch |aEvent| to our child.  If there's a relevant
     // transform in place, |aOutEvent| is the transformed |aEvent| to
     // dispatch to content.
     void MaybeForwardEventToRenderFrame(const nsInputEvent& aEvent,
--- a/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
@@ -1628,18 +1628,22 @@ uint32_t nsWindowWatcher::CalculateChrom
   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()) {
-    chromeFlags &= ~nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
+  if (docshell) {
+    bool belowContentBoundary = false;
+    docshell->GetIsBelowContentBoundary(&belowContentBoundary);
+    if (belowContentBoundary) {
+      chromeFlags &= ~nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
+    }
   }
 
   return chromeFlags;
 }
 
 // static
 int32_t
 nsWindowWatcher::WinHasOption(const char *aOptions, const char *aName,
--- a/xpfe/appshell/src/nsContentTreeOwner.cpp
+++ b/xpfe/appshell/src/nsContentTreeOwner.cpp
@@ -846,17 +846,17 @@ nsContentTreeOwner::ProvideWindow(nsIDOM
                                static_cast<nsIDocShellTreeOwner*>(this)),
                "Parent from wrong docshell tree?");
 #endif
 
   // If aParent is inside an <iframe mozbrowser> and this isn't a request to
   // open a modal-type window, we're going to create a new <iframe mozbrowser>
   // and return its window here.
   nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent);
-  if (docshell && docshell->GetIsInBrowserOrApp() &&
+  if (docshell && docshell->GetIsBelowContentBoundary() &&
       !(aChromeFlags & (nsIWebBrowserChrome::CHROME_MODAL |
                         nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
                         nsIWebBrowserChrome::CHROME_OPENAS_CHROME))) {
     *aWindowIsNew =
       BrowserElementParent::OpenWindowInProcess(aParent, aURI, aName,
                                                 aFeatures, aReturn);
 
     // If OpenWindowInProcess failed (perhaps because the embedder blocked the