content/base/src/nsFrameLoader.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 sw=2 et tw=78: */
     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/. */
     7 /*
     8  * Class for managing loading of a subframe (creation of the docshell,
     9  * handling of loads in it, recursion-checking).
    10  */
    12 #include "base/basictypes.h"
    14 #include "prenv.h"
    16 #include "mozIApplication.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 "nsIDOMFile.h"
    27 #include "nsPIDOMWindow.h"
    28 #include "nsIWebNavigation.h"
    29 #include "nsIWebProgress.h"
    30 #include "nsIDocShell.h"
    31 #include "nsIDocShellTreeOwner.h"
    32 #include "nsIDocShellLoadInfo.h"
    33 #include "nsIDOMApplicationRegistry.h"
    34 #include "nsIBaseWindow.h"
    35 #include "nsContentUtils.h"
    36 #include "nsCxPusher.h"
    37 #include "nsIXPConnect.h"
    38 #include "nsUnicharUtils.h"
    39 #include "nsIScriptGlobalObject.h"
    40 #include "nsIScriptSecurityManager.h"
    41 #include "nsIScrollable.h"
    42 #include "nsFrameLoader.h"
    43 #include "nsIDOMEventTarget.h"
    44 #include "nsIFrame.h"
    45 #include "nsIScrollableFrame.h"
    46 #include "nsSubDocumentFrame.h"
    47 #include "nsError.h"
    48 #include "nsISHistory.h"
    49 #include "nsISHistoryInternal.h"
    50 #include "nsIDOMHTMLDocument.h"
    51 #include "nsIXULWindow.h"
    52 #include "nsIEditor.h"
    53 #include "nsIMozBrowserFrame.h"
    54 #include "nsIPermissionManager.h"
    55 #include "nsISHistory.h"
    56 #include "nsNullPrincipal.h"
    58 #include "nsLayoutUtils.h"
    59 #include "nsView.h"
    61 #include "nsIURI.h"
    62 #include "nsIURL.h"
    63 #include "nsNetUtil.h"
    65 #include "nsGkAtoms.h"
    66 #include "nsNameSpaceManager.h"
    68 #include "nsThreadUtils.h"
    70 #include "nsIDOMChromeWindow.h"
    71 #include "nsInProcessTabChildGlobal.h"
    73 #include "Layers.h"
    75 #include "AppProcessChecker.h"
    76 #include "ContentParent.h"
    77 #include "TabParent.h"
    78 #include "mozilla/AsyncEventDispatcher.h"
    79 #include "mozilla/GuardObjects.h"
    80 #include "mozilla/Preferences.h"
    81 #include "mozilla/unused.h"
    82 #include "mozilla/dom/Element.h"
    83 #include "mozilla/layout/RenderFrameParent.h"
    84 #include "nsIAppsService.h"
    85 #include "GeckoProfiler.h"
    87 #include "jsapi.h"
    88 #include "mozilla/dom/HTMLIFrameElement.h"
    89 #include "nsSandboxFlags.h"
    90 #include "JavaScriptParent.h"
    92 #include "mozilla/dom/StructuredCloneUtils.h"
    94 #ifdef MOZ_XUL
    95 #include "nsXULPopupManager.h"
    96 #endif
    98 using namespace mozilla;
    99 using namespace mozilla::hal;
   100 using namespace mozilla::dom;
   101 using namespace mozilla::dom::ipc;
   102 using namespace mozilla::layers;
   103 using namespace mozilla::layout;
   104 typedef FrameMetrics::ViewID ViewID;
   106 class nsAsyncDocShellDestroyer : public nsRunnable
   107 {
   108 public:
   109   nsAsyncDocShellDestroyer(nsIDocShell* aDocShell)
   110     : mDocShell(aDocShell)
   111   {
   112   }
   114   NS_IMETHOD Run()
   115   {
   116     nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell));
   117     if (base_win) {
   118       base_win->Destroy();
   119     }
   120     return NS_OK;
   121   }
   122   nsRefPtr<nsIDocShell> mDocShell;
   123 };
   125 NS_IMPL_ISUPPORTS(nsContentView, nsIContentView)
   127 nsresult
   128 nsContentView::Update(const ViewConfig& aConfig)
   129 {
   130   if (aConfig == mConfig) {
   131     return NS_OK;
   132   }
   133   mConfig = aConfig;
   135   // View changed.  Try to locate our subdoc frame and invalidate
   136   // it if found.
   137   if (!mFrameLoader) {
   138     if (IsRoot()) {
   139       // Oops, don't have a frame right now.  That's OK; the view
   140       // config persists and will apply to the next frame we get, if we
   141       // ever get one.
   142       return NS_OK;
   143     } else {
   144       // This view is no longer valid.
   145       return NS_ERROR_NOT_AVAILABLE;
   146     }
   147   }
   149   if (RenderFrameParent* rfp = mFrameLoader->GetCurrentRemoteFrame()) {
   150     rfp->ContentViewScaleChanged(this);
   151   }
   153   return NS_OK;
   154 }
   156 NS_IMETHODIMP
   157 nsContentView::ScrollTo(float aXpx, float aYpx)
   158 {
   159   ViewConfig config(mConfig);
   160   config.mScrollOffset = nsPoint(nsPresContext::CSSPixelsToAppUnits(aXpx),
   161                                  nsPresContext::CSSPixelsToAppUnits(aYpx));
   162   return Update(config);
   163 }
   165 NS_IMETHODIMP
   166 nsContentView::ScrollBy(float aDXpx, float aDYpx)
   167 {
   168   ViewConfig config(mConfig);
   169   config.mScrollOffset.MoveBy(nsPresContext::CSSPixelsToAppUnits(aDXpx),
   170                               nsPresContext::CSSPixelsToAppUnits(aDYpx));
   171   return Update(config);
   172 }
   174 NS_IMETHODIMP
   175 nsContentView::SetScale(float aXScale, float aYScale)
   176 {
   177   ViewConfig config(mConfig);
   178   config.mXScale = aXScale;
   179   config.mYScale = aYScale;
   180   return Update(config);
   181 }
   183 NS_IMETHODIMP
   184 nsContentView::GetScrollX(float* aViewScrollX)
   185 {
   186   *aViewScrollX = nsPresContext::AppUnitsToFloatCSSPixels(
   187     mConfig.mScrollOffset.x);
   188   return NS_OK;
   189 }
   191 NS_IMETHODIMP
   192 nsContentView::GetScrollY(float* aViewScrollY)
   193 {
   194   *aViewScrollY = nsPresContext::AppUnitsToFloatCSSPixels(
   195     mConfig.mScrollOffset.y);
   196   return NS_OK;
   197 }
   199 NS_IMETHODIMP
   200 nsContentView::GetViewportWidth(float* aWidth)
   201 {
   202   *aWidth = nsPresContext::AppUnitsToFloatCSSPixels(mViewportSize.width);
   203   return NS_OK;
   204 }
   206 NS_IMETHODIMP
   207 nsContentView::GetViewportHeight(float* aHeight)
   208 {
   209   *aHeight = nsPresContext::AppUnitsToFloatCSSPixels(mViewportSize.height);
   210   return NS_OK;
   211 }
   213 NS_IMETHODIMP
   214 nsContentView::GetContentWidth(float* aWidth)
   215 {
   216   *aWidth = nsPresContext::AppUnitsToFloatCSSPixels(mContentSize.width);
   217   return NS_OK;
   218 }
   220 NS_IMETHODIMP
   221 nsContentView::GetContentHeight(float* aHeight)
   222 {
   223   *aHeight = nsPresContext::AppUnitsToFloatCSSPixels(mContentSize.height);
   224   return NS_OK;
   225 }
   227 NS_IMETHODIMP
   228 nsContentView::GetId(nsContentViewId* aId)
   229 {
   230   NS_ASSERTION(sizeof(nsContentViewId) == sizeof(ViewID),
   231                "ID size for XPCOM ID and internal ID type are not the same!");
   232   *aId = mScrollId;
   233   return NS_OK;
   234 }
   236 // Bug 136580: Limit to the number of nested content frames that can have the
   237 //             same URL. This is to stop content that is recursively loading
   238 //             itself.  Note that "#foo" on the end of URL doesn't affect
   239 //             whether it's considered identical, but "?foo" or ";foo" are
   240 //             considered and compared.
   241 // Bug 228829: Limit this to 1, like IE does.
   242 #define MAX_SAME_URL_CONTENT_FRAMES 1
   244 // Bug 8065: Limit content frame depth to some reasonable level. This
   245 // does not count chrome frames when determining depth, nor does it
   246 // prevent chrome recursion.  Number is fairly arbitrary, but meant to
   247 // keep number of shells to a reasonable number on accidental recursion with a
   248 // small (but not 1) branching factor.  With large branching factors the number
   249 // of shells can rapidly become huge and run us out of memory.  To solve that,
   250 // we'd need to re-institute a fixed version of bug 98158.
   251 #define MAX_DEPTH_CONTENT_FRAMES 10
   253 NS_IMPL_CYCLE_COLLECTION(nsFrameLoader, mDocShell, mMessageManager, mChildMessageManager)
   254 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameLoader)
   255 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameLoader)
   257 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader)
   258   NS_INTERFACE_MAP_ENTRY(nsIFrameLoader)
   259   NS_INTERFACE_MAP_ENTRY(nsIContentViewManager)
   260   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFrameLoader)
   261 NS_INTERFACE_MAP_END
   263 nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
   264   : mOwnerContent(aOwner)
   265   , mAppIdSentToPermissionManager(nsIScriptSecurityManager::NO_APP_ID)
   266   , mDetachedSubdocViews(nullptr)
   267   , mDepthTooGreat(false)
   268   , mIsTopLevelContent(false)
   269   , mDestroyCalled(false)
   270   , mNeedsAsyncDestroy(false)
   271   , mInSwap(false)
   272   , mInShow(false)
   273   , mHideCalled(false)
   274   , mNetworkCreated(aNetworkCreated)
   275   , mRemoteBrowserShown(false)
   276   , mRemoteFrame(false)
   277   , mClipSubdocument(true)
   278   , mClampScrollPosition(true)
   279   , mRemoteBrowserInitialized(false)
   280   , mObservingOwnerContent(false)
   281   , mVisible(true)
   282   , mCurrentRemoteFrame(nullptr)
   283   , mRemoteBrowser(nullptr)
   284   , mChildID(0)
   285   , mRenderMode(RENDER_MODE_DEFAULT)
   286   , mEventMode(EVENT_MODE_NORMAL_DISPATCH)
   287   , mPendingFrameSent(false)
   288 {
   289   ResetPermissionManagerStatus();
   290 }
   292 nsFrameLoader::~nsFrameLoader()
   293 {
   294   mNeedsAsyncDestroy = true;
   295   if (mMessageManager) {
   296     mMessageManager->Disconnect();
   297   }
   298   nsFrameLoader::Destroy();
   299 }
   301 nsFrameLoader*
   302 nsFrameLoader::Create(Element* aOwner, bool aNetworkCreated)
   303 {
   304   NS_ENSURE_TRUE(aOwner, nullptr);
   305   nsIDocument* doc = aOwner->OwnerDoc();
   306   NS_ENSURE_TRUE(!doc->IsResourceDoc() &&
   307                  ((!doc->IsLoadedAsData() && aOwner->GetCurrentDoc()) ||
   308                    doc->IsStaticDocument()),
   309                  nullptr);
   311   return new nsFrameLoader(aOwner, aNetworkCreated);
   312 }
   314 NS_IMETHODIMP
   315 nsFrameLoader::LoadFrame()
   316 {
   317   NS_ENSURE_TRUE(mOwnerContent, NS_ERROR_NOT_INITIALIZED);
   319   nsAutoString src;
   321   bool isSrcdoc = mOwnerContent->IsHTML(nsGkAtoms::iframe) &&
   322                   mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc);
   323   if (isSrcdoc) {
   324     src.AssignLiteral("about:srcdoc");
   325   }
   326   else {
   327     GetURL(src);
   329     src.Trim(" \t\n\r");
   331     if (src.IsEmpty()) {
   332       // If the frame is a XUL element and has the attribute 'nodefaultsrc=true'
   333       // then we will not use 'about:blank' as fallback but return early without
   334       // starting a load if no 'src' attribute is given (or it's empty).
   335       if (mOwnerContent->IsXUL() &&
   336           mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::nodefaultsrc,
   337                                      nsGkAtoms::_true, eCaseMatters)) {
   338         return NS_OK;
   339       }
   340       src.AssignLiteral("about:blank");
   341     }
   342   }
   344   nsIDocument* doc = mOwnerContent->OwnerDoc();
   345   if (doc->IsStaticDocument()) {
   346     return NS_OK;
   347   }
   349   nsCOMPtr<nsIURI> base_uri = mOwnerContent->GetBaseURI();
   350   const nsAFlatCString &doc_charset = doc->GetDocumentCharacterSet();
   351   const char *charset = doc_charset.IsEmpty() ? nullptr : doc_charset.get();
   353   nsCOMPtr<nsIURI> uri;
   354   nsresult rv = NS_NewURI(getter_AddRefs(uri), src, charset, base_uri);
   356   // If the URI was malformed, try to recover by loading about:blank.
   357   if (rv == NS_ERROR_MALFORMED_URI) {
   358     rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("about:blank"),
   359                    charset, base_uri);
   360   }
   362   if (NS_SUCCEEDED(rv)) {
   363     rv = LoadURI(uri);
   364   }
   366   if (NS_FAILED(rv)) {
   367     FireErrorEvent();
   369     return rv;
   370   }
   372   return NS_OK;
   373 }
   375 void
   376 nsFrameLoader::FireErrorEvent()
   377 {
   378   if (!mOwnerContent) {
   379     return;
   380   }
   381   nsRefPtr<AsyncEventDispatcher > loadBlockingAsyncDispatcher =
   382     new LoadBlockingAsyncEventDispatcher(mOwnerContent,
   383                                          NS_LITERAL_STRING("error"),
   384                                          false, false);
   385   loadBlockingAsyncDispatcher->PostDOMEvent();
   386 }
   388 NS_IMETHODIMP
   389 nsFrameLoader::LoadURI(nsIURI* aURI)
   390 {
   391   if (!aURI)
   392     return NS_ERROR_INVALID_POINTER;
   393   NS_ENSURE_STATE(!mDestroyCalled && mOwnerContent);
   395   nsCOMPtr<nsIDocument> doc = mOwnerContent->OwnerDoc();
   397   nsresult rv = CheckURILoad(aURI);
   398   NS_ENSURE_SUCCESS(rv, rv);
   400   mURIToLoad = aURI;
   401   rv = doc->InitializeFrameLoader(this);
   402   if (NS_FAILED(rv)) {
   403     mURIToLoad = nullptr;
   404   }
   405   return rv;
   406 }
   408 nsresult
   409 nsFrameLoader::ReallyStartLoading()
   410 {
   411   nsresult rv = ReallyStartLoadingInternal();
   412   if (NS_FAILED(rv)) {
   413     FireErrorEvent();
   414   }
   416   return rv;
   417 }
   419 class DelayedStartLoadingRunnable : public nsRunnable
   420 {
   421 public:
   422   DelayedStartLoadingRunnable(nsFrameLoader* aFrameLoader)
   423     : mFrameLoader(aFrameLoader)
   424   {
   425   }
   427   NS_IMETHOD Run()
   428   {
   429     // Retry the request.
   430     mFrameLoader->ReallyStartLoading();
   432     // We delayed nsFrameLoader::ReallyStartLoading() after the child process is
   433     // ready and might not be able to notify the remote browser in
   434     // UpdatePositionAndSize() when reflow finished. Retrigger reflow.
   435     nsIFrame* frame = mFrameLoader->GetPrimaryFrameOfOwningContent();
   436     if (!frame) {
   437       return NS_OK;
   438     }
   439     frame->InvalidateFrame();
   440     frame->PresContext()->PresShell()->
   441       FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
   443     return NS_OK;
   444   }
   446 private:
   447   nsRefPtr<nsFrameLoader> mFrameLoader;
   448 };
   450 nsresult
   451 nsFrameLoader::ReallyStartLoadingInternal()
   452 {
   453   NS_ENSURE_STATE(mURIToLoad && mOwnerContent && mOwnerContent->IsInDoc());
   455   PROFILER_LABEL("nsFrameLoader", "ReallyStartLoading");
   457   nsresult rv = MaybeCreateDocShell();
   458   if (NS_FAILED(rv)) {
   459     return rv;
   460   }
   462   if (mRemoteFrame) {
   463     if (!mRemoteBrowser) {
   464       if (!mPendingFrameSent) {
   465         nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   466         if (os && !mRemoteBrowserInitialized) {
   467           os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
   468                               "remote-browser-pending", nullptr);
   469           mPendingFrameSent = true;
   470         }
   471       }
   472       if (Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false) &&
   473           !ContentParent::PreallocatedProcessReady()) {
   475         ContentParent::RunAfterPreallocatedProcessReady(
   476             new DelayedStartLoadingRunnable(this));
   477         return NS_ERROR_FAILURE;
   478       }
   480       TryRemoteBrowser();
   482       if (!mRemoteBrowser) {
   483         NS_WARNING("Couldn't create child process for iframe.");
   484         return NS_ERROR_FAILURE;
   485       }
   486     }
   488     if (mRemoteBrowserShown || ShowRemoteFrame(nsIntSize(0, 0))) {
   489       // FIXME get error codes from child
   490       mRemoteBrowser->LoadURL(mURIToLoad);
   491     } else {
   492       NS_WARNING("[nsFrameLoader] ReallyStartLoadingInternal tried but couldn't show remote browser.\n");
   493     }
   495     return NS_OK;
   496   }
   498   NS_ASSERTION(mDocShell,
   499                "MaybeCreateDocShell succeeded with a null mDocShell");
   501   // Just to be safe, recheck uri.
   502   rv = CheckURILoad(mURIToLoad);
   503   NS_ENSURE_SUCCESS(rv, rv);
   505   nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
   506   mDocShell->CreateLoadInfo(getter_AddRefs(loadInfo));
   507   NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
   509   // If this frame is sandboxed with respect to origin we will set it up with
   510   // a null principal later in nsDocShell::DoURILoad.
   511   // We do it there to correctly sandbox content that was loaded into
   512   // the frame via other methods than the src attribute.
   513   // We'll use our principal, not that of the document loaded inside us.  This
   514   // is very important; needed to prevent XSS attacks on documents loaded in
   515   // subframes!
   516   loadInfo->SetOwner(mOwnerContent->NodePrincipal());
   518   nsCOMPtr<nsIURI> referrer;
   520   nsAutoString srcdoc;
   521   bool isSrcdoc = mOwnerContent->IsHTML(nsGkAtoms::iframe) &&
   522                   mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::srcdoc,
   523                                          srcdoc);
   525   if (isSrcdoc) {
   526     nsAutoString referrerStr;
   527     mOwnerContent->OwnerDoc()->GetReferrer(referrerStr);
   528     rv = NS_NewURI(getter_AddRefs(referrer), referrerStr);
   530     loadInfo->SetSrcdocData(srcdoc);
   531     nsCOMPtr<nsIURI> baseURI = mOwnerContent->GetBaseURI();
   532     loadInfo->SetBaseURI(baseURI);
   533   }
   534   else {
   535     rv = mOwnerContent->NodePrincipal()->GetURI(getter_AddRefs(referrer));
   536     NS_ENSURE_SUCCESS(rv, rv);
   537   }
   539   // Use referrer as long as it is not an nsNullPrincipalURI.
   540   // We could add a method such as GetReferrerURI to principals to make this
   541   // cleaner, but given that we need to start using Source Browsing Context for
   542   // referrer (see Bug 960639) this may be wasted effort at this stage.
   543   if (referrer) {
   544     bool isNullPrincipalScheme;
   545     rv = referrer->SchemeIs(NS_NULLPRINCIPAL_SCHEME, &isNullPrincipalScheme);
   546     if (NS_SUCCEEDED(rv) && !isNullPrincipalScheme) {
   547       loadInfo->SetReferrer(referrer);
   548     }
   549   }
   551   // Default flags:
   552   int32_t flags = nsIWebNavigation::LOAD_FLAGS_NONE;
   554   // Flags for browser frame:
   555   if (OwnerIsBrowserFrame()) {
   556     flags = nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
   557             nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
   558   }
   560   // Kick off the load...
   561   bool tmpState = mNeedsAsyncDestroy;
   562   mNeedsAsyncDestroy = true;
   563   nsCOMPtr<nsIURI> uriToLoad = mURIToLoad;
   564   rv = mDocShell->LoadURI(uriToLoad, loadInfo, flags, false);
   565   mNeedsAsyncDestroy = tmpState;
   566   mURIToLoad = nullptr;
   567   NS_ENSURE_SUCCESS(rv, rv);
   569   return NS_OK;
   570 }
   572 nsresult
   573 nsFrameLoader::CheckURILoad(nsIURI* aURI)
   574 {
   575   // Check for security.  The fun part is trying to figure out what principals
   576   // to use.  The way I figure it, if we're doing a LoadFrame() accidentally
   577   // (eg someone created a frame/iframe node, we're being parsed, XUL iframes
   578   // are being reframed, etc.) then we definitely want to use the node
   579   // principal of mOwnerContent for security checks.  If, on the other hand,
   580   // someone's setting the src on our owner content, or created it via script,
   581   // or whatever, then they can clearly access it... and we should still use
   582   // the principal of mOwnerContent.  I don't think that leads to privilege
   583   // escalation, and it's reasonably guaranteed to not lead to XSS issues
   584   // (since caller can already access mOwnerContent in this case).  So just use
   585   // the principal of mOwnerContent no matter what.  If script wants to run
   586   // things with its own permissions, which differ from those of mOwnerContent
   587   // (which means the script is privileged in some way) it should set
   588   // window.location instead.
   589   nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
   591   // Get our principal
   592   nsIPrincipal* principal = mOwnerContent->NodePrincipal();
   594   // Check if we are allowed to load absURL
   595   nsresult rv =
   596     secMan->CheckLoadURIWithPrincipal(principal, aURI,
   597                                       nsIScriptSecurityManager::STANDARD);
   598   if (NS_FAILED(rv)) {
   599     return rv; // We're not
   600   }
   602   // Bail out if this is an infinite recursion scenario
   603   rv = MaybeCreateDocShell();
   604   if (NS_FAILED(rv)) {
   605     return rv;
   606   }
   607   if (mRemoteFrame) {
   608     return NS_OK;
   609   }
   610   return CheckForRecursiveLoad(aURI);
   611 }
   613 NS_IMETHODIMP
   614 nsFrameLoader::GetDocShell(nsIDocShell **aDocShell)
   615 {
   616   *aDocShell = nullptr;
   617   nsresult rv = NS_OK;
   619   // If we have an owner, make sure we have a docshell and return
   620   // that. If not, we're most likely in the middle of being torn down,
   621   // then we just return null.
   622   if (mOwnerContent) {
   623     nsresult rv = MaybeCreateDocShell();
   624     if (NS_FAILED(rv))
   625       return rv;
   626     if (mRemoteFrame) {
   627       NS_WARNING("No docshells for remote frames!");
   628       return rv;
   629     }
   630     NS_ASSERTION(mDocShell,
   631                  "MaybeCreateDocShell succeeded, but null mDocShell");
   632   }
   634   *aDocShell = mDocShell;
   635   NS_IF_ADDREF(*aDocShell);
   637   return rv;
   638 }
   640 void
   641 nsFrameLoader::Finalize()
   642 {
   643   nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell));
   644   if (base_win) {
   645     base_win->Destroy();
   646   }
   647   mDocShell = nullptr;
   648 }
   650 static void
   651 FirePageHideEvent(nsIDocShellTreeItem* aItem,
   652                   EventTarget* aChromeEventHandler)
   653 {
   654   nsCOMPtr<nsIDocument> internalDoc = do_GetInterface(aItem);
   655   NS_ASSERTION(internalDoc, "What happened here?");
   656   internalDoc->OnPageHide(true, aChromeEventHandler);
   658   int32_t childCount = 0;
   659   aItem->GetChildCount(&childCount);
   660   nsAutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids;
   661   kids.AppendElements(childCount);
   662   for (int32_t i = 0; i < childCount; ++i) {
   663     aItem->GetChildAt(i, getter_AddRefs(kids[i]));
   664   }
   666   for (uint32_t i = 0; i < kids.Length(); ++i) {
   667     if (kids[i]) {
   668       FirePageHideEvent(kids[i], aChromeEventHandler);
   669     }
   670   }
   671 }
   673 // The pageshow event is fired for a given document only if IsShowing() returns
   674 // the same thing as aFireIfShowing.  This gives us a way to fire pageshow only
   675 // on documents that are still loading or only on documents that are already
   676 // loaded.
   677 static void
   678 FirePageShowEvent(nsIDocShellTreeItem* aItem,
   679                   EventTarget* aChromeEventHandler,
   680                   bool aFireIfShowing)
   681 {
   682   int32_t childCount = 0;
   683   aItem->GetChildCount(&childCount);
   684   nsAutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids;
   685   kids.AppendElements(childCount);
   686   for (int32_t i = 0; i < childCount; ++i) {
   687     aItem->GetChildAt(i, getter_AddRefs(kids[i]));
   688   }
   690   for (uint32_t i = 0; i < kids.Length(); ++i) {
   691     if (kids[i]) {
   692       FirePageShowEvent(kids[i], aChromeEventHandler, aFireIfShowing);
   693     }
   694   }
   696   nsCOMPtr<nsIDocument> internalDoc = do_GetInterface(aItem);
   697   NS_ASSERTION(internalDoc, "What happened here?");
   698   if (internalDoc->IsShowing() == aFireIfShowing) {
   699     internalDoc->OnPageShow(true, aChromeEventHandler);
   700   }
   701 }
   703 static void
   704 SetTreeOwnerAndChromeEventHandlerOnDocshellTree(nsIDocShellTreeItem* aItem,
   705                                                 nsIDocShellTreeOwner* aOwner,
   706                                                 EventTarget* aHandler)
   707 {
   708   NS_PRECONDITION(aItem, "Must have item");
   710   aItem->SetTreeOwner(aOwner);
   712   int32_t childCount = 0;
   713   aItem->GetChildCount(&childCount);
   714   for (int32_t i = 0; i < childCount; ++i) {
   715     nsCOMPtr<nsIDocShellTreeItem> item;
   716     aItem->GetChildAt(i, getter_AddRefs(item));
   717     if (aHandler) {
   718       nsCOMPtr<nsIDocShell> shell(do_QueryInterface(item));
   719       shell->SetChromeEventHandler(aHandler);
   720     }
   721     SetTreeOwnerAndChromeEventHandlerOnDocshellTree(item, aOwner, aHandler);
   722   }
   723 }
   725 /**
   726  * Set the type of the treeitem and hook it up to the treeowner.
   727  * @param aItem the treeitem we're working with
   728  * @param aTreeOwner the relevant treeowner; might be null
   729  * @param aParentType the nsIDocShellTreeItem::GetType of our parent docshell
   730  * @param aParentNode if non-null, the docshell we should be added as a child to
   731  *
   732  * @return whether aItem is top-level content
   733  */
   734 bool
   735 nsFrameLoader::AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
   736                                       nsIDocShellTreeOwner* aOwner,
   737                                       int32_t aParentType,
   738                                       nsIDocShell* aParentNode)
   739 {
   740   NS_PRECONDITION(aItem, "Must have docshell treeitem");
   741   NS_PRECONDITION(mOwnerContent, "Must have owning content");
   743   nsAutoString value;
   744   bool isContent = false;
   745   mOwnerContent->GetAttr(kNameSpaceID_None, TypeAttrName(), value);
   747   // we accept "content" and "content-xxx" values.
   748   // at time of writing, we expect "xxx" to be "primary" or "targetable", but
   749   // someday it might be an integer expressing priority or something else.
   751   isContent = value.LowerCaseEqualsLiteral("content") ||
   752     StringBeginsWith(value, NS_LITERAL_STRING("content-"),
   753                      nsCaseInsensitiveStringComparator());
   755   // Force mozbrowser frames to always be typeContent, even if the
   756   // mozbrowser interfaces are disabled.
   757   nsCOMPtr<nsIDOMMozBrowserFrame> mozbrowser =
   758     do_QueryInterface(mOwnerContent);
   759   if (mozbrowser) {
   760     bool isMozbrowser = false;
   761     mozbrowser->GetMozbrowser(&isMozbrowser);
   762     isContent |= isMozbrowser;
   763   }
   765   if (isContent) {
   766     // The web shell's type is content.
   768     aItem->SetItemType(nsIDocShellTreeItem::typeContent);
   769   } else {
   770     // Inherit our type from our parent docshell.  If it is
   771     // chrome, we'll be chrome.  If it is content, we'll be
   772     // content.
   774     aItem->SetItemType(aParentType);
   775   }
   777   // Now that we have our type set, add ourselves to the parent, as needed.
   778   if (aParentNode) {
   779     aParentNode->AddChild(aItem);
   780   }
   782   bool retval = false;
   783   if (aParentType == nsIDocShellTreeItem::typeChrome && isContent) {
   784     retval = true;
   786     bool is_primary = value.LowerCaseEqualsLiteral("content-primary");
   788     if (aOwner) {
   789       bool is_targetable = is_primary ||
   790         value.LowerCaseEqualsLiteral("content-targetable");
   791       mOwnerContent->AddMutationObserver(this);
   792       mObservingOwnerContent = true;
   793       aOwner->ContentShellAdded(aItem, is_primary, is_targetable, value);
   794     }
   795   }
   797   return retval;
   798 }
   800 static bool
   801 AllDescendantsOfType(nsIDocShellTreeItem* aParentItem, int32_t aType)
   802 {
   803   int32_t childCount = 0;
   804   aParentItem->GetChildCount(&childCount);
   806   for (int32_t i = 0; i < childCount; ++i) {
   807     nsCOMPtr<nsIDocShellTreeItem> kid;
   808     aParentItem->GetChildAt(i, getter_AddRefs(kid));
   810     if (kid->ItemType() != aType || !AllDescendantsOfType(kid, aType)) {
   811       return false;
   812     }
   813   }
   815   return true;
   816 }
   818 /**
   819  * A class that automatically sets mInShow to false when it goes
   820  * out of scope.
   821  */
   822 class MOZ_STACK_CLASS AutoResetInShow {
   823   private:
   824     nsFrameLoader* mFrameLoader;
   825     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   826   public:
   827     AutoResetInShow(nsFrameLoader* aFrameLoader MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
   828       : mFrameLoader(aFrameLoader)
   829     {
   830       MOZ_GUARD_OBJECT_NOTIFIER_INIT;
   831     }
   832     ~AutoResetInShow() { mFrameLoader->mInShow = false; }
   833 };
   836 bool
   837 nsFrameLoader::Show(int32_t marginWidth, int32_t marginHeight,
   838                     int32_t scrollbarPrefX, int32_t scrollbarPrefY,
   839                     nsSubDocumentFrame* frame)
   840 {
   841   if (mInShow) {
   842     return false;
   843   }
   844   // Reset mInShow if we exit early.
   845   AutoResetInShow resetInShow(this);
   846   mInShow = true;
   848   nsresult rv = MaybeCreateDocShell();
   849   if (NS_FAILED(rv)) {
   850     return false;
   851   }
   853   if (!mRemoteFrame) {
   854     if (!mDocShell)
   855       return false;
   857     mDocShell->SetMarginWidth(marginWidth);
   858     mDocShell->SetMarginHeight(marginHeight);
   860     nsCOMPtr<nsIScrollable> sc = do_QueryInterface(mDocShell);
   861     if (sc) {
   862       sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X,
   863                                          scrollbarPrefX);
   864       sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y,
   865                                          scrollbarPrefY);
   866     }
   868     nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
   869     if (presShell) {
   870       // Ensure root scroll frame is reflowed in case scroll preferences or
   871       // margins have changed
   872       nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
   873       if (rootScrollFrame) {
   874         presShell->FrameNeedsReflow(rootScrollFrame, nsIPresShell::eResize,
   875                                     NS_FRAME_IS_DIRTY);
   876       }
   877       return true;
   878     }
   879   }
   881   nsIntSize size = frame->GetSubdocumentSize();
   882   if (mRemoteFrame) {
   883     return ShowRemoteFrame(size, frame);
   884   }
   886   nsView* view = frame->EnsureInnerView();
   887   if (!view)
   888     return false;
   890   nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mDocShell);
   891   NS_ASSERTION(baseWindow, "Found a nsIDocShell that isn't a nsIBaseWindow.");
   892   baseWindow->InitWindow(nullptr, view->GetWidget(), 0, 0,
   893                          size.width, size.height);
   894   // This is kinda whacky, this "Create()" call doesn't really
   895   // create anything, one starts to wonder why this was named
   896   // "Create"...
   897   baseWindow->Create();
   898   baseWindow->SetVisibility(true);
   899   NS_ENSURE_TRUE(mDocShell, false);
   901   // Trigger editor re-initialization if midas is turned on in the
   902   // sub-document. This shouldn't be necessary, but given the way our
   903   // editor works, it is. See
   904   // https://bugzilla.mozilla.org/show_bug.cgi?id=284245
   905   nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
   906   if (presShell) {
   907     nsCOMPtr<nsIDOMHTMLDocument> doc =
   908       do_QueryInterface(presShell->GetDocument());
   910     if (doc) {
   911       nsAutoString designMode;
   912       doc->GetDesignMode(designMode);
   914       if (designMode.EqualsLiteral("on")) {
   915         // Hold on to the editor object to let the document reattach to the
   916         // same editor object, instead of creating a new one.
   917         nsCOMPtr<nsIEditor> editor;
   918         nsresult rv = mDocShell->GetEditor(getter_AddRefs(editor));
   919         NS_ENSURE_SUCCESS(rv, false);
   921         doc->SetDesignMode(NS_LITERAL_STRING("off"));
   922         doc->SetDesignMode(NS_LITERAL_STRING("on"));
   923       } else {
   924         // Re-initialize the presentation for contenteditable documents
   925         bool editable = false,
   926              hasEditingSession = false;
   927         mDocShell->GetEditable(&editable);
   928         mDocShell->GetHasEditingSession(&hasEditingSession);
   929         nsCOMPtr<nsIEditor> editor;
   930         mDocShell->GetEditor(getter_AddRefs(editor));
   931         if (editable && hasEditingSession && editor) {
   932           editor->PostCreate();
   933         }
   934       }
   935     }
   936   }
   938   mInShow = false;
   939   if (mHideCalled) {
   940     mHideCalled = false;
   941     Hide();
   942     return false;
   943   }
   944   return true;
   945 }
   947 void
   948 nsFrameLoader::MarginsChanged(uint32_t aMarginWidth,
   949                               uint32_t aMarginHeight)
   950 {
   951   // We assume that the margins are always zero for remote frames.
   952   if (mRemoteFrame)
   953     return;
   955   // If there's no docshell, we're probably not up and running yet.
   956   // nsFrameLoader::Show() will take care of setting the right
   957   // margins.
   958   if (!mDocShell)
   959     return;
   961   // Set the margins
   962   mDocShell->SetMarginWidth(aMarginWidth);
   963   mDocShell->SetMarginHeight(aMarginHeight);
   965   // Trigger a restyle if there's a prescontext
   966   nsRefPtr<nsPresContext> presContext;
   967   mDocShell->GetPresContext(getter_AddRefs(presContext));
   968   if (presContext)
   969     presContext->RebuildAllStyleData(nsChangeHint(0));
   970 }
   972 bool
   973 nsFrameLoader::ShowRemoteFrame(const nsIntSize& size,
   974                                nsSubDocumentFrame *aFrame)
   975 {
   976   NS_ASSERTION(mRemoteFrame, "ShowRemote only makes sense on remote frames.");
   978   if (!mRemoteBrowser) {
   979     TryRemoteBrowser();
   981     if (!mRemoteBrowser) {
   982       NS_ERROR("Couldn't create child process.");
   983       return false;
   984     }
   985   }
   987   // FIXME/bug 589337: Show()/Hide() is pretty expensive for
   988   // cross-process layers; need to figure out what behavior we really
   989   // want here.  For now, hack.
   990   if (!mRemoteBrowserShown) {
   991     if (!mOwnerContent ||
   992         !mOwnerContent->GetCurrentDoc()) {
   993       return false;
   994     }
   996     nsRefPtr<layers::LayerManager> layerManager =
   997       nsContentUtils::LayerManagerForDocument(mOwnerContent->GetCurrentDoc());
   998     if (!layerManager) {
   999       // This is just not going to work.
  1000       return false;
  1003     mRemoteBrowser->Show(size);
  1004     mRemoteBrowserShown = true;
  1006     EnsureMessageManager();
  1008     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
  1009     if (os && !mRemoteBrowserInitialized) {
  1010       if (!mPendingFrameSent) {
  1011         os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
  1012                             "remote-browser-pending", nullptr);
  1013         mPendingFrameSent = true;
  1015       os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
  1016                           "remote-browser-shown", nullptr);
  1017       mRemoteBrowserInitialized = true;
  1019   } else {
  1020     nsRect dimensions;
  1021     NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), false);
  1023     // Don't show remote iframe if we are waiting for the completion of reflow.
  1024     if (!aFrame || !(aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
  1025       mRemoteBrowser->UpdateDimensions(dimensions, size);
  1029   return true;
  1032 void
  1033 nsFrameLoader::Hide()
  1035   if (mHideCalled) {
  1036     return;
  1038   if (mInShow) {
  1039     mHideCalled = true;
  1040     return;
  1043   if (!mDocShell)
  1044     return;
  1046   nsCOMPtr<nsIContentViewer> contentViewer;
  1047   mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
  1048   if (contentViewer)
  1049     contentViewer->SetSticky(false);
  1051   nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
  1052   NS_ASSERTION(baseWin,
  1053                "Found an nsIDocShell which doesn't implement nsIBaseWindow.");
  1054   baseWin->SetVisibility(false);
  1055   baseWin->SetParentWidget(nullptr);
  1058 nsresult
  1059 nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
  1060                                    nsRefPtr<nsFrameLoader>& aFirstToSwap,
  1061                                    nsRefPtr<nsFrameLoader>& aSecondToSwap)
  1063   NS_PRECONDITION((aFirstToSwap == this && aSecondToSwap == aOther) ||
  1064                   (aFirstToSwap == aOther && aSecondToSwap == this),
  1065                   "Swapping some sort of random loaders?");
  1066   NS_ENSURE_STATE(!mInShow && !aOther->mInShow);
  1068   Element* ourContent = mOwnerContent;
  1069   Element* otherContent = aOther->mOwnerContent;
  1071   if (!ourContent || !otherContent) {
  1072     // Can't handle this
  1073     return NS_ERROR_NOT_IMPLEMENTED;
  1076   // Make sure there are no same-origin issues
  1077   bool equal;
  1078   nsresult rv =
  1079     ourContent->NodePrincipal()->Equals(otherContent->NodePrincipal(), &equal);
  1080   if (NS_FAILED(rv) || !equal) {
  1081     // Security problems loom.  Just bail on it all
  1082     return NS_ERROR_DOM_SECURITY_ERR;
  1085   nsCOMPtr<nsIDocShell> ourDocshell = GetExistingDocShell();
  1086   nsCOMPtr<nsIDocShell> otherDocshell = aOther->GetExistingDocShell();
  1087   if (!ourDocshell || !otherDocshell) {
  1088     // How odd
  1089     return NS_ERROR_NOT_IMPLEMENTED;
  1092   // To avoid having to mess with session history, avoid swapping
  1093   // frameloaders that don't correspond to root same-type docshells,
  1094   // unless both roots have session history disabled.
  1095   nsCOMPtr<nsIDocShellTreeItem> ourRootTreeItem, otherRootTreeItem;
  1096   ourDocshell->GetSameTypeRootTreeItem(getter_AddRefs(ourRootTreeItem));
  1097   otherDocshell->GetSameTypeRootTreeItem(getter_AddRefs(otherRootTreeItem));
  1098   nsCOMPtr<nsIWebNavigation> ourRootWebnav =
  1099     do_QueryInterface(ourRootTreeItem);
  1100   nsCOMPtr<nsIWebNavigation> otherRootWebnav =
  1101     do_QueryInterface(otherRootTreeItem);
  1103   if (!ourRootWebnav || !otherRootWebnav) {
  1104     return NS_ERROR_NOT_IMPLEMENTED;
  1107   nsCOMPtr<nsISHistory> ourHistory;
  1108   nsCOMPtr<nsISHistory> otherHistory;
  1109   ourRootWebnav->GetSessionHistory(getter_AddRefs(ourHistory));
  1110   otherRootWebnav->GetSessionHistory(getter_AddRefs(otherHistory));
  1112   if ((ourRootTreeItem != ourDocshell || otherRootTreeItem != otherDocshell) &&
  1113       (ourHistory || otherHistory)) {
  1114     return NS_ERROR_NOT_IMPLEMENTED;
  1117   // Also make sure that the two docshells are the same type. Otherwise
  1118   // swapping is certainly not safe. If this needs to be changed then
  1119   // the code below needs to be audited as it assumes identical types.
  1120   int32_t ourType = ourDocshell->ItemType();
  1121   int32_t otherType = otherDocshell->ItemType();
  1122   if (ourType != otherType) {
  1123     return NS_ERROR_NOT_IMPLEMENTED;
  1126   // One more twist here.  Setting up the right treeowners in a heterogeneous
  1127   // tree is a bit of a pain.  So make sure that if ourType is not
  1128   // nsIDocShellTreeItem::typeContent then all of our descendants are the same
  1129   // type as us.
  1130   if (ourType != nsIDocShellTreeItem::typeContent &&
  1131       (!AllDescendantsOfType(ourDocshell, ourType) ||
  1132        !AllDescendantsOfType(otherDocshell, otherType))) {
  1133     return NS_ERROR_NOT_IMPLEMENTED;
  1136   // Save off the tree owners, frame elements, chrome event handlers, and
  1137   // docshell and document parents before doing anything else.
  1138   nsCOMPtr<nsIDocShellTreeOwner> ourOwner, otherOwner;
  1139   ourDocshell->GetTreeOwner(getter_AddRefs(ourOwner));
  1140   otherDocshell->GetTreeOwner(getter_AddRefs(otherOwner));
  1141   // Note: it's OK to have null treeowners.
  1143   nsCOMPtr<nsIDocShellTreeItem> ourParentItem, otherParentItem;
  1144   ourDocshell->GetParent(getter_AddRefs(ourParentItem));
  1145   otherDocshell->GetParent(getter_AddRefs(otherParentItem));
  1146   if (!ourParentItem || !otherParentItem) {
  1147     return NS_ERROR_NOT_IMPLEMENTED;
  1150   // Make sure our parents are the same type too
  1151   int32_t ourParentType = ourParentItem->ItemType();
  1152   int32_t otherParentType = otherParentItem->ItemType();
  1153   if (ourParentType != otherParentType) {
  1154     return NS_ERROR_NOT_IMPLEMENTED;
  1157   nsCOMPtr<nsPIDOMWindow> ourWindow = do_GetInterface(ourDocshell);
  1158   nsCOMPtr<nsPIDOMWindow> otherWindow = do_GetInterface(otherDocshell);
  1160   nsCOMPtr<Element> ourFrameElement =
  1161     ourWindow->GetFrameElementInternal();
  1162   nsCOMPtr<Element> otherFrameElement =
  1163     otherWindow->GetFrameElementInternal();
  1165   nsCOMPtr<EventTarget> ourChromeEventHandler =
  1166     do_QueryInterface(ourWindow->GetChromeEventHandler());
  1167   nsCOMPtr<EventTarget> otherChromeEventHandler =
  1168     do_QueryInterface(otherWindow->GetChromeEventHandler());
  1170   NS_ASSERTION(SameCOMIdentity(ourFrameElement, ourContent) &&
  1171                SameCOMIdentity(otherFrameElement, otherContent) &&
  1172                SameCOMIdentity(ourChromeEventHandler, ourContent) &&
  1173                SameCOMIdentity(otherChromeEventHandler, otherContent),
  1174                "How did that happen, exactly?");
  1176   nsCOMPtr<nsIDocument> ourChildDocument = ourWindow->GetExtantDoc();
  1177   nsCOMPtr<nsIDocument> otherChildDocument = otherWindow ->GetExtantDoc();
  1178   if (!ourChildDocument || !otherChildDocument) {
  1179     // This shouldn't be happening
  1180     return NS_ERROR_NOT_IMPLEMENTED;
  1183   nsCOMPtr<nsIDocument> ourParentDocument =
  1184     ourChildDocument->GetParentDocument();
  1185   nsCOMPtr<nsIDocument> otherParentDocument =
  1186     otherChildDocument->GetParentDocument();
  1188   // Make sure to swap docshells between the two frames.
  1189   nsIDocument* ourDoc = ourContent->GetCurrentDoc();
  1190   nsIDocument* otherDoc = otherContent->GetCurrentDoc();
  1191   if (!ourDoc || !otherDoc) {
  1192     // Again, how odd, given that we had docshells
  1193     return NS_ERROR_NOT_IMPLEMENTED;
  1196   NS_ASSERTION(ourDoc == ourParentDocument, "Unexpected parent document");
  1197   NS_ASSERTION(otherDoc == otherParentDocument, "Unexpected parent document");
  1199   nsIPresShell* ourShell = ourDoc->GetShell();
  1200   nsIPresShell* otherShell = otherDoc->GetShell();
  1201   if (!ourShell || !otherShell) {
  1202     return NS_ERROR_NOT_IMPLEMENTED;
  1205   if (ourDocshell->GetIsBrowserElement() !=
  1206       otherDocshell->GetIsBrowserElement() ||
  1207       ourDocshell->GetIsApp() != otherDocshell->GetIsApp()) {
  1208       return NS_ERROR_NOT_IMPLEMENTED;
  1211   if (mInSwap || aOther->mInSwap) {
  1212     return NS_ERROR_NOT_IMPLEMENTED;
  1214   mInSwap = aOther->mInSwap = true;
  1216   // Fire pageshow events on still-loading pages, and then fire pagehide
  1217   // events.  Note that we do NOT fire these in the normal way, but just fire
  1218   // them on the chrome event handlers.
  1219   FirePageShowEvent(ourDocshell, ourChromeEventHandler, false);
  1220   FirePageShowEvent(otherDocshell, otherChromeEventHandler, false);
  1221   FirePageHideEvent(ourDocshell, ourChromeEventHandler);
  1222   FirePageHideEvent(otherDocshell, otherChromeEventHandler);
  1224   nsIFrame* ourFrame = ourContent->GetPrimaryFrame();
  1225   nsIFrame* otherFrame = otherContent->GetPrimaryFrame();
  1226   if (!ourFrame || !otherFrame) {
  1227     mInSwap = aOther->mInSwap = false;
  1228     FirePageShowEvent(ourDocshell, ourChromeEventHandler, true);
  1229     FirePageShowEvent(otherDocshell, otherChromeEventHandler, true);
  1230     return NS_ERROR_NOT_IMPLEMENTED;
  1233   nsSubDocumentFrame* ourFrameFrame = do_QueryFrame(ourFrame);
  1234   if (!ourFrameFrame) {
  1235     mInSwap = aOther->mInSwap = false;
  1236     FirePageShowEvent(ourDocshell, ourChromeEventHandler, true);
  1237     FirePageShowEvent(otherDocshell, otherChromeEventHandler, true);
  1238     return NS_ERROR_NOT_IMPLEMENTED;
  1241   // OK.  First begin to swap the docshells in the two nsIFrames
  1242   rv = ourFrameFrame->BeginSwapDocShells(otherFrame);
  1243   if (NS_FAILED(rv)) {
  1244     mInSwap = aOther->mInSwap = false;
  1245     FirePageShowEvent(ourDocshell, ourChromeEventHandler, true);
  1246     FirePageShowEvent(otherDocshell, otherChromeEventHandler, true);
  1247     return rv;
  1250   // Now move the docshells to the right docshell trees.  Note that this
  1251   // resets their treeowners to null.
  1252   ourParentItem->RemoveChild(ourDocshell);
  1253   otherParentItem->RemoveChild(otherDocshell);
  1254   if (ourType == nsIDocShellTreeItem::typeContent) {
  1255     ourOwner->ContentShellRemoved(ourDocshell);
  1256     otherOwner->ContentShellRemoved(otherDocshell);
  1259   ourParentItem->AddChild(otherDocshell);
  1260   otherParentItem->AddChild(ourDocshell);
  1262   // Restore the correct chrome event handlers.
  1263   ourDocshell->SetChromeEventHandler(otherChromeEventHandler);
  1264   otherDocshell->SetChromeEventHandler(ourChromeEventHandler);
  1265   // Restore the correct treeowners
  1266   // (and also chrome event handlers for content frames only).
  1267   SetTreeOwnerAndChromeEventHandlerOnDocshellTree(ourDocshell, otherOwner,
  1268     ourType == nsIDocShellTreeItem::typeContent ? otherChromeEventHandler : nullptr);
  1269   SetTreeOwnerAndChromeEventHandlerOnDocshellTree(otherDocshell, ourOwner,
  1270     ourType == nsIDocShellTreeItem::typeContent ? ourChromeEventHandler : nullptr);
  1272   // Switch the owner content before we start calling AddTreeItemToTreeOwner.
  1273   // Note that we rely on this to deal with setting mObservingOwnerContent to
  1274   // false and calling RemoveMutationObserver as needed.
  1275   SetOwnerContent(otherContent);
  1276   aOther->SetOwnerContent(ourContent);
  1278   AddTreeItemToTreeOwner(ourDocshell, otherOwner, otherParentType, nullptr);
  1279   aOther->AddTreeItemToTreeOwner(otherDocshell, ourOwner, ourParentType,
  1280                                  nullptr);
  1282   // SetSubDocumentFor nulls out parent documents on the old child doc if a
  1283   // new non-null document is passed in, so just go ahead and remove both
  1284   // kids before reinserting in the parent subdoc maps, to avoid
  1285   // complications.
  1286   ourParentDocument->SetSubDocumentFor(ourContent, nullptr);
  1287   otherParentDocument->SetSubDocumentFor(otherContent, nullptr);
  1288   ourParentDocument->SetSubDocumentFor(ourContent, otherChildDocument);
  1289   otherParentDocument->SetSubDocumentFor(otherContent, ourChildDocument);
  1291   ourWindow->SetFrameElementInternal(otherFrameElement);
  1292   otherWindow->SetFrameElementInternal(ourFrameElement);
  1294   nsRefPtr<nsFrameMessageManager> ourMessageManager = mMessageManager;
  1295   nsRefPtr<nsFrameMessageManager> otherMessageManager = aOther->mMessageManager;
  1296   // Swap pointers in child message managers.
  1297   if (mChildMessageManager) {
  1298     nsInProcessTabChildGlobal* tabChild =
  1299       static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get());
  1300     tabChild->SetOwner(otherContent);
  1301     tabChild->SetChromeMessageManager(otherMessageManager);
  1303   if (aOther->mChildMessageManager) {
  1304     nsInProcessTabChildGlobal* otherTabChild =
  1305       static_cast<nsInProcessTabChildGlobal*>(aOther->mChildMessageManager.get());
  1306     otherTabChild->SetOwner(ourContent);
  1307     otherTabChild->SetChromeMessageManager(ourMessageManager);
  1309   // Swap and setup things in parent message managers.
  1310   if (mMessageManager) {
  1311     mMessageManager->SetCallback(aOther);
  1313   if (aOther->mMessageManager) {
  1314     aOther->mMessageManager->SetCallback(this);
  1316   mMessageManager.swap(aOther->mMessageManager);
  1318   aFirstToSwap.swap(aSecondToSwap);
  1320   // Drop any cached content viewers in the two session histories.
  1321   nsCOMPtr<nsISHistoryInternal> ourInternalHistory =
  1322     do_QueryInterface(ourHistory);
  1323   nsCOMPtr<nsISHistoryInternal> otherInternalHistory =
  1324     do_QueryInterface(otherHistory);
  1325   if (ourInternalHistory) {
  1326     ourInternalHistory->EvictAllContentViewers();
  1328   if (otherInternalHistory) {
  1329     otherInternalHistory->EvictAllContentViewers();
  1332   NS_ASSERTION(ourFrame == ourContent->GetPrimaryFrame() &&
  1333                otherFrame == otherContent->GetPrimaryFrame(),
  1334                "changed primary frame");
  1336   ourFrameFrame->EndSwapDocShells(otherFrame);
  1338   // If the content being swapped came from windows on two screens with
  1339   // incompatible backing resolution (e.g. dragging a tab between windows on
  1340   // hi-dpi and low-dpi screens), it will have style data that is based on
  1341   // the wrong appUnitsPerDevPixel value. So we tell the PresShells that their
  1342   // backing scale factor may have changed. (Bug 822266)
  1343   ourShell->BackingScaleFactorChanged();
  1344   otherShell->BackingScaleFactorChanged();
  1346   ourParentDocument->FlushPendingNotifications(Flush_Layout);
  1347   otherParentDocument->FlushPendingNotifications(Flush_Layout);
  1349   FirePageShowEvent(ourDocshell, otherChromeEventHandler, true);
  1350   FirePageShowEvent(otherDocshell, ourChromeEventHandler, true);
  1352   mInSwap = aOther->mInSwap = false;
  1353   return NS_OK;
  1356 void
  1357 nsFrameLoader::DestroyChild()
  1359   if (mRemoteBrowser) {
  1360     mRemoteBrowser->SetOwnerElement(nullptr);
  1361     mRemoteBrowser->Destroy();
  1362     mRemoteBrowser = nullptr;
  1366 NS_IMETHODIMP
  1367 nsFrameLoader::Destroy()
  1369   if (mDestroyCalled) {
  1370     return NS_OK;
  1372   mDestroyCalled = true;
  1374   if (mMessageManager) {
  1375     mMessageManager->Disconnect();
  1377   if (mChildMessageManager) {
  1378     static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get())->Disconnect();
  1381   nsCOMPtr<nsIDocument> doc;
  1382   bool dynamicSubframeRemoval = false;
  1383   if (mOwnerContent) {
  1384     doc = mOwnerContent->OwnerDoc();
  1385     dynamicSubframeRemoval = !mIsTopLevelContent && !doc->InUnlinkOrDeletion();
  1386     doc->SetSubDocumentFor(mOwnerContent, nullptr);
  1388     SetOwnerContent(nullptr);
  1390   DestroyChild();
  1392   // Seems like this is a dynamic frame removal.
  1393   if (dynamicSubframeRemoval) {
  1394     if (mDocShell) {
  1395       mDocShell->RemoveFromSessionHistory();
  1399   // Let the tree owner know we're gone.
  1400   if (mIsTopLevelContent) {
  1401     if (mDocShell) {
  1402       nsCOMPtr<nsIDocShellTreeItem> parentItem;
  1403       mDocShell->GetParent(getter_AddRefs(parentItem));
  1404       nsCOMPtr<nsIDocShellTreeOwner> owner = do_GetInterface(parentItem);
  1405       if (owner) {
  1406         owner->ContentShellRemoved(mDocShell);
  1411   // Let our window know that we are gone
  1412   nsCOMPtr<nsPIDOMWindow> win_private(do_GetInterface(mDocShell));
  1413   if (win_private) {
  1414     win_private->SetFrameElementInternal(nullptr);
  1417   if ((mNeedsAsyncDestroy || !doc ||
  1418        NS_FAILED(doc->FinalizeFrameLoader(this))) && mDocShell) {
  1419     nsCOMPtr<nsIRunnable> event = new nsAsyncDocShellDestroyer(mDocShell);
  1420     NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
  1421     NS_DispatchToCurrentThread(event);
  1423     // Let go of our docshell now that the async destroyer holds on to
  1424     // the docshell.
  1426     mDocShell = nullptr;
  1429   // NOTE: 'this' may very well be gone by now.
  1431   return NS_OK;
  1434 NS_IMETHODIMP
  1435 nsFrameLoader::GetDepthTooGreat(bool* aDepthTooGreat)
  1437   *aDepthTooGreat = mDepthTooGreat;
  1438   return NS_OK;
  1441 void
  1442 nsFrameLoader::SetOwnerContent(Element* aContent)
  1444   if (mObservingOwnerContent) {
  1445     mObservingOwnerContent = false;
  1446     mOwnerContent->RemoveMutationObserver(this);
  1448   mOwnerContent = aContent;
  1449   if (RenderFrameParent* rfp = GetCurrentRemoteFrame()) {
  1450     rfp->OwnerContentChanged(aContent);
  1453   ResetPermissionManagerStatus();
  1456 bool
  1457 nsFrameLoader::OwnerIsBrowserOrAppFrame()
  1459   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
  1460   return browserFrame ? browserFrame->GetReallyIsBrowserOrApp() : false;
  1463 // The xpcom getter version
  1464 NS_IMETHODIMP
  1465 nsFrameLoader::GetOwnerIsBrowserOrAppFrame(bool* aResult)
  1467   *aResult = OwnerIsBrowserOrAppFrame();
  1468   return NS_OK;
  1471 bool
  1472 nsFrameLoader::OwnerIsAppFrame()
  1474   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
  1475   return browserFrame ? browserFrame->GetReallyIsApp() : false;
  1478 bool
  1479 nsFrameLoader::OwnerIsBrowserFrame()
  1481   return OwnerIsBrowserOrAppFrame() && !OwnerIsAppFrame();
  1484 void
  1485 nsFrameLoader::GetOwnerAppManifestURL(nsAString& aOut)
  1487   aOut.Truncate();
  1488   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
  1489   if (browserFrame) {
  1490     browserFrame->GetAppManifestURL(aOut);
  1494 already_AddRefed<mozIApplication>
  1495 nsFrameLoader::GetOwnApp()
  1497   nsAutoString manifest;
  1498   GetOwnerAppManifestURL(manifest);
  1499   if (manifest.IsEmpty()) {
  1500     return nullptr;
  1503   nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
  1504   NS_ENSURE_TRUE(appsService, nullptr);
  1506   nsCOMPtr<mozIApplication> app;
  1507   appsService->GetAppByManifestURL(manifest, getter_AddRefs(app));
  1509   return app.forget();
  1512 already_AddRefed<mozIApplication>
  1513 nsFrameLoader::GetContainingApp()
  1515   // See if our owner content's principal has an associated app.
  1516   uint32_t appId = mOwnerContent->NodePrincipal()->GetAppId();
  1517   MOZ_ASSERT(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
  1519   if (appId == nsIScriptSecurityManager::NO_APP_ID ||
  1520       appId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
  1521     return nullptr;
  1524   nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
  1525   NS_ENSURE_TRUE(appsService, nullptr);
  1527   nsCOMPtr<mozIApplication> app;
  1528   appsService->GetAppByLocalId(appId, getter_AddRefs(app));
  1530   return app.forget();
  1533 bool
  1534 nsFrameLoader::ShouldUseRemoteProcess()
  1536   if (PR_GetEnv("MOZ_DISABLE_OOP_TABS") ||
  1537       Preferences::GetBool("dom.ipc.tabs.disabled", false)) {
  1538     return false;
  1541   // If we're inside a content process, don't use a remote process for this
  1542   // frame; it won't work properly until bug 761935 is fixed.
  1543   if (XRE_GetProcessType() == GeckoProcessType_Content) {
  1544     return false;
  1547   // If we're an <iframe mozbrowser> and we don't have a "remote" attribute,
  1548   // fall back to the default.
  1549   if (OwnerIsBrowserOrAppFrame() &&
  1550       !mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::Remote)) {
  1552     return Preferences::GetBool("dom.ipc.browser_frames.oop_by_default", false);
  1555   // Otherwise, we're remote if we have "remote=true" and we're either a
  1556   // browser frame or a XUL element.
  1557   return (OwnerIsBrowserOrAppFrame() ||
  1558           mOwnerContent->GetNameSpaceID() == kNameSpaceID_XUL) &&
  1559          mOwnerContent->AttrValueIs(kNameSpaceID_None,
  1560                                     nsGkAtoms::Remote,
  1561                                     nsGkAtoms::_true,
  1562                                     eCaseMatters);
  1565 nsresult
  1566 nsFrameLoader::MaybeCreateDocShell()
  1568   if (mDocShell) {
  1569     return NS_OK;
  1571   if (mRemoteFrame) {
  1572     return NS_OK;
  1574   NS_ENSURE_STATE(!mDestroyCalled);
  1576   if (ShouldUseRemoteProcess()) {
  1577     mRemoteFrame = true;
  1578     return NS_OK;
  1581   // Get our parent docshell off the document of mOwnerContent
  1582   // XXXbz this is such a total hack.... We really need to have a
  1583   // better setup for doing this.
  1584   nsIDocument* doc = mOwnerContent->OwnerDoc();
  1585   if (!(doc->IsStaticDocument() || mOwnerContent->IsInDoc())) {
  1586     return NS_ERROR_UNEXPECTED;
  1589   if (doc->IsResourceDoc() || !doc->IsActive()) {
  1590     // Don't allow subframe loads in resource documents, nor
  1591     // in non-active documents.
  1592     return NS_ERROR_NOT_AVAILABLE;
  1595   nsCOMPtr<nsIDocShell> docShell = doc->GetDocShell();
  1596   nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_QueryInterface(docShell);
  1597   NS_ENSURE_STATE(parentAsWebNav);
  1599   // Create the docshell...
  1600   mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
  1601   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
  1603   // Apply sandbox flags even if our owner is not an iframe, as this copies
  1604   // flags from our owning content's owning document.
  1605   uint32_t sandboxFlags = 0;
  1606   HTMLIFrameElement* iframe = HTMLIFrameElement::FromContent(mOwnerContent);
  1607   if (iframe) {
  1608     sandboxFlags = iframe->GetSandboxFlags();
  1610   ApplySandboxFlags(sandboxFlags);
  1612   if (!mNetworkCreated) {
  1613     if (mDocShell) {
  1614       mDocShell->SetCreatedDynamically(true);
  1618   // Get the frame name and tell the docshell about it.
  1619   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
  1620   nsAutoString frameName;
  1622   int32_t namespaceID = mOwnerContent->GetNameSpaceID();
  1623   if (namespaceID == kNameSpaceID_XHTML && !mOwnerContent->IsInHTMLDocument()) {
  1624     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
  1625   } else {
  1626     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, frameName);
  1627     // XXX if no NAME then use ID, after a transition period this will be
  1628     // changed so that XUL only uses ID too (bug 254284).
  1629     if (frameName.IsEmpty() && namespaceID == kNameSpaceID_XUL) {
  1630       mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
  1634   if (!frameName.IsEmpty()) {
  1635     mDocShell->SetName(frameName);
  1638   // Inform our docShell that it has a new child.
  1639   // Note: This logic duplicates a lot of logic in
  1640   // nsSubDocumentFrame::AttributeChanged.  We should fix that.
  1642   int32_t parentType = docShell->ItemType();
  1644   // XXXbz why is this in content code, exactly?  We should handle
  1645   // this some other way.....  Not sure how yet.
  1646   nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
  1647   docShell->GetTreeOwner(getter_AddRefs(parentTreeOwner));
  1648   NS_ENSURE_STATE(parentTreeOwner);
  1649   mIsTopLevelContent =
  1650     AddTreeItemToTreeOwner(mDocShell, parentTreeOwner, parentType, docShell);
  1652   // Make sure all shells have links back to the content element
  1653   // in the nearest enclosing chrome shell.
  1654   nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
  1656   if (parentType == nsIDocShellTreeItem::typeChrome) {
  1657     // Our parent shell is a chrome shell. It is therefore our nearest
  1658     // enclosing chrome shell.
  1660     chromeEventHandler = do_QueryInterface(mOwnerContent);
  1661     NS_ASSERTION(chromeEventHandler,
  1662                  "This mContent should implement this.");
  1663   } else {
  1664     // Our parent shell is a content shell. Get the chrome event
  1665     // handler from it and use that for our shell as well.
  1667     docShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
  1670   mDocShell->SetChromeEventHandler(chromeEventHandler);
  1672   // This is nasty, this code (the do_GetInterface(mDocShell) below)
  1673   // *must* come *after* the above call to
  1674   // mDocShell->SetChromeEventHandler() for the global window to get
  1675   // the right chrome event handler.
  1677   // Tell the window about the frame that hosts it.
  1678   nsCOMPtr<Element> frame_element = mOwnerContent;
  1679   NS_ASSERTION(frame_element, "frame loader owner element not a DOM element!");
  1681   nsCOMPtr<nsPIDOMWindow> win_private(do_GetInterface(mDocShell));
  1682   nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell));
  1683   if (win_private) {
  1684     win_private->SetFrameElementInternal(frame_element);
  1687   // This is kinda whacky, this call doesn't really create anything,
  1688   // but it must be called to make sure things are properly
  1689   // initialized.
  1690   if (NS_FAILED(base_win->Create()) || !win_private) {
  1691     // Do not call Destroy() here. See bug 472312.
  1692     NS_WARNING("Something wrong when creating the docshell for a frameloader!");
  1693     return NS_ERROR_FAILURE;
  1696   if (mIsTopLevelContent &&
  1697       mOwnerContent->IsXUL(nsGkAtoms::browser) &&
  1698       !mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::disablehistory)) {
  1699     nsresult rv;
  1700     nsCOMPtr<nsISHistory> sessionHistory =
  1701       do_CreateInstance(NS_SHISTORY_CONTRACTID, &rv);
  1702     NS_ENSURE_SUCCESS(rv, rv);
  1704     nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
  1705     webNav->SetSessionHistory(sessionHistory);
  1708   EnsureMessageManager();
  1710   if (OwnerIsAppFrame()) {
  1711     // You can't be both an app and a browser frame.
  1712     MOZ_ASSERT(!OwnerIsBrowserFrame());
  1714     nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
  1715     MOZ_ASSERT(ownApp);
  1716     uint32_t ownAppId = nsIScriptSecurityManager::NO_APP_ID;
  1717     if (ownApp) {
  1718       NS_ENSURE_SUCCESS(ownApp->GetLocalId(&ownAppId), NS_ERROR_FAILURE);
  1721     mDocShell->SetIsApp(ownAppId);
  1724   if (OwnerIsBrowserFrame()) {
  1725     // You can't be both a browser and an app frame.
  1726     MOZ_ASSERT(!OwnerIsAppFrame());
  1728     nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
  1729     uint32_t containingAppId = nsIScriptSecurityManager::NO_APP_ID;
  1730     if (containingApp) {
  1731       NS_ENSURE_SUCCESS(containingApp->GetLocalId(&containingAppId),
  1732                         NS_ERROR_FAILURE);
  1734     mDocShell->SetIsBrowserInsideApp(containingAppId);
  1737   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
  1738   if (os) {
  1739     os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
  1740                         "inprocess-browser-shown", nullptr);
  1743   if (OwnerIsBrowserOrAppFrame() && mMessageManager) {
  1744     mMessageManager->LoadFrameScript(
  1745       NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js"),
  1746       /* allowDelayedLoad = */ true,
  1747       /* aRunInGlobalScope */ true);
  1750   return NS_OK;
  1753 void
  1754 nsFrameLoader::GetURL(nsString& aURI)
  1756   aURI.Truncate();
  1758   if (mOwnerContent->Tag() == nsGkAtoms::object) {
  1759     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, aURI);
  1760   } else {
  1761     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, aURI);
  1765 nsresult
  1766 nsFrameLoader::CheckForRecursiveLoad(nsIURI* aURI)
  1768   nsresult rv;
  1770   mDepthTooGreat = false;
  1771   rv = MaybeCreateDocShell();
  1772   if (NS_FAILED(rv)) {
  1773     return rv;
  1775   NS_ASSERTION(!mRemoteFrame,
  1776                "Shouldn't call CheckForRecursiveLoad on remote frames.");
  1777   if (!mDocShell) {
  1778     return NS_ERROR_FAILURE;
  1781   // Check that we're still in the docshell tree.
  1782   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
  1783   mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
  1784   NS_WARN_IF_FALSE(treeOwner,
  1785                    "Trying to load a new url to a docshell without owner!");
  1786   NS_ENSURE_STATE(treeOwner);
  1788   if (mDocShell->ItemType() != nsIDocShellTreeItem::typeContent) {
  1789     // No need to do recursion-protection here XXXbz why not??  Do we really
  1790     // trust people not to screw up with non-content docshells?
  1791     return NS_OK;
  1794   // Bug 8065: Don't exceed some maximum depth in content frames
  1795   // (MAX_DEPTH_CONTENT_FRAMES)
  1796   nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
  1797   mDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem));
  1798   int32_t depth = 0;
  1799   while (parentAsItem) {
  1800     ++depth;
  1802     if (depth >= MAX_DEPTH_CONTENT_FRAMES) {
  1803       mDepthTooGreat = true;
  1804       NS_WARNING("Too many nested content frames so giving up");
  1806       return NS_ERROR_UNEXPECTED; // Too deep, give up!  (silently?)
  1809     nsCOMPtr<nsIDocShellTreeItem> temp;
  1810     temp.swap(parentAsItem);
  1811     temp->GetSameTypeParent(getter_AddRefs(parentAsItem));
  1814   // Bug 136580: Check for recursive frame loading excluding about:srcdoc URIs.
  1815   // srcdoc URIs require their contents to be specified inline, so it isn't
  1816   // possible for undesirable recursion to occur without the aid of a
  1817   // non-srcdoc URI,  which this method will block normally.
  1818   // Besides, URI is not enough to guarantee uniqueness of srcdoc documents.
  1819   nsAutoCString buffer;
  1820   rv = aURI->GetScheme(buffer);
  1821   if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("about")) {
  1822     rv = aURI->GetPath(buffer);
  1823     if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("srcdoc")) {
  1824       // Duplicates allowed up to depth limits
  1825       return NS_OK;
  1828   int32_t matchCount = 0;
  1829   mDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem));
  1830   while (parentAsItem) {
  1831     // Check the parent URI with the URI we're loading
  1832     nsCOMPtr<nsIWebNavigation> parentAsNav(do_QueryInterface(parentAsItem));
  1833     if (parentAsNav) {
  1834       // Does the URI match the one we're about to load?
  1835       nsCOMPtr<nsIURI> parentURI;
  1836       parentAsNav->GetCurrentURI(getter_AddRefs(parentURI));
  1837       if (parentURI) {
  1838         // Bug 98158/193011: We need to ignore data after the #
  1839         bool equal;
  1840         rv = aURI->EqualsExceptRef(parentURI, &equal);
  1841         NS_ENSURE_SUCCESS(rv, rv);
  1843         if (equal) {
  1844           matchCount++;
  1845           if (matchCount >= MAX_SAME_URL_CONTENT_FRAMES) {
  1846             NS_WARNING("Too many nested content frames have the same url (recursion?) so giving up");
  1847             return NS_ERROR_UNEXPECTED;
  1852     nsCOMPtr<nsIDocShellTreeItem> temp;
  1853     temp.swap(parentAsItem);
  1854     temp->GetSameTypeParent(getter_AddRefs(parentAsItem));
  1857   return NS_OK;
  1860 nsresult
  1861 nsFrameLoader::GetWindowDimensions(nsRect& aRect)
  1863   // Need to get outer window position here
  1864   nsIDocument* doc = mOwnerContent->GetDocument();
  1865   if (!doc) {
  1866     return NS_ERROR_FAILURE;
  1869   if (doc->IsResourceDoc()) {
  1870     return NS_ERROR_FAILURE;
  1873   nsCOMPtr<nsIWebNavigation> parentAsWebNav =
  1874     do_GetInterface(doc->GetWindow());
  1876   if (!parentAsWebNav) {
  1877     return NS_ERROR_FAILURE;
  1880   nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsWebNav));
  1882   nsCOMPtr<nsIDocShellTreeOwner> parentOwner;
  1883   if (NS_FAILED(parentAsItem->GetTreeOwner(getter_AddRefs(parentOwner))) ||
  1884       !parentOwner) {
  1885     return NS_ERROR_FAILURE;
  1888   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_GetInterface(parentOwner));
  1889   treeOwnerAsWin->GetPosition(&aRect.x, &aRect.y);
  1890   treeOwnerAsWin->GetSize(&aRect.width, &aRect.height);
  1891   return NS_OK;
  1894 NS_IMETHODIMP
  1895 nsFrameLoader::UpdatePositionAndSize(nsSubDocumentFrame *aIFrame)
  1897   if (mRemoteFrame) {
  1898     if (mRemoteBrowser) {
  1899       nsIntSize size = aIFrame->GetSubdocumentSize();
  1900       nsRect dimensions;
  1901       NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), NS_ERROR_FAILURE);
  1902       mRemoteBrowser->UpdateDimensions(dimensions, size);
  1904     return NS_OK;
  1906   return UpdateBaseWindowPositionAndSize(aIFrame);
  1909 nsresult
  1910 nsFrameLoader::UpdateBaseWindowPositionAndSize(nsSubDocumentFrame *aIFrame)
  1912   nsCOMPtr<nsIDocShell> docShell;
  1913   GetDocShell(getter_AddRefs(docShell));
  1914   nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
  1916   // resize the sub document
  1917   if (baseWindow) {
  1918     int32_t x = 0;
  1919     int32_t y = 0;
  1921     nsWeakFrame weakFrame(aIFrame);
  1923     baseWindow->GetPositionAndSize(&x, &y, nullptr, nullptr);
  1925     if (!weakFrame.IsAlive()) {
  1926       // GetPositionAndSize() killed us
  1927       return NS_OK;
  1930     nsIntSize size = aIFrame->GetSubdocumentSize();
  1932     baseWindow->SetPositionAndSize(x, y, size.width, size.height, false);
  1935   return NS_OK;
  1938 NS_IMETHODIMP
  1939 nsFrameLoader::GetRenderMode(uint32_t* aRenderMode)
  1941   *aRenderMode = mRenderMode;
  1942   return NS_OK;
  1945 NS_IMETHODIMP
  1946 nsFrameLoader::SetRenderMode(uint32_t aRenderMode)
  1948   if (aRenderMode == mRenderMode) {
  1949     return NS_OK;
  1952   mRenderMode = aRenderMode;
  1953   return NS_OK;
  1956 NS_IMETHODIMP
  1957 nsFrameLoader::GetEventMode(uint32_t* aEventMode)
  1959   *aEventMode = mEventMode;
  1960   return NS_OK;
  1963 NS_IMETHODIMP
  1964 nsFrameLoader::SetEventMode(uint32_t aEventMode)
  1966   mEventMode = aEventMode;
  1967   return NS_OK;
  1970 NS_IMETHODIMP
  1971 nsFrameLoader::GetClipSubdocument(bool* aResult)
  1973   *aResult = mClipSubdocument;
  1974   return NS_OK;
  1977 NS_IMETHODIMP
  1978 nsFrameLoader::SetClipSubdocument(bool aClip)
  1980   mClipSubdocument = aClip;
  1981   nsIFrame* frame = GetPrimaryFrameOfOwningContent();
  1982   if (frame) {
  1983     frame->InvalidateFrame();
  1984     frame->PresContext()->PresShell()->
  1985       FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
  1986     nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);
  1987     if (subdocFrame) {
  1988       nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame();
  1989       if (subdocRootFrame) {
  1990         nsIFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()->
  1991           GetRootScrollFrame();
  1992         if (subdocRootScrollFrame) {
  1993           frame->PresContext()->PresShell()->
  1994             FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
  1999   return NS_OK;
  2002 NS_IMETHODIMP
  2003 nsFrameLoader::GetClampScrollPosition(bool* aResult)
  2005   *aResult = mClampScrollPosition;
  2006   return NS_OK;
  2009 NS_IMETHODIMP
  2010 nsFrameLoader::SetClampScrollPosition(bool aClamp)
  2012   mClampScrollPosition = aClamp;
  2014   // When turning clamping on, make sure the current position is clamped.
  2015   if (aClamp) {
  2016     nsIFrame* frame = GetPrimaryFrameOfOwningContent();
  2017     nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);
  2018     if (subdocFrame) {
  2019       nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame();
  2020       if (subdocRootFrame) {
  2021         nsIScrollableFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()->
  2022           GetRootScrollFrameAsScrollable();
  2023         if (subdocRootScrollFrame) {
  2024           subdocRootScrollFrame->ScrollTo(subdocRootScrollFrame->GetScrollPosition(), nsIScrollableFrame::INSTANT);
  2029   return NS_OK;
  2032 bool
  2033 nsFrameLoader::TryRemoteBrowser()
  2035   NS_ASSERTION(!mRemoteBrowser, "TryRemoteBrowser called with a remote browser already?");
  2037   nsIDocument* doc = mOwnerContent->GetDocument();
  2038   if (!doc) {
  2039     return false;
  2042   if (doc->IsResourceDoc()) {
  2043     // Don't allow subframe loads in external reference documents
  2044     return false;
  2047   nsCOMPtr<nsIWebNavigation> parentAsWebNav =
  2048     do_GetInterface(doc->GetWindow());
  2050   if (!parentAsWebNav) {
  2051     return false;
  2054   nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsWebNav));
  2056   // <iframe mozbrowser> gets to skip these checks.
  2057   if (!OwnerIsBrowserOrAppFrame()) {
  2058     if (parentAsItem->ItemType() != nsIDocShellTreeItem::typeChrome) {
  2059       return false;
  2062     if (!mOwnerContent->IsXUL()) {
  2063       return false;
  2066     nsAutoString value;
  2067     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
  2069     if (!value.LowerCaseEqualsLiteral("content") &&
  2070         !StringBeginsWith(value, NS_LITERAL_STRING("content-"),
  2071                           nsCaseInsensitiveStringComparator())) {
  2072       return false;
  2076   uint32_t chromeFlags = 0;
  2077   nsCOMPtr<nsIDocShellTreeOwner> parentOwner;
  2078   if (NS_FAILED(parentAsItem->GetTreeOwner(getter_AddRefs(parentOwner))) ||
  2079       !parentOwner) {
  2080     return false;
  2082   nsCOMPtr<nsIXULWindow> window(do_GetInterface(parentOwner));
  2083   if (!window) {
  2084     return false;
  2086   if (NS_FAILED(window->GetChromeFlags(&chromeFlags))) {
  2087     return false;
  2090   PROFILER_LABEL("nsFrameLoader", "CreateRemoteBrowser");
  2092   MutableTabContext context;
  2093   nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
  2094   nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
  2095   ScrollingBehavior scrollingBehavior = DEFAULT_SCROLLING;
  2097   if (Preferences::GetBool("dom.browser_frames.useAsyncPanZoom", false) ||
  2098       mOwnerContent->AttrValueIs(kNameSpaceID_None,
  2099                                  nsGkAtoms::mozasyncpanzoom,
  2100                                  nsGkAtoms::_true,
  2101                                  eCaseMatters)) {
  2102     scrollingBehavior = ASYNC_PAN_ZOOM;
  2105   bool rv = true;
  2106   if (ownApp) {
  2107     rv = context.SetTabContextForAppFrame(ownApp, containingApp, scrollingBehavior);
  2108   } else if (OwnerIsBrowserFrame()) {
  2109     // The |else| above is unnecessary; OwnerIsBrowserFrame() implies !ownApp.
  2110     rv = context.SetTabContextForBrowserFrame(containingApp, scrollingBehavior);
  2111   } else {
  2112     rv = context.SetTabContextForNormalFrame(scrollingBehavior);
  2114   NS_ENSURE_TRUE(rv, false);
  2116   nsCOMPtr<Element> ownerElement = mOwnerContent;
  2117   mRemoteBrowser = ContentParent::CreateBrowserOrApp(context, ownerElement);
  2118   if (mRemoteBrowser) {
  2119     mChildID = mRemoteBrowser->Manager()->ChildID();
  2120     nsCOMPtr<nsIDocShellTreeItem> rootItem;
  2121     parentAsItem->GetRootTreeItem(getter_AddRefs(rootItem));
  2122     nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
  2123     nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin);
  2124     NS_ABORT_IF_FALSE(rootChromeWin, "How did we not get a chrome window here?");
  2126     nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
  2127     rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
  2128     mRemoteBrowser->SetBrowserDOMWindow(browserDOMWin);
  2130     mContentParent = mRemoteBrowser->Manager();
  2132     if (mOwnerContent->AttrValueIs(kNameSpaceID_None,
  2133                                    nsGkAtoms::mozpasspointerevents,
  2134                                    nsGkAtoms::_true,
  2135                                    eCaseMatters)) {
  2136       unused << mRemoteBrowser->SendSetUpdateHitRegion(true);
  2139   return true;
  2142 mozilla::dom::PBrowserParent*
  2143 nsFrameLoader::GetRemoteBrowser()
  2145   return mRemoteBrowser;
  2148 NS_IMETHODIMP
  2149 nsFrameLoader::ActivateRemoteFrame() {
  2150   if (mRemoteBrowser) {
  2151     mRemoteBrowser->Activate();
  2152     return NS_OK;
  2154   return NS_ERROR_UNEXPECTED;
  2157 NS_IMETHODIMP
  2158 nsFrameLoader::DeactivateRemoteFrame() {
  2159   if (mRemoteBrowser) {
  2160     mRemoteBrowser->Deactivate();
  2161     return NS_OK;
  2163   return NS_ERROR_UNEXPECTED;
  2166 NS_IMETHODIMP
  2167 nsFrameLoader::SendCrossProcessMouseEvent(const nsAString& aType,
  2168                                           float aX,
  2169                                           float aY,
  2170                                           int32_t aButton,
  2171                                           int32_t aClickCount,
  2172                                           int32_t aModifiers,
  2173                                           bool aIgnoreRootScrollFrame)
  2175   if (mRemoteBrowser) {
  2176     mRemoteBrowser->SendMouseEvent(aType, aX, aY, aButton,
  2177                                    aClickCount, aModifiers,
  2178                                    aIgnoreRootScrollFrame);
  2179     return NS_OK;
  2181   return NS_ERROR_FAILURE;
  2184 NS_IMETHODIMP
  2185 nsFrameLoader::ActivateFrameEvent(const nsAString& aType,
  2186                                   bool aCapture)
  2188   if (mRemoteBrowser) {
  2189     return mRemoteBrowser->SendActivateFrameEvent(nsString(aType), aCapture) ?
  2190       NS_OK : NS_ERROR_NOT_AVAILABLE;
  2192   return NS_ERROR_FAILURE;
  2195 NS_IMETHODIMP
  2196 nsFrameLoader::SendCrossProcessKeyEvent(const nsAString& aType,
  2197                                         int32_t aKeyCode,
  2198                                         int32_t aCharCode,
  2199                                         int32_t aModifiers,
  2200                                         bool aPreventDefault)
  2202   if (mRemoteBrowser) {
  2203     mRemoteBrowser->SendKeyEvent(aType, aKeyCode, aCharCode, aModifiers,
  2204                                  aPreventDefault);
  2205     return NS_OK;
  2207   return NS_ERROR_FAILURE;
  2210 nsresult
  2211 nsFrameLoader::CreateStaticClone(nsIFrameLoader* aDest)
  2213   nsFrameLoader* dest = static_cast<nsFrameLoader*>(aDest);
  2214   dest->MaybeCreateDocShell();
  2215   NS_ENSURE_STATE(dest->mDocShell);
  2217   nsCOMPtr<nsIDocument> dummy = do_GetInterface(dest->mDocShell);
  2218   nsCOMPtr<nsIContentViewer> viewer;
  2219   dest->mDocShell->GetContentViewer(getter_AddRefs(viewer));
  2220   NS_ENSURE_STATE(viewer);
  2222   nsCOMPtr<nsIDocShell> origDocShell;
  2223   GetDocShell(getter_AddRefs(origDocShell));
  2224   nsCOMPtr<nsIDocument> doc = do_GetInterface(origDocShell);
  2225   NS_ENSURE_STATE(doc);
  2226   nsCOMPtr<nsIDocument> clonedDoc = doc->CreateStaticClone(dest->mDocShell);
  2227   nsCOMPtr<nsIDOMDocument> clonedDOMDoc = do_QueryInterface(clonedDoc);
  2229   viewer->SetDOMDocument(clonedDOMDoc);
  2230   return NS_OK;
  2233 bool
  2234 nsFrameLoader::DoLoadFrameScript(const nsAString& aURL, bool aRunInGlobalScope)
  2236   mozilla::dom::PBrowserParent* tabParent = GetRemoteBrowser();
  2237   if (tabParent) {
  2238     return tabParent->SendLoadRemoteScript(nsString(aURL), aRunInGlobalScope);
  2240   nsRefPtr<nsInProcessTabChildGlobal> tabChild =
  2241     static_cast<nsInProcessTabChildGlobal*>(GetTabChildGlobalAsEventTarget());
  2242   if (tabChild) {
  2243     tabChild->LoadFrameScript(aURL, aRunInGlobalScope);
  2245   return true;
  2248 class nsAsyncMessageToChild : public nsSameProcessAsyncMessageBase,
  2249                               public nsRunnable
  2251 public:
  2252   nsAsyncMessageToChild(JSContext* aCx,
  2253                         nsFrameLoader* aFrameLoader,
  2254                         const nsAString& aMessage,
  2255                         const StructuredCloneData& aData,
  2256                         JS::Handle<JSObject *> aCpows,
  2257                         nsIPrincipal* aPrincipal)
  2258     : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal)
  2259     , mFrameLoader(aFrameLoader)
  2263   NS_IMETHOD Run()
  2265     nsInProcessTabChildGlobal* tabChild =
  2266       static_cast<nsInProcessTabChildGlobal*>(mFrameLoader->mChildMessageManager.get());
  2267     if (tabChild && tabChild->GetInnerManager()) {
  2268       nsCOMPtr<nsIXPConnectJSObjectHolder> kungFuDeathGrip(tabChild->GetGlobal());
  2269       ReceiveMessage(static_cast<EventTarget*>(tabChild),
  2270                      tabChild->GetInnerManager());
  2272     return NS_OK;
  2274   nsRefPtr<nsFrameLoader> mFrameLoader;
  2275 };
  2277 bool
  2278 nsFrameLoader::DoSendAsyncMessage(JSContext* aCx,
  2279                                   const nsAString& aMessage,
  2280                                   const StructuredCloneData& aData,
  2281                                   JS::Handle<JSObject *> aCpows,
  2282                                   nsIPrincipal* aPrincipal)
  2284   TabParent* tabParent = mRemoteBrowser;
  2285   if (tabParent) {
  2286     ClonedMessageData data;
  2287     ContentParent* cp = tabParent->Manager();
  2288     if (!BuildClonedMessageDataForParent(cp, aData, data)) {
  2289       return false;
  2291     InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
  2292     if (aCpows && !cp->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
  2293       return false;
  2295     return tabParent->SendAsyncMessage(nsString(aMessage), data, cpows,
  2296                                        aPrincipal);
  2299   if (mChildMessageManager) {
  2300     nsRefPtr<nsIRunnable> ev = new nsAsyncMessageToChild(aCx, this, aMessage,
  2301                                                          aData, aCpows,
  2302                                                          aPrincipal);
  2303     NS_DispatchToCurrentThread(ev);
  2304     return true;
  2307   // We don't have any targets to send our asynchronous message to.
  2308   return false;
  2311 bool
  2312 nsFrameLoader::CheckPermission(const nsAString& aPermission)
  2314   return AssertAppProcessPermission(GetRemoteBrowser(),
  2315                                     NS_ConvertUTF16toUTF8(aPermission).get());
  2318 bool
  2319 nsFrameLoader::CheckManifestURL(const nsAString& aManifestURL)
  2321   return AssertAppProcessManifestURL(GetRemoteBrowser(),
  2322                                      NS_ConvertUTF16toUTF8(aManifestURL).get());
  2325 bool
  2326 nsFrameLoader::CheckAppHasPermission(const nsAString& aPermission)
  2328   return AssertAppHasPermission(GetRemoteBrowser(),
  2329                                 NS_ConvertUTF16toUTF8(aPermission).get());
  2332 NS_IMETHODIMP
  2333 nsFrameLoader::GetMessageManager(nsIMessageSender** aManager)
  2335   EnsureMessageManager();
  2336   if (mMessageManager) {
  2337     CallQueryInterface(mMessageManager, aManager);
  2339   return NS_OK;
  2342 NS_IMETHODIMP
  2343 nsFrameLoader::GetContentViewsIn(float aXPx, float aYPx,
  2344                                  float aTopSize, float aRightSize,
  2345                                  float aBottomSize, float aLeftSize,
  2346                                  uint32_t* aLength,
  2347                                  nsIContentView*** aResult)
  2349   nscoord x = nsPresContext::CSSPixelsToAppUnits(aXPx - aLeftSize);
  2350   nscoord y = nsPresContext::CSSPixelsToAppUnits(aYPx - aTopSize);
  2351   nscoord w = nsPresContext::CSSPixelsToAppUnits(aLeftSize + aRightSize) + 1;
  2352   nscoord h = nsPresContext::CSSPixelsToAppUnits(aTopSize + aBottomSize) + 1;
  2353   nsRect target(x, y, w, h);
  2355   nsIFrame* frame = GetPrimaryFrameOfOwningContent();
  2357   nsTArray<ViewID> ids;
  2358   nsLayoutUtils::GetRemoteContentIds(frame, target, ids, true);
  2359   if (ids.Length() == 0 || !GetCurrentRemoteFrame()) {
  2360     *aResult = nullptr;
  2361     *aLength = 0;
  2362     return NS_OK;
  2365   nsIContentView** result = reinterpret_cast<nsIContentView**>(
  2366     NS_Alloc(ids.Length() * sizeof(nsIContentView*)));
  2368   for (uint32_t i = 0; i < ids.Length(); i++) {
  2369     nsIContentView* view = GetCurrentRemoteFrame()->GetContentView(ids[i]);
  2370     NS_ABORT_IF_FALSE(view, "Retrieved ID from RenderFrameParent, it should be valid!");
  2371     nsRefPtr<nsIContentView>(view).forget(&result[i]);
  2374   *aResult = result;
  2375   *aLength = ids.Length();
  2377   return NS_OK;
  2380 NS_IMETHODIMP
  2381 nsFrameLoader::GetRootContentView(nsIContentView** aContentView)
  2383   RenderFrameParent* rfp = GetCurrentRemoteFrame();
  2384   if (!rfp) {
  2385     *aContentView = nullptr;
  2386     return NS_OK;
  2389   nsContentView* view = rfp->GetRootContentView();
  2390   NS_ABORT_IF_FALSE(view, "Should always be able to create root scrollable!");
  2391   nsRefPtr<nsIContentView>(view).forget(aContentView);
  2393   return NS_OK;
  2396 nsresult
  2397 nsFrameLoader::EnsureMessageManager()
  2399   NS_ENSURE_STATE(mOwnerContent);
  2401   nsresult rv = MaybeCreateDocShell();
  2402   if (NS_FAILED(rv)) {
  2403     return rv;
  2406   if (!mIsTopLevelContent && !OwnerIsBrowserOrAppFrame() && !mRemoteFrame) {
  2407     return NS_OK;
  2410   if (mMessageManager) {
  2411     if (ShouldUseRemoteProcess() && mRemoteBrowserShown) {
  2412       mMessageManager->InitWithCallback(this);
  2414     return NS_OK;
  2417   nsIScriptContext* sctx = mOwnerContent->GetContextForEventHandlers(&rv);
  2418   NS_ENSURE_SUCCESS(rv, rv);
  2419   NS_ENSURE_STATE(sctx);
  2420   AutoPushJSContext cx(sctx->GetNativeContext());
  2421   NS_ENSURE_STATE(cx);
  2423   nsCOMPtr<nsIDOMChromeWindow> chromeWindow =
  2424     do_QueryInterface(GetOwnerDoc()->GetWindow());
  2425   nsCOMPtr<nsIMessageBroadcaster> parentManager;
  2426   if (chromeWindow) {
  2427     chromeWindow->GetMessageManager(getter_AddRefs(parentManager));
  2430   if (ShouldUseRemoteProcess()) {
  2431     mMessageManager = new nsFrameMessageManager(mRemoteBrowserShown ? this : nullptr,
  2432                                                 static_cast<nsFrameMessageManager*>(parentManager.get()),
  2433                                                 MM_CHROME);
  2434   } else {
  2435     mMessageManager = new nsFrameMessageManager(nullptr,
  2436                                                 static_cast<nsFrameMessageManager*>(parentManager.get()),
  2437                                                 MM_CHROME);
  2439     mChildMessageManager =
  2440       new nsInProcessTabChildGlobal(mDocShell, mOwnerContent, mMessageManager);
  2441     // Force pending frame scripts to be loaded.
  2442     mMessageManager->InitWithCallback(this);
  2444   return NS_OK;
  2447 EventTarget*
  2448 nsFrameLoader::GetTabChildGlobalAsEventTarget()
  2450   return static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get());
  2453 NS_IMETHODIMP
  2454 nsFrameLoader::GetOwnerElement(nsIDOMElement **aElement)
  2456   nsCOMPtr<nsIDOMElement> ownerElement = do_QueryInterface(mOwnerContent);
  2457   ownerElement.forget(aElement);
  2458   return NS_OK;
  2461 NS_IMETHODIMP
  2462 nsFrameLoader::GetChildID(uint64_t* aChildID)
  2464   *aChildID = mChildID;
  2465   return NS_OK;
  2468 void
  2469 nsFrameLoader::SetRemoteBrowser(nsITabParent* aTabParent)
  2471   MOZ_ASSERT(!mRemoteBrowser);
  2472   MOZ_ASSERT(!mCurrentRemoteFrame);
  2473   mRemoteFrame = true;
  2474   mRemoteBrowser = static_cast<TabParent*>(aTabParent);
  2475   mChildID = mRemoteBrowser ? mRemoteBrowser->Manager()->ChildID() : 0;
  2476   ShowRemoteFrame(nsIntSize(0, 0));
  2479 void
  2480 nsFrameLoader::SetDetachedSubdocView(nsView* aDetachedViews,
  2481                                      nsIDocument* aContainerDoc)
  2483   mDetachedSubdocViews = aDetachedViews;
  2484   mContainerDocWhileDetached = aContainerDoc;
  2487 nsView*
  2488 nsFrameLoader::GetDetachedSubdocView(nsIDocument** aContainerDoc) const
  2490   NS_IF_ADDREF(*aContainerDoc = mContainerDocWhileDetached);
  2491   return mDetachedSubdocViews;
  2494 void
  2495 nsFrameLoader::ApplySandboxFlags(uint32_t sandboxFlags)
  2497   if (mDocShell) {
  2498     uint32_t parentSandboxFlags = mOwnerContent->OwnerDoc()->GetSandboxFlags();
  2500     // The child can only add restrictions, never remove them.
  2501     sandboxFlags |= parentSandboxFlags;
  2502     mDocShell->SetSandboxFlags(sandboxFlags);
  2506 /* virtual */ void
  2507 nsFrameLoader::AttributeChanged(nsIDocument* aDocument,
  2508                                 mozilla::dom::Element* aElement,
  2509                                 int32_t      aNameSpaceID,
  2510                                 nsIAtom*     aAttribute,
  2511                                 int32_t      aModType)
  2513   MOZ_ASSERT(mObservingOwnerContent);
  2514   // TODO: Implement ContentShellAdded for remote browsers (bug 658304)
  2515   MOZ_ASSERT(!mRemoteBrowser);
  2517   if (aNameSpaceID != kNameSpaceID_None || aAttribute != TypeAttrName()) {
  2518     return;
  2521   if (aElement != mOwnerContent) {
  2522     return;
  2525   // Note: This logic duplicates a lot of logic in
  2526   // MaybeCreateDocshell.  We should fix that.
  2528   // Notify our enclosing chrome that our type has changed.  We only do this
  2529   // if our parent is chrome, since in all other cases we're random content
  2530   // subframes and the treeowner shouldn't worry about us.
  2531   if (!mDocShell) {
  2532     return;
  2535   nsCOMPtr<nsIDocShellTreeItem> parentItem;
  2536   mDocShell->GetParent(getter_AddRefs(parentItem));
  2537   if (!parentItem) {
  2538     return;
  2541   if (parentItem->ItemType() != nsIDocShellTreeItem::typeChrome) {
  2542     return;
  2545   nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
  2546   parentItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
  2547   if (!parentTreeOwner) {
  2548     return;
  2551   nsAutoString value;
  2552   aElement->GetAttr(kNameSpaceID_None, TypeAttrName(), value);
  2554   bool is_primary = value.LowerCaseEqualsLiteral("content-primary");
  2556 #ifdef MOZ_XUL
  2557   // when a content panel is no longer primary, hide any open popups it may have
  2558   if (!is_primary) {
  2559     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
  2560     if (pm)
  2561       pm->HidePopupsInDocShell(mDocShell);
  2563 #endif
  2565   parentTreeOwner->ContentShellRemoved(mDocShell);
  2566   if (value.LowerCaseEqualsLiteral("content") ||
  2567       StringBeginsWith(value, NS_LITERAL_STRING("content-"),
  2568                        nsCaseInsensitiveStringComparator())) {
  2569     bool is_targetable = is_primary ||
  2570       value.LowerCaseEqualsLiteral("content-targetable");
  2572     parentTreeOwner->ContentShellAdded(mDocShell, is_primary,
  2573                                        is_targetable, value);
  2577 void
  2578 nsFrameLoader::ResetPermissionManagerStatus()
  2580   // The resetting of the permissions status can run only
  2581   // in the main process.
  2582   if (XRE_GetProcessType() == GeckoProcessType_Content) {
  2583     return;
  2586   // Finding the new app Id:
  2587   // . first we check if the owner is an app frame
  2588   // . second, we check if the owner is a browser frame
  2589   // in both cases we populate the appId variable.
  2590   uint32_t appId = nsIScriptSecurityManager::NO_APP_ID;
  2591   if (OwnerIsAppFrame()) {
  2592     // You can't be both an app and a browser frame.
  2593     MOZ_ASSERT(!OwnerIsBrowserFrame());
  2595     nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
  2596     MOZ_ASSERT(ownApp);
  2597     uint32_t ownAppId = nsIScriptSecurityManager::NO_APP_ID;
  2598     if (ownApp && NS_SUCCEEDED(ownApp->GetLocalId(&ownAppId))) {
  2599       appId = ownAppId;
  2603   if (OwnerIsBrowserFrame()) {
  2604     // You can't be both a browser and an app frame.
  2605     MOZ_ASSERT(!OwnerIsAppFrame());
  2607     nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
  2608     uint32_t containingAppId = nsIScriptSecurityManager::NO_APP_ID;
  2609     if (containingApp && NS_SUCCEEDED(containingApp->GetLocalId(&containingAppId))) {
  2610       appId = containingAppId;
  2614   // Nothing changed.
  2615   if (appId == mAppIdSentToPermissionManager) {
  2616     return;
  2619   nsCOMPtr<nsIPermissionManager> permMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
  2620   if (!permMgr) {
  2621     NS_ERROR("No PermissionManager available!");
  2622     return;
  2625   // If previously we registered an appId, we have to unregister it.
  2626   if (mAppIdSentToPermissionManager != nsIScriptSecurityManager::NO_APP_ID) {
  2627     permMgr->ReleaseAppId(mAppIdSentToPermissionManager);
  2628     mAppIdSentToPermissionManager = nsIScriptSecurityManager::NO_APP_ID;
  2631   // Register the new AppId.
  2632   if (appId != nsIScriptSecurityManager::NO_APP_ID) {
  2633     mAppIdSentToPermissionManager = appId;
  2634     permMgr->AddrefAppId(mAppIdSentToPermissionManager);
  2638 /* [infallible] */ NS_IMETHODIMP
  2639 nsFrameLoader::SetVisible(bool aVisible)
  2641   if (mVisible == aVisible) {
  2642     return NS_OK;
  2645   mVisible = aVisible;
  2646   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
  2647   if (os) {
  2648     os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
  2649                         "frameloader-visible-changed", nullptr);
  2651   return NS_OK;
  2654 /* [infallible] */ NS_IMETHODIMP
  2655 nsFrameLoader::GetVisible(bool* aVisible)
  2657   *aVisible = mVisible;
  2658   return NS_OK;
  2661 NS_IMETHODIMP
  2662 nsFrameLoader::GetTabParent(nsITabParent** aTabParent)
  2664   nsCOMPtr<nsITabParent> tp = mRemoteBrowser;
  2665   tp.forget(aTabParent);
  2666   return NS_OK;
  2669 NS_IMETHODIMP
  2670 nsFrameLoader::GetLoadContext(nsILoadContext** aLoadContext)
  2672   nsCOMPtr<nsILoadContext> loadContext;
  2673   if (mRemoteBrowser) {
  2674     loadContext = mRemoteBrowser->GetLoadContext();
  2675   } else {
  2676     nsCOMPtr<nsIDocShell> docShell;
  2677     GetDocShell(getter_AddRefs(docShell));
  2678     loadContext = do_GetInterface(docShell);
  2680   loadContext.forget(aLoadContext);
  2681   return NS_OK;

mercurial