LCOV - code coverage report
Current view: top level - dom/base - nsFrameLoader.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 691 1774 39.0 %
Date: 2017-07-14 16:53:18 Functions: 57 149 38.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * Class for managing loading of a subframe (creation of the docshell,
       9             :  * handling of loads in it, recursion-checking).
      10             :  */
      11             : 
      12             : #include "base/basictypes.h"
      13             : 
      14             : #include "prenv.h"
      15             : 
      16             : #include "nsDocShell.h"
      17             : #include "nsIDOMHTMLIFrameElement.h"
      18             : #include "nsIDOMHTMLFrameElement.h"
      19             : #include "nsIDOMMozBrowserFrame.h"
      20             : #include "nsIDOMWindow.h"
      21             : #include "nsIPresShell.h"
      22             : #include "nsIContentInlines.h"
      23             : #include "nsIContentViewer.h"
      24             : #include "nsIDocument.h"
      25             : #include "nsIDOMDocument.h"
      26             : #include "nsPIDOMWindow.h"
      27             : #include "nsIWebNavigation.h"
      28             : #include "nsIWebProgress.h"
      29             : #include "nsIDocShell.h"
      30             : #include "nsIDocShellTreeOwner.h"
      31             : #include "nsIDocShellLoadInfo.h"
      32             : #include "nsIBaseWindow.h"
      33             : #include "nsIBrowser.h"
      34             : #include "nsContentUtils.h"
      35             : #include "nsIXPConnect.h"
      36             : #include "nsUnicharUtils.h"
      37             : #include "nsIScriptGlobalObject.h"
      38             : #include "nsIScriptSecurityManager.h"
      39             : #include "nsIScrollable.h"
      40             : #include "nsFrameLoader.h"
      41             : #include "nsIDOMEventTarget.h"
      42             : #include "nsIFrame.h"
      43             : #include "nsIScrollableFrame.h"
      44             : #include "nsSubDocumentFrame.h"
      45             : #include "nsError.h"
      46             : #include "nsISHistory.h"
      47             : #include "nsISHistoryInternal.h"
      48             : #include "nsIDOMHTMLDocument.h"
      49             : #include "nsIXULWindow.h"
      50             : #include "nsIEditor.h"
      51             : #include "nsIMozBrowserFrame.h"
      52             : #include "nsISHistory.h"
      53             : #include "NullPrincipal.h"
      54             : #include "nsIScriptError.h"
      55             : #include "nsGlobalWindow.h"
      56             : #include "nsPIWindowRoot.h"
      57             : #include "nsLayoutUtils.h"
      58             : #include "nsMappedAttributes.h"
      59             : #include "nsView.h"
      60             : #include "nsBaseWidget.h"
      61             : #include "GroupedSHistory.h"
      62             : #include "PartialSHistory.h"
      63             : 
      64             : #include "nsIURI.h"
      65             : #include "nsIURL.h"
      66             : #include "nsNetUtil.h"
      67             : 
      68             : #include "nsGkAtoms.h"
      69             : #include "nsNameSpaceManager.h"
      70             : 
      71             : #include "nsThreadUtils.h"
      72             : 
      73             : #include "nsIDOMChromeWindow.h"
      74             : #include "nsInProcessTabChildGlobal.h"
      75             : 
      76             : #include "Layers.h"
      77             : #include "ClientLayerManager.h"
      78             : 
      79             : #include "ContentParent.h"
      80             : #include "TabParent.h"
      81             : #include "mozilla/AsyncEventDispatcher.h"
      82             : #include "mozilla/BasePrincipal.h"
      83             : #include "mozilla/GuardObjects.h"
      84             : #include "mozilla/Preferences.h"
      85             : #include "mozilla/Unused.h"
      86             : #include "mozilla/dom/Element.h"
      87             : #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
      88             : #include "mozilla/layout/RenderFrameParent.h"
      89             : #include "GeckoProfiler.h"
      90             : 
      91             : #include "jsapi.h"
      92             : #include "mozilla/dom/HTMLIFrameElement.h"
      93             : #include "nsSandboxFlags.h"
      94             : #include "mozilla/layers/CompositorBridgeChild.h"
      95             : #include "mozilla/dom/CustomEvent.h"
      96             : 
      97             : #include "mozilla/dom/ipc/StructuredCloneData.h"
      98             : #include "mozilla/WebBrowserPersistLocalDocument.h"
      99             : #include "mozilla/dom/GroupedHistoryEvent.h"
     100             : #include "mozilla/dom/Promise.h"
     101             : #include "mozilla/dom/PromiseNativeHandler.h"
     102             : 
     103             : #include "mozilla/dom/HTMLBodyElement.h"
     104             : 
     105             : #include "ContentPrincipal.h"
     106             : 
     107             : #ifdef XP_WIN
     108             : #include "mozilla/plugins/PPluginWidgetParent.h"
     109             : #include "../plugins/ipc/PluginWidgetParent.h"
     110             : #endif
     111             : 
     112             : #ifdef MOZ_XUL
     113             : #include "nsXULPopupManager.h"
     114             : #endif
     115             : 
     116             : #ifdef NS_PRINTING
     117             : #include "mozilla/embedding/printingui/PrintingParent.h"
     118             : #include "nsIWebBrowserPrint.h"
     119             : #endif
     120             : 
     121             : using namespace mozilla;
     122             : using namespace mozilla::hal;
     123             : using namespace mozilla::dom;
     124             : using namespace mozilla::dom::ipc;
     125             : using namespace mozilla::layers;
     126             : using namespace mozilla::layout;
     127             : typedef FrameMetrics::ViewID ViewID;
     128             : 
     129             : // Bug 136580: Limit to the number of nested content frames that can have the
     130             : //             same URL. This is to stop content that is recursively loading
     131             : //             itself.  Note that "#foo" on the end of URL doesn't affect
     132             : //             whether it's considered identical, but "?foo" or ";foo" are
     133             : //             considered and compared.
     134             : // Bug 228829: Limit this to 1, like IE does.
     135             : #define MAX_SAME_URL_CONTENT_FRAMES 1
     136             : 
     137             : // Bug 8065: Limit content frame depth to some reasonable level. This
     138             : // does not count chrome frames when determining depth, nor does it
     139             : // prevent chrome recursion.  Number is fairly arbitrary, but meant to
     140             : // keep number of shells to a reasonable number on accidental recursion with a
     141             : // small (but not 1) branching factor.  With large branching factors the number
     142             : // of shells can rapidly become huge and run us out of memory.  To solve that,
     143             : // we'd need to re-institute a fixed version of bug 98158.
     144             : #define MAX_DEPTH_CONTENT_FRAMES 10
     145             : 
     146           0 : NS_IMPL_CYCLE_COLLECTION(nsFrameLoader,
     147             :                          mDocShell,
     148             :                          mMessageManager,
     149             :                          mChildMessageManager,
     150             :                          mOpener,
     151             :                          mPartialSHistory)
     152         362 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameLoader)
     153         343 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameLoader)
     154             : 
     155         650 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader)
     156         646 :   NS_INTERFACE_MAP_ENTRY(nsIFrameLoader)
     157         456 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFrameLoader)
     158         320 :   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPersistable)
     159         320 : NS_INTERFACE_MAP_END
     160             : 
     161           4 : nsFrameLoader::nsFrameLoader(Element* aOwner, nsPIDOMWindowOuter* aOpener,
     162           4 :                              bool aNetworkCreated, int32_t aJSPluginID)
     163             :   : mOwnerContent(aOwner)
     164             :   , mDetachedSubdocFrame(nullptr)
     165             :   , mOpener(aOpener)
     166             :   , mRemoteBrowser(nullptr)
     167             :   , mChildID(0)
     168             :   , mJSPluginID(aJSPluginID)
     169             :   , mEventMode(EVENT_MODE_NORMAL_DISPATCH)
     170             :   , mBrowserChangingProcessBlockers(nullptr)
     171             :   , mIsPrerendered(false)
     172             :   , mDepthTooGreat(false)
     173             :   , mIsTopLevelContent(false)
     174             :   , mDestroyCalled(false)
     175             :   , mNeedsAsyncDestroy(false)
     176             :   , mInSwap(false)
     177             :   , mInShow(false)
     178             :   , mHideCalled(false)
     179             :   , mNetworkCreated(aNetworkCreated)
     180             :   , mRemoteBrowserShown(false)
     181             :   , mRemoteFrame(false)
     182             :   , mClipSubdocument(true)
     183             :   , mClampScrollPosition(true)
     184           4 :   , mObservingOwnerContent(false)
     185             : {
     186           4 :   mRemoteFrame = ShouldUseRemoteProcess();
     187           4 :   MOZ_ASSERT(!mRemoteFrame || !aOpener,
     188             :              "Cannot pass aOpener for a remote frame!");
     189           4 : }
     190             : 
     191           0 : nsFrameLoader::~nsFrameLoader()
     192             : {
     193           0 :   if (mMessageManager) {
     194           0 :     mMessageManager->Disconnect();
     195             :   }
     196           0 :   MOZ_RELEASE_ASSERT(mDestroyCalled);
     197           0 : }
     198             : 
     199             : nsFrameLoader*
     200           4 : nsFrameLoader::Create(Element* aOwner, nsPIDOMWindowOuter* aOpener, bool aNetworkCreated,
     201             :                       int32_t aJSPluginId)
     202             : {
     203           4 :   NS_ENSURE_TRUE(aOwner, nullptr);
     204           4 :   nsIDocument* doc = aOwner->OwnerDoc();
     205             : 
     206             :   // We never create nsFrameLoaders for elements in resource documents.
     207             :   //
     208             :   // We never create nsFrameLoaders for elements in data documents, unless the
     209             :   // document is a static document.
     210             :   // Static documents are an exception because any sub-documents need an
     211             :   // nsFrameLoader to keep the relevant docShell alive, even though the
     212             :   // nsFrameLoader isn't used to load anything (the sub-document is created by
     213             :   // the static clone process).
     214             :   //
     215             :   // We never create nsFrameLoaders for elements that are not
     216             :   // in-composed-document, unless the element belongs to a static document.
     217             :   // Static documents are an exception because this method is called at a point
     218             :   // in the static clone process before aOwner has been inserted into its
     219             :   // document.  For other types of documents this wouldn't be a problem since
     220             :   // we'd create the nsFrameLoader as necessary after aOwner is inserted into a
     221             :   // document, but the mechanisms that take care of that don't apply for static
     222             :   // documents so we need to create the nsFrameLoader now. (This isn't wasteful
     223             :   // since for a static document we know aOwner will end up in a document and
     224             :   // the nsFrameLoader will be used for its docShell.)
     225             :   //
     226           4 :   NS_ENSURE_TRUE(!doc->IsResourceDoc() &&
     227             :                  ((!doc->IsLoadedAsData() && aOwner->IsInComposedDoc()) ||
     228             :                   doc->IsStaticDocument()),
     229             :                  nullptr);
     230             : 
     231           4 :   return new nsFrameLoader(aOwner, aOpener, aNetworkCreated, aJSPluginId);
     232             : }
     233             : 
     234             : NS_IMETHODIMP
     235           4 : nsFrameLoader::LoadFrame()
     236             : {
     237           4 :   NS_ENSURE_TRUE(mOwnerContent, NS_ERROR_NOT_INITIALIZED);
     238             : 
     239           8 :   nsAutoString src;
     240             : 
     241           4 :   bool isSrcdoc = mOwnerContent->IsHTMLElement(nsGkAtoms::iframe) &&
     242           4 :                   mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc);
     243           4 :   if (isSrcdoc) {
     244           0 :     src.AssignLiteral("about:srcdoc");
     245             :   }
     246             :   else {
     247           4 :     GetURL(src);
     248             : 
     249           4 :     src.Trim(" \t\n\r");
     250             : 
     251           4 :     if (src.IsEmpty()) {
     252             :       // If the frame is a XUL element and has the attribute 'nodefaultsrc=true'
     253             :       // then we will not use 'about:blank' as fallback but return early without
     254             :       // starting a load if no 'src' attribute is given (or it's empty).
     255           8 :       if (mOwnerContent->IsXULElement() &&
     256           4 :           mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::nodefaultsrc,
     257             :                                      nsGkAtoms::_true, eCaseMatters)) {
     258           0 :         return NS_OK;
     259             :       }
     260           4 :       src.AssignLiteral("about:blank");
     261             :     }
     262             :   }
     263             : 
     264           4 :   nsIDocument* doc = mOwnerContent->OwnerDoc();
     265           4 :   if (doc->IsStaticDocument()) {
     266           0 :     return NS_OK;
     267             :   }
     268             : 
     269           4 :   if (doc->IsLoadedAsInteractiveData()) {
     270             :     // XBL bindings doc shouldn't load sub-documents.
     271           1 :     return NS_OK;
     272             :   }
     273             : 
     274           6 :   nsCOMPtr<nsIURI> base_uri = mOwnerContent->GetBaseURI();
     275           3 :   auto encoding = doc->GetDocumentCharacterSet();
     276             : 
     277           6 :   nsCOMPtr<nsIURI> uri;
     278           3 :   nsresult rv = NS_NewURI(getter_AddRefs(uri), src, encoding, base_uri);
     279             : 
     280             :   // If the URI was malformed, try to recover by loading about:blank.
     281           3 :   if (rv == NS_ERROR_MALFORMED_URI) {
     282           0 :     rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("about:blank"),
     283           0 :                    encoding, base_uri);
     284             :   }
     285             : 
     286           3 :   if (NS_SUCCEEDED(rv)) {
     287           3 :     rv = LoadURI(uri);
     288             :   }
     289             : 
     290           3 :   if (NS_FAILED(rv)) {
     291           0 :     FireErrorEvent();
     292             : 
     293           0 :     return rv;
     294             :   }
     295             : 
     296           3 :   return NS_OK;
     297             : }
     298             : 
     299             : void
     300           0 : nsFrameLoader::FireErrorEvent()
     301             : {
     302           0 :   if (!mOwnerContent) {
     303           0 :     return;
     304             :   }
     305             :   RefPtr<AsyncEventDispatcher > loadBlockingAsyncDispatcher =
     306           0 :     new LoadBlockingAsyncEventDispatcher(mOwnerContent,
     307           0 :                                          NS_LITERAL_STRING("error"),
     308           0 :                                          false, false);
     309           0 :   loadBlockingAsyncDispatcher->PostDOMEvent();
     310             : }
     311             : 
     312             : NS_IMETHODIMP
     313           3 : nsFrameLoader::LoadURI(nsIURI* aURI)
     314             : {
     315           3 :   if (!aURI)
     316           0 :     return NS_ERROR_INVALID_POINTER;
     317           3 :   NS_ENSURE_STATE(!mDestroyCalled && mOwnerContent);
     318             : 
     319           6 :   nsCOMPtr<nsIDocument> doc = mOwnerContent->OwnerDoc();
     320             : 
     321             :   nsresult rv;
     322             :   // If IsForJSPlugin() returns true then we want to allow the load. We're just
     323             :   // loading the source for the implementation of the JS plugin from a URI
     324             :   // that's under our control. We will already have done the security checks for
     325             :   // loading the plugin content itself in the object/embed loading code.
     326           3 :   if (!IsForJSPlugin()) {
     327           3 :     rv = CheckURILoad(aURI);
     328           3 :     NS_ENSURE_SUCCESS(rv, rv);
     329             :   }
     330             : 
     331           3 :   mURIToLoad = aURI;
     332           3 :   rv = doc->InitializeFrameLoader(this);
     333           3 :   if (NS_FAILED(rv)) {
     334           0 :     mURIToLoad = nullptr;
     335             :   }
     336           3 :   return rv;
     337             : }
     338             : 
     339             : NS_IMETHODIMP
     340           0 : nsFrameLoader::SetIsPrerendered()
     341             : {
     342           0 :   MOZ_ASSERT(!mDocShell, "Please call SetIsPrerendered before docShell is created");
     343           0 :   mIsPrerendered = true;
     344             : 
     345           0 :   return NS_OK;
     346             : }
     347             : 
     348             : NS_IMETHODIMP
     349           0 : nsFrameLoader::MakePrerenderedLoaderActive()
     350             : {
     351           0 :   MOZ_ASSERT(mIsPrerendered, "This frameloader was not in prerendered mode.");
     352             : 
     353           0 :   mIsPrerendered = false;
     354           0 :   if (IsRemoteFrame()) {
     355           0 :     if (!mRemoteBrowser) {
     356           0 :       NS_WARNING("Missing remote browser.");
     357           0 :       return NS_ERROR_FAILURE;
     358             :     }
     359             : 
     360           0 :     mRemoteBrowser->SetDocShellIsActive(true);
     361             :   } else {
     362           0 :     if (!mDocShell) {
     363           0 :       NS_WARNING("Missing docshell.");
     364           0 :       return NS_ERROR_FAILURE;
     365             :     }
     366             : 
     367           0 :     nsresult rv = mDocShell->SetIsActive(true);
     368           0 :     NS_ENSURE_SUCCESS(rv, rv);
     369             :   }
     370             : 
     371           0 :   return NS_OK;
     372             : }
     373             : 
     374             : NS_IMETHODIMP
     375           0 : nsFrameLoader::GetPartialSHistory(nsIPartialSHistory** aResult)
     376             : {
     377           0 :   if (mRemoteBrowser && !mPartialSHistory) {
     378             :     // For remote case we can lazy initialize PartialSHistory since
     379             :     // it doens't need to be registered as a listener to nsISHistory directly.
     380           0 :     mPartialSHistory = new PartialSHistory(this);
     381             :   }
     382             : 
     383           0 :   nsCOMPtr<nsIPartialSHistory> partialHistory(mPartialSHistory);
     384           0 :   partialHistory.forget(aResult);
     385           0 :   return NS_OK;
     386             : }
     387             : 
     388             : NS_IMETHODIMP
     389           0 : nsFrameLoader::EnsureGroupedSHistory(nsIGroupedSHistory** aResult)
     390             : {
     391           0 :   nsCOMPtr<nsIPartialSHistory> partialHistory;
     392           0 :   GetPartialSHistory(getter_AddRefs(partialHistory));
     393           0 :   MOZ_ASSERT(partialHistory);
     394             : 
     395           0 :   nsCOMPtr<nsIGroupedSHistory> groupedHistory;
     396           0 :   partialHistory->GetGroupedSHistory(getter_AddRefs(groupedHistory));
     397           0 :   if (!groupedHistory) {
     398           0 :     groupedHistory = new GroupedSHistory();
     399           0 :     groupedHistory->AppendPartialSHistory(partialHistory);
     400             : 
     401             : #ifdef DEBUG
     402           0 :     nsCOMPtr<nsIGroupedSHistory> test;
     403           0 :     GetGroupedSHistory(getter_AddRefs(test));
     404           0 :     MOZ_ASSERT(test == groupedHistory, "GroupedHistory must match");
     405             : #endif
     406             :   }
     407             : 
     408           0 :   groupedHistory.forget(aResult);
     409           0 :   return NS_OK;
     410             : }
     411             : 
     412             : NS_IMETHODIMP
     413           0 : nsFrameLoader::GetGroupedSHistory(nsIGroupedSHistory** aResult)
     414             : {
     415           0 :   nsCOMPtr<nsIGroupedSHistory> groupedSHistory;
     416           0 :   if (mPartialSHistory) {
     417           0 :     mPartialSHistory->GetGroupedSHistory(getter_AddRefs(groupedSHistory));
     418             :   }
     419           0 :   groupedSHistory.forget(aResult);
     420           0 :   return NS_OK;
     421             : }
     422             : 
     423             : bool
     424           0 : nsFrameLoader::SwapBrowsersAndNotify(nsFrameLoader* aOther)
     425             : {
     426             :   // Cache the owner content before calling SwapBrowsers, which will change
     427             :   // these member variables.
     428           0 :   RefPtr<mozilla::dom::Element> primaryContent = mOwnerContent;
     429           0 :   RefPtr<mozilla::dom::Element> secondaryContent = aOther->mOwnerContent;
     430             : 
     431             :   // Swap loaders through our owner, so the owner's listeners will be correctly
     432             :   // setup.
     433           0 :   nsCOMPtr<nsIBrowser> ourBrowser = do_QueryInterface(primaryContent);
     434           0 :   nsCOMPtr<nsIBrowser> otherBrowser = do_QueryInterface(secondaryContent);
     435           0 :   if (NS_WARN_IF(!ourBrowser || !otherBrowser)) {
     436           0 :     return false;
     437             :   }
     438           0 :   nsresult rv = ourBrowser->SwapBrowsers(otherBrowser, nsIBrowser::SWAP_KEEP_PERMANENT_KEY);
     439           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     440           0 :     return false;
     441             :   }
     442             : 
     443             :   // Dispatch the BrowserChangedProcess event to tell JS that the process swap
     444             :   // has occurred.
     445           0 :   GroupedHistoryEventInit eventInit;
     446           0 :   eventInit.mBubbles = true;
     447           0 :   eventInit.mCancelable= false;
     448           0 :   eventInit.mOtherBrowser = secondaryContent;
     449             :   RefPtr<GroupedHistoryEvent> event =
     450           0 :     GroupedHistoryEvent::Constructor(primaryContent,
     451           0 :                                      NS_LITERAL_STRING("BrowserChangedProcess"),
     452           0 :                                      eventInit);
     453           0 :   event->SetTrusted(true);
     454             :   bool dummy;
     455           0 :   primaryContent->DispatchEvent(event, &dummy);
     456             : 
     457           0 :   return true;
     458             : }
     459             : 
     460             : class AppendPartialSHistoryAndSwapHelper : public PromiseNativeHandler
     461             : {
     462             : public:
     463             :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     464           0 :   NS_DECL_CYCLE_COLLECTION_CLASS(AppendPartialSHistoryAndSwapHelper)
     465             : 
     466           0 :   AppendPartialSHistoryAndSwapHelper(nsFrameLoader* aThis,
     467             :                                      nsFrameLoader* aOther,
     468             :                                      Promise* aPromise)
     469           0 :     : mThis(aThis), mOther(aOther), mPromise(aPromise) {}
     470             : 
     471             :   void
     472           0 :   ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
     473             :   {
     474           0 :     nsCOMPtr<nsIGroupedSHistory> otherGroupedHistory;
     475           0 :     mOther->GetGroupedSHistory(getter_AddRefs(otherGroupedHistory));
     476           0 :     MOZ_ASSERT(!otherGroupedHistory,
     477             :                "Cannot append a GroupedSHistory owner to another.");
     478           0 :     if (otherGroupedHistory) {
     479           0 :       mPromise->MaybeRejectWithUndefined();
     480           0 :       return;
     481             :     }
     482             : 
     483             :     // Append ourselves.
     484             :     nsresult rv;
     485           0 :     nsCOMPtr<nsIGroupedSHistory> groupedSHistory;
     486           0 :     rv = mThis->EnsureGroupedSHistory(getter_AddRefs(groupedSHistory));
     487           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     488           0 :       mPromise->MaybeRejectWithUndefined();
     489           0 :       return;
     490             :     }
     491             : 
     492             :     // Append the other.
     493           0 :     nsCOMPtr<nsIPartialSHistory> otherPartialSHistory;
     494           0 :     MOZ_ALWAYS_SUCCEEDS(mOther->GetPartialSHistory(getter_AddRefs(otherPartialSHistory)));
     495           0 :     rv = groupedSHistory->AppendPartialSHistory(otherPartialSHistory);
     496           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     497           0 :       mPromise->MaybeRejectWithUndefined();
     498           0 :       return;
     499             :     }
     500             : 
     501             :     // Swap the browsers and fire the BrowserChangedProcess event.
     502           0 :     if (mThis->SwapBrowsersAndNotify(mOther)) {
     503           0 :       mPromise->MaybeResolveWithUndefined();
     504             :     } else {
     505           0 :       mPromise->MaybeRejectWithUndefined();
     506             :     }
     507             :   }
     508             : 
     509             :   void
     510           0 :   RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
     511             :   {
     512           0 :     mPromise->MaybeRejectWithUndefined();
     513           0 :   }
     514             : 
     515             : private:
     516           0 :   ~AppendPartialSHistoryAndSwapHelper() {}
     517             :   RefPtr<nsFrameLoader> mThis;
     518             :   RefPtr<nsFrameLoader> mOther;
     519             :   RefPtr<Promise> mPromise;
     520             : };
     521             : 
     522           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(AppendPartialSHistoryAndSwapHelper)
     523           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(AppendPartialSHistoryAndSwapHelper)
     524           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AppendPartialSHistoryAndSwapHelper)
     525           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     526           0 : NS_INTERFACE_MAP_END
     527           0 : NS_IMPL_CYCLE_COLLECTION(AppendPartialSHistoryAndSwapHelper,
     528             :                          mThis, mPromise)
     529             : 
     530             : class RequestGroupedHistoryNavigationHelper : public PromiseNativeHandler
     531             : {
     532             : public:
     533             :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     534           0 :   NS_DECL_CYCLE_COLLECTION_CLASS(RequestGroupedHistoryNavigationHelper)
     535             : 
     536           0 :   RequestGroupedHistoryNavigationHelper(nsFrameLoader* aThis,
     537             :                                         uint32_t aGlobalIndex,
     538             :                                         Promise* aPromise)
     539           0 :     : mThis(aThis), mGlobalIndex(aGlobalIndex), mPromise(aPromise) {}
     540             : 
     541             :   void
     542           0 :   ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
     543             :   {
     544           0 :     if (NS_WARN_IF(!mThis->mOwnerContent)) {
     545           0 :       mPromise->MaybeRejectWithUndefined();
     546           0 :       return;
     547             :     }
     548             : 
     549           0 :     nsCOMPtr<nsIGroupedSHistory> groupedSHistory;
     550           0 :     mThis->GetGroupedSHistory(getter_AddRefs(groupedSHistory));
     551           0 :     if (NS_WARN_IF(!groupedSHistory)) {
     552           0 :       mPromise->MaybeRejectWithUndefined();
     553           0 :       return;
     554             :     }
     555             : 
     556             :     // Navigate the loader to the new index
     557           0 :     nsCOMPtr<nsIFrameLoader> otherLoader;
     558           0 :     nsresult rv = groupedSHistory->GotoIndex(mGlobalIndex, getter_AddRefs(otherLoader));
     559             : 
     560             :     // Check if the gotoIndex failed because the target frameloader is dead. We
     561             :     // need to perform a navigateAndRestoreByIndex and then return to recover.
     562           0 :     if (rv == NS_ERROR_NOT_AVAILABLE) {
     563             :       // Get the nsIXULBrowserWindow so that we can call NavigateAndRestoreByIndex on it.
     564           0 :       nsCOMPtr<nsIDocShell> docShell = mThis->mOwnerContent->OwnerDoc()->GetDocShell();
     565           0 :       if (NS_WARN_IF(!docShell)) {
     566           0 :         mPromise->MaybeRejectWithUndefined();
     567           0 :         return;
     568             :       }
     569             : 
     570           0 :       nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
     571           0 :       docShell->GetTreeOwner(getter_AddRefs(treeOwner));
     572           0 :       if (NS_WARN_IF(!treeOwner)) {
     573           0 :         mPromise->MaybeRejectWithUndefined();
     574           0 :         return;
     575             :       }
     576             : 
     577           0 :       nsCOMPtr<nsIXULWindow> window = do_GetInterface(treeOwner);
     578           0 :       if (NS_WARN_IF(!window)) {
     579           0 :         mPromise->MaybeRejectWithUndefined();
     580           0 :         return;
     581             :       }
     582             : 
     583           0 :       nsCOMPtr<nsIXULBrowserWindow> xbw;
     584           0 :       window->GetXULBrowserWindow(getter_AddRefs(xbw));
     585           0 :       if (NS_WARN_IF(!xbw)) {
     586           0 :         mPromise->MaybeRejectWithUndefined();
     587           0 :         return;
     588             :       }
     589             : 
     590           0 :       nsCOMPtr<nsIBrowser> ourBrowser = do_QueryInterface(mThis->mOwnerContent);
     591           0 :       if (NS_WARN_IF(!ourBrowser)) {
     592           0 :         mPromise->MaybeRejectWithUndefined();
     593           0 :         return;
     594             :       }
     595             : 
     596           0 :       rv = xbw->NavigateAndRestoreByIndex(ourBrowser, mGlobalIndex);
     597           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     598           0 :         mPromise->MaybeRejectWithUndefined();
     599           0 :         return;
     600             :       }
     601           0 :       mPromise->MaybeResolveWithUndefined();
     602           0 :       return;
     603             :     }
     604             : 
     605             :     // Check for any other type of failure
     606           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     607           0 :       mPromise->MaybeRejectWithUndefined();
     608           0 :       return;
     609             :     }
     610             : 
     611             :     // Perform the swap.
     612           0 :     nsFrameLoader* other = static_cast<nsFrameLoader*>(otherLoader.get());
     613           0 :     if (!other || other == mThis) {
     614           0 :       mPromise->MaybeRejectWithUndefined();
     615           0 :       return;
     616             :     }
     617             : 
     618             :     // Swap the browsers and fire the BrowserChangedProcess event.
     619           0 :     if (mThis->SwapBrowsersAndNotify(other)) {
     620           0 :       mPromise->MaybeResolveWithUndefined();
     621             :     } else {
     622           0 :       mPromise->MaybeRejectWithUndefined();
     623             :     }
     624             :   }
     625             : 
     626             :   void
     627           0 :   RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
     628             :   {
     629           0 :     mPromise->MaybeRejectWithUndefined();
     630           0 :   }
     631             : 
     632             : private:
     633           0 :   ~RequestGroupedHistoryNavigationHelper() {}
     634             :   RefPtr<nsFrameLoader> mThis;
     635             :   uint32_t mGlobalIndex;
     636             :   RefPtr<Promise> mPromise;
     637             : };
     638             : 
     639           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(RequestGroupedHistoryNavigationHelper)
     640           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(RequestGroupedHistoryNavigationHelper)
     641           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RequestGroupedHistoryNavigationHelper)
     642           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     643           0 : NS_INTERFACE_MAP_END
     644           0 : NS_IMPL_CYCLE_COLLECTION(RequestGroupedHistoryNavigationHelper,
     645             :                          mThis, mPromise)
     646             : 
     647             : already_AddRefed<Promise>
     648           0 : nsFrameLoader::FireWillChangeProcessEvent()
     649             : {
     650           0 :   AutoJSAPI jsapi;
     651           0 :   if (NS_WARN_IF(!jsapi.Init(mOwnerContent->GetOwnerGlobal()))) {
     652           0 :     return nullptr;
     653             :   }
     654           0 :   JSContext* cx = jsapi.cx();
     655           0 :   GlobalObject global(cx, mOwnerContent->GetOwnerGlobal()->GetGlobalJSObject());
     656           0 :   MOZ_ASSERT(!global.Failed());
     657             : 
     658             :   // Set our mBrowserChangingProcessBlockers property to refer to the blockers
     659             :   // list. We will synchronously dispatch a DOM event to collect this list of
     660             :   // blockers.
     661           0 :   nsTArray<RefPtr<Promise>> blockers;
     662           0 :   mBrowserChangingProcessBlockers = &blockers;
     663             : 
     664           0 :   GroupedHistoryEventInit eventInit;
     665           0 :   eventInit.mBubbles = true;
     666           0 :   eventInit.mCancelable = false;
     667           0 :   eventInit.mOtherBrowser = nullptr;
     668             :   RefPtr<GroupedHistoryEvent> event =
     669           0 :     GroupedHistoryEvent::Constructor(mOwnerContent,
     670           0 :                                      NS_LITERAL_STRING("BrowserWillChangeProcess"),
     671           0 :                                      eventInit);
     672           0 :   event->SetTrusted(true);
     673             :   bool dummy;
     674           0 :   mOwnerContent->DispatchEvent(event, &dummy);
     675             : 
     676           0 :   mBrowserChangingProcessBlockers = nullptr;
     677             : 
     678           0 :   ErrorResult rv;
     679           0 :   RefPtr<Promise> allPromise = Promise::All(global, blockers, rv);
     680           0 :   return allPromise.forget();
     681             : }
     682             : 
     683             : NS_IMETHODIMP
     684           0 : nsFrameLoader::AppendPartialSHistoryAndSwap(nsIFrameLoader* aOther, nsISupports** aPromise)
     685             : {
     686           0 :   if (!aOther) {
     687           0 :     return NS_ERROR_INVALID_POINTER;
     688             :   }
     689             : 
     690           0 :   if (aOther == this) {
     691           0 :     return NS_OK;
     692             :   }
     693             : 
     694           0 :   RefPtr<nsFrameLoader> otherLoader = static_cast<nsFrameLoader*>(aOther);
     695             : 
     696           0 :   RefPtr<Promise> ready = FireWillChangeProcessEvent();
     697           0 :   if (NS_WARN_IF(!ready)) {
     698           0 :     return NS_ERROR_FAILURE;
     699             :   }
     700             : 
     701             :   // This promise will be resolved when the swap has finished, we return it now
     702             :   // and pass it to our helper so our helper can resolve it.
     703           0 :   ErrorResult rv;
     704           0 :   RefPtr<Promise> complete = Promise::Create(mOwnerContent->GetOwnerGlobal(), rv);
     705           0 :   if (NS_WARN_IF(rv.Failed())) {
     706           0 :     return rv.StealNSResult();
     707             :   }
     708             : 
     709             :   // Attach our handler to the ready promise, and make it fulfil the complete
     710             :   // promise when we are done.
     711             :   RefPtr<AppendPartialSHistoryAndSwapHelper> helper =
     712           0 :     new AppendPartialSHistoryAndSwapHelper(this, otherLoader, complete);
     713           0 :   ready->AppendNativeHandler(helper);
     714           0 :   complete.forget(aPromise);
     715           0 :   return NS_OK;
     716             : }
     717             : 
     718             : NS_IMETHODIMP
     719           0 : nsFrameLoader::RequestGroupedHistoryNavigation(uint32_t aGlobalIndex, nsISupports** aPromise)
     720             : {
     721             : 
     722           0 :   RefPtr<Promise> ready = FireWillChangeProcessEvent();
     723           0 :   if (NS_WARN_IF(!ready)) {
     724           0 :     return NS_ERROR_FAILURE;
     725             :   }
     726             : 
     727             :   // This promise will be resolved when the swap has finished, we return it now
     728             :   // and pass it to our helper so our helper can resolve it.
     729           0 :   ErrorResult rv;
     730           0 :   RefPtr<Promise> complete = Promise::Create(mOwnerContent->GetOwnerGlobal(), rv);
     731           0 :   if (NS_WARN_IF(rv.Failed())) {
     732           0 :     return rv.StealNSResult();
     733             :   }
     734             : 
     735             :   // Attach our handler to the ready promise, and make it fulfil the complete
     736             :   // promise when we are done.
     737             :   RefPtr<RequestGroupedHistoryNavigationHelper> helper =
     738           0 :     new RequestGroupedHistoryNavigationHelper(this, aGlobalIndex, complete);
     739           0 :   ready->AppendNativeHandler(helper);
     740           0 :   complete.forget(aPromise);
     741           0 :   return NS_OK;
     742             : }
     743             : 
     744             : NS_IMETHODIMP
     745           0 : nsFrameLoader::AddProcessChangeBlockingPromise(js::Handle<js::Value> aPromise,
     746             :                                                JSContext* aCx)
     747             : {
     748           0 :   nsCOMPtr<nsIGlobalObject> go = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
     749           0 :   if (!go) {
     750           0 :     return NS_ERROR_FAILURE;
     751             :   }
     752           0 :   ErrorResult rv;
     753           0 :   RefPtr<Promise> promise = Promise::Resolve(go, aCx, aPromise, rv);
     754           0 :   if (NS_WARN_IF(rv.Failed())) {
     755           0 :     return rv.StealNSResult();
     756             :   }
     757             : 
     758           0 :   if (NS_WARN_IF(!mBrowserChangingProcessBlockers)) {
     759           0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
     760             :   }
     761             : 
     762           0 :   mBrowserChangingProcessBlockers->AppendElement(promise);
     763           0 :   return NS_OK;
     764             : }
     765             : 
     766             : nsresult
     767           3 : nsFrameLoader::ReallyStartLoading()
     768             : {
     769           3 :   nsresult rv = ReallyStartLoadingInternal();
     770           3 :   if (NS_FAILED(rv)) {
     771           0 :     FireErrorEvent();
     772             :   }
     773             : 
     774           3 :   return rv;
     775             : }
     776             : 
     777             : nsresult
     778           3 : nsFrameLoader::ReallyStartLoadingInternal()
     779             : {
     780           3 :   NS_ENSURE_STATE(mURIToLoad && mOwnerContent && mOwnerContent->IsInComposedDoc());
     781             : 
     782           6 :   AUTO_PROFILER_LABEL("nsFrameLoader::ReallyStartLoadingInternal", OTHER);
     783             : 
     784           3 :   if (IsRemoteFrame()) {
     785           1 :     if (!mRemoteBrowser && !TryRemoteBrowser()) {
     786           0 :         NS_WARNING("Couldn't create child process for iframe.");
     787           0 :         return NS_ERROR_FAILURE;
     788             :     }
     789             : 
     790             :     // FIXME get error codes from child
     791           1 :     mRemoteBrowser->LoadURL(mURIToLoad);
     792             : 
     793           1 :     if (!mRemoteBrowserShown && !ShowRemoteFrame(ScreenIntSize(0, 0))) {
     794           0 :       NS_WARNING("[nsFrameLoader] ReallyStartLoadingInternal tried but couldn't show remote browser.\n");
     795             :     }
     796             : 
     797           1 :     return NS_OK;
     798             :   }
     799             : 
     800           2 :   nsresult rv = MaybeCreateDocShell();
     801           2 :   if (NS_FAILED(rv)) {
     802           0 :     return rv;
     803             :   }
     804           2 :   NS_ASSERTION(mDocShell,
     805             :                "MaybeCreateDocShell succeeded with a null mDocShell");
     806             : 
     807             :   // Just to be safe, recheck uri.
     808           2 :   rv = CheckURILoad(mURIToLoad);
     809           2 :   NS_ENSURE_SUCCESS(rv, rv);
     810             : 
     811           4 :   nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
     812           2 :   mDocShell->CreateLoadInfo(getter_AddRefs(loadInfo));
     813           2 :   NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
     814             : 
     815             :   // If this frame is sandboxed with respect to origin we will set it up with
     816             :   // a null principal later in nsDocShell::DoURILoad.
     817             :   // We do it there to correctly sandbox content that was loaded into
     818             :   // the frame via other methods than the src attribute.
     819             :   // We'll use our principal, not that of the document loaded inside us.  This
     820             :   // is very important; needed to prevent XSS attacks on documents loaded in
     821             :   // subframes!
     822           2 :   loadInfo->SetTriggeringPrincipal(mOwnerContent->NodePrincipal());
     823             : 
     824           4 :   nsCOMPtr<nsIURI> referrer;
     825             : 
     826           4 :   nsAutoString srcdoc;
     827           2 :   bool isSrcdoc = mOwnerContent->IsHTMLElement(nsGkAtoms::iframe) &&
     828           0 :                   mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::srcdoc,
     829           2 :                                          srcdoc);
     830             : 
     831           2 :   if (isSrcdoc) {
     832           0 :     nsAutoString referrerStr;
     833           0 :     mOwnerContent->OwnerDoc()->GetReferrer(referrerStr);
     834           0 :     rv = NS_NewURI(getter_AddRefs(referrer), referrerStr);
     835             : 
     836           0 :     loadInfo->SetSrcdocData(srcdoc);
     837           0 :     nsCOMPtr<nsIURI> baseURI = mOwnerContent->GetBaseURI();
     838           0 :     loadInfo->SetBaseURI(baseURI);
     839             :   }
     840             :   else {
     841           2 :     rv = mOwnerContent->NodePrincipal()->GetURI(getter_AddRefs(referrer));
     842           2 :     NS_ENSURE_SUCCESS(rv, rv);
     843             :   }
     844             : 
     845             :   // Use referrer as long as it is not an NullPrincipalURI.
     846             :   // We could add a method such as GetReferrerURI to principals to make this
     847             :   // cleaner, but given that we need to start using Source Browsing Context for
     848             :   // referrer (see Bug 960639) this may be wasted effort at this stage.
     849           2 :   if (referrer) {
     850             :     bool isNullPrincipalScheme;
     851           0 :     rv = referrer->SchemeIs(NS_NULLPRINCIPAL_SCHEME, &isNullPrincipalScheme);
     852           0 :     if (NS_SUCCEEDED(rv) && !isNullPrincipalScheme) {
     853           0 :       loadInfo->SetReferrer(referrer);
     854             :     }
     855             :   }
     856             : 
     857             :   // get referrer policy for this iframe:
     858             :   // first load document wide policy, then
     859             :   // load iframe referrer attribute if enabled in preferences
     860             :   // per element referrer overrules document wide referrer if enabled
     861           2 :   net::ReferrerPolicy referrerPolicy = mOwnerContent->OwnerDoc()->GetReferrerPolicy();
     862           2 :   HTMLIFrameElement* iframe = HTMLIFrameElement::FromContent(mOwnerContent);
     863           2 :   if (iframe) {
     864           0 :     net::ReferrerPolicy iframeReferrerPolicy = iframe->GetReferrerPolicyAsEnum();
     865           0 :     if (iframeReferrerPolicy != net::RP_Unset) {
     866           0 :       referrerPolicy = iframeReferrerPolicy;
     867             :     }
     868             :   }
     869           2 :   loadInfo->SetReferrerPolicy(referrerPolicy);
     870             : 
     871             :   // Default flags:
     872           2 :   int32_t flags = nsIWebNavigation::LOAD_FLAGS_NONE;
     873             : 
     874             :   // Flags for browser frame:
     875           2 :   if (OwnerIsMozBrowserFrame()) {
     876           0 :     flags = nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
     877             :             nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL;
     878             :   }
     879             : 
     880             :   // Kick off the load...
     881           2 :   bool tmpState = mNeedsAsyncDestroy;
     882           2 :   mNeedsAsyncDestroy = true;
     883           4 :   nsCOMPtr<nsIURI> uriToLoad = mURIToLoad;
     884           2 :   rv = mDocShell->LoadURI(uriToLoad, loadInfo, flags, false);
     885           2 :   mNeedsAsyncDestroy = tmpState;
     886           2 :   mURIToLoad = nullptr;
     887           2 :   NS_ENSURE_SUCCESS(rv, rv);
     888             : 
     889           2 :   return NS_OK;
     890             : }
     891             : 
     892             : nsresult
     893           5 : nsFrameLoader::CheckURILoad(nsIURI* aURI)
     894             : {
     895             :   // Check for security.  The fun part is trying to figure out what principals
     896             :   // to use.  The way I figure it, if we're doing a LoadFrame() accidentally
     897             :   // (eg someone created a frame/iframe node, we're being parsed, XUL iframes
     898             :   // are being reframed, etc.) then we definitely want to use the node
     899             :   // principal of mOwnerContent for security checks.  If, on the other hand,
     900             :   // someone's setting the src on our owner content, or created it via script,
     901             :   // or whatever, then they can clearly access it... and we should still use
     902             :   // the principal of mOwnerContent.  I don't think that leads to privilege
     903             :   // escalation, and it's reasonably guaranteed to not lead to XSS issues
     904             :   // (since caller can already access mOwnerContent in this case).  So just use
     905             :   // the principal of mOwnerContent no matter what.  If script wants to run
     906             :   // things with its own permissions, which differ from those of mOwnerContent
     907             :   // (which means the script is privileged in some way) it should set
     908             :   // window.location instead.
     909           5 :   nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
     910             : 
     911             :   // Get our principal
     912           5 :   nsIPrincipal* principal = mOwnerContent->NodePrincipal();
     913             : 
     914             :   // Check if we are allowed to load absURL
     915             :   nsresult rv =
     916             :     secMan->CheckLoadURIWithPrincipal(principal, aURI,
     917           5 :                                       nsIScriptSecurityManager::STANDARD);
     918           5 :   if (NS_FAILED(rv)) {
     919           0 :     return rv; // We're not
     920             :   }
     921             : 
     922             :   // Bail out if this is an infinite recursion scenario
     923           5 :   if (IsRemoteFrame()) {
     924           1 :     return NS_OK;
     925             :   }
     926           4 :   return CheckForRecursiveLoad(aURI);
     927             : }
     928             : 
     929             : NS_IMETHODIMP
     930           5 : nsFrameLoader::GetDocShell(nsIDocShell **aDocShell)
     931             : {
     932           5 :   *aDocShell = nullptr;
     933           5 :   nsresult rv = NS_OK;
     934             : 
     935           5 :   if (IsRemoteFrame()) {
     936           3 :     return rv;
     937             :   }
     938             : 
     939             :   // If we have an owner, make sure we have a docshell and return
     940             :   // that. If not, we're most likely in the middle of being torn down,
     941             :   // then we just return null.
     942           2 :   if (mOwnerContent) {
     943           2 :     nsresult rv = MaybeCreateDocShell();
     944           2 :     if (NS_FAILED(rv)) {
     945           0 :       return rv;
     946             :     }
     947           2 :     NS_ASSERTION(mDocShell,
     948             :                  "MaybeCreateDocShell succeeded, but null mDocShell");
     949             :   }
     950             : 
     951           2 :   *aDocShell = mDocShell;
     952           2 :   NS_IF_ADDREF(*aDocShell);
     953             : 
     954           2 :   return rv;
     955             : }
     956             : 
     957             : static void
     958           0 : SetTreeOwnerAndChromeEventHandlerOnDocshellTree(nsIDocShellTreeItem* aItem,
     959             :                                                 nsIDocShellTreeOwner* aOwner,
     960             :                                                 EventTarget* aHandler)
     961             : {
     962           0 :   NS_PRECONDITION(aItem, "Must have item");
     963             : 
     964           0 :   aItem->SetTreeOwner(aOwner);
     965             : 
     966           0 :   int32_t childCount = 0;
     967           0 :   aItem->GetChildCount(&childCount);
     968           0 :   for (int32_t i = 0; i < childCount; ++i) {
     969           0 :     nsCOMPtr<nsIDocShellTreeItem> item;
     970           0 :     aItem->GetChildAt(i, getter_AddRefs(item));
     971           0 :     if (aHandler) {
     972           0 :       nsCOMPtr<nsIDocShell> shell(do_QueryInterface(item));
     973           0 :       shell->SetChromeEventHandler(aHandler);
     974             :     }
     975           0 :     SetTreeOwnerAndChromeEventHandlerOnDocshellTree(item, aOwner, aHandler);
     976             :   }
     977           0 : }
     978             : 
     979             : /**
     980             :  * Set the type of the treeitem and hook it up to the treeowner.
     981             :  * @param aItem the treeitem we're working with
     982             :  * @param aTreeOwner the relevant treeowner; might be null
     983             :  * @param aParentType the nsIDocShellTreeItem::GetType of our parent docshell
     984             :  * @param aParentNode if non-null, the docshell we should be added as a child to
     985             :  *
     986             :  * @return whether aItem is top-level content
     987             :  */
     988             : bool
     989           2 : nsFrameLoader::AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
     990             :                                       nsIDocShellTreeOwner* aOwner,
     991             :                                       int32_t aParentType,
     992             :                                       nsIDocShell* aParentNode)
     993             : {
     994           2 :   NS_PRECONDITION(aItem, "Must have docshell treeitem");
     995           2 :   NS_PRECONDITION(mOwnerContent, "Must have owning content");
     996             : 
     997           4 :   nsAutoString value;
     998           2 :   bool isContent = false;
     999           2 :   mOwnerContent->GetAttr(kNameSpaceID_None, TypeAttrName(), value);
    1000             : 
    1001             :   // we accept "content" and "content-xxx" values.
    1002             :   // We ignore anything that comes after 'content-'.
    1003           5 :   isContent = value.LowerCaseEqualsLiteral("content") ||
    1004           4 :     StringBeginsWith(value, NS_LITERAL_STRING("content-"),
    1005           4 :                      nsCaseInsensitiveStringComparator());
    1006             : 
    1007             : 
    1008             :   // Force mozbrowser frames to always be typeContent, even if the
    1009             :   // mozbrowser interfaces are disabled.
    1010             :   nsCOMPtr<nsIDOMMozBrowserFrame> mozbrowser =
    1011           4 :     do_QueryInterface(mOwnerContent);
    1012           2 :   if (mozbrowser) {
    1013           0 :     bool isMozbrowser = false;
    1014           0 :     mozbrowser->GetMozbrowser(&isMozbrowser);
    1015           0 :     isContent |= isMozbrowser;
    1016             :   }
    1017             : 
    1018           2 :   if (isContent) {
    1019             :     // The web shell's type is content.
    1020             : 
    1021           1 :     aItem->SetItemType(nsIDocShellTreeItem::typeContent);
    1022             :   } else {
    1023             :     // Inherit our type from our parent docshell.  If it is
    1024             :     // chrome, we'll be chrome.  If it is content, we'll be
    1025             :     // content.
    1026             : 
    1027           1 :     aItem->SetItemType(aParentType);
    1028             :   }
    1029             : 
    1030             :   // Now that we have our type set, add ourselves to the parent, as needed.
    1031           2 :   if (aParentNode) {
    1032           2 :     aParentNode->AddChild(aItem);
    1033             :   }
    1034             : 
    1035           2 :   bool retval = false;
    1036           2 :   if (aParentType == nsIDocShellTreeItem::typeChrome && isContent) {
    1037           1 :     retval = true;
    1038             : 
    1039             :     bool is_primary =
    1040           1 :       mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary,
    1041           1 :                                  nsGkAtoms::_true, eIgnoreCase);
    1042           1 :     if (aOwner) {
    1043           1 :       mOwnerContent->AddMutationObserver(this);
    1044           1 :       mObservingOwnerContent = true;
    1045           1 :       aOwner->ContentShellAdded(aItem, is_primary);
    1046             :     }
    1047             :   }
    1048             : 
    1049           4 :   return retval;
    1050             : }
    1051             : 
    1052             : static bool
    1053           0 : AllDescendantsOfType(nsIDocShellTreeItem* aParentItem, int32_t aType)
    1054             : {
    1055           0 :   int32_t childCount = 0;
    1056           0 :   aParentItem->GetChildCount(&childCount);
    1057             : 
    1058           0 :   for (int32_t i = 0; i < childCount; ++i) {
    1059           0 :     nsCOMPtr<nsIDocShellTreeItem> kid;
    1060           0 :     aParentItem->GetChildAt(i, getter_AddRefs(kid));
    1061             : 
    1062           0 :     if (kid->ItemType() != aType || !AllDescendantsOfType(kid, aType)) {
    1063           0 :       return false;
    1064             :     }
    1065             :   }
    1066             : 
    1067           0 :   return true;
    1068             : }
    1069             : 
    1070             : /**
    1071             :  * A class that automatically sets mInShow to false when it goes
    1072             :  * out of scope.
    1073             :  */
    1074             : class MOZ_RAII AutoResetInShow {
    1075             :   private:
    1076             :     nsFrameLoader* mFrameLoader;
    1077             :     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
    1078             :   public:
    1079           3 :     explicit AutoResetInShow(nsFrameLoader* aFrameLoader MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    1080           3 :       : mFrameLoader(aFrameLoader)
    1081             :     {
    1082           3 :       MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    1083           3 :     }
    1084           3 :     ~AutoResetInShow() { mFrameLoader->mInShow = false; }
    1085             : };
    1086             : 
    1087             : static bool
    1088           1 : ParentWindowIsActive(nsIDocument* aDoc)
    1089             : {
    1090           2 :   nsCOMPtr<nsPIWindowRoot> root = nsContentUtils::GetWindowRoot(aDoc);
    1091           1 :   if (root) {
    1092           1 :     nsPIDOMWindowOuter* rootWin = root->GetWindow();
    1093           1 :     return rootWin && rootWin->IsActive();
    1094             :   }
    1095           0 :   return false;
    1096             : }
    1097             : 
    1098             : bool
    1099           3 : nsFrameLoader::Show(int32_t marginWidth, int32_t marginHeight,
    1100             :                     int32_t scrollbarPrefX, int32_t scrollbarPrefY,
    1101             :                     nsSubDocumentFrame* frame)
    1102             : {
    1103           3 :   if (mInShow) {
    1104           0 :     return false;
    1105             :   }
    1106             :   // Reset mInShow if we exit early.
    1107           6 :   AutoResetInShow resetInShow(this);
    1108           3 :   mInShow = true;
    1109             : 
    1110           3 :   ScreenIntSize size = frame->GetSubdocumentSize();
    1111           3 :   if (IsRemoteFrame()) {
    1112           2 :     return ShowRemoteFrame(size, frame);
    1113             :   }
    1114             : 
    1115           1 :   nsresult rv = MaybeCreateDocShell();
    1116           1 :   if (NS_FAILED(rv)) {
    1117           0 :     return false;
    1118             :   }
    1119           1 :   NS_ASSERTION(mDocShell,
    1120             :                "MaybeCreateDocShell succeeded, but null mDocShell");
    1121           1 :   if (!mDocShell) {
    1122           0 :     return false;
    1123             :   }
    1124             : 
    1125           1 :   mDocShell->SetMarginWidth(marginWidth);
    1126           1 :   mDocShell->SetMarginHeight(marginHeight);
    1127             : 
    1128           2 :   nsCOMPtr<nsIScrollable> sc = do_QueryInterface(mDocShell);
    1129           1 :   if (sc) {
    1130           1 :     sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X,
    1131           1 :                                        scrollbarPrefX);
    1132           1 :     sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y,
    1133           1 :                                        scrollbarPrefY);
    1134             :   }
    1135             : 
    1136           2 :   nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
    1137           1 :   if (presShell) {
    1138             :     // Ensure root scroll frame is reflowed in case scroll preferences or
    1139             :     // margins have changed
    1140           1 :     nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
    1141           1 :     if (rootScrollFrame) {
    1142           0 :       presShell->FrameNeedsReflow(rootScrollFrame, nsIPresShell::eResize,
    1143           0 :                                   NS_FRAME_IS_DIRTY);
    1144             :     }
    1145           1 :     return true;
    1146             :   }
    1147             : 
    1148           0 :   nsView* view = frame->EnsureInnerView();
    1149           0 :   if (!view)
    1150           0 :     return false;
    1151             : 
    1152           0 :   nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mDocShell);
    1153           0 :   NS_ASSERTION(baseWindow, "Found a nsIDocShell that isn't a nsIBaseWindow.");
    1154           0 :   baseWindow->InitWindow(nullptr, view->GetWidget(), 0, 0,
    1155           0 :                          size.width, size.height);
    1156             :   // This is kinda whacky, this "Create()" call doesn't really
    1157             :   // create anything, one starts to wonder why this was named
    1158             :   // "Create"...
    1159           0 :   baseWindow->Create();
    1160           0 :   baseWindow->SetVisibility(true);
    1161           0 :   NS_ENSURE_TRUE(mDocShell, false);
    1162             : 
    1163             :   // Trigger editor re-initialization if midas is turned on in the
    1164             :   // sub-document. This shouldn't be necessary, but given the way our
    1165             :   // editor works, it is. See
    1166             :   // https://bugzilla.mozilla.org/show_bug.cgi?id=284245
    1167           0 :   presShell = mDocShell->GetPresShell();
    1168           0 :   if (presShell) {
    1169             :     nsCOMPtr<nsIDOMHTMLDocument> doc =
    1170           0 :       do_QueryInterface(presShell->GetDocument());
    1171             : 
    1172           0 :     if (doc) {
    1173           0 :       nsAutoString designMode;
    1174           0 :       doc->GetDesignMode(designMode);
    1175             : 
    1176           0 :       if (designMode.EqualsLiteral("on")) {
    1177             :         // Hold on to the editor object to let the document reattach to the
    1178             :         // same editor object, instead of creating a new one.
    1179           0 :         nsCOMPtr<nsIEditor> editor;
    1180           0 :         nsresult rv = mDocShell->GetEditor(getter_AddRefs(editor));
    1181           0 :         NS_ENSURE_SUCCESS(rv, false);
    1182             : 
    1183           0 :         doc->SetDesignMode(NS_LITERAL_STRING("off"));
    1184           0 :         doc->SetDesignMode(NS_LITERAL_STRING("on"));
    1185             :       } else {
    1186             :         // Re-initialize the presentation for contenteditable documents
    1187           0 :         bool editable = false,
    1188           0 :              hasEditingSession = false;
    1189           0 :         mDocShell->GetEditable(&editable);
    1190           0 :         mDocShell->GetHasEditingSession(&hasEditingSession);
    1191           0 :         nsCOMPtr<nsIEditor> editor;
    1192           0 :         mDocShell->GetEditor(getter_AddRefs(editor));
    1193           0 :         if (editable && hasEditingSession && editor) {
    1194           0 :           editor->PostCreate();
    1195             :         }
    1196             :       }
    1197             :     }
    1198             :   }
    1199             : 
    1200           0 :   mInShow = false;
    1201           0 :   if (mHideCalled) {
    1202           0 :     mHideCalled = false;
    1203           0 :     Hide();
    1204           0 :     return false;
    1205             :   }
    1206           0 :   return true;
    1207             : }
    1208             : 
    1209             : void
    1210           0 : nsFrameLoader::MarginsChanged(uint32_t aMarginWidth,
    1211             :                               uint32_t aMarginHeight)
    1212             : {
    1213             :   // We assume that the margins are always zero for remote frames.
    1214           0 :   if (IsRemoteFrame())
    1215           0 :     return;
    1216             : 
    1217             :   // If there's no docshell, we're probably not up and running yet.
    1218             :   // nsFrameLoader::Show() will take care of setting the right
    1219             :   // margins.
    1220           0 :   if (!mDocShell)
    1221           0 :     return;
    1222             : 
    1223             :   // Set the margins
    1224           0 :   mDocShell->SetMarginWidth(aMarginWidth);
    1225           0 :   mDocShell->SetMarginHeight(aMarginHeight);
    1226             : 
    1227             :   // There's a cached property declaration block
    1228             :   // that needs to be updated
    1229           0 :   if (nsIDocument* doc = mDocShell->GetDocument()) {
    1230             :     // We don't need to do anything for Gecko here because
    1231             :     // we plan to RebuildAllStyleData anyway.
    1232           0 :     if (doc->GetStyleBackendType() == StyleBackendType::Servo) {
    1233           0 :       for (nsINode* cur = doc; cur; cur = cur->GetNextNode()) {
    1234           0 :         if (cur->IsHTMLElement(nsGkAtoms::body)) {
    1235           0 :           static_cast<HTMLBodyElement*>(cur)->ClearMappedServoStyle();
    1236             :         }
    1237             :       }
    1238             :     }
    1239             :   }
    1240             : 
    1241             :   // Trigger a restyle if there's a prescontext
    1242             :   // FIXME: This could do something much less expensive.
    1243           0 :   RefPtr<nsPresContext> presContext;
    1244           0 :   mDocShell->GetPresContext(getter_AddRefs(presContext));
    1245           0 :   if (presContext)
    1246             :     // rebuild, because now the same nsMappedAttributes* will produce
    1247             :     // a different style
    1248           0 :     presContext->RebuildAllStyleData(nsChangeHint(0), eRestyle_Subtree);
    1249             : }
    1250             : 
    1251             : bool
    1252           2 : nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
    1253             :                                nsSubDocumentFrame *aFrame)
    1254             : {
    1255           4 :   AUTO_PROFILER_LABEL("nsFrameLoader::ShowRemoteFrame", GRAPHICS);
    1256           2 :   NS_ASSERTION(IsRemoteFrame(), "ShowRemote only makes sense on remote frames.");
    1257             : 
    1258           2 :   if (!mRemoteBrowser && !TryRemoteBrowser()) {
    1259           0 :     NS_ERROR("Couldn't create child process.");
    1260           0 :     return false;
    1261             :   }
    1262             : 
    1263             :   // FIXME/bug 589337: Show()/Hide() is pretty expensive for
    1264             :   // cross-process layers; need to figure out what behavior we really
    1265             :   // want here.  For now, hack.
    1266           2 :   if (!mRemoteBrowserShown) {
    1267           2 :     if (!mOwnerContent ||
    1268           1 :         !mOwnerContent->GetComposedDoc()) {
    1269           0 :       return false;
    1270             :     }
    1271             : 
    1272             :     // We never want to host remote frameloaders in simple popups, like menus.
    1273           1 :     nsIWidget* widget = nsContentUtils::WidgetForContent(mOwnerContent);
    1274           1 :     if (!widget || static_cast<nsBaseWidget*>(widget)->IsSmallPopup()) {
    1275           0 :       return false;
    1276             :     }
    1277             : 
    1278           1 :     RenderFrameParent* rfp = GetCurrentRenderFrame();
    1279           1 :     if (!rfp) {
    1280           0 :       return false;
    1281             :     }
    1282             : 
    1283           1 :     if (!rfp->AttachLayerManager()) {
    1284             :       // This is just not going to work.
    1285           0 :       return false;
    1286             :     }
    1287             : 
    1288           1 :     mRemoteBrowser->Show(size, ParentWindowIsActive(mOwnerContent->OwnerDoc()));
    1289           1 :     mRemoteBrowserShown = true;
    1290             : 
    1291           2 :     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
    1292           1 :     if (os) {
    1293           2 :       os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
    1294           2 :                           "remote-browser-shown", nullptr);
    1295             :     }
    1296             :   } else {
    1297           1 :     nsIntRect dimensions;
    1298           1 :     NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), false);
    1299             : 
    1300             :     // Don't show remote iframe if we are waiting for the completion of reflow.
    1301           1 :     if (!aFrame || !(aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
    1302           0 :       mRemoteBrowser->UpdateDimensions(dimensions, size);
    1303             :     }
    1304             :   }
    1305             : 
    1306           2 :   return true;
    1307             : }
    1308             : 
    1309             : void
    1310           2 : nsFrameLoader::Hide()
    1311             : {
    1312           2 :   if (mHideCalled) {
    1313           1 :     return;
    1314             :   }
    1315           2 :   if (mInShow) {
    1316           0 :     mHideCalled = true;
    1317           0 :     return;
    1318             :   }
    1319             : 
    1320           2 :   if (!mDocShell)
    1321           1 :     return;
    1322             : 
    1323           2 :   nsCOMPtr<nsIContentViewer> contentViewer;
    1324           1 :   mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
    1325           1 :   if (contentViewer)
    1326           1 :     contentViewer->SetSticky(false);
    1327             : 
    1328           2 :   nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
    1329           1 :   NS_ASSERTION(baseWin,
    1330             :                "Found an nsIDocShell which doesn't implement nsIBaseWindow.");
    1331           1 :   baseWin->SetVisibility(false);
    1332           1 :   baseWin->SetParentWidget(nullptr);
    1333             : }
    1334             : 
    1335             : nsresult
    1336           0 : nsFrameLoader::SwapWithOtherRemoteLoader(nsFrameLoader* aOther,
    1337             :                                          nsIFrameLoaderOwner* aThisOwner,
    1338             :                                          nsIFrameLoaderOwner* aOtherOwner)
    1339             : {
    1340           0 :   MOZ_ASSERT(NS_IsMainThread());
    1341             : 
    1342             : #ifdef DEBUG
    1343           0 :   RefPtr<nsFrameLoader> first = aThisOwner->GetFrameLoader();
    1344           0 :   RefPtr<nsFrameLoader> second = aOtherOwner->GetFrameLoader();
    1345           0 :   MOZ_ASSERT(first == this, "aThisOwner must own this");
    1346           0 :   MOZ_ASSERT(second == aOther, "aOtherOwner must own aOther");
    1347             : #endif
    1348             : 
    1349           0 :   Element* ourContent = mOwnerContent;
    1350           0 :   Element* otherContent = aOther->mOwnerContent;
    1351             : 
    1352           0 :   if (!ourContent || !otherContent) {
    1353             :     // Can't handle this
    1354           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1355             :   }
    1356             : 
    1357             :   // Make sure there are no same-origin issues
    1358             :   bool equal;
    1359             :   nsresult rv =
    1360           0 :     ourContent->NodePrincipal()->Equals(otherContent->NodePrincipal(), &equal);
    1361           0 :   if (NS_FAILED(rv) || !equal) {
    1362             :     // Security problems loom.  Just bail on it all
    1363           0 :     return NS_ERROR_DOM_SECURITY_ERR;
    1364             :   }
    1365             : 
    1366           0 :   nsIDocument* ourDoc = ourContent->GetComposedDoc();
    1367           0 :   nsIDocument* otherDoc = otherContent->GetComposedDoc();
    1368           0 :   if (!ourDoc || !otherDoc) {
    1369             :     // Again, how odd, given that we had docshells
    1370           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1371             :   }
    1372             : 
    1373           0 :   nsIPresShell* ourShell = ourDoc->GetShell();
    1374           0 :   nsIPresShell* otherShell = otherDoc->GetShell();
    1375           0 :   if (!ourShell || !otherShell) {
    1376           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1377             :   }
    1378             : 
    1379           0 :   if (!mRemoteBrowser || !aOther->mRemoteBrowser) {
    1380           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1381             :   }
    1382             : 
    1383           0 :   if (mRemoteBrowser->IsIsolatedMozBrowserElement() !=
    1384           0 :       aOther->mRemoteBrowser->IsIsolatedMozBrowserElement()) {
    1385           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1386             :   }
    1387             : 
    1388             :   // When we swap docShells, maybe we have to deal with a new page created just
    1389             :   // for this operation. In this case, the browser code should already have set
    1390             :   // the correct userContextId attribute value in the owning XULElement, but our
    1391             :   // docShell, that has been created way before) doesn't know that that
    1392             :   // happened.
    1393             :   // This is the reason why now we must retrieve the correct value from the
    1394             :   // usercontextid attribute before comparing our originAttributes with the
    1395             :   // other one.
    1396             :   OriginAttributes ourOriginAttributes =
    1397           0 :     mRemoteBrowser->OriginAttributesRef();
    1398           0 :   rv = PopulateUserContextIdFromAttribute(ourOriginAttributes);
    1399           0 :   NS_ENSURE_SUCCESS(rv,rv);
    1400             : 
    1401             :   OriginAttributes otherOriginAttributes =
    1402           0 :     aOther->mRemoteBrowser->OriginAttributesRef();
    1403           0 :   rv = aOther->PopulateUserContextIdFromAttribute(otherOriginAttributes);
    1404           0 :   NS_ENSURE_SUCCESS(rv,rv);
    1405             : 
    1406           0 :   if (ourOriginAttributes != otherOriginAttributes) {
    1407           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1408             :   }
    1409             : 
    1410             :   bool ourHasHistory =
    1411           0 :     mIsTopLevelContent &&
    1412           0 :     ourContent->IsXULElement(nsGkAtoms::browser) &&
    1413           0 :     !ourContent->HasAttr(kNameSpaceID_None, nsGkAtoms::disablehistory);
    1414             :   bool otherHasHistory =
    1415           0 :     aOther->mIsTopLevelContent &&
    1416           0 :     otherContent->IsXULElement(nsGkAtoms::browser) &&
    1417           0 :     !otherContent->HasAttr(kNameSpaceID_None, nsGkAtoms::disablehistory);
    1418           0 :   if (ourHasHistory != otherHasHistory) {
    1419           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1420             :   }
    1421             : 
    1422           0 :   if (mInSwap || aOther->mInSwap) {
    1423           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1424             :   }
    1425           0 :   mInSwap = aOther->mInSwap = true;
    1426             : 
    1427           0 :   nsIFrame* ourFrame = ourContent->GetPrimaryFrame();
    1428           0 :   nsIFrame* otherFrame = otherContent->GetPrimaryFrame();
    1429           0 :   if (!ourFrame || !otherFrame) {
    1430           0 :     mInSwap = aOther->mInSwap = false;
    1431           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1432             :   }
    1433             : 
    1434           0 :   nsSubDocumentFrame* ourFrameFrame = do_QueryFrame(ourFrame);
    1435           0 :   if (!ourFrameFrame) {
    1436           0 :     mInSwap = aOther->mInSwap = false;
    1437           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1438             :   }
    1439             : 
    1440           0 :   rv = ourFrameFrame->BeginSwapDocShells(otherFrame);
    1441           0 :   if (NS_FAILED(rv)) {
    1442           0 :     mInSwap = aOther->mInSwap = false;
    1443           0 :     return rv;
    1444             :   }
    1445             : 
    1446             :   nsCOMPtr<nsIBrowserDOMWindow> otherBrowserDOMWindow =
    1447           0 :     aOther->mRemoteBrowser->GetBrowserDOMWindow();
    1448             :   nsCOMPtr<nsIBrowserDOMWindow> browserDOMWindow =
    1449           0 :     mRemoteBrowser->GetBrowserDOMWindow();
    1450             : 
    1451           0 :   if (!!otherBrowserDOMWindow != !!browserDOMWindow) {
    1452           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1453             :   }
    1454             : 
    1455             :   // Destroy browser frame scripts for content leaving a frame with browser API
    1456           0 :   if (OwnerIsMozBrowserFrame() && !aOther->OwnerIsMozBrowserFrame()) {
    1457           0 :     DestroyBrowserFrameScripts();
    1458             :   }
    1459           0 :   if (!OwnerIsMozBrowserFrame() && aOther->OwnerIsMozBrowserFrame()) {
    1460           0 :     aOther->DestroyBrowserFrameScripts();
    1461             :   }
    1462             : 
    1463           0 :   aOther->mRemoteBrowser->SetBrowserDOMWindow(browserDOMWindow);
    1464           0 :   mRemoteBrowser->SetBrowserDOMWindow(otherBrowserDOMWindow);
    1465             : 
    1466             : #ifdef XP_WIN
    1467             :   // Native plugin windows used by this remote content need to be reparented.
    1468             :   if (nsPIDOMWindowOuter* newWin = ourDoc->GetWindow()) {
    1469             :     RefPtr<nsIWidget> newParent = nsGlobalWindow::Cast(newWin)->GetMainWidget();
    1470             :     const ManagedContainer<mozilla::plugins::PPluginWidgetParent>& plugins =
    1471             :       aOther->mRemoteBrowser->ManagedPPluginWidgetParent();
    1472             :     for (auto iter = plugins.ConstIter(); !iter.Done(); iter.Next()) {
    1473             :       static_cast<mozilla::plugins::PluginWidgetParent*>(iter.Get()->GetKey())->SetParent(newParent);
    1474             :     }
    1475             :   }
    1476             : #endif // XP_WIN
    1477             : 
    1478           0 :   MaybeUpdatePrimaryTabParent(eTabParentRemoved);
    1479           0 :   aOther->MaybeUpdatePrimaryTabParent(eTabParentRemoved);
    1480             : 
    1481           0 :   SetOwnerContent(otherContent);
    1482           0 :   aOther->SetOwnerContent(ourContent);
    1483             : 
    1484           0 :   mRemoteBrowser->SetOwnerElement(otherContent);
    1485           0 :   aOther->mRemoteBrowser->SetOwnerElement(ourContent);
    1486             : 
    1487             :   // Update window activation state for the swapped owner content.
    1488           0 :   Unused << mRemoteBrowser->Manager()->AsContentParent()->SendParentActivated(
    1489           0 :     mRemoteBrowser, ParentWindowIsActive(otherContent->OwnerDoc()));
    1490           0 :   Unused << aOther->mRemoteBrowser->Manager()->AsContentParent()->SendParentActivated(
    1491           0 :     aOther->mRemoteBrowser, ParentWindowIsActive(ourContent->OwnerDoc()));
    1492             : 
    1493           0 :   MaybeUpdatePrimaryTabParent(eTabParentChanged);
    1494           0 :   aOther->MaybeUpdatePrimaryTabParent(eTabParentChanged);
    1495             : 
    1496           0 :   RefPtr<nsFrameMessageManager> ourMessageManager = mMessageManager;
    1497           0 :   RefPtr<nsFrameMessageManager> otherMessageManager = aOther->mMessageManager;
    1498             :   // Swap and setup things in parent message managers.
    1499           0 :   if (ourMessageManager) {
    1500           0 :     ourMessageManager->SetCallback(aOther);
    1501             :   }
    1502           0 :   if (otherMessageManager) {
    1503           0 :     otherMessageManager->SetCallback(this);
    1504             :   }
    1505           0 :   mMessageManager.swap(aOther->mMessageManager);
    1506             : 
    1507             :   // Perform the actual swap of the internal refptrs. We keep a strong reference
    1508             :   // to ourselves to make sure we don't die while we overwrite our reference to
    1509             :   // ourself.
    1510           0 :   nsCOMPtr<nsIFrameLoader> kungFuDeathGrip(this);
    1511           0 :   aThisOwner->InternalSetFrameLoader(aOther);
    1512           0 :   aOtherOwner->InternalSetFrameLoader(kungFuDeathGrip);
    1513             : 
    1514           0 :   ourFrameFrame->EndSwapDocShells(otherFrame);
    1515             : 
    1516           0 :   ourShell->BackingScaleFactorChanged();
    1517           0 :   otherShell->BackingScaleFactorChanged();
    1518             : 
    1519             :   // Initialize browser API if needed now that owner content has changed.
    1520           0 :   InitializeBrowserAPI();
    1521           0 :   aOther->InitializeBrowserAPI();
    1522             : 
    1523           0 :   mInSwap = aOther->mInSwap = false;
    1524             : 
    1525             :   // Send an updated tab context since owner content type may have changed.
    1526           0 :   MutableTabContext ourContext;
    1527           0 :   rv = GetNewTabContext(&ourContext);
    1528           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1529           0 :     return rv;
    1530             :   }
    1531           0 :   MutableTabContext otherContext;
    1532           0 :   rv = aOther->GetNewTabContext(&otherContext);
    1533           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1534           0 :     return rv;
    1535             :   }
    1536             : 
    1537             :   // Swap the remoteType property as the frameloaders are being swapped
    1538           0 :   nsAutoString ourRemoteType;
    1539           0 :   if (!ourContent->GetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType,
    1540             :                            ourRemoteType)) {
    1541           0 :     ourRemoteType.AssignLiteral(DEFAULT_REMOTE_TYPE);
    1542             :   }
    1543           0 :   nsAutoString otherRemoteType;
    1544           0 :   if (!otherContent->GetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType,
    1545             :                              otherRemoteType)) {
    1546           0 :     otherRemoteType.AssignLiteral(DEFAULT_REMOTE_TYPE);
    1547             :   }
    1548           0 :   ourContent->SetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType, otherRemoteType, false);
    1549           0 :   otherContent->SetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType, ourRemoteType, false);
    1550             : 
    1551           0 :   Unused << mRemoteBrowser->SendSwappedWithOtherRemoteLoader(
    1552           0 :     ourContext.AsIPCTabContext());
    1553           0 :   Unused << aOther->mRemoteBrowser->SendSwappedWithOtherRemoteLoader(
    1554           0 :     otherContext.AsIPCTabContext());
    1555           0 :   return NS_OK;
    1556             : }
    1557             : 
    1558             : class MOZ_RAII AutoResetInFrameSwap final
    1559             : {
    1560             : public:
    1561           0 :   AutoResetInFrameSwap(nsFrameLoader* aThisFrameLoader,
    1562             :                        nsFrameLoader* aOtherFrameLoader,
    1563             :                        nsDocShell* aThisDocShell,
    1564             :                        nsDocShell* aOtherDocShell,
    1565             :                        EventTarget* aThisEventTarget,
    1566             :                        EventTarget* aOtherEventTarget
    1567             :                        MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    1568           0 :     : mThisFrameLoader(aThisFrameLoader)
    1569             :     , mOtherFrameLoader(aOtherFrameLoader)
    1570             :     , mThisDocShell(aThisDocShell)
    1571             :     , mOtherDocShell(aOtherDocShell)
    1572             :     , mThisEventTarget(aThisEventTarget)
    1573           0 :     , mOtherEventTarget(aOtherEventTarget)
    1574             :   {
    1575           0 :     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    1576             : 
    1577           0 :     mThisFrameLoader->mInSwap = true;
    1578           0 :     mOtherFrameLoader->mInSwap = true;
    1579           0 :     mThisDocShell->SetInFrameSwap(true);
    1580           0 :     mOtherDocShell->SetInFrameSwap(true);
    1581             : 
    1582             :     // Fire pageshow events on still-loading pages, and then fire pagehide
    1583             :     // events.  Note that we do NOT fire these in the normal way, but just fire
    1584             :     // them on the chrome event handlers.
    1585           0 :     nsContentUtils::FirePageShowEvent(mThisDocShell, mThisEventTarget, false);
    1586           0 :     nsContentUtils::FirePageShowEvent(mOtherDocShell, mOtherEventTarget, false);
    1587           0 :     nsContentUtils::FirePageHideEvent(mThisDocShell, mThisEventTarget);
    1588           0 :     nsContentUtils::FirePageHideEvent(mOtherDocShell, mOtherEventTarget);
    1589           0 :   }
    1590             : 
    1591           0 :   ~AutoResetInFrameSwap()
    1592           0 :   {
    1593           0 :     nsContentUtils::FirePageShowEvent(mThisDocShell, mThisEventTarget, true);
    1594           0 :     nsContentUtils::FirePageShowEvent(mOtherDocShell, mOtherEventTarget, true);
    1595             : 
    1596           0 :     mThisFrameLoader->mInSwap = false;
    1597           0 :     mOtherFrameLoader->mInSwap = false;
    1598           0 :     mThisDocShell->SetInFrameSwap(false);
    1599           0 :     mOtherDocShell->SetInFrameSwap(false);
    1600           0 :   }
    1601             : 
    1602             : private:
    1603             :   RefPtr<nsFrameLoader> mThisFrameLoader;
    1604             :   RefPtr<nsFrameLoader> mOtherFrameLoader;
    1605             :   RefPtr<nsDocShell> mThisDocShell;
    1606             :   RefPtr<nsDocShell> mOtherDocShell;
    1607             :   nsCOMPtr<EventTarget> mThisEventTarget;
    1608             :   nsCOMPtr<EventTarget> mOtherEventTarget;
    1609             :   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
    1610             : };
    1611             : 
    1612             : nsresult
    1613           0 : nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
    1614             :                                    nsIFrameLoaderOwner* aThisOwner,
    1615             :                                    nsIFrameLoaderOwner* aOtherOwner)
    1616             : {
    1617             : #ifdef DEBUG
    1618           0 :   RefPtr<nsFrameLoader> first = aThisOwner->GetFrameLoader();
    1619           0 :   RefPtr<nsFrameLoader> second = aOtherOwner->GetFrameLoader();
    1620           0 :   MOZ_ASSERT(first == this, "aThisOwner must own this");
    1621           0 :   MOZ_ASSERT(second == aOther, "aOtherOwner must own aOther");
    1622             : #endif
    1623             : 
    1624           0 :   NS_ENSURE_STATE(!mInShow && !aOther->mInShow);
    1625             : 
    1626           0 :   if (IsRemoteFrame() != aOther->IsRemoteFrame()) {
    1627           0 :     NS_WARNING("Swapping remote and non-remote frames is not currently supported");
    1628           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1629             :   }
    1630             : 
    1631           0 :   Element* ourContent = mOwnerContent;
    1632           0 :   Element* otherContent = aOther->mOwnerContent;
    1633             : 
    1634           0 :   if (!ourContent || !otherContent) {
    1635             :     // Can't handle this
    1636           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1637             :   }
    1638             : 
    1639           0 :   bool ourHasSrcdoc = ourContent->IsHTMLElement(nsGkAtoms::iframe) &&
    1640           0 :                       ourContent->HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc);
    1641           0 :   bool otherHasSrcdoc = otherContent->IsHTMLElement(nsGkAtoms::iframe) &&
    1642           0 :                         otherContent->HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc);
    1643           0 :   if (ourHasSrcdoc || otherHasSrcdoc) {
    1644             :     // Ignore this case entirely for now, since we support XUL <-> HTML swapping
    1645           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1646             :   }
    1647             : 
    1648             :   bool ourFullscreenAllowed =
    1649           0 :     ourContent->IsXULElement() ||
    1650           0 :     (OwnerIsMozBrowserFrame() &&
    1651           0 :       (ourContent->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) ||
    1652           0 :        ourContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen)));
    1653             :   bool otherFullscreenAllowed =
    1654           0 :     otherContent->IsXULElement() ||
    1655           0 :     (aOther->OwnerIsMozBrowserFrame() &&
    1656           0 :       (otherContent->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) ||
    1657           0 :        otherContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen)));
    1658           0 :   if (ourFullscreenAllowed != otherFullscreenAllowed) {
    1659           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1660             :   }
    1661             : 
    1662             :   // Divert to a separate path for the remaining steps in the remote case
    1663           0 :   if (IsRemoteFrame()) {
    1664           0 :     MOZ_ASSERT(aOther->IsRemoteFrame());
    1665           0 :     return SwapWithOtherRemoteLoader(aOther, aThisOwner, aOtherOwner);
    1666             :   }
    1667             : 
    1668             :   // Make sure there are no same-origin issues
    1669             :   bool equal;
    1670             :   nsresult rv =
    1671           0 :     ourContent->NodePrincipal()->Equals(otherContent->NodePrincipal(), &equal);
    1672           0 :   if (NS_FAILED(rv) || !equal) {
    1673             :     // Security problems loom.  Just bail on it all
    1674           0 :     return NS_ERROR_DOM_SECURITY_ERR;
    1675             :   }
    1676             : 
    1677           0 :   RefPtr<nsDocShell> ourDocshell = static_cast<nsDocShell*>(GetExistingDocShell());
    1678           0 :   RefPtr<nsDocShell> otherDocshell = static_cast<nsDocShell*>(aOther->GetExistingDocShell());
    1679           0 :   if (!ourDocshell || !otherDocshell) {
    1680             :     // How odd
    1681           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1682             :   }
    1683             : 
    1684             :   // To avoid having to mess with session history, avoid swapping
    1685             :   // frameloaders that don't correspond to root same-type docshells,
    1686             :   // unless both roots have session history disabled.
    1687           0 :   nsCOMPtr<nsIDocShellTreeItem> ourRootTreeItem, otherRootTreeItem;
    1688           0 :   ourDocshell->GetSameTypeRootTreeItem(getter_AddRefs(ourRootTreeItem));
    1689           0 :   otherDocshell->GetSameTypeRootTreeItem(getter_AddRefs(otherRootTreeItem));
    1690             :   nsCOMPtr<nsIWebNavigation> ourRootWebnav =
    1691           0 :     do_QueryInterface(ourRootTreeItem);
    1692             :   nsCOMPtr<nsIWebNavigation> otherRootWebnav =
    1693           0 :     do_QueryInterface(otherRootTreeItem);
    1694             : 
    1695           0 :   if (!ourRootWebnav || !otherRootWebnav) {
    1696           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1697             :   }
    1698             : 
    1699           0 :   nsCOMPtr<nsISHistory> ourHistory;
    1700           0 :   nsCOMPtr<nsISHistory> otherHistory;
    1701           0 :   ourRootWebnav->GetSessionHistory(getter_AddRefs(ourHistory));
    1702           0 :   otherRootWebnav->GetSessionHistory(getter_AddRefs(otherHistory));
    1703             : 
    1704           0 :   if ((ourRootTreeItem != ourDocshell || otherRootTreeItem != otherDocshell) &&
    1705           0 :       (ourHistory || otherHistory)) {
    1706           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1707             :   }
    1708             : 
    1709             :   // Also make sure that the two docshells are the same type. Otherwise
    1710             :   // swapping is certainly not safe. If this needs to be changed then
    1711             :   // the code below needs to be audited as it assumes identical types.
    1712           0 :   int32_t ourType = ourDocshell->ItemType();
    1713           0 :   int32_t otherType = otherDocshell->ItemType();
    1714           0 :   if (ourType != otherType) {
    1715           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1716             :   }
    1717             : 
    1718             :   // One more twist here.  Setting up the right treeowners in a heterogeneous
    1719             :   // tree is a bit of a pain.  So make sure that if ourType is not
    1720             :   // nsIDocShellTreeItem::typeContent then all of our descendants are the same
    1721             :   // type as us.
    1722           0 :   if (ourType != nsIDocShellTreeItem::typeContent &&
    1723           0 :       (!AllDescendantsOfType(ourDocshell, ourType) ||
    1724           0 :        !AllDescendantsOfType(otherDocshell, otherType))) {
    1725           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1726             :   }
    1727             : 
    1728             :   // Save off the tree owners, frame elements, chrome event handlers, and
    1729             :   // docshell and document parents before doing anything else.
    1730           0 :   nsCOMPtr<nsIDocShellTreeOwner> ourOwner, otherOwner;
    1731           0 :   ourDocshell->GetTreeOwner(getter_AddRefs(ourOwner));
    1732           0 :   otherDocshell->GetTreeOwner(getter_AddRefs(otherOwner));
    1733             :   // Note: it's OK to have null treeowners.
    1734             : 
    1735           0 :   nsCOMPtr<nsIDocShellTreeItem> ourParentItem, otherParentItem;
    1736           0 :   ourDocshell->GetParent(getter_AddRefs(ourParentItem));
    1737           0 :   otherDocshell->GetParent(getter_AddRefs(otherParentItem));
    1738           0 :   if (!ourParentItem || !otherParentItem) {
    1739           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1740             :   }
    1741             : 
    1742             :   // Make sure our parents are the same type too
    1743           0 :   int32_t ourParentType = ourParentItem->ItemType();
    1744           0 :   int32_t otherParentType = otherParentItem->ItemType();
    1745           0 :   if (ourParentType != otherParentType) {
    1746           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1747             :   }
    1748             : 
    1749           0 :   nsCOMPtr<nsPIDOMWindowOuter> ourWindow = ourDocshell->GetWindow();
    1750           0 :   nsCOMPtr<nsPIDOMWindowOuter> otherWindow = otherDocshell->GetWindow();
    1751             : 
    1752             :   nsCOMPtr<Element> ourFrameElement =
    1753           0 :     ourWindow->GetFrameElementInternal();
    1754             :   nsCOMPtr<Element> otherFrameElement =
    1755           0 :     otherWindow->GetFrameElementInternal();
    1756             : 
    1757             :   nsCOMPtr<EventTarget> ourChromeEventHandler =
    1758           0 :     do_QueryInterface(ourWindow->GetChromeEventHandler());
    1759             :   nsCOMPtr<EventTarget> otherChromeEventHandler =
    1760           0 :     do_QueryInterface(otherWindow->GetChromeEventHandler());
    1761             : 
    1762           0 :   nsCOMPtr<EventTarget> ourEventTarget = ourWindow->GetParentTarget();
    1763           0 :   nsCOMPtr<EventTarget> otherEventTarget = otherWindow->GetParentTarget();
    1764             : 
    1765           0 :   NS_ASSERTION(SameCOMIdentity(ourFrameElement, ourContent) &&
    1766             :                SameCOMIdentity(otherFrameElement, otherContent) &&
    1767             :                SameCOMIdentity(ourChromeEventHandler, ourContent) &&
    1768             :                SameCOMIdentity(otherChromeEventHandler, otherContent),
    1769             :                "How did that happen, exactly?");
    1770             : 
    1771           0 :   nsCOMPtr<nsIDocument> ourChildDocument = ourWindow->GetExtantDoc();
    1772           0 :   nsCOMPtr<nsIDocument> otherChildDocument = otherWindow ->GetExtantDoc();
    1773           0 :   if (!ourChildDocument || !otherChildDocument) {
    1774             :     // This shouldn't be happening
    1775           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1776             :   }
    1777             : 
    1778             :   nsCOMPtr<nsIDocument> ourParentDocument =
    1779           0 :     ourChildDocument->GetParentDocument();
    1780             :   nsCOMPtr<nsIDocument> otherParentDocument =
    1781           0 :     otherChildDocument->GetParentDocument();
    1782             : 
    1783             :   // Make sure to swap docshells between the two frames.
    1784           0 :   nsIDocument* ourDoc = ourContent->GetComposedDoc();
    1785           0 :   nsIDocument* otherDoc = otherContent->GetComposedDoc();
    1786           0 :   if (!ourDoc || !otherDoc) {
    1787             :     // Again, how odd, given that we had docshells
    1788           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1789             :   }
    1790             : 
    1791           0 :   NS_ASSERTION(ourDoc == ourParentDocument, "Unexpected parent document");
    1792           0 :   NS_ASSERTION(otherDoc == otherParentDocument, "Unexpected parent document");
    1793             : 
    1794           0 :   nsIPresShell* ourShell = ourDoc->GetShell();
    1795           0 :   nsIPresShell* otherShell = otherDoc->GetShell();
    1796           0 :   if (!ourShell || !otherShell) {
    1797           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1798             :   }
    1799             : 
    1800           0 :   if (ourDocshell->GetIsIsolatedMozBrowserElement() !=
    1801           0 :       otherDocshell->GetIsIsolatedMozBrowserElement()) {
    1802           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1803             :   }
    1804             : 
    1805             :   // When we swap docShells, maybe we have to deal with a new page created just
    1806             :   // for this operation. In this case, the browser code should already have set
    1807             :   // the correct userContextId attribute value in the owning XULElement, but our
    1808             :   // docShell, that has been created way before) doesn't know that that
    1809             :   // happened.
    1810             :   // This is the reason why now we must retrieve the correct value from the
    1811             :   // usercontextid attribute before comparing our originAttributes with the
    1812             :   // other one.
    1813             :   OriginAttributes ourOriginAttributes =
    1814           0 :     ourDocshell->GetOriginAttributes();
    1815           0 :   rv = PopulateUserContextIdFromAttribute(ourOriginAttributes);
    1816           0 :   NS_ENSURE_SUCCESS(rv,rv);
    1817             : 
    1818             :   OriginAttributes otherOriginAttributes =
    1819           0 :     otherDocshell->GetOriginAttributes();
    1820           0 :   rv = aOther->PopulateUserContextIdFromAttribute(otherOriginAttributes);
    1821           0 :   NS_ENSURE_SUCCESS(rv,rv);
    1822             : 
    1823           0 :   if (ourOriginAttributes != otherOriginAttributes) {
    1824           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1825             :   }
    1826             : 
    1827           0 :   if (mInSwap || aOther->mInSwap) {
    1828           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1829             :   }
    1830             :   AutoResetInFrameSwap autoFrameSwap(this, aOther, ourDocshell, otherDocshell,
    1831           0 :                                      ourEventTarget, otherEventTarget);
    1832             : 
    1833           0 :   nsIFrame* ourFrame = ourContent->GetPrimaryFrame();
    1834           0 :   nsIFrame* otherFrame = otherContent->GetPrimaryFrame();
    1835           0 :   if (!ourFrame || !otherFrame) {
    1836           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1837             :   }
    1838             : 
    1839           0 :   nsSubDocumentFrame* ourFrameFrame = do_QueryFrame(ourFrame);
    1840           0 :   if (!ourFrameFrame) {
    1841           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1842             :   }
    1843             : 
    1844             :   // OK.  First begin to swap the docshells in the two nsIFrames
    1845           0 :   rv = ourFrameFrame->BeginSwapDocShells(otherFrame);
    1846           0 :   if (NS_FAILED(rv)) {
    1847           0 :     return rv;
    1848             :   }
    1849             : 
    1850             :   // Destroy browser frame scripts for content leaving a frame with browser API
    1851           0 :   if (OwnerIsMozBrowserFrame() && !aOther->OwnerIsMozBrowserFrame()) {
    1852           0 :     DestroyBrowserFrameScripts();
    1853             :   }
    1854           0 :   if (!OwnerIsMozBrowserFrame() && aOther->OwnerIsMozBrowserFrame()) {
    1855           0 :     aOther->DestroyBrowserFrameScripts();
    1856             :   }
    1857             : 
    1858             :   // Now move the docshells to the right docshell trees.  Note that this
    1859             :   // resets their treeowners to null.
    1860           0 :   ourParentItem->RemoveChild(ourDocshell);
    1861           0 :   otherParentItem->RemoveChild(otherDocshell);
    1862           0 :   if (ourType == nsIDocShellTreeItem::typeContent) {
    1863           0 :     ourOwner->ContentShellRemoved(ourDocshell);
    1864           0 :     otherOwner->ContentShellRemoved(otherDocshell);
    1865             :   }
    1866             : 
    1867           0 :   ourParentItem->AddChild(otherDocshell);
    1868           0 :   otherParentItem->AddChild(ourDocshell);
    1869             : 
    1870             :   // Restore the correct chrome event handlers.
    1871           0 :   ourDocshell->SetChromeEventHandler(otherChromeEventHandler);
    1872           0 :   otherDocshell->SetChromeEventHandler(ourChromeEventHandler);
    1873             :   // Restore the correct treeowners
    1874             :   // (and also chrome event handlers for content frames only).
    1875           0 :   SetTreeOwnerAndChromeEventHandlerOnDocshellTree(ourDocshell, otherOwner,
    1876           0 :     ourType == nsIDocShellTreeItem::typeContent ? otherChromeEventHandler.get() : nullptr);
    1877           0 :   SetTreeOwnerAndChromeEventHandlerOnDocshellTree(otherDocshell, ourOwner,
    1878           0 :     ourType == nsIDocShellTreeItem::typeContent ? ourChromeEventHandler.get() : nullptr);
    1879             : 
    1880             :   // Switch the owner content before we start calling AddTreeItemToTreeOwner.
    1881             :   // Note that we rely on this to deal with setting mObservingOwnerContent to
    1882             :   // false and calling RemoveMutationObserver as needed.
    1883           0 :   SetOwnerContent(otherContent);
    1884           0 :   aOther->SetOwnerContent(ourContent);
    1885             : 
    1886           0 :   AddTreeItemToTreeOwner(ourDocshell, otherOwner, otherParentType, nullptr);
    1887           0 :   aOther->AddTreeItemToTreeOwner(otherDocshell, ourOwner, ourParentType,
    1888           0 :                                  nullptr);
    1889             : 
    1890             :   // SetSubDocumentFor nulls out parent documents on the old child doc if a
    1891             :   // new non-null document is passed in, so just go ahead and remove both
    1892             :   // kids before reinserting in the parent subdoc maps, to avoid
    1893             :   // complications.
    1894           0 :   ourParentDocument->SetSubDocumentFor(ourContent, nullptr);
    1895           0 :   otherParentDocument->SetSubDocumentFor(otherContent, nullptr);
    1896           0 :   ourParentDocument->SetSubDocumentFor(ourContent, otherChildDocument);
    1897           0 :   otherParentDocument->SetSubDocumentFor(otherContent, ourChildDocument);
    1898             : 
    1899           0 :   ourWindow->SetFrameElementInternal(otherFrameElement);
    1900           0 :   otherWindow->SetFrameElementInternal(ourFrameElement);
    1901             : 
    1902           0 :   RefPtr<nsFrameMessageManager> ourMessageManager = mMessageManager;
    1903           0 :   RefPtr<nsFrameMessageManager> otherMessageManager = aOther->mMessageManager;
    1904             :   // Swap pointers in child message managers.
    1905           0 :   if (mChildMessageManager) {
    1906             :     nsInProcessTabChildGlobal* tabChild =
    1907           0 :       static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get());
    1908           0 :     tabChild->SetOwner(otherContent);
    1909           0 :     tabChild->SetChromeMessageManager(otherMessageManager);
    1910             :   }
    1911           0 :   if (aOther->mChildMessageManager) {
    1912             :     nsInProcessTabChildGlobal* otherTabChild =
    1913           0 :       static_cast<nsInProcessTabChildGlobal*>(aOther->mChildMessageManager.get());
    1914           0 :     otherTabChild->SetOwner(ourContent);
    1915           0 :     otherTabChild->SetChromeMessageManager(ourMessageManager);
    1916             :   }
    1917             :   // Swap and setup things in parent message managers.
    1918           0 :   if (mMessageManager) {
    1919           0 :     mMessageManager->SetCallback(aOther);
    1920             :   }
    1921           0 :   if (aOther->mMessageManager) {
    1922           0 :     aOther->mMessageManager->SetCallback(this);
    1923             :   }
    1924           0 :   mMessageManager.swap(aOther->mMessageManager);
    1925             : 
    1926             :   // Perform the actual swap of the internal refptrs. We keep a strong reference
    1927             :   // to ourselves to make sure we don't die while we overwrite our reference to
    1928             :   // ourself.
    1929           0 :   nsCOMPtr<nsIFrameLoader> kungFuDeathGrip(this);
    1930           0 :   aThisOwner->InternalSetFrameLoader(aOther);
    1931           0 :   aOtherOwner->InternalSetFrameLoader(kungFuDeathGrip);
    1932             : 
    1933             :   // Drop any cached content viewers in the two session histories.
    1934             :   nsCOMPtr<nsISHistoryInternal> ourInternalHistory =
    1935           0 :     do_QueryInterface(ourHistory);
    1936             :   nsCOMPtr<nsISHistoryInternal> otherInternalHistory =
    1937           0 :     do_QueryInterface(otherHistory);
    1938           0 :   if (ourInternalHistory) {
    1939           0 :     ourInternalHistory->EvictAllContentViewers();
    1940             :   }
    1941           0 :   if (otherInternalHistory) {
    1942           0 :     otherInternalHistory->EvictAllContentViewers();
    1943             :   }
    1944             : 
    1945           0 :   NS_ASSERTION(ourFrame == ourContent->GetPrimaryFrame() &&
    1946             :                otherFrame == otherContent->GetPrimaryFrame(),
    1947             :                "changed primary frame");
    1948             : 
    1949           0 :   ourFrameFrame->EndSwapDocShells(otherFrame);
    1950             : 
    1951             :   // If the content being swapped came from windows on two screens with
    1952             :   // incompatible backing resolution (e.g. dragging a tab between windows on
    1953             :   // hi-dpi and low-dpi screens), it will have style data that is based on
    1954             :   // the wrong appUnitsPerDevPixel value. So we tell the PresShells that their
    1955             :   // backing scale factor may have changed. (Bug 822266)
    1956           0 :   ourShell->BackingScaleFactorChanged();
    1957           0 :   otherShell->BackingScaleFactorChanged();
    1958             : 
    1959             :   // Initialize browser API if needed now that owner content has changed
    1960           0 :   InitializeBrowserAPI();
    1961           0 :   aOther->InitializeBrowserAPI();
    1962             : 
    1963           0 :   return NS_OK;
    1964             : }
    1965             : 
    1966             : NS_IMETHODIMP
    1967           1 : nsFrameLoader::Destroy()
    1968             : {
    1969           1 :   StartDestroy();
    1970           1 :   return NS_OK;
    1971             : }
    1972             : 
    1973           3 : class nsFrameLoaderDestroyRunnable : public Runnable
    1974             : {
    1975             :   enum DestroyPhase
    1976             :   {
    1977             :     // See the implementation of Run for an explanation of these phases.
    1978             :     eDestroyDocShell,
    1979             :     eWaitForUnloadMessage,
    1980             :     eDestroyComplete
    1981             :   };
    1982             : 
    1983             :   RefPtr<nsFrameLoader> mFrameLoader;
    1984             :   DestroyPhase mPhase;
    1985             : 
    1986             : public:
    1987           1 :   explicit nsFrameLoaderDestroyRunnable(nsFrameLoader* aFrameLoader)
    1988           1 :     : mozilla::Runnable("nsFrameLoaderDestroyRunnable")
    1989             :     , mFrameLoader(aFrameLoader)
    1990           1 :     , mPhase(eDestroyDocShell)
    1991             :   {
    1992           1 :   }
    1993             : 
    1994             :   NS_IMETHOD Run() override;
    1995             : };
    1996             : 
    1997             : void
    1998           1 : nsFrameLoader::StartDestroy()
    1999             : {
    2000             :   // nsFrameLoader::StartDestroy is called just before the frameloader is
    2001             :   // detached from the <browser> element. Destruction continues in phases via
    2002             :   // the nsFrameLoaderDestroyRunnable.
    2003             : 
    2004           1 :   if (mDestroyCalled) {
    2005           0 :     return;
    2006             :   }
    2007           1 :   mDestroyCalled = true;
    2008             : 
    2009             :   // After this point, we return an error when trying to send a message using
    2010             :   // the message manager on the frame.
    2011           1 :   if (mMessageManager) {
    2012           1 :     mMessageManager->Close();
    2013             :   }
    2014             : 
    2015             :   // Retain references to the <browser> element and the frameloader in case we
    2016             :   // receive any messages from the message manager on the frame. These
    2017             :   // references are dropped in DestroyComplete.
    2018           1 :   if (mChildMessageManager || mRemoteBrowser) {
    2019           1 :     mOwnerContentStrong = mOwnerContent;
    2020           1 :     if (mRemoteBrowser) {
    2021           0 :       mRemoteBrowser->CacheFrameLoader(this);
    2022             :     }
    2023           1 :     if (mChildMessageManager) {
    2024           1 :       mChildMessageManager->CacheFrameLoader(this);
    2025             :     }
    2026             :   }
    2027             : 
    2028             :   // If the TabParent has installed any event listeners on the window, this is
    2029             :   // its last chance to remove them while we're still in the document.
    2030           1 :   if (mRemoteBrowser) {
    2031           0 :     mRemoteBrowser->RemoveWindowListeners();
    2032             :   }
    2033             : 
    2034           2 :   nsCOMPtr<nsIDocument> doc;
    2035           1 :   bool dynamicSubframeRemoval = false;
    2036           1 :   if (mOwnerContent) {
    2037           1 :     doc = mOwnerContent->OwnerDoc();
    2038           1 :     dynamicSubframeRemoval = !mIsTopLevelContent && !doc->InUnlinkOrDeletion();
    2039           1 :     doc->SetSubDocumentFor(mOwnerContent, nullptr);
    2040           1 :     MaybeUpdatePrimaryTabParent(eTabParentRemoved);
    2041           1 :     SetOwnerContent(nullptr);
    2042             :   }
    2043             : 
    2044             :   // Seems like this is a dynamic frame removal.
    2045           1 :   if (dynamicSubframeRemoval) {
    2046           0 :     if (mDocShell) {
    2047           0 :       mDocShell->RemoveFromSessionHistory();
    2048             :     }
    2049             :   }
    2050             : 
    2051             :   // Let the tree owner know we're gone.
    2052           1 :   if (mIsTopLevelContent) {
    2053           1 :     if (mDocShell) {
    2054           2 :       nsCOMPtr<nsIDocShellTreeItem> parentItem;
    2055           1 :       mDocShell->GetParent(getter_AddRefs(parentItem));
    2056           2 :       nsCOMPtr<nsIDocShellTreeOwner> owner = do_GetInterface(parentItem);
    2057           1 :       if (owner) {
    2058           1 :         owner->ContentShellRemoved(mDocShell);
    2059             :       }
    2060             :     }
    2061             :   }
    2062             : 
    2063             :   // Let our window know that we are gone
    2064           1 :   if (mDocShell) {
    2065           2 :     nsCOMPtr<nsPIDOMWindowOuter> win_private(mDocShell->GetWindow());
    2066           1 :     if (win_private) {
    2067           1 :       win_private->SetFrameElementInternal(nullptr);
    2068             :     }
    2069             :   }
    2070             : 
    2071             :   // Destroy the other frame loader owners now that we are being destroyed.
    2072           1 :   if (mPartialSHistory &&
    2073           1 :       mPartialSHistory->GetActiveState() == nsIPartialSHistory::STATE_ACTIVE) {
    2074           0 :     nsCOMPtr<nsIGroupedSHistory> groupedSHistory;
    2075           0 :     GetGroupedSHistory(getter_AddRefs(groupedSHistory));
    2076           0 :     if (groupedSHistory) {
    2077           0 :       NS_DispatchToCurrentThread(NS_NewRunnableFunction(
    2078           0 :         "nsFrameLoader::StartDestroy", [groupedSHistory]() {
    2079           0 :           groupedSHistory->CloseInactiveFrameLoaderOwners();
    2080           0 :         }));
    2081             :     }
    2082             :   }
    2083             : 
    2084           2 :   nsCOMPtr<nsIRunnable> destroyRunnable = new nsFrameLoaderDestroyRunnable(this);
    2085           2 :   if (mNeedsAsyncDestroy || !doc ||
    2086           1 :       NS_FAILED(doc->FinalizeFrameLoader(this, destroyRunnable))) {
    2087           0 :     NS_DispatchToCurrentThread(destroyRunnable);
    2088             :   }
    2089             : }
    2090             : 
    2091             : nsresult
    2092           3 : nsFrameLoaderDestroyRunnable::Run()
    2093             : {
    2094           3 :   switch (mPhase) {
    2095             :   case eDestroyDocShell:
    2096           1 :     mFrameLoader->DestroyDocShell();
    2097             : 
    2098             :     // In the out-of-process case, TabParent will eventually call
    2099             :     // DestroyComplete once it receives a __delete__ message from the child. In
    2100             :     // the in-process case, we dispatch a series of runnables to ensure that
    2101             :     // DestroyComplete gets called at the right time. The frame loader is kept
    2102             :     // alive by mFrameLoader during this time.
    2103           1 :     if (mFrameLoader->mChildMessageManager) {
    2104             :       // When the docshell is destroyed, NotifyWindowIDDestroyed is called to
    2105             :       // asynchronously notify {outer,inner}-window-destroyed via a runnable. We
    2106             :       // don't want DestroyComplete to run until after those runnables have
    2107             :       // run. Since we're enqueueing ourselves after the window-destroyed
    2108             :       // runnables are enqueued, we're guaranteed to run after.
    2109           1 :       mPhase = eWaitForUnloadMessage;
    2110           1 :       NS_DispatchToCurrentThread(this);
    2111             :     }
    2112           1 :     break;
    2113             : 
    2114             :    case eWaitForUnloadMessage:
    2115             :      // The *-window-destroyed observers have finished running at this
    2116             :      // point. However, it's possible that a *-window-destroyed observer might
    2117             :      // have sent a message using the message manager. These messages might not
    2118             :      // have been processed yet. So we enqueue ourselves again to ensure that
    2119             :      // DestroyComplete runs after all messages sent by *-window-destroyed
    2120             :      // observers have been processed.
    2121           1 :      mPhase = eDestroyComplete;
    2122           1 :      NS_DispatchToCurrentThread(this);
    2123           1 :      break;
    2124             : 
    2125             :    case eDestroyComplete:
    2126             :      // Now that all messages sent by unload listeners and window destroyed
    2127             :      // observers have been processed, we disconnect the message manager and
    2128             :      // finish destruction.
    2129           1 :      mFrameLoader->DestroyComplete();
    2130           1 :      break;
    2131             :   }
    2132             : 
    2133           3 :   return NS_OK;
    2134             : }
    2135             : 
    2136             : void
    2137           1 : nsFrameLoader::DestroyDocShell()
    2138             : {
    2139             :   // This code runs after the frameloader has been detached from the <browser>
    2140             :   // element. We postpone this work because we may not be allowed to run
    2141             :   // script at that time.
    2142             : 
    2143             :   // Ask the TabChild to fire the frame script "unload" event, destroy its
    2144             :   // docshell, and finally destroy the PBrowser actor. This eventually leads to
    2145             :   // nsFrameLoader::DestroyComplete being called.
    2146           1 :   if (mRemoteBrowser) {
    2147           0 :     mRemoteBrowser->Destroy();
    2148             :   }
    2149             : 
    2150             :   // Fire the "unload" event if we're in-process.
    2151           1 :   if (mChildMessageManager) {
    2152           1 :     static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get())->FireUnloadEvent();
    2153             :   }
    2154             : 
    2155             :   // Destroy the docshell.
    2156           2 :   nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell));
    2157           1 :   if (base_win) {
    2158           1 :     base_win->Destroy();
    2159             :   }
    2160           1 :   mDocShell = nullptr;
    2161             : 
    2162           1 :   if (mChildMessageManager) {
    2163             :     // Stop handling events in the in-process frame script.
    2164           1 :     static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get())->DisconnectEventListeners();
    2165             :   }
    2166           1 : }
    2167             : 
    2168             : void
    2169           1 : nsFrameLoader::DestroyComplete()
    2170             : {
    2171             :   // We get here, as part of StartDestroy, after the docshell has been destroyed
    2172             :   // and all message manager messages sent during docshell destruction have been
    2173             :   // dispatched.  We also get here if the child process crashes. In the latter
    2174             :   // case, StartDestroy might not have been called.
    2175             : 
    2176             :   // Drop the strong references created in StartDestroy.
    2177           1 :   if (mChildMessageManager || mRemoteBrowser) {
    2178           1 :     mOwnerContentStrong = nullptr;
    2179           1 :     if (mRemoteBrowser) {
    2180           0 :       mRemoteBrowser->CacheFrameLoader(nullptr);
    2181             :     }
    2182           1 :     if (mChildMessageManager) {
    2183           1 :       mChildMessageManager->CacheFrameLoader(nullptr);
    2184             :     }
    2185             :   }
    2186             : 
    2187             :   // Call TabParent::Destroy if we haven't already (in case of a crash).
    2188           1 :   if (mRemoteBrowser) {
    2189           0 :     mRemoteBrowser->SetOwnerElement(nullptr);
    2190           0 :     mRemoteBrowser->Destroy();
    2191           0 :     mRemoteBrowser = nullptr;
    2192             :   }
    2193             : 
    2194           1 :   if (mMessageManager) {
    2195           1 :     mMessageManager->Disconnect();
    2196             :   }
    2197             : 
    2198           1 :   if (mChildMessageManager) {
    2199           1 :     static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get())->Disconnect();
    2200             :   }
    2201             : 
    2202           1 :   mMessageManager = nullptr;
    2203           1 :   mChildMessageManager = nullptr;
    2204           1 : }
    2205             : 
    2206             : NS_IMETHODIMP
    2207           0 : nsFrameLoader::GetDepthTooGreat(bool* aDepthTooGreat)
    2208             : {
    2209           0 :   *aDepthTooGreat = mDepthTooGreat;
    2210           0 :   return NS_OK;
    2211             : }
    2212             : 
    2213             : void
    2214           1 : nsFrameLoader::SetOwnerContent(Element* aContent)
    2215             : {
    2216           1 :   if (mObservingOwnerContent) {
    2217           1 :     mObservingOwnerContent = false;
    2218           1 :     mOwnerContent->RemoveMutationObserver(this);
    2219             :   }
    2220           1 :   mOwnerContent = aContent;
    2221           1 :   if (RenderFrameParent* rfp = GetCurrentRenderFrame()) {
    2222           0 :     rfp->OwnerContentChanged(aContent);
    2223             :   }
    2224           1 : }
    2225             : 
    2226             : bool
    2227          21 : nsFrameLoader::OwnerIsMozBrowserFrame()
    2228             : {
    2229          42 :   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
    2230          42 :   return browserFrame ? browserFrame->GetReallyIsBrowser() : false;
    2231             : }
    2232             : 
    2233             : // The xpcom getter version
    2234             : NS_IMETHODIMP
    2235           0 : nsFrameLoader::GetOwnerIsMozBrowserFrame(bool* aResult)
    2236             : {
    2237           0 :   *aResult = OwnerIsMozBrowserFrame();
    2238           0 :   return NS_OK;
    2239             : }
    2240             : 
    2241             : bool
    2242           1 : nsFrameLoader::OwnerIsIsolatedMozBrowserFrame()
    2243             : {
    2244           2 :   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
    2245           1 :   if (!browserFrame) {
    2246           1 :     return false;
    2247             :   }
    2248             : 
    2249           0 :   if (!OwnerIsMozBrowserFrame()) {
    2250           0 :     return false;
    2251             :   }
    2252             : 
    2253           0 :   bool isolated = browserFrame->GetIsolated();
    2254           0 :   if (isolated) {
    2255           0 :     return true;
    2256             :   }
    2257             : 
    2258           0 :   return false;
    2259             : }
    2260             : 
    2261             : bool
    2262           4 : nsFrameLoader::ShouldUseRemoteProcess()
    2263             : {
    2264           4 :   if (IsForJSPlugin()) {
    2265           0 :     return true;
    2266             :   }
    2267             : 
    2268           8 :   if (PR_GetEnv("MOZ_DISABLE_OOP_TABS") ||
    2269           4 :       Preferences::GetBool("dom.ipc.tabs.disabled", false)) {
    2270           0 :     return false;
    2271             :   }
    2272             : 
    2273             :   // Don't try to launch nested children if we don't have OMTC.
    2274             :   // They won't render!
    2275           4 :   if (XRE_IsContentProcess() &&
    2276           0 :       !CompositorBridgeChild::ChildProcessHasCompositorBridge()) {
    2277           0 :     return false;
    2278             :   }
    2279             : 
    2280           4 :   if (XRE_IsContentProcess() &&
    2281           0 :       !(PR_GetEnv("MOZ_NESTED_OOP_TABS") ||
    2282           0 :         Preferences::GetBool("dom.ipc.tabs.nested.enabled", false))) {
    2283           0 :     return false;
    2284             :   }
    2285             : 
    2286             :   // If we're an <iframe mozbrowser> and we don't have a "remote" attribute,
    2287             :   // fall back to the default.
    2288           4 :   if (OwnerIsMozBrowserFrame() &&
    2289           0 :       !mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::Remote)) {
    2290             : 
    2291           0 :     return Preferences::GetBool("dom.ipc.browser_frames.oop_by_default", false);
    2292             :   }
    2293             : 
    2294             :   // Otherwise, we're remote if we have "remote=true" and we're either a
    2295             :   // browser frame or a XUL element.
    2296           8 :   return (OwnerIsMozBrowserFrame() ||
    2297           8 :           mOwnerContent->GetNameSpaceID() == kNameSpaceID_XUL) &&
    2298           4 :          mOwnerContent->AttrValueIs(kNameSpaceID_None,
    2299             :                                     nsGkAtoms::Remote,
    2300             :                                     nsGkAtoms::_true,
    2301           4 :                                     eCaseMatters);
    2302             : }
    2303             : 
    2304             : bool
    2305          32 : nsFrameLoader::IsRemoteFrame()
    2306             : {
    2307          32 :   if (mRemoteFrame) {
    2308          15 :     MOZ_ASSERT(!mDocShell, "Found a remote frame with a DocShell");
    2309          15 :     return true;
    2310             :   }
    2311          17 :   return false;
    2312             : }
    2313             : 
    2314             : nsresult
    2315          10 : nsFrameLoader::MaybeCreateDocShell()
    2316             : {
    2317          10 :   if (mDocShell) {
    2318           8 :     return NS_OK;
    2319             :   }
    2320           2 :   if (IsRemoteFrame()) {
    2321           0 :     return NS_OK;
    2322             :   }
    2323           2 :   NS_ENSURE_STATE(!mDestroyCalled);
    2324             : 
    2325             :   // Get our parent docshell off the document of mOwnerContent
    2326             :   // XXXbz this is such a total hack.... We really need to have a
    2327             :   // better setup for doing this.
    2328           2 :   nsIDocument* doc = mOwnerContent->OwnerDoc();
    2329             : 
    2330           2 :   MOZ_RELEASE_ASSERT(!doc->IsResourceDoc(), "We shouldn't even exist");
    2331             : 
    2332           2 :   if (!(doc->IsStaticDocument() || mOwnerContent->IsInComposedDoc())) {
    2333           0 :     return NS_ERROR_UNEXPECTED;
    2334             :   }
    2335             : 
    2336           2 :   if (!doc->IsActive()) {
    2337             :     // Don't allow subframe loads in non-active documents.
    2338             :     // (See bug 610571 comment 5.)
    2339           0 :     return NS_ERROR_NOT_AVAILABLE;
    2340             :   }
    2341             : 
    2342           4 :   nsCOMPtr<nsIDocShell> docShell = doc->GetDocShell();
    2343           4 :   nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_QueryInterface(docShell);
    2344           2 :   NS_ENSURE_STATE(parentAsWebNav);
    2345             : 
    2346             :   // Create the docshell...
    2347           2 :   mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
    2348           2 :   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
    2349             : 
    2350           2 :   if (mIsPrerendered) {
    2351           0 :     nsresult rv = mDocShell->SetIsPrerendered();
    2352           0 :     NS_ENSURE_SUCCESS(rv,rv);
    2353             :   }
    2354             : 
    2355           2 :   if (!mNetworkCreated) {
    2356           2 :     if (mDocShell) {
    2357           2 :       mDocShell->SetCreatedDynamically(true);
    2358             :     }
    2359             :   }
    2360             : 
    2361             :   // Get the frame name and tell the docshell about it.
    2362           2 :   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
    2363           4 :   nsAutoString frameName;
    2364             : 
    2365           2 :   int32_t namespaceID = mOwnerContent->GetNameSpaceID();
    2366           2 :   if (namespaceID == kNameSpaceID_XHTML && !mOwnerContent->IsInHTMLDocument()) {
    2367           0 :     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
    2368             :   } else {
    2369           2 :     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, frameName);
    2370             :     // XXX if no NAME then use ID, after a transition period this will be
    2371             :     // changed so that XUL only uses ID too (bug 254284).
    2372           2 :     if (frameName.IsEmpty() && namespaceID == kNameSpaceID_XUL) {
    2373           2 :       mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
    2374             :     }
    2375             :   }
    2376             : 
    2377           2 :   if (!frameName.IsEmpty()) {
    2378           1 :     mDocShell->SetName(frameName);
    2379             :   }
    2380             : 
    2381             :   // Inform our docShell that it has a new child.
    2382             :   // Note: This logic duplicates a lot of logic in
    2383             :   // nsSubDocumentFrame::AttributeChanged.  We should fix that.
    2384             : 
    2385           2 :   int32_t parentType = docShell->ItemType();
    2386             : 
    2387             :   // XXXbz why is this in content code, exactly?  We should handle
    2388             :   // this some other way.....  Not sure how yet.
    2389           4 :   nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
    2390           2 :   docShell->GetTreeOwner(getter_AddRefs(parentTreeOwner));
    2391           2 :   NS_ENSURE_STATE(parentTreeOwner);
    2392           2 :   mIsTopLevelContent =
    2393           2 :     AddTreeItemToTreeOwner(mDocShell, parentTreeOwner, parentType, docShell);
    2394             : 
    2395             :   // Make sure all shells have links back to the content element
    2396             :   // in the nearest enclosing chrome shell.
    2397           4 :   nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
    2398             : 
    2399           2 :   if (parentType == nsIDocShellTreeItem::typeChrome) {
    2400             :     // Our parent shell is a chrome shell. It is therefore our nearest
    2401             :     // enclosing chrome shell.
    2402             : 
    2403           2 :     chromeEventHandler = do_QueryInterface(mOwnerContent);
    2404           2 :     NS_ASSERTION(chromeEventHandler,
    2405             :                  "This mContent should implement this.");
    2406             :   } else {
    2407             :     // Our parent shell is a content shell. Get the chrome event
    2408             :     // handler from it and use that for our shell as well.
    2409             : 
    2410           0 :     docShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
    2411             :   }
    2412             : 
    2413           2 :   mDocShell->SetChromeEventHandler(chromeEventHandler);
    2414             : 
    2415             :   // This is nasty, this code (the mDocShell->GetWindow() below)
    2416             :   // *must* come *after* the above call to
    2417             :   // mDocShell->SetChromeEventHandler() for the global window to get
    2418             :   // the right chrome event handler.
    2419             : 
    2420             :   // Tell the window about the frame that hosts it.
    2421           4 :   nsCOMPtr<Element> frame_element = mOwnerContent;
    2422           2 :   NS_ASSERTION(frame_element, "frame loader owner element not a DOM element!");
    2423             : 
    2424           4 :   nsCOMPtr<nsPIDOMWindowOuter> win_private(mDocShell->GetWindow());
    2425           4 :   nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell));
    2426           2 :   if (win_private) {
    2427           2 :     win_private->SetFrameElementInternal(frame_element);
    2428             : 
    2429             :     // Set the opener window if we have one provided here
    2430           2 :     if (mOpener) {
    2431           0 :       win_private->SetOpenerWindow(mOpener, true);
    2432           0 :       mOpener = nullptr;
    2433             :     }
    2434             :   }
    2435             : 
    2436             :   // This is kinda whacky, this call doesn't really create anything,
    2437             :   // but it must be called to make sure things are properly
    2438             :   // initialized.
    2439           2 :   if (NS_FAILED(base_win->Create()) || !win_private) {
    2440             :     // Do not call Destroy() here. See bug 472312.
    2441           0 :     NS_WARNING("Something wrong when creating the docshell for a frameloader!");
    2442           0 :     return NS_ERROR_FAILURE;
    2443             :   }
    2444             : 
    2445           5 :   if (mIsTopLevelContent &&
    2446           3 :       mOwnerContent->IsXULElement(nsGkAtoms::browser) &&
    2447           1 :       !mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::disablehistory)) {
    2448             :     nsresult rv;
    2449             :     nsCOMPtr<nsISHistory> sessionHistory =
    2450           2 :       do_CreateInstance(NS_SHISTORY_CONTRACTID, &rv);
    2451           1 :     NS_ENSURE_SUCCESS(rv, rv);
    2452             : 
    2453           2 :     nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
    2454           1 :     webNav->SetSessionHistory(sessionHistory);
    2455             : 
    2456             : 
    2457           1 :     if (GroupedSHistory::GroupedHistoryEnabled()) {
    2458           0 :       mPartialSHistory = new PartialSHistory(this);
    2459           0 :       nsCOMPtr<nsISHistoryListener> listener(do_QueryInterface(mPartialSHistory));
    2460           0 :       nsCOMPtr<nsIPartialSHistoryListener> partialListener(do_QueryInterface(mPartialSHistory));
    2461           0 :       sessionHistory->AddSHistoryListener(listener);
    2462           0 :       sessionHistory->SetPartialSHistoryListener(partialListener);
    2463             :     }
    2464             :   }
    2465             : 
    2466           4 :   OriginAttributes attrs;
    2467           2 :   if (docShell->ItemType() == mDocShell->ItemType()) {
    2468           1 :     attrs = nsDocShell::Cast(docShell)->GetOriginAttributes();
    2469             :   }
    2470             : 
    2471             :   // Inherit origin attributes from parent document if
    2472             :   // 1. It's in a content docshell.
    2473             :   // 2. its nodePrincipal is not a SystemPrincipal.
    2474             :   // 3. It's not a mozbrowser frame.
    2475             :   //
    2476             :   // For example, firstPartyDomain is computed from top-level document, it
    2477             :   // doesn't exist in the top-level docshell.
    2478           2 :   if (parentType == nsIDocShellTreeItem::typeContent &&
    2479           2 :       !nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()) &&
    2480           0 :       !OwnerIsMozBrowserFrame()) {
    2481           0 :     OriginAttributes oa = doc->NodePrincipal()->OriginAttributesRef();
    2482             : 
    2483             :     // Assert on the firstPartyDomain from top-level docshell should be empty
    2484           0 :     MOZ_ASSERT_IF(mIsTopLevelContent, attrs.mFirstPartyDomain.IsEmpty());
    2485             : 
    2486             :     // So far we want to make sure Inherit doesn't override any other origin
    2487             :     // attribute than firstPartyDomain.
    2488           0 :     MOZ_ASSERT(attrs.mAppId == oa.mAppId,
    2489             :               "docshell and document should have the same appId attribute.");
    2490           0 :     MOZ_ASSERT(attrs.mUserContextId == oa.mUserContextId,
    2491             :               "docshell and document should have the same userContextId attribute.");
    2492           0 :     MOZ_ASSERT(attrs.mInIsolatedMozBrowser == oa.mInIsolatedMozBrowser,
    2493             :               "docshell and document should have the same inIsolatedMozBrowser attribute.");
    2494           0 :     MOZ_ASSERT(attrs.mPrivateBrowsingId == oa.mPrivateBrowsingId,
    2495             :               "docshell and document should have the same privateBrowsingId attribute.");
    2496             : 
    2497           0 :     attrs = oa;
    2498             :   }
    2499             : 
    2500           2 :   if (OwnerIsMozBrowserFrame()) {
    2501           0 :     attrs.mAppId = nsIScriptSecurityManager::NO_APP_ID;
    2502           0 :     attrs.mInIsolatedMozBrowser = OwnerIsIsolatedMozBrowserFrame();
    2503           0 :     mDocShell->SetFrameType(nsIDocShell::FRAME_TYPE_BROWSER);
    2504             :   }
    2505             : 
    2506             :   // Apply sandbox flags even if our owner is not an iframe, as this copies
    2507             :   // flags from our owning content's owning document.
    2508             :   // Note: ApplySandboxFlags should be called after mDocShell->SetFrameType
    2509             :   // because we need to get the correct presentation URL in ApplySandboxFlags.
    2510           2 :   uint32_t sandboxFlags = 0;
    2511           2 :   HTMLIFrameElement* iframe = HTMLIFrameElement::FromContent(mOwnerContent);
    2512           2 :   if (iframe) {
    2513           0 :     sandboxFlags = iframe->GetSandboxFlags();
    2514             :   }
    2515           2 :   ApplySandboxFlags(sandboxFlags);
    2516             : 
    2517             :   // Grab the userContextId from owner if XUL
    2518           2 :   nsresult rv = PopulateUserContextIdFromAttribute(attrs);
    2519           2 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2520           0 :     return rv;
    2521             :   }
    2522             : 
    2523           2 :   bool isPrivate = false;
    2524           4 :   nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(docShell);
    2525           2 :   NS_ENSURE_STATE(parentContext);
    2526             : 
    2527           2 :   rv = parentContext->GetUsePrivateBrowsing(&isPrivate);
    2528           2 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2529           0 :     return rv;
    2530             :   }
    2531           2 :   attrs.SyncAttributesWithPrivateBrowsing(isPrivate);
    2532             : 
    2533           2 :   if (OwnerIsMozBrowserFrame()) {
    2534             :     // For inproc frames, set the docshell properties.
    2535           0 :     nsAutoString name;
    2536           0 :     if (mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name)) {
    2537           0 :       docShell->SetName(name);
    2538             :     }
    2539           0 :     mDocShell->SetFullscreenAllowed(
    2540           0 :       mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) ||
    2541           0 :       mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen));
    2542           0 :     bool isPrivate = mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozprivatebrowsing);
    2543           0 :     if (isPrivate) {
    2544           0 :       if (mDocShell->GetHasLoadedNonBlankURI()) {
    2545           0 :         nsContentUtils::ReportToConsoleNonLocalized(
    2546           0 :           NS_LITERAL_STRING("We should not switch to Private Browsing after loading a document."),
    2547             :           nsIScriptError::warningFlag,
    2548           0 :           NS_LITERAL_CSTRING("mozprivatebrowsing"),
    2549           0 :           nullptr);
    2550             :       } else {
    2551             :         // This handles the case where a frames private browsing is set by chrome flags
    2552             :         // and not inherited by its parent.
    2553           0 :         attrs.SyncAttributesWithPrivateBrowsing(isPrivate);
    2554             :       }
    2555             :     }
    2556             :   }
    2557             : 
    2558           2 :   nsDocShell::Cast(mDocShell)->SetOriginAttributes(attrs);
    2559             : 
    2560           2 :   ReallyLoadFrameScripts();
    2561           2 :   InitializeBrowserAPI();
    2562             : 
    2563           4 :   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
    2564           2 :   if (os) {
    2565           4 :     os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
    2566           4 :                         "inprocess-browser-shown", nullptr);
    2567             :   }
    2568             : 
    2569           2 :   return NS_OK;
    2570             : }
    2571             : 
    2572             : void
    2573           4 : nsFrameLoader::GetURL(nsString& aURI)
    2574             : {
    2575           4 :   aURI.Truncate();
    2576             : 
    2577           4 :   if (mOwnerContent->IsHTMLElement(nsGkAtoms::object)) {
    2578           0 :     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, aURI);
    2579             :   } else {
    2580           4 :     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, aURI);
    2581             :   }
    2582           4 : }
    2583             : 
    2584             : nsresult
    2585           4 : nsFrameLoader::CheckForRecursiveLoad(nsIURI* aURI)
    2586             : {
    2587             :   nsresult rv;
    2588             : 
    2589           4 :   MOZ_ASSERT(!IsRemoteFrame(),
    2590             :              "Shouldn't call CheckForRecursiveLoad on remote frames.");
    2591             : 
    2592           4 :   mDepthTooGreat = false;
    2593           4 :   rv = MaybeCreateDocShell();
    2594           4 :   if (NS_FAILED(rv)) {
    2595           0 :     return rv;
    2596             :   }
    2597           4 :   NS_ASSERTION(mDocShell,
    2598             :                "MaybeCreateDocShell succeeded, but null mDocShell");
    2599           4 :   if (!mDocShell) {
    2600           0 :     return NS_ERROR_FAILURE;
    2601             :   }
    2602             : 
    2603             :   // Check that we're still in the docshell tree.
    2604           8 :   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
    2605           4 :   mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
    2606           4 :   NS_WARNING_ASSERTION(treeOwner,
    2607             :                        "Trying to load a new url to a docshell without owner!");
    2608           4 :   NS_ENSURE_STATE(treeOwner);
    2609             : 
    2610           4 :   if (mDocShell->ItemType() != nsIDocShellTreeItem::typeContent) {
    2611             :     // No need to do recursion-protection here XXXbz why not??  Do we really
    2612             :     // trust people not to screw up with non-content docshells?
    2613           2 :     return NS_OK;
    2614             :   }
    2615             : 
    2616             :   // Bug 8065: Don't exceed some maximum depth in content frames
    2617             :   // (MAX_DEPTH_CONTENT_FRAMES)
    2618           4 :   nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
    2619           2 :   mDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem));
    2620           2 :   int32_t depth = 0;
    2621           2 :   while (parentAsItem) {
    2622           0 :     ++depth;
    2623             : 
    2624           0 :     if (depth >= MAX_DEPTH_CONTENT_FRAMES) {
    2625           0 :       mDepthTooGreat = true;
    2626           0 :       NS_WARNING("Too many nested content frames so giving up");
    2627             : 
    2628           0 :       return NS_ERROR_UNEXPECTED; // Too deep, give up!  (silently?)
    2629             :     }
    2630             : 
    2631           0 :     nsCOMPtr<nsIDocShellTreeItem> temp;
    2632           0 :     temp.swap(parentAsItem);
    2633           0 :     temp->GetSameTypeParent(getter_AddRefs(parentAsItem));
    2634             :   }
    2635             : 
    2636             :   // Bug 136580: Check for recursive frame loading excluding about:srcdoc URIs.
    2637             :   // srcdoc URIs require their contents to be specified inline, so it isn't
    2638             :   // possible for undesirable recursion to occur without the aid of a
    2639             :   // non-srcdoc URI,  which this method will block normally.
    2640             :   // Besides, URI is not enough to guarantee uniqueness of srcdoc documents.
    2641           4 :   nsAutoCString buffer;
    2642           2 :   rv = aURI->GetScheme(buffer);
    2643           2 :   if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("about")) {
    2644           2 :     rv = aURI->GetPath(buffer);
    2645           2 :     if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("srcdoc")) {
    2646             :       // Duplicates allowed up to depth limits
    2647           0 :       return NS_OK;
    2648             :     }
    2649             :   }
    2650           2 :   int32_t matchCount = 0;
    2651           2 :   mDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem));
    2652           2 :   while (parentAsItem) {
    2653             :     // Check the parent URI with the URI we're loading
    2654           0 :     nsCOMPtr<nsIWebNavigation> parentAsNav(do_QueryInterface(parentAsItem));
    2655           0 :     if (parentAsNav) {
    2656             :       // Does the URI match the one we're about to load?
    2657           0 :       nsCOMPtr<nsIURI> parentURI;
    2658           0 :       parentAsNav->GetCurrentURI(getter_AddRefs(parentURI));
    2659           0 :       if (parentURI) {
    2660             :         // Bug 98158/193011: We need to ignore data after the #
    2661             :         bool equal;
    2662           0 :         rv = aURI->EqualsExceptRef(parentURI, &equal);
    2663           0 :         NS_ENSURE_SUCCESS(rv, rv);
    2664             : 
    2665           0 :         if (equal) {
    2666           0 :           matchCount++;
    2667           0 :           if (matchCount >= MAX_SAME_URL_CONTENT_FRAMES) {
    2668           0 :             NS_WARNING("Too many nested content frames have the same url (recursion?) so giving up");
    2669           0 :             return NS_ERROR_UNEXPECTED;
    2670             :           }
    2671             :         }
    2672             :       }
    2673             :     }
    2674           0 :     nsCOMPtr<nsIDocShellTreeItem> temp;
    2675           0 :     temp.swap(parentAsItem);
    2676           0 :     temp->GetSameTypeParent(getter_AddRefs(parentAsItem));
    2677             :   }
    2678             : 
    2679           2 :   return NS_OK;
    2680             : }
    2681             : 
    2682             : nsresult
    2683           9 : nsFrameLoader::GetWindowDimensions(nsIntRect& aRect)
    2684             : {
    2685             :   // Need to get outer window position here
    2686           9 :   nsIDocument* doc = mOwnerContent->GetComposedDoc();
    2687           9 :   if (!doc) {
    2688           0 :     return NS_ERROR_FAILURE;
    2689             :   }
    2690             : 
    2691           9 :   MOZ_RELEASE_ASSERT(!doc->IsResourceDoc(), "We shouldn't even exist");
    2692             : 
    2693          18 :   nsCOMPtr<nsPIDOMWindowOuter> win = doc->GetWindow();
    2694           9 :   if (!win) {
    2695           0 :     return NS_ERROR_FAILURE;
    2696             :   }
    2697             : 
    2698          18 :   nsCOMPtr<nsIDocShellTreeItem> parentAsItem(win->GetDocShell());
    2699           9 :   if (!parentAsItem) {
    2700           0 :     return NS_ERROR_FAILURE;
    2701             :   }
    2702             : 
    2703          18 :   nsCOMPtr<nsIDocShellTreeOwner> parentOwner;
    2704          18 :   if (NS_FAILED(parentAsItem->GetTreeOwner(getter_AddRefs(parentOwner))) ||
    2705           9 :       !parentOwner) {
    2706           0 :     return NS_ERROR_FAILURE;
    2707             :   }
    2708             : 
    2709          18 :   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_GetInterface(parentOwner));
    2710           9 :   treeOwnerAsWin->GetPosition(&aRect.x, &aRect.y);
    2711           9 :   treeOwnerAsWin->GetSize(&aRect.width, &aRect.height);
    2712           9 :   return NS_OK;
    2713             : }
    2714             : 
    2715             : NS_IMETHODIMP
    2716           3 : nsFrameLoader::UpdatePositionAndSize(nsSubDocumentFrame *aIFrame)
    2717             : {
    2718           3 :   if (IsRemoteFrame()) {
    2719           3 :     if (mRemoteBrowser) {
    2720           3 :       ScreenIntSize size = aIFrame->GetSubdocumentSize();
    2721           3 :       nsIntRect dimensions;
    2722           3 :       NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), NS_ERROR_FAILURE);
    2723           3 :       mLazySize = size;
    2724           3 :       mRemoteBrowser->UpdateDimensions(dimensions, size);
    2725             :     }
    2726           3 :     return NS_OK;
    2727             :   }
    2728           0 :   UpdateBaseWindowPositionAndSize(aIFrame);
    2729           0 :   return NS_OK;
    2730             : }
    2731             : 
    2732             : void
    2733           0 : nsFrameLoader::UpdateBaseWindowPositionAndSize(nsSubDocumentFrame *aIFrame)
    2734             : {
    2735           0 :   nsCOMPtr<nsIDocShell> docShell;
    2736           0 :   GetDocShell(getter_AddRefs(docShell));
    2737           0 :   nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
    2738             : 
    2739             :   // resize the sub document
    2740           0 :   if (baseWindow) {
    2741           0 :     int32_t x = 0;
    2742           0 :     int32_t y = 0;
    2743             : 
    2744           0 :     AutoWeakFrame weakFrame(aIFrame);
    2745             : 
    2746           0 :     baseWindow->GetPosition(&x, &y);
    2747             : 
    2748           0 :     if (!weakFrame.IsAlive()) {
    2749             :       // GetPosition() killed us
    2750           0 :       return;
    2751             :     }
    2752             : 
    2753           0 :     ScreenIntSize size = aIFrame->GetSubdocumentSize();
    2754           0 :     mLazySize = size;
    2755             : 
    2756           0 :     baseWindow->SetPositionAndSize(x, y, size.width, size.height,
    2757           0 :                                    nsIBaseWindow::eDelayResize);
    2758             :   }
    2759             : }
    2760             : 
    2761             : NS_IMETHODIMP
    2762           0 : nsFrameLoader::GetLazyWidth(uint32_t* aLazyWidth)
    2763             : {
    2764           0 :   *aLazyWidth = mLazySize.width;
    2765             : 
    2766           0 :   nsIFrame* frame = GetPrimaryFrameOfOwningContent();
    2767           0 :   if (frame) {
    2768           0 :     *aLazyWidth = frame->PresContext()->DevPixelsToIntCSSPixels(*aLazyWidth);
    2769             :   }
    2770             : 
    2771           0 :   return NS_OK;
    2772             : }
    2773             : 
    2774             : NS_IMETHODIMP
    2775           0 : nsFrameLoader::GetLazyHeight(uint32_t* aLazyHeight)
    2776             : {
    2777           0 :   *aLazyHeight = mLazySize.height;
    2778             : 
    2779           0 :   nsIFrame* frame = GetPrimaryFrameOfOwningContent();
    2780           0 :   if (frame) {
    2781           0 :     *aLazyHeight = frame->PresContext()->DevPixelsToIntCSSPixels(*aLazyHeight);
    2782             :   }
    2783             : 
    2784           0 :   return NS_OK;
    2785             : }
    2786             : 
    2787             : NS_IMETHODIMP
    2788           6 : nsFrameLoader::GetEventMode(uint32_t* aEventMode)
    2789             : {
    2790           6 :   *aEventMode = mEventMode;
    2791           6 :   return NS_OK;
    2792             : }
    2793             : 
    2794             : NS_IMETHODIMP
    2795           0 : nsFrameLoader::SetEventMode(uint32_t aEventMode)
    2796             : {
    2797           0 :   mEventMode = aEventMode;
    2798           0 :   return NS_OK;
    2799             : }
    2800             : 
    2801             : NS_IMETHODIMP
    2802           0 : nsFrameLoader::GetClipSubdocument(bool* aResult)
    2803             : {
    2804           0 :   *aResult = mClipSubdocument;
    2805           0 :   return NS_OK;
    2806             : }
    2807             : 
    2808             : NS_IMETHODIMP
    2809           0 : nsFrameLoader::SetClipSubdocument(bool aClip)
    2810             : {
    2811           0 :   mClipSubdocument = aClip;
    2812           0 :   nsIFrame* frame = GetPrimaryFrameOfOwningContent();
    2813           0 :   if (frame) {
    2814           0 :     frame->InvalidateFrame();
    2815           0 :     frame->PresContext()->PresShell()->
    2816           0 :       FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
    2817           0 :     nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);
    2818           0 :     if (subdocFrame) {
    2819           0 :       nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame();
    2820           0 :       if (subdocRootFrame) {
    2821             :         nsIFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()->
    2822           0 :           GetRootScrollFrame();
    2823           0 :         if (subdocRootScrollFrame) {
    2824           0 :           frame->PresContext()->PresShell()->
    2825           0 :             FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
    2826             :         }
    2827             :       }
    2828             :     }
    2829             :   }
    2830           0 :   return NS_OK;
    2831             : }
    2832             : 
    2833             : NS_IMETHODIMP
    2834           0 : nsFrameLoader::GetClampScrollPosition(bool* aResult)
    2835             : {
    2836           0 :   *aResult = mClampScrollPosition;
    2837           0 :   return NS_OK;
    2838             : }
    2839             : 
    2840             : NS_IMETHODIMP
    2841           0 : nsFrameLoader::SetClampScrollPosition(bool aClamp)
    2842             : {
    2843           0 :   mClampScrollPosition = aClamp;
    2844             : 
    2845             :   // When turning clamping on, make sure the current position is clamped.
    2846           0 :   if (aClamp) {
    2847           0 :     nsIFrame* frame = GetPrimaryFrameOfOwningContent();
    2848           0 :     nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);
    2849           0 :     if (subdocFrame) {
    2850           0 :       nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame();
    2851           0 :       if (subdocRootFrame) {
    2852             :         nsIScrollableFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()->
    2853           0 :           GetRootScrollFrameAsScrollable();
    2854           0 :         if (subdocRootScrollFrame) {
    2855           0 :           subdocRootScrollFrame->ScrollTo(subdocRootScrollFrame->GetScrollPosition(), nsIScrollableFrame::INSTANT);
    2856             :         }
    2857             :       }
    2858             :     }
    2859             :   }
    2860           0 :   return NS_OK;
    2861             : }
    2862             : 
    2863             : static
    2864             : Tuple<ContentParent*, TabParent*>
    2865           1 : GetContentParent(Element* aBrowser)
    2866             : {
    2867             :   using ReturnTuple = Tuple<ContentParent*, TabParent*>;
    2868             : 
    2869           2 :   nsCOMPtr<nsIBrowser> browser = do_QueryInterface(aBrowser);
    2870           1 :   if (!browser) {
    2871           0 :     return ReturnTuple(nullptr, nullptr);
    2872             :   }
    2873             : 
    2874           2 :   nsCOMPtr<nsIFrameLoader> otherLoader;
    2875           1 :   browser->GetSameProcessAsFrameLoader(getter_AddRefs(otherLoader));
    2876           1 :   if (!otherLoader) {
    2877           1 :     return ReturnTuple(nullptr, nullptr);
    2878             :   }
    2879             : 
    2880           0 :   TabParent* tabParent = TabParent::GetFrom(otherLoader);
    2881           0 :   if (tabParent &&
    2882           0 :       tabParent->Manager() &&
    2883           0 :       tabParent->Manager()->IsContentParent()) {
    2884           0 :     return MakeTuple(tabParent->Manager()->AsContentParent(), tabParent);
    2885             :   }
    2886             : 
    2887           0 :   return ReturnTuple(nullptr, nullptr);
    2888             : }
    2889             : 
    2890             : bool
    2891           1 : nsFrameLoader::TryRemoteBrowser()
    2892             : {
    2893           1 :   NS_ASSERTION(!mRemoteBrowser, "TryRemoteBrowser called with a remote browser already?");
    2894             : 
    2895             :   //XXXsmaug Per spec (2014/08/21) frameloader should not work in case the
    2896             :   //         element isn't in document, only in shadow dom, but that will change
    2897             :   //         https://www.w3.org/Bugs/Public/show_bug.cgi?id=26365#c0
    2898           1 :   nsIDocument* doc = mOwnerContent->GetComposedDoc();
    2899           1 :   if (!doc) {
    2900           0 :     return false;
    2901             :   }
    2902             : 
    2903           1 :   MOZ_RELEASE_ASSERT(!doc->IsResourceDoc(), "We shouldn't even exist");
    2904             : 
    2905           1 :   if (!doc->IsActive()) {
    2906             :     // Don't allow subframe loads in non-active documents.
    2907             :     // (See bug 610571 comment 5.)
    2908           0 :     return false;
    2909             :   }
    2910             : 
    2911           2 :   nsCOMPtr<nsPIDOMWindowOuter> parentWin = doc->GetWindow();
    2912           1 :   if (!parentWin) {
    2913           0 :     return false;
    2914             :   }
    2915             : 
    2916           2 :   nsCOMPtr<nsIDocShell> parentDocShell = parentWin->GetDocShell();
    2917           1 :   if (!parentDocShell) {
    2918           0 :     return false;
    2919             :   }
    2920             : 
    2921           1 :   TabParent* openingTab = TabParent::GetFrom(parentDocShell->GetOpener());
    2922           2 :   RefPtr<ContentParent> openerContentParent;
    2923           2 :   RefPtr<TabParent> sameTabGroupAs;
    2924             : 
    2925           1 :   if (openingTab &&
    2926           1 :       openingTab->Manager() &&
    2927           0 :       openingTab->Manager()->IsContentParent()) {
    2928           0 :     openerContentParent = openingTab->Manager()->AsContentParent();
    2929             :   }
    2930             : 
    2931             :   // <iframe mozbrowser> gets to skip these checks.
    2932             :   // iframes for JS plugins also get to skip these checks. We control the URL that gets
    2933             :   // loaded, but the load is triggered from the document containing the plugin.
    2934           1 :   if (!OwnerIsMozBrowserFrame() && !IsForJSPlugin()) {
    2935           1 :     if (parentDocShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
    2936             :       // Allow about:addon an exception to this rule so it can load remote
    2937             :       // extension options pages.
    2938             :       //
    2939             :       // Note that the new frame's message manager will not be a child of the
    2940             :       // chrome window message manager, and, the values of window.top and
    2941             :       // window.parent will be different than they would be for a non-remote
    2942             :       // frame.
    2943           0 :       nsCOMPtr<nsIWebNavigation> parentWebNav;
    2944           0 :       nsCOMPtr<nsIURI> aboutAddons;
    2945           0 :       nsCOMPtr<nsIURI> parentURI;
    2946             :       bool equals;
    2947           0 :       if (!((parentWebNav = do_GetInterface(parentDocShell)) &&
    2948           0 :             NS_SUCCEEDED(NS_NewURI(getter_AddRefs(aboutAddons), "about:addons")) &&
    2949           0 :             NS_SUCCEEDED(parentWebNav->GetCurrentURI(getter_AddRefs(parentURI))) &&
    2950           0 :             NS_SUCCEEDED(parentURI->EqualsExceptRef(aboutAddons, &equals)) && equals)) {
    2951           0 :         return false;
    2952             :       }
    2953             :     }
    2954             : 
    2955           1 :     if (!mOwnerContent->IsXULElement()) {
    2956           0 :       return false;
    2957             :     }
    2958             : 
    2959           2 :     nsAutoString value;
    2960           1 :     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
    2961             : 
    2962           3 :     if (!value.LowerCaseEqualsLiteral("content") &&
    2963           1 :         !StringBeginsWith(value, NS_LITERAL_STRING("content-"),
    2964           1 :                           nsCaseInsensitiveStringComparator())) {
    2965           0 :       return false;
    2966             :     }
    2967             : 
    2968             :     // Try to get the related content parent from our browser element.
    2969           1 :     Tie(openerContentParent, sameTabGroupAs) = GetContentParent(mOwnerContent);
    2970             :   }
    2971             : 
    2972           1 :   uint32_t chromeFlags = 0;
    2973           2 :   nsCOMPtr<nsIDocShellTreeOwner> parentOwner;
    2974           2 :   if (NS_FAILED(parentDocShell->GetTreeOwner(getter_AddRefs(parentOwner))) ||
    2975           1 :       !parentOwner) {
    2976           0 :     return false;
    2977             :   }
    2978           2 :   nsCOMPtr<nsIXULWindow> window(do_GetInterface(parentOwner));
    2979           1 :   if (window && NS_FAILED(window->GetChromeFlags(&chromeFlags))) {
    2980           0 :     return false;
    2981             :   }
    2982             : 
    2983           2 :   AUTO_PROFILER_LABEL("nsFrameLoader::TryRemoteBrowser:Create", OTHER);
    2984             : 
    2985           2 :   MutableTabContext context;
    2986           1 :   nsresult rv = GetNewTabContext(&context);
    2987           1 :   NS_ENSURE_SUCCESS(rv, false);
    2988             : 
    2989           1 :   uint64_t nextTabParentId = 0;
    2990           1 :   if (mOwnerContent) {
    2991           2 :     nsAutoString nextTabParentIdAttr;
    2992           1 :     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nextTabParentId,
    2993           2 :                            nextTabParentIdAttr);
    2994           1 :     nextTabParentId = strtoull(NS_ConvertUTF16toUTF8(nextTabParentIdAttr).get(),
    2995             :                                nullptr, 10);
    2996             : 
    2997             :     // We may be in a window that was just opened, so try the
    2998             :     // nsIBrowserDOMWindow API as a backup.
    2999           1 :     if (!nextTabParentId && window) {
    3000           1 :       Unused << window->GetNextTabParentId(&nextTabParentId);
    3001             :     }
    3002             :   }
    3003             : 
    3004           2 :   nsCOMPtr<Element> ownerElement = mOwnerContent;
    3005           1 :   mRemoteBrowser = ContentParent::CreateBrowser(context, ownerElement,
    3006             :                                                 openerContentParent,
    3007             :                                                 sameTabGroupAs,
    3008             :                                                 nextTabParentId);
    3009           1 :   if (!mRemoteBrowser) {
    3010           0 :     return false;
    3011             :   }
    3012             :   // Now that mRemoteBrowser is set, we can initialize the RenderFrameParent
    3013           1 :   mRemoteBrowser->InitRenderFrame();
    3014             : 
    3015           1 :   MaybeUpdatePrimaryTabParent(eTabParentChanged);
    3016             : 
    3017           1 :   mChildID = mRemoteBrowser->Manager()->ChildID();
    3018             : 
    3019           2 :   nsCOMPtr<nsIDocShellTreeItem> rootItem;
    3020           1 :   parentDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
    3021           2 :   nsCOMPtr<nsPIDOMWindowOuter> rootWin = rootItem->GetWindow();
    3022           2 :   nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin);
    3023             : 
    3024           1 :   if (rootChromeWin) {
    3025           2 :     nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
    3026           1 :     rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
    3027           1 :     mRemoteBrowser->SetBrowserDOMWindow(browserDOMWin);
    3028             :   }
    3029             : 
    3030             :   // Send down the name of the browser through mRemoteBrowser if it is set.
    3031             :   // Only do this on xul:browsers for now.
    3032           1 :   if (mOwnerContent->IsXULElement()) {
    3033           2 :     nsAutoString frameName;
    3034           1 :     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, frameName);
    3035           1 :     if (nsContentUtils::IsOverridingWindowName(frameName)) {
    3036           0 :       Unused << mRemoteBrowser->SendSetWindowName(frameName);
    3037             :     }
    3038             :   }
    3039             : 
    3040           1 :   ReallyLoadFrameScripts();
    3041           1 :   InitializeBrowserAPI();
    3042             : 
    3043           1 :  return true;
    3044             : }
    3045             : 
    3046             : mozilla::dom::PBrowserParent*
    3047          47 : nsFrameLoader::GetRemoteBrowser() const
    3048             : {
    3049          47 :   return mRemoteBrowser;
    3050             : }
    3051             : 
    3052             : RenderFrameParent*
    3053          35 : nsFrameLoader::GetCurrentRenderFrame() const
    3054             : {
    3055          35 :   if (mRemoteBrowser) {
    3056          34 :     return mRemoteBrowser->GetRenderFrame();
    3057             :   }
    3058           1 :   return nullptr;
    3059             : }
    3060             : 
    3061             : NS_IMETHODIMP
    3062           0 : nsFrameLoader::ActivateRemoteFrame() {
    3063           0 :   if (mRemoteBrowser) {
    3064           0 :     mRemoteBrowser->Activate();
    3065           0 :     return NS_OK;
    3066             :   }
    3067           0 :   return NS_ERROR_UNEXPECTED;
    3068             : }
    3069             : 
    3070             : NS_IMETHODIMP
    3071           0 : nsFrameLoader::DeactivateRemoteFrame() {
    3072           0 :   if (mRemoteBrowser) {
    3073           0 :     mRemoteBrowser->Deactivate();
    3074           0 :     return NS_OK;
    3075             :   }
    3076           0 :   return NS_ERROR_UNEXPECTED;
    3077             : }
    3078             : 
    3079             : NS_IMETHODIMP
    3080           0 : nsFrameLoader::SendCrossProcessMouseEvent(const nsAString& aType,
    3081             :                                           float aX,
    3082             :                                           float aY,
    3083             :                                           int32_t aButton,
    3084             :                                           int32_t aClickCount,
    3085             :                                           int32_t aModifiers,
    3086             :                                           bool aIgnoreRootScrollFrame)
    3087             : {
    3088           0 :   if (mRemoteBrowser) {
    3089           0 :     mRemoteBrowser->SendMouseEvent(aType, aX, aY, aButton,
    3090             :                                    aClickCount, aModifiers,
    3091           0 :                                    aIgnoreRootScrollFrame);
    3092           0 :     return NS_OK;
    3093             :   }
    3094           0 :   return NS_ERROR_FAILURE;
    3095             : }
    3096             : 
    3097             : NS_IMETHODIMP
    3098           0 : nsFrameLoader::ActivateFrameEvent(const nsAString& aType,
    3099             :                                   bool aCapture)
    3100             : {
    3101           0 :   if (mRemoteBrowser) {
    3102           0 :     return mRemoteBrowser->SendActivateFrameEvent(nsString(aType), aCapture) ?
    3103           0 :       NS_OK : NS_ERROR_NOT_AVAILABLE;
    3104             :   }
    3105           0 :   return NS_ERROR_FAILURE;
    3106             : }
    3107             : 
    3108             : NS_IMETHODIMP
    3109           0 : nsFrameLoader::SendCrossProcessKeyEvent(const nsAString& aType,
    3110             :                                         int32_t aKeyCode,
    3111             :                                         int32_t aCharCode,
    3112             :                                         int32_t aModifiers,
    3113             :                                         bool aPreventDefault)
    3114             : {
    3115           0 :   if (mRemoteBrowser) {
    3116           0 :     mRemoteBrowser->SendKeyEvent(aType, aKeyCode, aCharCode, aModifiers,
    3117           0 :                                  aPreventDefault);
    3118           0 :     return NS_OK;
    3119             :   }
    3120           0 :   return NS_ERROR_FAILURE;
    3121             : }
    3122             : 
    3123             : nsresult
    3124           0 : nsFrameLoader::CreateStaticClone(nsIFrameLoader* aDest)
    3125             : {
    3126           0 :   nsFrameLoader* dest = static_cast<nsFrameLoader*>(aDest);
    3127           0 :   dest->MaybeCreateDocShell();
    3128           0 :   NS_ENSURE_STATE(dest->mDocShell);
    3129             : 
    3130           0 :   nsCOMPtr<nsIDocument> kungFuDeathGrip = dest->mDocShell->GetDocument();
    3131             :   Unused << kungFuDeathGrip;
    3132             : 
    3133           0 :   nsCOMPtr<nsIContentViewer> viewer;
    3134           0 :   dest->mDocShell->GetContentViewer(getter_AddRefs(viewer));
    3135           0 :   NS_ENSURE_STATE(viewer);
    3136             : 
    3137           0 :   nsCOMPtr<nsIDocShell> origDocShell;
    3138           0 :   GetDocShell(getter_AddRefs(origDocShell));
    3139           0 :   NS_ENSURE_STATE(origDocShell);
    3140             : 
    3141           0 :   nsCOMPtr<nsIDocument> doc = origDocShell->GetDocument();
    3142           0 :   NS_ENSURE_STATE(doc);
    3143             : 
    3144           0 :   nsCOMPtr<nsIDocument> clonedDoc = doc->CreateStaticClone(dest->mDocShell);
    3145           0 :   nsCOMPtr<nsIDOMDocument> clonedDOMDoc = do_QueryInterface(clonedDoc);
    3146             : 
    3147           0 :   viewer->SetDOMDocument(clonedDOMDoc);
    3148           0 :   return NS_OK;
    3149             : }
    3150             : 
    3151             : bool
    3152          18 : nsFrameLoader::DoLoadMessageManagerScript(const nsAString& aURL, bool aRunInGlobalScope)
    3153             : {
    3154          18 :   auto* tabParent = TabParent::GetFrom(GetRemoteBrowser());
    3155          18 :   if (tabParent) {
    3156          12 :     return tabParent->SendLoadRemoteScript(nsString(aURL), aRunInGlobalScope);
    3157             :   }
    3158             :   RefPtr<nsInProcessTabChildGlobal> tabChild =
    3159          12 :     static_cast<nsInProcessTabChildGlobal*>(GetTabChildGlobalAsEventTarget());
    3160           6 :   if (tabChild) {
    3161           6 :     tabChild->LoadFrameScript(aURL, aRunInGlobalScope);
    3162             :   }
    3163           6 :   return true;
    3164             : }
    3165             : 
    3166           0 : class nsAsyncMessageToChild : public nsSameProcessAsyncMessageBase,
    3167             :                               public Runnable
    3168             : {
    3169             : public:
    3170           0 :   nsAsyncMessageToChild(JS::RootingContext* aRootingCx,
    3171             :                         JS::Handle<JSObject*> aCpows,
    3172             :                         nsFrameLoader* aFrameLoader)
    3173           0 :     : nsSameProcessAsyncMessageBase(aRootingCx, aCpows)
    3174             :     , mozilla::Runnable("nsAsyncMessageToChild")
    3175           0 :     , mFrameLoader(aFrameLoader)
    3176             :   {
    3177           0 :   }
    3178             : 
    3179           0 :   NS_IMETHOD Run() override
    3180             :   {
    3181             :     nsInProcessTabChildGlobal* tabChild =
    3182           0 :       static_cast<nsInProcessTabChildGlobal*>(mFrameLoader->mChildMessageManager.get());
    3183             :     // Since bug 1126089, messages can arrive even when the docShell is destroyed.
    3184             :     // Here we make sure that those messages are not delivered.
    3185           0 :     if (tabChild && tabChild->GetInnerManager() && mFrameLoader->GetExistingDocShell()) {
    3186           0 :       JS::Rooted<JSObject*> kungFuDeathGrip(dom::RootingCx(), tabChild->GetGlobal());
    3187           0 :       ReceiveMessage(static_cast<EventTarget*>(tabChild), mFrameLoader,
    3188           0 :                      tabChild->GetInnerManager());
    3189             :     }
    3190           0 :     return NS_OK;
    3191             :   }
    3192             :   RefPtr<nsFrameLoader> mFrameLoader;
    3193             : };
    3194             : 
    3195             : nsresult
    3196           8 : nsFrameLoader::DoSendAsyncMessage(JSContext* aCx,
    3197             :                                   const nsAString& aMessage,
    3198             :                                   StructuredCloneData& aData,
    3199             :                                   JS::Handle<JSObject *> aCpows,
    3200             :                                   nsIPrincipal* aPrincipal)
    3201             : {
    3202           8 :   TabParent* tabParent = mRemoteBrowser;
    3203           8 :   if (tabParent) {
    3204          16 :     ClonedMessageData data;
    3205           8 :     nsIContentParent* cp = tabParent->Manager();
    3206           8 :     if (!BuildClonedMessageDataForParent(cp, aData, data)) {
    3207           0 :       MOZ_CRASH();
    3208             :       return NS_ERROR_DOM_DATA_CLONE_ERR;
    3209             :     }
    3210          16 :     InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
    3211           8 :     jsipc::CPOWManager* mgr = cp->GetCPOWManager();
    3212           8 :     if (aCpows && (!mgr || !mgr->Wrap(aCx, aCpows, &cpows))) {
    3213           0 :       return NS_ERROR_UNEXPECTED;
    3214             :     }
    3215          16 :     if (tabParent->SendAsyncMessage(nsString(aMessage), cpows,
    3216          16 :                                     IPC::Principal(aPrincipal), data)) {
    3217           8 :       return NS_OK;
    3218             :     } else {
    3219           0 :       return NS_ERROR_UNEXPECTED;
    3220             :     }
    3221             :   }
    3222             : 
    3223           0 :   if (mChildMessageManager) {
    3224           0 :     JS::RootingContext* rcx = JS::RootingContext::get(aCx);
    3225           0 :     RefPtr<nsAsyncMessageToChild> ev = new nsAsyncMessageToChild(rcx, aCpows, this);
    3226           0 :     nsresult rv = ev->Init(aMessage, aData, aPrincipal);
    3227           0 :     if (NS_FAILED(rv)) {
    3228           0 :       return rv;
    3229             :     }
    3230           0 :     rv = NS_DispatchToCurrentThread(ev);
    3231           0 :     if (NS_FAILED(rv)) {
    3232           0 :       return rv;
    3233             :     }
    3234           0 :     return rv;
    3235             :   }
    3236             : 
    3237             :   // We don't have any targets to send our asynchronous message to.
    3238           0 :   return NS_ERROR_UNEXPECTED;
    3239             : }
    3240             : 
    3241             : NS_IMETHODIMP
    3242          44 : nsFrameLoader::GetMessageManager(nsIMessageSender** aManager)
    3243             : {
    3244          44 :   EnsureMessageManager();
    3245          44 :   if (mMessageManager) {
    3246          88 :     RefPtr<nsFrameMessageManager> mm(mMessageManager);
    3247          44 :     mm.forget(aManager);
    3248          44 :     return NS_OK;
    3249             :   }
    3250           0 :   return NS_OK;
    3251             : }
    3252             : 
    3253             : nsresult
    3254          47 : nsFrameLoader::EnsureMessageManager()
    3255             : {
    3256          47 :   NS_ENSURE_STATE(mOwnerContent);
    3257             : 
    3258          47 :   if (mMessageManager) {
    3259          44 :     return NS_OK;
    3260             :   }
    3261             : 
    3262           8 :   if (!mIsTopLevelContent &&
    3263           4 :       !OwnerIsMozBrowserFrame() &&
    3264           7 :       !IsRemoteFrame() &&
    3265           2 :       !(mOwnerContent->IsXULElement() &&
    3266           1 :         mOwnerContent->AttrValueIs(kNameSpaceID_None,
    3267             :                                    nsGkAtoms::forcemessagemanager,
    3268             :                                    nsGkAtoms::_true, eCaseMatters))) {
    3269           1 :     return NS_OK;
    3270             :   }
    3271             : 
    3272             :   nsCOMPtr<nsIDOMChromeWindow> chromeWindow =
    3273           4 :     do_QueryInterface(GetOwnerDoc()->GetWindow());
    3274           4 :   nsCOMPtr<nsIMessageBroadcaster> parentManager;
    3275             : 
    3276           2 :   if (chromeWindow) {
    3277           4 :     nsAutoString messagemanagergroup;
    3278           4 :     if (mOwnerContent->IsXULElement() &&
    3279           2 :         mOwnerContent->GetAttr(kNameSpaceID_None,
    3280             :                                nsGkAtoms::messagemanagergroup,
    3281             :                                messagemanagergroup)) {
    3282           2 :       chromeWindow->GetGroupMessageManager(messagemanagergroup, getter_AddRefs(parentManager));
    3283             :     }
    3284             : 
    3285           2 :     if (!parentManager) {
    3286           0 :       chromeWindow->GetMessageManager(getter_AddRefs(parentManager));
    3287             :     }
    3288             :   } else {
    3289           0 :     parentManager = do_GetService("@mozilla.org/globalmessagemanager;1");
    3290             :   }
    3291             : 
    3292             :   mMessageManager = new nsFrameMessageManager(nullptr,
    3293           2 :                                               static_cast<nsFrameMessageManager*>(parentManager.get()),
    3294           2 :                                               MM_CHROME);
    3295           2 :   if (!IsRemoteFrame()) {
    3296           1 :     nsresult rv = MaybeCreateDocShell();
    3297           1 :     if (NS_FAILED(rv)) {
    3298           0 :       return rv;
    3299             :     }
    3300           1 :     NS_ASSERTION(mDocShell,
    3301             :                  "MaybeCreateDocShell succeeded, but null mDocShell");
    3302           1 :     if (!mDocShell) {
    3303           0 :       return NS_ERROR_FAILURE;
    3304             :     }
    3305             :     mChildMessageManager =
    3306           2 :       new nsInProcessTabChildGlobal(mDocShell, mOwnerContent, mMessageManager);
    3307             :   }
    3308           2 :   return NS_OK;
    3309             : }
    3310             : 
    3311             : nsresult
    3312           3 : nsFrameLoader::ReallyLoadFrameScripts()
    3313             : {
    3314           3 :   nsresult rv = EnsureMessageManager();
    3315           3 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3316           0 :     return rv;
    3317             :   }
    3318           3 :   if (mMessageManager) {
    3319           2 :     mMessageManager->InitWithCallback(this);
    3320             :   }
    3321           3 :   return NS_OK;
    3322             : }
    3323             : 
    3324             : EventTarget*
    3325          14 : nsFrameLoader::GetTabChildGlobalAsEventTarget()
    3326             : {
    3327          14 :   return static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get());
    3328             : }
    3329             : 
    3330             : NS_IMETHODIMP
    3331           0 : nsFrameLoader::GetOwnerElement(nsIDOMElement **aElement)
    3332             : {
    3333           0 :   nsCOMPtr<nsIDOMElement> ownerElement = do_QueryInterface(mOwnerContent);
    3334           0 :   ownerElement.forget(aElement);
    3335           0 :   return NS_OK;
    3336             : }
    3337             : 
    3338             : NS_IMETHODIMP
    3339           0 : nsFrameLoader::GetChildID(uint64_t* aChildID)
    3340             : {
    3341           0 :   *aChildID = mChildID;
    3342           0 :   return NS_OK;
    3343             : }
    3344             : 
    3345             : void
    3346           0 : nsFrameLoader::SetRemoteBrowser(nsITabParent* aTabParent)
    3347             : {
    3348           0 :   MOZ_ASSERT(!mRemoteBrowser);
    3349           0 :   mRemoteFrame = true;
    3350           0 :   mRemoteBrowser = TabParent::GetFrom(aTabParent);
    3351           0 :   mChildID = mRemoteBrowser ? mRemoteBrowser->Manager()->ChildID() : 0;
    3352           0 :   MaybeUpdatePrimaryTabParent(eTabParentChanged);
    3353           0 :   ReallyLoadFrameScripts();
    3354           0 :   InitializeBrowserAPI();
    3355           0 :   ShowRemoteFrame(ScreenIntSize(0, 0));
    3356           0 : }
    3357             : 
    3358             : void
    3359           5 : nsFrameLoader::SetDetachedSubdocFrame(nsIFrame* aDetachedFrame,
    3360             :                                       nsIDocument* aContainerDoc)
    3361             : {
    3362           5 :   mDetachedSubdocFrame = aDetachedFrame;
    3363           5 :   mContainerDocWhileDetached = aContainerDoc;
    3364           5 : }
    3365             : 
    3366             : nsIFrame*
    3367           6 : nsFrameLoader::GetDetachedSubdocFrame(nsIDocument** aContainerDoc) const
    3368             : {
    3369           6 :   NS_IF_ADDREF(*aContainerDoc = mContainerDocWhileDetached);
    3370           6 :   return mDetachedSubdocFrame.GetFrame();
    3371             : }
    3372             : 
    3373             : void
    3374           2 : nsFrameLoader::ApplySandboxFlags(uint32_t sandboxFlags)
    3375             : {
    3376           2 :   if (mDocShell) {
    3377           2 :     uint32_t parentSandboxFlags = mOwnerContent->OwnerDoc()->GetSandboxFlags();
    3378             : 
    3379             :     // The child can only add restrictions, never remove them.
    3380           2 :     sandboxFlags |= parentSandboxFlags;
    3381             : 
    3382             :     // If this frame is a receiving browsing context, we should add
    3383             :     // sandboxed auxiliary navigation flag to sandboxFlags. See
    3384             :     // https://w3c.github.io/presentation-api/#creating-a-receiving-browsing-context
    3385           4 :     nsAutoString presentationURL;
    3386           2 :     nsContentUtils::GetPresentationURL(mDocShell, presentationURL);
    3387           2 :     if (!presentationURL.IsEmpty()) {
    3388           0 :       sandboxFlags |= SANDBOXED_AUXILIARY_NAVIGATION;
    3389             :     }
    3390           2 :     mDocShell->SetSandboxFlags(sandboxFlags);
    3391             :   }
    3392           2 : }
    3393             : 
    3394             : /* virtual */ void
    3395           1 : nsFrameLoader::AttributeChanged(nsIDocument* aDocument,
    3396             :                                 mozilla::dom::Element* aElement,
    3397             :                                 int32_t      aNameSpaceID,
    3398             :                                 nsIAtom*     aAttribute,
    3399             :                                 int32_t      aModType,
    3400             :                                 const nsAttrValue* aOldValue)
    3401             : {
    3402           1 :   MOZ_ASSERT(mObservingOwnerContent);
    3403             : 
    3404           3 :   if (aNameSpaceID != kNameSpaceID_None ||
    3405           2 :       (aAttribute != TypeAttrName() && aAttribute != nsGkAtoms::primary)) {
    3406           2 :     return;
    3407             :   }
    3408             : 
    3409           0 :   if (aElement != mOwnerContent) {
    3410           0 :     return;
    3411             :   }
    3412             : 
    3413             :   // Note: This logic duplicates a lot of logic in
    3414             :   // MaybeCreateDocshell.  We should fix that.
    3415             : 
    3416             :   // Notify our enclosing chrome that our type has changed.  We only do this
    3417             :   // if our parent is chrome, since in all other cases we're random content
    3418             :   // subframes and the treeowner shouldn't worry about us.
    3419           0 :   if (!mDocShell) {
    3420           0 :     MaybeUpdatePrimaryTabParent(eTabParentChanged);
    3421           0 :     return;
    3422             :   }
    3423             : 
    3424           0 :   nsCOMPtr<nsIDocShellTreeItem> parentItem;
    3425           0 :   mDocShell->GetParent(getter_AddRefs(parentItem));
    3426           0 :   if (!parentItem) {
    3427           0 :     return;
    3428             :   }
    3429             : 
    3430           0 :   if (parentItem->ItemType() != nsIDocShellTreeItem::typeChrome) {
    3431           0 :     return;
    3432             :   }
    3433             : 
    3434           0 :   nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
    3435           0 :   parentItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
    3436           0 :   if (!parentTreeOwner) {
    3437           0 :     return;
    3438             :   }
    3439             : 
    3440             :   bool is_primary =
    3441           0 :     aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary, nsGkAtoms::_true, eIgnoreCase);
    3442             : 
    3443             : #ifdef MOZ_XUL
    3444             :   // when a content panel is no longer primary, hide any open popups it may have
    3445           0 :   if (!is_primary) {
    3446           0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
    3447           0 :     if (pm)
    3448           0 :       pm->HidePopupsInDocShell(mDocShell);
    3449             :   }
    3450             : #endif
    3451             : 
    3452           0 :   parentTreeOwner->ContentShellRemoved(mDocShell);
    3453             : 
    3454           0 :   nsAutoString value;
    3455           0 :   aElement->GetAttr(kNameSpaceID_None, TypeAttrName(), value);
    3456             : 
    3457           0 :   if (value.LowerCaseEqualsLiteral("content") ||
    3458           0 :       StringBeginsWith(value, NS_LITERAL_STRING("content-"),
    3459           0 :                        nsCaseInsensitiveStringComparator())) {
    3460           0 :     parentTreeOwner->ContentShellAdded(mDocShell, is_primary);
    3461             :   }
    3462             : }
    3463             : 
    3464             : /**
    3465             :  * Send the RequestNotifyAfterRemotePaint message to the current Tab.
    3466             :  */
    3467             : NS_IMETHODIMP
    3468           0 : nsFrameLoader::RequestNotifyAfterRemotePaint()
    3469             : {
    3470             :   // If remote browsing (e10s), handle this with the TabParent.
    3471           0 :   if (mRemoteBrowser) {
    3472           0 :     Unused << mRemoteBrowser->SendRequestNotifyAfterRemotePaint();
    3473             :   }
    3474             : 
    3475           0 :   return NS_OK;
    3476             : }
    3477             : 
    3478             : NS_IMETHODIMP
    3479           0 : nsFrameLoader::RequestFrameLoaderClose()
    3480             : {
    3481           0 :   nsCOMPtr<nsIBrowser> browser = do_QueryInterface(mOwnerContent);
    3482           0 :   if (NS_WARN_IF(!browser)) {
    3483             :     // OwnerElement other than nsIBrowser is not supported yet.
    3484           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    3485             :   }
    3486             : 
    3487           0 :   return browser->CloseBrowser();
    3488             : }
    3489             : 
    3490             : NS_IMETHODIMP
    3491           0 : nsFrameLoader::Print(uint64_t aOuterWindowID,
    3492             :                      nsIPrintSettings* aPrintSettings,
    3493             :                      nsIWebProgressListener* aProgressListener)
    3494             : {
    3495             : #if defined(NS_PRINTING)
    3496           0 :   if (mRemoteBrowser) {
    3497             :     RefPtr<embedding::PrintingParent> printingParent =
    3498           0 :       mRemoteBrowser->Manager()->AsContentParent()->GetPrintingParent();
    3499             : 
    3500           0 :     embedding::PrintData printData;
    3501           0 :     nsresult rv = printingParent->SerializeAndEnsureRemotePrintJob(
    3502           0 :       aPrintSettings, aProgressListener, nullptr, &printData);
    3503           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    3504           0 :       return rv;
    3505             :     }
    3506             : 
    3507           0 :     bool success = mRemoteBrowser->SendPrint(aOuterWindowID, printData);
    3508           0 :     return success ? NS_OK : NS_ERROR_FAILURE;
    3509             :   }
    3510             : 
    3511             :   nsGlobalWindow* outerWindow =
    3512           0 :     nsGlobalWindow::GetOuterWindowWithId(aOuterWindowID);
    3513           0 :   if (NS_WARN_IF(!outerWindow)) {
    3514           0 :     return NS_ERROR_FAILURE;
    3515             :   }
    3516             : 
    3517             :   nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint =
    3518           0 :     do_GetInterface(outerWindow->AsOuter());
    3519           0 :   if (NS_WARN_IF(!webBrowserPrint)) {
    3520           0 :     return NS_ERROR_FAILURE;
    3521             :   }
    3522             : 
    3523           0 :   return webBrowserPrint->Print(aPrintSettings, aProgressListener);
    3524             : #endif
    3525             :   return NS_OK;
    3526             : }
    3527             : 
    3528             : NS_IMETHODIMP
    3529           5 : nsFrameLoader::GetTabParent(nsITabParent** aTabParent)
    3530             : {
    3531          10 :   nsCOMPtr<nsITabParent> tp = mRemoteBrowser;
    3532           5 :   tp.forget(aTabParent);
    3533          10 :   return NS_OK;
    3534             : }
    3535             : 
    3536             : NS_IMETHODIMP
    3537           1 : nsFrameLoader::GetLoadContext(nsILoadContext** aLoadContext)
    3538             : {
    3539           2 :   nsCOMPtr<nsILoadContext> loadContext;
    3540           3 :   if (IsRemoteFrame() &&
    3541           1 :       (mRemoteBrowser || TryRemoteBrowser())) {
    3542           1 :     loadContext = mRemoteBrowser->GetLoadContext();
    3543             :   } else {
    3544           0 :     nsCOMPtr<nsIDocShell> docShell;
    3545           0 :     GetDocShell(getter_AddRefs(docShell));
    3546           0 :     loadContext = do_GetInterface(docShell);
    3547             :   }
    3548           1 :   loadContext.forget(aLoadContext);
    3549           2 :   return NS_OK;
    3550             : }
    3551             : 
    3552             : void
    3553           3 : nsFrameLoader::InitializeBrowserAPI()
    3554             : {
    3555           3 :   if (!OwnerIsMozBrowserFrame()) {
    3556           6 :     return;
    3557             :   }
    3558           0 :   if (!IsRemoteFrame()) {
    3559           0 :     nsresult rv = EnsureMessageManager();
    3560           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    3561           0 :       return;
    3562             :     }
    3563           0 :     if (mMessageManager) {
    3564           0 :       mMessageManager->LoadFrameScript(
    3565           0 :         NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js"),
    3566             :         /* allowDelayedLoad = */ true,
    3567           0 :         /* aRunInGlobalScope */ true);
    3568             :     }
    3569             :   }
    3570           0 :   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
    3571           0 :   if (browserFrame) {
    3572           0 :     browserFrame->InitializeBrowserAPI();
    3573             :   }
    3574             : }
    3575             : 
    3576             : void
    3577           0 : nsFrameLoader::DestroyBrowserFrameScripts()
    3578             : {
    3579           0 :   if (!OwnerIsMozBrowserFrame()) {
    3580           0 :     return;
    3581             :   }
    3582           0 :   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
    3583           0 :   if (browserFrame) {
    3584           0 :     browserFrame->DestroyBrowserFrameScripts();
    3585             :   }
    3586             : }
    3587             : 
    3588             : NS_IMETHODIMP
    3589           0 : nsFrameLoader::StartPersistence(uint64_t aOuterWindowID,
    3590             :                                 nsIWebBrowserPersistDocumentReceiver* aRecv)
    3591             : {
    3592           0 :   if (!aRecv) {
    3593           0 :     return NS_ERROR_INVALID_POINTER;
    3594             :   }
    3595             : 
    3596           0 :   if (mRemoteBrowser) {
    3597           0 :     return mRemoteBrowser->StartPersistence(aOuterWindowID, aRecv);
    3598             :   }
    3599             : 
    3600             :   nsCOMPtr<nsIDocument> rootDoc =
    3601           0 :     mDocShell ? mDocShell->GetDocument() : nullptr;
    3602           0 :   nsCOMPtr<nsIDocument> foundDoc;
    3603           0 :   if (aOuterWindowID) {
    3604           0 :     foundDoc = nsContentUtils::GetSubdocumentWithOuterWindowId(rootDoc, aOuterWindowID);
    3605             :   } else {
    3606           0 :     foundDoc = rootDoc;
    3607             :   }
    3608             : 
    3609           0 :   if (!foundDoc) {
    3610           0 :     aRecv->OnError(NS_ERROR_NO_CONTENT);
    3611             :   } else {
    3612             :     nsCOMPtr<nsIWebBrowserPersistDocument> pdoc =
    3613           0 :       new mozilla::WebBrowserPersistLocalDocument(foundDoc);
    3614           0 :     aRecv->OnDocumentReady(pdoc);
    3615             :   }
    3616           0 :   return NS_OK;
    3617             : }
    3618             : 
    3619             : void
    3620           2 : nsFrameLoader::MaybeUpdatePrimaryTabParent(TabParentChange aChange)
    3621             : {
    3622           2 :   if (mRemoteBrowser && mOwnerContent) {
    3623           2 :     nsCOMPtr<nsIDocShell> docShell = mOwnerContent->OwnerDoc()->GetDocShell();
    3624           1 :     if (!docShell) {
    3625           0 :       return;
    3626             :     }
    3627             : 
    3628           1 :     int32_t parentType = docShell->ItemType();
    3629           1 :     if (parentType != nsIDocShellTreeItem::typeChrome) {
    3630           0 :       return;
    3631             :     }
    3632             : 
    3633           2 :     nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
    3634           1 :     docShell->GetTreeOwner(getter_AddRefs(parentTreeOwner));
    3635           1 :     if (!parentTreeOwner) {
    3636           0 :       return;
    3637             :     }
    3638             : 
    3639           1 :     if (!mObservingOwnerContent) {
    3640           1 :       mOwnerContent->AddMutationObserver(this);
    3641           1 :       mObservingOwnerContent = true;
    3642             :     }
    3643             : 
    3644           1 :     parentTreeOwner->TabParentRemoved(mRemoteBrowser);
    3645           1 :     if (aChange == eTabParentChanged) {
    3646             :       bool isPrimary =
    3647           1 :         mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary,
    3648           1 :                                    nsGkAtoms::_true, eIgnoreCase);
    3649           1 :       parentTreeOwner->TabParentAdded(mRemoteBrowser, isPrimary);
    3650             :     }
    3651             :   }
    3652             : }
    3653             : 
    3654             : nsresult
    3655           1 : nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext,
    3656             :                                 nsIURI* aURI)
    3657             : {
    3658           1 :   if (IsForJSPlugin()) {
    3659           0 :     return aTabContext->SetTabContextForJSPluginFrame(mJSPluginID) ? NS_OK :
    3660           0 :            NS_ERROR_FAILURE;
    3661             :   }
    3662             : 
    3663           2 :   OriginAttributes attrs;
    3664           1 :   attrs.mInIsolatedMozBrowser = OwnerIsIsolatedMozBrowserFrame();
    3665             :   nsresult rv;
    3666             : 
    3667           1 :   attrs.mAppId = nsIScriptSecurityManager::NO_APP_ID;
    3668             : 
    3669             :   // set the userContextId on the attrs before we pass them into
    3670             :   // the tab context
    3671           1 :   rv = PopulateUserContextIdFromAttribute(attrs);
    3672           1 :   NS_ENSURE_SUCCESS(rv, rv);
    3673             : 
    3674           2 :   nsAutoString presentationURLStr;
    3675           1 :   mOwnerContent->GetAttr(kNameSpaceID_None,
    3676             :                          nsGkAtoms::mozpresentation,
    3677           2 :                          presentationURLStr);
    3678             : 
    3679           2 :   nsCOMPtr<nsIDocShell> docShell = mOwnerContent->OwnerDoc()->GetDocShell();
    3680           2 :   nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(docShell);
    3681           1 :   NS_ENSURE_STATE(parentContext);
    3682             : 
    3683           1 :   bool isPrivate = parentContext->UsePrivateBrowsing();
    3684           1 :   attrs.SyncAttributesWithPrivateBrowsing(isPrivate);
    3685             : 
    3686           1 :   UIStateChangeType showAccelerators = UIStateChangeType_NoChange;
    3687           1 :   UIStateChangeType showFocusRings = UIStateChangeType_NoChange;
    3688           1 :   nsIDocument* doc = mOwnerContent->OwnerDoc();
    3689           1 :   if (doc) {
    3690           2 :     nsCOMPtr<nsPIWindowRoot> root = nsContentUtils::GetWindowRoot(doc);
    3691           1 :     if (root) {
    3692           1 :       showAccelerators =
    3693           1 :         root->ShowAccelerators() ? UIStateChangeType_Set : UIStateChangeType_Clear;
    3694           1 :       showFocusRings =
    3695           1 :         root->ShowFocusRings() ? UIStateChangeType_Set : UIStateChangeType_Clear;
    3696             :     }
    3697             :   }
    3698             : 
    3699             :   bool tabContextUpdated =
    3700           1 :     aTabContext->SetTabContext(OwnerIsMozBrowserFrame(),
    3701           1 :                                mIsPrerendered,
    3702             :                                showAccelerators,
    3703             :                                showFocusRings,
    3704             :                                attrs,
    3705           1 :                                presentationURLStr);
    3706           1 :   NS_ENSURE_STATE(tabContextUpdated);
    3707             : 
    3708           1 :   return NS_OK;
    3709             : }
    3710             : 
    3711             : nsresult
    3712           3 : nsFrameLoader::PopulateUserContextIdFromAttribute(OriginAttributes& aAttr)
    3713             : {
    3714           3 :   if (aAttr.mUserContextId ==
    3715             :         nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID)  {
    3716             :     // Grab the userContextId from owner if XUL
    3717           6 :     nsAutoString userContextIdStr;
    3718           3 :     int32_t namespaceID = mOwnerContent->GetNameSpaceID();
    3719           6 :     if ((namespaceID == kNameSpaceID_XUL) &&
    3720           3 :         mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::usercontextid,
    3721           3 :                                userContextIdStr) &&
    3722           0 :         !userContextIdStr.IsEmpty()) {
    3723             :       nsresult rv;
    3724           0 :       aAttr.mUserContextId = userContextIdStr.ToInteger(&rv);
    3725           0 :       NS_ENSURE_SUCCESS(rv, rv);
    3726             :     }
    3727             :   }
    3728             : 
    3729           3 :   return NS_OK;
    3730             : }
    3731             : 
    3732             : NS_IMETHODIMP
    3733           0 : nsFrameLoader::GetIsDead(bool* aIsDead)
    3734             : {
    3735           0 :   *aIsDead = mDestroyCalled;
    3736           0 :   return NS_OK;
    3737             : }
    3738             : 
    3739             : nsIMessageSender*
    3740           0 : nsFrameLoader::GetProcessMessageManager() const
    3741             : {
    3742           0 :   return mRemoteBrowser ? mRemoteBrowser->Manager()->GetMessageManager()
    3743           0 :                         : nullptr;
    3744             : };

Generated by: LCOV version 1.13