Bug 960783 - Add nsILoadContext flags for remote (out-of-process) windows (r=ehsan)
authorBill McCloskey <wmccloskey@mozilla.com>
Tue, 11 Feb 2014 09:00:54 -0800
changeset 168252 ff1b69bfa7f2848519974cd665e9446bea6ca3b4
parent 168251 b95f0e417ba1ac50585efbbb3409922d9484df69
child 168253 08b4b4b4aef3fd01b342dd50ee44bf2c9590e854
push idunknown
push userunknown
push dateunknown
reviewersehsan
bugs960783
milestone30.0a1
Bug 960783 - Add nsILoadContext flags for remote (out-of-process) windows (r=ehsan)
docshell/base/LoadContext.cpp
docshell/base/LoadContext.h
docshell/base/SerializedLoadContext.cpp
docshell/base/SerializedLoadContext.h
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsILoadContext.idl
dom/ipc/TabChild.cpp
dom/ipc/TabParent.cpp
embedding/browser/webBrowser/nsIWebBrowserChrome.idl
embedding/components/windowwatcher/src/nsWindowWatcher.cpp
uriloader/prefetch/OfflineCacheUpdateParent.cpp
--- a/docshell/base/LoadContext.cpp
+++ b/docshell/base/LoadContext.cpp
@@ -85,16 +85,36 @@ LoadContext::SetPrivateBrowsing(bool aUs
 {
   MOZ_ASSERT(mIsNotNull);
 
   // We shouldn't need this on parent...
   return NS_ERROR_UNEXPECTED;
 }
 
 NS_IMETHODIMP
+LoadContext::GetUseRemoteTabs(bool* aUseRemoteTabs)
+{
+  MOZ_ASSERT(mIsNotNull);
+
+  NS_ENSURE_ARG_POINTER(aUseRemoteTabs);
+
+  *aUseRemoteTabs = mUseRemoteTabs;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+LoadContext::SetRemoteTabs(bool aUseRemoteTabs)
+{
+  MOZ_ASSERT(mIsNotNull);
+
+  // We shouldn't need this on parent...
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
 LoadContext::GetIsInBrowserElement(bool* aIsInBrowserElement)
 {
   MOZ_ASSERT(mIsNotNull);
 
   NS_ENSURE_ARG_POINTER(aIsInBrowserElement);
 
   *aIsInBrowserElement = mIsInBrowserElement;
   return NS_OK;
--- a/docshell/base/LoadContext.h
+++ b/docshell/base/LoadContext.h
@@ -43,54 +43,59 @@ public:
   // by child process.
   LoadContext(const IPC::SerializedLoadContext& aToCopy,
               dom::Element* aTopFrameElement,
               uint32_t aAppId, bool aInBrowser)
     : mTopFrameElement(do_GetWeakReference(aTopFrameElement))
     , mAppId(aAppId)
     , mIsContent(aToCopy.mIsContent)
     , mUsePrivateBrowsing(aToCopy.mUsePrivateBrowsing)
+    , mUseRemoteTabs(aToCopy.mUseRemoteTabs)
     , mIsInBrowserElement(aInBrowser)
 #ifdef DEBUG
     , mIsNotNull(aToCopy.mIsNotNull)
 #endif
   {}
 
   LoadContext(dom::Element* aTopFrameElement,
               uint32_t aAppId,
               bool aIsContent,
               bool aUsePrivateBrowsing,
+              bool aUseRemoteTabs,
               bool aIsInBrowserElement)
     : mTopFrameElement(do_GetWeakReference(aTopFrameElement))
     , mAppId(aAppId)
     , mIsContent(aIsContent)
     , mUsePrivateBrowsing(aUsePrivateBrowsing)
+    , mUseRemoteTabs(aUseRemoteTabs)
     , mIsInBrowserElement(aIsInBrowserElement)
 #ifdef DEBUG
     , mIsNotNull(true)
 #endif
   {}
 
   // Constructor taking reserved appId for the safebrowsing cookie.
   LoadContext(uint32_t aAppId)
     : mTopFrameElement(nullptr)
     , mAppId(aAppId)
     , mIsContent(false)
     , mUsePrivateBrowsing(false)
+    , mUseRemoteTabs(false)
     , mIsInBrowserElement(false)
 #ifdef DEBUG
     , mIsNotNull(true)
 #endif
   {}
 
 private:
   nsWeakPtr     mTopFrameElement;
   uint32_t      mAppId;
   bool          mIsContent;
   bool          mUsePrivateBrowsing;
+  bool          mUseRemoteTabs;
   bool          mIsInBrowserElement;
 #ifdef DEBUG
   bool          mIsNotNull;
 #endif
 };
 
 } // namespace mozilla
 
--- a/docshell/base/SerializedLoadContext.cpp
+++ b/docshell/base/SerializedLoadContext.cpp
@@ -54,24 +54,26 @@ SerializedLoadContext::SerializedLoadCon
 void
 SerializedLoadContext::Init(nsILoadContext* aLoadContext)
 {
   if (aLoadContext) {
     mIsNotNull = true;
     mIsPrivateBitValid = true;
     aLoadContext->GetIsContent(&mIsContent);
     aLoadContext->GetUsePrivateBrowsing(&mUsePrivateBrowsing);
+    aLoadContext->GetUseRemoteTabs(&mUseRemoteTabs);
     aLoadContext->GetAppId(&mAppId);
     aLoadContext->GetIsInBrowserElement(&mIsInBrowserElement);
   } else {
     mIsNotNull = false;
     mIsPrivateBitValid = false;
     // none of below values really matter when mIsNotNull == false:
     // we won't be GetInterfaced to nsILoadContext
     mIsContent = true;
     mUsePrivateBrowsing = false;
+    mUseRemoteTabs = false;
     mAppId = 0;
     mIsInBrowserElement = false;
   }
 }
 
 } // namespace IPC
 
--- a/docshell/base/SerializedLoadContext.h
+++ b/docshell/base/SerializedLoadContext.h
@@ -49,42 +49,45 @@ public:
 
   // used to indicate if child-side LoadContext * was null.
   bool          mIsNotNull;
   // used to indicate if child-side mUsePrivateBrowsing flag is valid, even if
   // mIsNotNull is false, i.e., child LoadContext was null.
   bool          mIsPrivateBitValid;
   bool          mIsContent;
   bool          mUsePrivateBrowsing;
+  bool          mUseRemoteTabs;
   bool          mIsInBrowserElement;
   uint32_t      mAppId;
 };
 
 // Function to serialize over IPDL
 template<>
 struct ParamTraits<SerializedLoadContext>
 {
   typedef SerializedLoadContext paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mIsNotNull);
     WriteParam(aMsg, aParam.mIsContent);
     WriteParam(aMsg, aParam.mIsPrivateBitValid);
     WriteParam(aMsg, aParam.mUsePrivateBrowsing);
+    WriteParam(aMsg, aParam.mUseRemoteTabs);
     WriteParam(aMsg, aParam.mAppId);
     WriteParam(aMsg, aParam.mIsInBrowserElement);
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     if (!ReadParam(aMsg, aIter, &aResult->mIsNotNull) ||
         !ReadParam(aMsg, aIter, &aResult->mIsContent)  ||
         !ReadParam(aMsg, aIter, &aResult->mIsPrivateBitValid)  ||
         !ReadParam(aMsg, aIter, &aResult->mUsePrivateBrowsing)  ||
+        !ReadParam(aMsg, aIter, &aResult->mUseRemoteTabs)  ||
         !ReadParam(aMsg, aIter, &aResult->mAppId)  ||
         !ReadParam(aMsg, aIter, &aResult->mIsInBrowserElement)) {
       return false;
     }
 
     return true;
   }
 };
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -824,16 +824,17 @@ nsDocShell::nsDocShell():
     mObserveErrorPages(true),
     mAllowAuth(true),
     mAllowKeywordFixup(false),
     mIsOffScreenBrowser(false),
     mIsActive(true),
     mIsAppTab(false),
     mUseGlobalHistory(false),
     mInPrivateBrowsing(false),
+    mUseRemoteTabs(false),
     mDeviceSizeIsPageSize(false),
     mCanExecuteScripts(false),
     mFiredUnloadEvent(false),
     mEODForCurrentDocument(false),
     mURIResultedInDocument(false),
     mIsBeingDestroyed(false),
     mIsExecutingOnLoadHandler(false),
     mIsPrintingOrPP(false),
@@ -2241,16 +2242,32 @@ nsDocShell::SetPrivateBrowsing(bool aUse
                 obs->PrivateModeChanged(aUsePrivateBrowsing);
             }
         }
     }
     return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDocShell::GetUseRemoteTabs(bool* aUseRemoteTabs)
+{
+    NS_ENSURE_ARG_POINTER(aUseRemoteTabs);
+
+    *aUseRemoteTabs = mUseRemoteTabs;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetRemoteTabs(bool aUseRemoteTabs)
+{
+    mUseRemoteTabs = aUseRemoteTabs;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDocShell::SetAffectPrivateSessionLifetime(bool aAffectLifetime)
 {
     bool change = aAffectLifetime != mAffectPrivateSessionLifetime;
     if (change && mInPrivateBrowsing) {
         if (aAffectLifetime) {
             IncreasePrivateDocShellCount();
         } else {
             DecreasePrivateDocShellCount();
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -208,16 +208,18 @@ public:
     NS_IMETHOD GetAssociatedWindow(nsIDOMWindow**);
     NS_IMETHOD GetTopWindow(nsIDOMWindow**);
     NS_IMETHOD GetTopFrameElement(nsIDOMElement**);
     NS_IMETHOD IsAppOfType(uint32_t, bool*);
     NS_IMETHOD GetIsContent(bool*);
     NS_IMETHOD GetUsePrivateBrowsing(bool*);
     NS_IMETHOD SetUsePrivateBrowsing(bool);
     NS_IMETHOD SetPrivateBrowsing(bool);
+    NS_IMETHOD GetUseRemoteTabs(bool*);
+    NS_IMETHOD SetRemoteTabs(bool);
 
     // Restores a cached presentation from history (mLSHE).
     // This method swaps out the content viewer and simulates loads for
     // subframes.  It then simulates the completion of the toplevel load.
     nsresult RestoreFromHistory();
 
     // Perform a URI load from a refresh timer.  This is just like the
     // ForceRefreshURI method on nsIRefreshURI, but makes sure to take
@@ -825,16 +827,17 @@ protected:
     bool                       mObserveErrorPages;
     bool                       mAllowAuth;
     bool                       mAllowKeywordFixup;
     bool                       mIsOffScreenBrowser;
     bool                       mIsActive;
     bool                       mIsAppTab;
     bool                       mUseGlobalHistory;
     bool                       mInPrivateBrowsing;
+    bool                       mUseRemoteTabs;
     bool                       mDeviceSizeIsPageSize;
 
     // Because scriptability depends on the mAllowJavascript values of our
     // ancestors, we cache the effective scriptability and recompute it when
     // it might have changed;
     bool                       mCanExecuteScripts;
     void RecomputeCanExecuteScripts();
 
--- a/docshell/base/nsILoadContext.idl
+++ b/docshell/base/nsILoadContext.idl
@@ -9,17 +9,17 @@
 interface nsIDOMWindow;
 interface nsIDOMElement;
 
 /**
  * An nsILoadContext represents the context of a load.  This interface
  * can be queried for various information about where the load is
  * happening.
  */
-[scriptable, uuid(d0029474-0cc4-42fd-bb21-d9ff22f5293c)]
+[scriptable, uuid(852ed1f0-8ec0-11e3-baa8-0800200c9a66)]
 interface nsILoadContext : nsISupports
 {
   /**
    * associatedWindow is the window with which the load is associated, if any.
    * Note that the load may be triggered by a document which is different from
    * the document in associatedWindow, and in fact the source of the load need
    * not be same-origin with the document in associatedWindow.  This attribute
    * may be null if there is no associated window.
@@ -61,33 +61,49 @@ interface nsILoadContext : nsISupports
    */
   readonly attribute boolean isContent;
 
   /*
    * Attribute that determines if private browsing should be used.
    */
   attribute boolean usePrivateBrowsing;
 
+  /**
+   * Attribute that determines if remote (out-of-process) tabs should be used.
+   */
+  readonly attribute boolean useRemoteTabs;
+
 %{C++
   /**
    * De-XPCOMed getter to make call-sites cleaner.
    */
   bool UsePrivateBrowsing() {
     bool usingPB;
     GetUsePrivateBrowsing(&usingPB);
     return usingPB;
   }
+
+  bool UseRemoteTabs() {
+    bool usingRT;
+    GetUseRemoteTabs(&usingRT);
+    return usingRT;
+  }
 %}
 
   /**
    * Set the private browsing state of the load context, meant to be used internally.
    */
   [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.
    */
   readonly attribute boolean isInBrowserElement;
 
   /**
    * 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.
    */
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -691,16 +691,18 @@ TabChild::Init()
   MOZ_ASSERT(docShell);
 
   docShell->SetAffectPrivateSessionLifetime(
       mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME);
   nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(mWebNav);
   MOZ_ASSERT(loadContext);
   loadContext->SetPrivateBrowsing(
       mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW);
+  loadContext->SetRemoteTabs(
+      mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
 
   nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
   NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE);
   webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_LOCATION);
 
   return NS_OK;
 }
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1914,16 +1914,17 @@ TabParent::GetLoadContext()
   nsCOMPtr<nsILoadContext> loadContext;
   if (mLoadContext) {
     loadContext = mLoadContext;
   } else {
     loadContext = new LoadContext(GetOwnerElement(),
                                   OwnOrContainingAppId(),
                                   true /* aIsContent */,
                                   mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW,
+                                  mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW,
                                   IsBrowserElement());
     mLoadContext = loadContext;
   }
   return loadContext.forget();
 }
 
 NS_IMETHODIMP
 TabParent::InjectTouchEvent(const nsAString& aType,
--- a/embedding/browser/webBrowser/nsIWebBrowserChrome.idl
+++ b/embedding/browser/webBrowser/nsIWebBrowserChrome.idl
@@ -75,16 +75,19 @@ interface nsIWebBrowserChrome : nsISuppo
     // docshells.
     const unsigned long CHROME_PRIVATE_WINDOW         = 0x00010000;
     const unsigned long CHROME_NON_PRIVATE_WINDOW     = 0x00020000;
     const unsigned long CHROME_PRIVATE_LIFETIME       = 0x00040000;
 
     // Whether this was opened by nsGlobalWindow::ShowModalDialog.
     const unsigned long CHROME_MODAL_CONTENT_WINDOW   = 0x00080000;
 
+    // Whether this window should use remote (out-of-process) tabs.
+    const unsigned long CHROME_REMOTE_WINDOW          = 0x00100000;
+
     // Prevents new window animations on Mac OS X Lion.  Ignored on other
     // platforms.
     const unsigned long CHROME_MAC_SUPPRESS_ANIMATION = 0x01000000;
 
     const unsigned long CHROME_WINDOW_RAISED          = 0x02000000;
     const unsigned long CHROME_WINDOW_LOWERED         = 0x04000000;
     const unsigned long CHROME_CENTER_SCREEN          = 0x08000000;
 
--- a/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
@@ -36,16 +36,17 @@
 #include "nsXPCOM.h"
 #include "nsIURI.h"
 #include "nsIWebBrowser.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIWebNavigation.h"
 #include "nsIWindowCreator.h"
 #include "nsIWindowCreator2.h"
 #include "nsIXPConnect.h"
+#include "nsIXULRuntime.h"
 #include "nsPIDOMWindow.h"
 #include "nsIMarkupDocumentViewer.h"
 #include "nsIContentViewer.h"
 #include "nsIWindowProvider.h"
 #include "nsIMutableArray.h"
 #include "nsISupportsArray.h"
 #include "nsIDOMStorage.h"
 #include "nsIDOMStorageManager.h"
@@ -829,27 +830,34 @@ nsWindowWatcher::OpenWindowInternal(nsID
     nsCOMPtr<nsIDocShellTreeItem> parentItem;
     GetWindowTreeItem(aParent, getter_AddRefs(parentItem));
     nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(parentItem);
     if (parentContext) {
       isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing();
     }
   }
 
+  // We rely on CalculateChromeFlags to decide whether remote (out-of-process)
+  // tabs should be used.
+  bool isRemoteWindow =
+    !!(chromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
+
   if (isNewToplevelWindow) {
     nsCOMPtr<nsIDocShellTreeItem> childRoot;
     newDocShellItem->GetRootTreeItem(getter_AddRefs(childRoot));
     nsCOMPtr<nsILoadContext> childContext = do_QueryInterface(childRoot);
     if (childContext) {
       childContext->SetPrivateBrowsing(isPrivateBrowsingWindow);
+      childContext->SetRemoteTabs(isRemoteWindow);
     }
   } else if (windowIsNew) {
     nsCOMPtr<nsILoadContext> childContext = do_QueryInterface(newDocShellItem);
     if (childContext) {
       childContext->SetPrivateBrowsing(isPrivateBrowsingWindow);
+      childContext->SetRemoteTabs(isRemoteWindow);
     }
   }
 
   nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
   if (uriToLoad && aNavigate) { // get the script principal and pass it to docshell
 
     // The historical ordering of attempts here is:
     // (1) Stack-top cx.
@@ -1423,16 +1431,29 @@ uint32_t nsWindowWatcher::CalculateChrom
   // Determine whether the window is a private browsing window
   if (isCallerChrome) {
     chromeFlags |= WinHasOption(aFeatures, "private", 0, &presenceFlag) ?
       nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW : 0;
     chromeFlags |= WinHasOption(aFeatures, "non-private", 0, &presenceFlag) ?
       nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW : 0;
   }
 
+  // Determine whether the window should have remote tabs.
+  if (isCallerChrome) {
+    bool remote;
+    if (Preferences::GetBool("browser.tabs.remote.autostart")) {
+      remote = !WinHasOption(aFeatures, "non-remote", 0, &presenceFlag);
+    } else {
+      remote = WinHasOption(aFeatures, "remote", 0, &presenceFlag);
+    }
+    if (remote) {
+      chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
+    }
+  }
+
   nsresult rv;
 
   nsCOMPtr<nsIPrefBranch> prefBranch;
   nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, true);
 
   rv = prefs->GetBranch("dom.disable_window_open_feature.", getter_AddRefs(prefBranch));
   NS_ENSURE_SUCCESS(rv, true);
--- a/uriloader/prefetch/OfflineCacheUpdateParent.cpp
+++ b/uriloader/prefetch/OfflineCacheUpdateParent.cpp
@@ -229,16 +229,28 @@ OfflineCacheUpdateParent::SetUsePrivateB
 
 NS_IMETHODIMP
 OfflineCacheUpdateParent::SetPrivateBrowsing(bool aUsePrivateBrowsing)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
+OfflineCacheUpdateParent::GetUseRemoteTabs(bool *aUseRemoteTabs)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+OfflineCacheUpdateParent::SetRemoteTabs(bool aUseRemoteTabs)
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 OfflineCacheUpdateParent::GetIsInBrowserElement(bool *aIsInBrowserElement)
 {
     *aIsInBrowserElement = mIsInBrowserElement;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 OfflineCacheUpdateParent::GetAppId(uint32_t *aAppId)