content/base/src/nsFrameLoader.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/base/src/nsFrameLoader.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2682 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 sw=2 et tw=78: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/*
    1.11 + * Class for managing loading of a subframe (creation of the docshell,
    1.12 + * handling of loads in it, recursion-checking).
    1.13 + */
    1.14 +
    1.15 +#include "base/basictypes.h"
    1.16 +
    1.17 +#include "prenv.h"
    1.18 +
    1.19 +#include "mozIApplication.h"
    1.20 +#include "nsIDOMHTMLIFrameElement.h"
    1.21 +#include "nsIDOMHTMLFrameElement.h"
    1.22 +#include "nsIDOMMozBrowserFrame.h"
    1.23 +#include "nsIDOMWindow.h"
    1.24 +#include "nsIPresShell.h"
    1.25 +#include "nsIContentInlines.h"
    1.26 +#include "nsIContentViewer.h"
    1.27 +#include "nsIDocument.h"
    1.28 +#include "nsIDOMDocument.h"
    1.29 +#include "nsIDOMFile.h"
    1.30 +#include "nsPIDOMWindow.h"
    1.31 +#include "nsIWebNavigation.h"
    1.32 +#include "nsIWebProgress.h"
    1.33 +#include "nsIDocShell.h"
    1.34 +#include "nsIDocShellTreeOwner.h"
    1.35 +#include "nsIDocShellLoadInfo.h"
    1.36 +#include "nsIDOMApplicationRegistry.h"
    1.37 +#include "nsIBaseWindow.h"
    1.38 +#include "nsContentUtils.h"
    1.39 +#include "nsCxPusher.h"
    1.40 +#include "nsIXPConnect.h"
    1.41 +#include "nsUnicharUtils.h"
    1.42 +#include "nsIScriptGlobalObject.h"
    1.43 +#include "nsIScriptSecurityManager.h"
    1.44 +#include "nsIScrollable.h"
    1.45 +#include "nsFrameLoader.h"
    1.46 +#include "nsIDOMEventTarget.h"
    1.47 +#include "nsIFrame.h"
    1.48 +#include "nsIScrollableFrame.h"
    1.49 +#include "nsSubDocumentFrame.h"
    1.50 +#include "nsError.h"
    1.51 +#include "nsISHistory.h"
    1.52 +#include "nsISHistoryInternal.h"
    1.53 +#include "nsIDOMHTMLDocument.h"
    1.54 +#include "nsIXULWindow.h"
    1.55 +#include "nsIEditor.h"
    1.56 +#include "nsIMozBrowserFrame.h"
    1.57 +#include "nsIPermissionManager.h"
    1.58 +#include "nsISHistory.h"
    1.59 +#include "nsNullPrincipal.h"
    1.60 +
    1.61 +#include "nsLayoutUtils.h"
    1.62 +#include "nsView.h"
    1.63 +
    1.64 +#include "nsIURI.h"
    1.65 +#include "nsIURL.h"
    1.66 +#include "nsNetUtil.h"
    1.67 +
    1.68 +#include "nsGkAtoms.h"
    1.69 +#include "nsNameSpaceManager.h"
    1.70 +
    1.71 +#include "nsThreadUtils.h"
    1.72 +
    1.73 +#include "nsIDOMChromeWindow.h"
    1.74 +#include "nsInProcessTabChildGlobal.h"
    1.75 +
    1.76 +#include "Layers.h"
    1.77 +
    1.78 +#include "AppProcessChecker.h"
    1.79 +#include "ContentParent.h"
    1.80 +#include "TabParent.h"
    1.81 +#include "mozilla/AsyncEventDispatcher.h"
    1.82 +#include "mozilla/GuardObjects.h"
    1.83 +#include "mozilla/Preferences.h"
    1.84 +#include "mozilla/unused.h"
    1.85 +#include "mozilla/dom/Element.h"
    1.86 +#include "mozilla/layout/RenderFrameParent.h"
    1.87 +#include "nsIAppsService.h"
    1.88 +#include "GeckoProfiler.h"
    1.89 +
    1.90 +#include "jsapi.h"
    1.91 +#include "mozilla/dom/HTMLIFrameElement.h"
    1.92 +#include "nsSandboxFlags.h"
    1.93 +#include "JavaScriptParent.h"
    1.94 +
    1.95 +#include "mozilla/dom/StructuredCloneUtils.h"
    1.96 +
    1.97 +#ifdef MOZ_XUL
    1.98 +#include "nsXULPopupManager.h"
    1.99 +#endif
   1.100 +
   1.101 +using namespace mozilla;
   1.102 +using namespace mozilla::hal;
   1.103 +using namespace mozilla::dom;
   1.104 +using namespace mozilla::dom::ipc;
   1.105 +using namespace mozilla::layers;
   1.106 +using namespace mozilla::layout;
   1.107 +typedef FrameMetrics::ViewID ViewID;
   1.108 +
   1.109 +class nsAsyncDocShellDestroyer : public nsRunnable
   1.110 +{
   1.111 +public:
   1.112 +  nsAsyncDocShellDestroyer(nsIDocShell* aDocShell)
   1.113 +    : mDocShell(aDocShell)
   1.114 +  {
   1.115 +  }
   1.116 +
   1.117 +  NS_IMETHOD Run()
   1.118 +  {
   1.119 +    nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell));
   1.120 +    if (base_win) {
   1.121 +      base_win->Destroy();
   1.122 +    }
   1.123 +    return NS_OK;
   1.124 +  }
   1.125 +  nsRefPtr<nsIDocShell> mDocShell;
   1.126 +};
   1.127 +
   1.128 +NS_IMPL_ISUPPORTS(nsContentView, nsIContentView)
   1.129 +
   1.130 +nsresult
   1.131 +nsContentView::Update(const ViewConfig& aConfig)
   1.132 +{
   1.133 +  if (aConfig == mConfig) {
   1.134 +    return NS_OK;
   1.135 +  }
   1.136 +  mConfig = aConfig;
   1.137 +
   1.138 +  // View changed.  Try to locate our subdoc frame and invalidate
   1.139 +  // it if found.
   1.140 +  if (!mFrameLoader) {
   1.141 +    if (IsRoot()) {
   1.142 +      // Oops, don't have a frame right now.  That's OK; the view
   1.143 +      // config persists and will apply to the next frame we get, if we
   1.144 +      // ever get one.
   1.145 +      return NS_OK;
   1.146 +    } else {
   1.147 +      // This view is no longer valid.
   1.148 +      return NS_ERROR_NOT_AVAILABLE;
   1.149 +    }
   1.150 +  }
   1.151 +
   1.152 +  if (RenderFrameParent* rfp = mFrameLoader->GetCurrentRemoteFrame()) {
   1.153 +    rfp->ContentViewScaleChanged(this);
   1.154 +  }
   1.155 +
   1.156 +  return NS_OK;
   1.157 +}
   1.158 +
   1.159 +NS_IMETHODIMP
   1.160 +nsContentView::ScrollTo(float aXpx, float aYpx)
   1.161 +{
   1.162 +  ViewConfig config(mConfig);
   1.163 +  config.mScrollOffset = nsPoint(nsPresContext::CSSPixelsToAppUnits(aXpx),
   1.164 +                                 nsPresContext::CSSPixelsToAppUnits(aYpx));
   1.165 +  return Update(config);
   1.166 +}
   1.167 +
   1.168 +NS_IMETHODIMP
   1.169 +nsContentView::ScrollBy(float aDXpx, float aDYpx)
   1.170 +{
   1.171 +  ViewConfig config(mConfig);
   1.172 +  config.mScrollOffset.MoveBy(nsPresContext::CSSPixelsToAppUnits(aDXpx),
   1.173 +                              nsPresContext::CSSPixelsToAppUnits(aDYpx));
   1.174 +  return Update(config);
   1.175 +}
   1.176 +
   1.177 +NS_IMETHODIMP
   1.178 +nsContentView::SetScale(float aXScale, float aYScale)
   1.179 +{
   1.180 +  ViewConfig config(mConfig);
   1.181 +  config.mXScale = aXScale;
   1.182 +  config.mYScale = aYScale;
   1.183 +  return Update(config);
   1.184 +}
   1.185 +
   1.186 +NS_IMETHODIMP
   1.187 +nsContentView::GetScrollX(float* aViewScrollX)
   1.188 +{
   1.189 +  *aViewScrollX = nsPresContext::AppUnitsToFloatCSSPixels(
   1.190 +    mConfig.mScrollOffset.x);
   1.191 +  return NS_OK;
   1.192 +}
   1.193 +
   1.194 +NS_IMETHODIMP
   1.195 +nsContentView::GetScrollY(float* aViewScrollY)
   1.196 +{
   1.197 +  *aViewScrollY = nsPresContext::AppUnitsToFloatCSSPixels(
   1.198 +    mConfig.mScrollOffset.y);
   1.199 +  return NS_OK;
   1.200 +}
   1.201 +
   1.202 +NS_IMETHODIMP
   1.203 +nsContentView::GetViewportWidth(float* aWidth)
   1.204 +{
   1.205 +  *aWidth = nsPresContext::AppUnitsToFloatCSSPixels(mViewportSize.width);
   1.206 +  return NS_OK;
   1.207 +}
   1.208 +
   1.209 +NS_IMETHODIMP
   1.210 +nsContentView::GetViewportHeight(float* aHeight)
   1.211 +{
   1.212 +  *aHeight = nsPresContext::AppUnitsToFloatCSSPixels(mViewportSize.height);
   1.213 +  return NS_OK;
   1.214 +}
   1.215 +
   1.216 +NS_IMETHODIMP
   1.217 +nsContentView::GetContentWidth(float* aWidth)
   1.218 +{
   1.219 +  *aWidth = nsPresContext::AppUnitsToFloatCSSPixels(mContentSize.width);
   1.220 +  return NS_OK;
   1.221 +}
   1.222 +
   1.223 +NS_IMETHODIMP
   1.224 +nsContentView::GetContentHeight(float* aHeight)
   1.225 +{
   1.226 +  *aHeight = nsPresContext::AppUnitsToFloatCSSPixels(mContentSize.height);
   1.227 +  return NS_OK;
   1.228 +}
   1.229 +
   1.230 +NS_IMETHODIMP
   1.231 +nsContentView::GetId(nsContentViewId* aId)
   1.232 +{
   1.233 +  NS_ASSERTION(sizeof(nsContentViewId) == sizeof(ViewID),
   1.234 +               "ID size for XPCOM ID and internal ID type are not the same!");
   1.235 +  *aId = mScrollId;
   1.236 +  return NS_OK;
   1.237 +}
   1.238 +
   1.239 +// Bug 136580: Limit to the number of nested content frames that can have the
   1.240 +//             same URL. This is to stop content that is recursively loading
   1.241 +//             itself.  Note that "#foo" on the end of URL doesn't affect
   1.242 +//             whether it's considered identical, but "?foo" or ";foo" are
   1.243 +//             considered and compared.
   1.244 +// Bug 228829: Limit this to 1, like IE does.
   1.245 +#define MAX_SAME_URL_CONTENT_FRAMES 1
   1.246 +
   1.247 +// Bug 8065: Limit content frame depth to some reasonable level. This
   1.248 +// does not count chrome frames when determining depth, nor does it
   1.249 +// prevent chrome recursion.  Number is fairly arbitrary, but meant to
   1.250 +// keep number of shells to a reasonable number on accidental recursion with a
   1.251 +// small (but not 1) branching factor.  With large branching factors the number
   1.252 +// of shells can rapidly become huge and run us out of memory.  To solve that,
   1.253 +// we'd need to re-institute a fixed version of bug 98158.
   1.254 +#define MAX_DEPTH_CONTENT_FRAMES 10
   1.255 +
   1.256 +NS_IMPL_CYCLE_COLLECTION(nsFrameLoader, mDocShell, mMessageManager, mChildMessageManager)
   1.257 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameLoader)
   1.258 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameLoader)
   1.259 +
   1.260 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader)
   1.261 +  NS_INTERFACE_MAP_ENTRY(nsIFrameLoader)
   1.262 +  NS_INTERFACE_MAP_ENTRY(nsIContentViewManager)
   1.263 +  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFrameLoader)
   1.264 +NS_INTERFACE_MAP_END
   1.265 +
   1.266 +nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
   1.267 +  : mOwnerContent(aOwner)
   1.268 +  , mAppIdSentToPermissionManager(nsIScriptSecurityManager::NO_APP_ID)
   1.269 +  , mDetachedSubdocViews(nullptr)
   1.270 +  , mDepthTooGreat(false)
   1.271 +  , mIsTopLevelContent(false)
   1.272 +  , mDestroyCalled(false)
   1.273 +  , mNeedsAsyncDestroy(false)
   1.274 +  , mInSwap(false)
   1.275 +  , mInShow(false)
   1.276 +  , mHideCalled(false)
   1.277 +  , mNetworkCreated(aNetworkCreated)
   1.278 +  , mRemoteBrowserShown(false)
   1.279 +  , mRemoteFrame(false)
   1.280 +  , mClipSubdocument(true)
   1.281 +  , mClampScrollPosition(true)
   1.282 +  , mRemoteBrowserInitialized(false)
   1.283 +  , mObservingOwnerContent(false)
   1.284 +  , mVisible(true)
   1.285 +  , mCurrentRemoteFrame(nullptr)
   1.286 +  , mRemoteBrowser(nullptr)
   1.287 +  , mChildID(0)
   1.288 +  , mRenderMode(RENDER_MODE_DEFAULT)
   1.289 +  , mEventMode(EVENT_MODE_NORMAL_DISPATCH)
   1.290 +  , mPendingFrameSent(false)
   1.291 +{
   1.292 +  ResetPermissionManagerStatus();
   1.293 +}
   1.294 +
   1.295 +nsFrameLoader::~nsFrameLoader()
   1.296 +{
   1.297 +  mNeedsAsyncDestroy = true;
   1.298 +  if (mMessageManager) {
   1.299 +    mMessageManager->Disconnect();
   1.300 +  }
   1.301 +  nsFrameLoader::Destroy();
   1.302 +}
   1.303 +
   1.304 +nsFrameLoader*
   1.305 +nsFrameLoader::Create(Element* aOwner, bool aNetworkCreated)
   1.306 +{
   1.307 +  NS_ENSURE_TRUE(aOwner, nullptr);
   1.308 +  nsIDocument* doc = aOwner->OwnerDoc();
   1.309 +  NS_ENSURE_TRUE(!doc->IsResourceDoc() &&
   1.310 +                 ((!doc->IsLoadedAsData() && aOwner->GetCurrentDoc()) ||
   1.311 +                   doc->IsStaticDocument()),
   1.312 +                 nullptr);
   1.313 +
   1.314 +  return new nsFrameLoader(aOwner, aNetworkCreated);
   1.315 +}
   1.316 +
   1.317 +NS_IMETHODIMP
   1.318 +nsFrameLoader::LoadFrame()
   1.319 +{
   1.320 +  NS_ENSURE_TRUE(mOwnerContent, NS_ERROR_NOT_INITIALIZED);
   1.321 +
   1.322 +  nsAutoString src;
   1.323 +
   1.324 +  bool isSrcdoc = mOwnerContent->IsHTML(nsGkAtoms::iframe) &&
   1.325 +                  mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc);
   1.326 +  if (isSrcdoc) {
   1.327 +    src.AssignLiteral("about:srcdoc");
   1.328 +  }
   1.329 +  else {
   1.330 +    GetURL(src);
   1.331 +
   1.332 +    src.Trim(" \t\n\r");
   1.333 +
   1.334 +    if (src.IsEmpty()) {
   1.335 +      // If the frame is a XUL element and has the attribute 'nodefaultsrc=true'
   1.336 +      // then we will not use 'about:blank' as fallback but return early without
   1.337 +      // starting a load if no 'src' attribute is given (or it's empty).
   1.338 +      if (mOwnerContent->IsXUL() &&
   1.339 +          mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::nodefaultsrc,
   1.340 +                                     nsGkAtoms::_true, eCaseMatters)) {
   1.341 +        return NS_OK;
   1.342 +      }
   1.343 +      src.AssignLiteral("about:blank");
   1.344 +    }
   1.345 +  }
   1.346 +
   1.347 +  nsIDocument* doc = mOwnerContent->OwnerDoc();
   1.348 +  if (doc->IsStaticDocument()) {
   1.349 +    return NS_OK;
   1.350 +  }
   1.351 +
   1.352 +  nsCOMPtr<nsIURI> base_uri = mOwnerContent->GetBaseURI();
   1.353 +  const nsAFlatCString &doc_charset = doc->GetDocumentCharacterSet();
   1.354 +  const char *charset = doc_charset.IsEmpty() ? nullptr : doc_charset.get();
   1.355 +
   1.356 +  nsCOMPtr<nsIURI> uri;
   1.357 +  nsresult rv = NS_NewURI(getter_AddRefs(uri), src, charset, base_uri);
   1.358 +
   1.359 +  // If the URI was malformed, try to recover by loading about:blank.
   1.360 +  if (rv == NS_ERROR_MALFORMED_URI) {
   1.361 +    rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("about:blank"),
   1.362 +                   charset, base_uri);
   1.363 +  }
   1.364 +
   1.365 +  if (NS_SUCCEEDED(rv)) {
   1.366 +    rv = LoadURI(uri);
   1.367 +  }
   1.368 +  
   1.369 +  if (NS_FAILED(rv)) {
   1.370 +    FireErrorEvent();
   1.371 +
   1.372 +    return rv;
   1.373 +  }
   1.374 +
   1.375 +  return NS_OK;
   1.376 +}
   1.377 +
   1.378 +void
   1.379 +nsFrameLoader::FireErrorEvent()
   1.380 +{
   1.381 +  if (!mOwnerContent) {
   1.382 +    return;
   1.383 +  }
   1.384 +  nsRefPtr<AsyncEventDispatcher > loadBlockingAsyncDispatcher =
   1.385 +    new LoadBlockingAsyncEventDispatcher(mOwnerContent,
   1.386 +                                         NS_LITERAL_STRING("error"),
   1.387 +                                         false, false);
   1.388 +  loadBlockingAsyncDispatcher->PostDOMEvent();
   1.389 +}
   1.390 +
   1.391 +NS_IMETHODIMP
   1.392 +nsFrameLoader::LoadURI(nsIURI* aURI)
   1.393 +{
   1.394 +  if (!aURI)
   1.395 +    return NS_ERROR_INVALID_POINTER;
   1.396 +  NS_ENSURE_STATE(!mDestroyCalled && mOwnerContent);
   1.397 +
   1.398 +  nsCOMPtr<nsIDocument> doc = mOwnerContent->OwnerDoc();
   1.399 +
   1.400 +  nsresult rv = CheckURILoad(aURI);
   1.401 +  NS_ENSURE_SUCCESS(rv, rv);
   1.402 +
   1.403 +  mURIToLoad = aURI;
   1.404 +  rv = doc->InitializeFrameLoader(this);
   1.405 +  if (NS_FAILED(rv)) {
   1.406 +    mURIToLoad = nullptr;
   1.407 +  }
   1.408 +  return rv;
   1.409 +}
   1.410 +
   1.411 +nsresult
   1.412 +nsFrameLoader::ReallyStartLoading()
   1.413 +{
   1.414 +  nsresult rv = ReallyStartLoadingInternal();
   1.415 +  if (NS_FAILED(rv)) {
   1.416 +    FireErrorEvent();
   1.417 +  }
   1.418 +  
   1.419 +  return rv;
   1.420 +}
   1.421 +
   1.422 +class DelayedStartLoadingRunnable : public nsRunnable
   1.423 +{
   1.424 +public:
   1.425 +  DelayedStartLoadingRunnable(nsFrameLoader* aFrameLoader)
   1.426 +    : mFrameLoader(aFrameLoader)
   1.427 +  {
   1.428 +  }
   1.429 +
   1.430 +  NS_IMETHOD Run()
   1.431 +  {
   1.432 +    // Retry the request.
   1.433 +    mFrameLoader->ReallyStartLoading();
   1.434 +
   1.435 +    // We delayed nsFrameLoader::ReallyStartLoading() after the child process is
   1.436 +    // ready and might not be able to notify the remote browser in
   1.437 +    // UpdatePositionAndSize() when reflow finished. Retrigger reflow.
   1.438 +    nsIFrame* frame = mFrameLoader->GetPrimaryFrameOfOwningContent();
   1.439 +    if (!frame) {
   1.440 +      return NS_OK;
   1.441 +    }
   1.442 +    frame->InvalidateFrame();
   1.443 +    frame->PresContext()->PresShell()->
   1.444 +      FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
   1.445 +
   1.446 +    return NS_OK;
   1.447 +  }
   1.448 +
   1.449 +private:
   1.450 +  nsRefPtr<nsFrameLoader> mFrameLoader;
   1.451 +};
   1.452 +
   1.453 +nsresult
   1.454 +nsFrameLoader::ReallyStartLoadingInternal()
   1.455 +{
   1.456 +  NS_ENSURE_STATE(mURIToLoad && mOwnerContent && mOwnerContent->IsInDoc());
   1.457 +
   1.458 +  PROFILER_LABEL("nsFrameLoader", "ReallyStartLoading");
   1.459 +
   1.460 +  nsresult rv = MaybeCreateDocShell();
   1.461 +  if (NS_FAILED(rv)) {
   1.462 +    return rv;
   1.463 +  }
   1.464 +
   1.465 +  if (mRemoteFrame) {
   1.466 +    if (!mRemoteBrowser) {
   1.467 +      if (!mPendingFrameSent) {
   1.468 +        nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   1.469 +        if (os && !mRemoteBrowserInitialized) {
   1.470 +          os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
   1.471 +                              "remote-browser-pending", nullptr);
   1.472 +          mPendingFrameSent = true;
   1.473 +        }
   1.474 +      }
   1.475 +      if (Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false) &&
   1.476 +          !ContentParent::PreallocatedProcessReady()) {
   1.477 +
   1.478 +        ContentParent::RunAfterPreallocatedProcessReady(
   1.479 +            new DelayedStartLoadingRunnable(this));
   1.480 +        return NS_ERROR_FAILURE;
   1.481 +      }
   1.482 +
   1.483 +      TryRemoteBrowser();
   1.484 +
   1.485 +      if (!mRemoteBrowser) {
   1.486 +        NS_WARNING("Couldn't create child process for iframe.");
   1.487 +        return NS_ERROR_FAILURE;
   1.488 +      }
   1.489 +    }
   1.490 +
   1.491 +    if (mRemoteBrowserShown || ShowRemoteFrame(nsIntSize(0, 0))) {
   1.492 +      // FIXME get error codes from child
   1.493 +      mRemoteBrowser->LoadURL(mURIToLoad);
   1.494 +    } else {
   1.495 +      NS_WARNING("[nsFrameLoader] ReallyStartLoadingInternal tried but couldn't show remote browser.\n");
   1.496 +    }
   1.497 +
   1.498 +    return NS_OK;
   1.499 +  }
   1.500 +
   1.501 +  NS_ASSERTION(mDocShell,
   1.502 +               "MaybeCreateDocShell succeeded with a null mDocShell");
   1.503 +
   1.504 +  // Just to be safe, recheck uri.
   1.505 +  rv = CheckURILoad(mURIToLoad);
   1.506 +  NS_ENSURE_SUCCESS(rv, rv);
   1.507 +
   1.508 +  nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
   1.509 +  mDocShell->CreateLoadInfo(getter_AddRefs(loadInfo));
   1.510 +  NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
   1.511 +
   1.512 +  // If this frame is sandboxed with respect to origin we will set it up with
   1.513 +  // a null principal later in nsDocShell::DoURILoad.
   1.514 +  // We do it there to correctly sandbox content that was loaded into
   1.515 +  // the frame via other methods than the src attribute.
   1.516 +  // We'll use our principal, not that of the document loaded inside us.  This
   1.517 +  // is very important; needed to prevent XSS attacks on documents loaded in
   1.518 +  // subframes!
   1.519 +  loadInfo->SetOwner(mOwnerContent->NodePrincipal());
   1.520 +
   1.521 +  nsCOMPtr<nsIURI> referrer;
   1.522 +  
   1.523 +  nsAutoString srcdoc;
   1.524 +  bool isSrcdoc = mOwnerContent->IsHTML(nsGkAtoms::iframe) &&
   1.525 +                  mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::srcdoc,
   1.526 +                                         srcdoc);
   1.527 +
   1.528 +  if (isSrcdoc) {
   1.529 +    nsAutoString referrerStr;
   1.530 +    mOwnerContent->OwnerDoc()->GetReferrer(referrerStr);
   1.531 +    rv = NS_NewURI(getter_AddRefs(referrer), referrerStr);
   1.532 +
   1.533 +    loadInfo->SetSrcdocData(srcdoc);
   1.534 +    nsCOMPtr<nsIURI> baseURI = mOwnerContent->GetBaseURI();
   1.535 +    loadInfo->SetBaseURI(baseURI);
   1.536 +  }
   1.537 +  else {
   1.538 +    rv = mOwnerContent->NodePrincipal()->GetURI(getter_AddRefs(referrer));
   1.539 +    NS_ENSURE_SUCCESS(rv, rv);
   1.540 +  }
   1.541 +
   1.542 +  // Use referrer as long as it is not an nsNullPrincipalURI.
   1.543 +  // We could add a method such as GetReferrerURI to principals to make this
   1.544 +  // cleaner, but given that we need to start using Source Browsing Context for
   1.545 +  // referrer (see Bug 960639) this may be wasted effort at this stage.
   1.546 +  if (referrer) {
   1.547 +    bool isNullPrincipalScheme;
   1.548 +    rv = referrer->SchemeIs(NS_NULLPRINCIPAL_SCHEME, &isNullPrincipalScheme);
   1.549 +    if (NS_SUCCEEDED(rv) && !isNullPrincipalScheme) {
   1.550 +      loadInfo->SetReferrer(referrer);
   1.551 +    }
   1.552 +  }
   1.553 +
   1.554 +  // Default flags:
   1.555 +  int32_t flags = nsIWebNavigation::LOAD_FLAGS_NONE;
   1.556 +
   1.557 +  // Flags for browser frame:
   1.558 +  if (OwnerIsBrowserFrame()) {
   1.559 +    flags = nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
   1.560 +            nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
   1.561 +  }
   1.562 +
   1.563 +  // Kick off the load...
   1.564 +  bool tmpState = mNeedsAsyncDestroy;
   1.565 +  mNeedsAsyncDestroy = true;
   1.566 +  nsCOMPtr<nsIURI> uriToLoad = mURIToLoad;
   1.567 +  rv = mDocShell->LoadURI(uriToLoad, loadInfo, flags, false);
   1.568 +  mNeedsAsyncDestroy = tmpState;
   1.569 +  mURIToLoad = nullptr;
   1.570 +  NS_ENSURE_SUCCESS(rv, rv);
   1.571 +
   1.572 +  return NS_OK;
   1.573 +}
   1.574 +
   1.575 +nsresult
   1.576 +nsFrameLoader::CheckURILoad(nsIURI* aURI)
   1.577 +{
   1.578 +  // Check for security.  The fun part is trying to figure out what principals
   1.579 +  // to use.  The way I figure it, if we're doing a LoadFrame() accidentally
   1.580 +  // (eg someone created a frame/iframe node, we're being parsed, XUL iframes
   1.581 +  // are being reframed, etc.) then we definitely want to use the node
   1.582 +  // principal of mOwnerContent for security checks.  If, on the other hand,
   1.583 +  // someone's setting the src on our owner content, or created it via script,
   1.584 +  // or whatever, then they can clearly access it... and we should still use
   1.585 +  // the principal of mOwnerContent.  I don't think that leads to privilege
   1.586 +  // escalation, and it's reasonably guaranteed to not lead to XSS issues
   1.587 +  // (since caller can already access mOwnerContent in this case).  So just use
   1.588 +  // the principal of mOwnerContent no matter what.  If script wants to run
   1.589 +  // things with its own permissions, which differ from those of mOwnerContent
   1.590 +  // (which means the script is privileged in some way) it should set
   1.591 +  // window.location instead.
   1.592 +  nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
   1.593 +
   1.594 +  // Get our principal
   1.595 +  nsIPrincipal* principal = mOwnerContent->NodePrincipal();
   1.596 +
   1.597 +  // Check if we are allowed to load absURL
   1.598 +  nsresult rv =
   1.599 +    secMan->CheckLoadURIWithPrincipal(principal, aURI,
   1.600 +                                      nsIScriptSecurityManager::STANDARD);
   1.601 +  if (NS_FAILED(rv)) {
   1.602 +    return rv; // We're not
   1.603 +  }
   1.604 +
   1.605 +  // Bail out if this is an infinite recursion scenario
   1.606 +  rv = MaybeCreateDocShell();
   1.607 +  if (NS_FAILED(rv)) {
   1.608 +    return rv;
   1.609 +  }
   1.610 +  if (mRemoteFrame) {
   1.611 +    return NS_OK;
   1.612 +  }
   1.613 +  return CheckForRecursiveLoad(aURI);
   1.614 +}
   1.615 +
   1.616 +NS_IMETHODIMP
   1.617 +nsFrameLoader::GetDocShell(nsIDocShell **aDocShell)
   1.618 +{
   1.619 +  *aDocShell = nullptr;
   1.620 +  nsresult rv = NS_OK;
   1.621 +
   1.622 +  // If we have an owner, make sure we have a docshell and return
   1.623 +  // that. If not, we're most likely in the middle of being torn down,
   1.624 +  // then we just return null.
   1.625 +  if (mOwnerContent) {
   1.626 +    nsresult rv = MaybeCreateDocShell();
   1.627 +    if (NS_FAILED(rv))
   1.628 +      return rv;
   1.629 +    if (mRemoteFrame) {
   1.630 +      NS_WARNING("No docshells for remote frames!");
   1.631 +      return rv;
   1.632 +    }
   1.633 +    NS_ASSERTION(mDocShell,
   1.634 +                 "MaybeCreateDocShell succeeded, but null mDocShell");
   1.635 +  }
   1.636 +
   1.637 +  *aDocShell = mDocShell;
   1.638 +  NS_IF_ADDREF(*aDocShell);
   1.639 +
   1.640 +  return rv;
   1.641 +}
   1.642 +
   1.643 +void
   1.644 +nsFrameLoader::Finalize()
   1.645 +{
   1.646 +  nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell));
   1.647 +  if (base_win) {
   1.648 +    base_win->Destroy();
   1.649 +  }
   1.650 +  mDocShell = nullptr;
   1.651 +}
   1.652 +
   1.653 +static void
   1.654 +FirePageHideEvent(nsIDocShellTreeItem* aItem,
   1.655 +                  EventTarget* aChromeEventHandler)
   1.656 +{
   1.657 +  nsCOMPtr<nsIDocument> internalDoc = do_GetInterface(aItem);
   1.658 +  NS_ASSERTION(internalDoc, "What happened here?");
   1.659 +  internalDoc->OnPageHide(true, aChromeEventHandler);
   1.660 +
   1.661 +  int32_t childCount = 0;
   1.662 +  aItem->GetChildCount(&childCount);
   1.663 +  nsAutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids;
   1.664 +  kids.AppendElements(childCount);
   1.665 +  for (int32_t i = 0; i < childCount; ++i) {
   1.666 +    aItem->GetChildAt(i, getter_AddRefs(kids[i]));
   1.667 +  }
   1.668 +
   1.669 +  for (uint32_t i = 0; i < kids.Length(); ++i) {
   1.670 +    if (kids[i]) {
   1.671 +      FirePageHideEvent(kids[i], aChromeEventHandler);
   1.672 +    }
   1.673 +  }
   1.674 +}
   1.675 +
   1.676 +// The pageshow event is fired for a given document only if IsShowing() returns
   1.677 +// the same thing as aFireIfShowing.  This gives us a way to fire pageshow only
   1.678 +// on documents that are still loading or only on documents that are already
   1.679 +// loaded.
   1.680 +static void
   1.681 +FirePageShowEvent(nsIDocShellTreeItem* aItem,
   1.682 +                  EventTarget* aChromeEventHandler,
   1.683 +                  bool aFireIfShowing)
   1.684 +{
   1.685 +  int32_t childCount = 0;
   1.686 +  aItem->GetChildCount(&childCount);
   1.687 +  nsAutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids;
   1.688 +  kids.AppendElements(childCount);
   1.689 +  for (int32_t i = 0; i < childCount; ++i) {
   1.690 +    aItem->GetChildAt(i, getter_AddRefs(kids[i]));
   1.691 +  }
   1.692 +
   1.693 +  for (uint32_t i = 0; i < kids.Length(); ++i) {
   1.694 +    if (kids[i]) {
   1.695 +      FirePageShowEvent(kids[i], aChromeEventHandler, aFireIfShowing);
   1.696 +    }
   1.697 +  }
   1.698 +
   1.699 +  nsCOMPtr<nsIDocument> internalDoc = do_GetInterface(aItem);
   1.700 +  NS_ASSERTION(internalDoc, "What happened here?");
   1.701 +  if (internalDoc->IsShowing() == aFireIfShowing) {
   1.702 +    internalDoc->OnPageShow(true, aChromeEventHandler);
   1.703 +  }
   1.704 +}
   1.705 +
   1.706 +static void
   1.707 +SetTreeOwnerAndChromeEventHandlerOnDocshellTree(nsIDocShellTreeItem* aItem,
   1.708 +                                                nsIDocShellTreeOwner* aOwner,
   1.709 +                                                EventTarget* aHandler)
   1.710 +{
   1.711 +  NS_PRECONDITION(aItem, "Must have item");
   1.712 +
   1.713 +  aItem->SetTreeOwner(aOwner);
   1.714 +
   1.715 +  int32_t childCount = 0;
   1.716 +  aItem->GetChildCount(&childCount);
   1.717 +  for (int32_t i = 0; i < childCount; ++i) {
   1.718 +    nsCOMPtr<nsIDocShellTreeItem> item;
   1.719 +    aItem->GetChildAt(i, getter_AddRefs(item));
   1.720 +    if (aHandler) {
   1.721 +      nsCOMPtr<nsIDocShell> shell(do_QueryInterface(item));
   1.722 +      shell->SetChromeEventHandler(aHandler);
   1.723 +    }
   1.724 +    SetTreeOwnerAndChromeEventHandlerOnDocshellTree(item, aOwner, aHandler);
   1.725 +  }
   1.726 +}
   1.727 +
   1.728 +/**
   1.729 + * Set the type of the treeitem and hook it up to the treeowner.
   1.730 + * @param aItem the treeitem we're working with
   1.731 + * @param aTreeOwner the relevant treeowner; might be null
   1.732 + * @param aParentType the nsIDocShellTreeItem::GetType of our parent docshell
   1.733 + * @param aParentNode if non-null, the docshell we should be added as a child to
   1.734 + *
   1.735 + * @return whether aItem is top-level content
   1.736 + */
   1.737 +bool
   1.738 +nsFrameLoader::AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
   1.739 +                                      nsIDocShellTreeOwner* aOwner,
   1.740 +                                      int32_t aParentType,
   1.741 +                                      nsIDocShell* aParentNode)
   1.742 +{
   1.743 +  NS_PRECONDITION(aItem, "Must have docshell treeitem");
   1.744 +  NS_PRECONDITION(mOwnerContent, "Must have owning content");
   1.745 +  
   1.746 +  nsAutoString value;
   1.747 +  bool isContent = false;
   1.748 +  mOwnerContent->GetAttr(kNameSpaceID_None, TypeAttrName(), value);
   1.749 +
   1.750 +  // we accept "content" and "content-xxx" values.
   1.751 +  // at time of writing, we expect "xxx" to be "primary" or "targetable", but
   1.752 +  // someday it might be an integer expressing priority or something else.
   1.753 +
   1.754 +  isContent = value.LowerCaseEqualsLiteral("content") ||
   1.755 +    StringBeginsWith(value, NS_LITERAL_STRING("content-"),
   1.756 +                     nsCaseInsensitiveStringComparator());
   1.757 +
   1.758 +  // Force mozbrowser frames to always be typeContent, even if the
   1.759 +  // mozbrowser interfaces are disabled.
   1.760 +  nsCOMPtr<nsIDOMMozBrowserFrame> mozbrowser =
   1.761 +    do_QueryInterface(mOwnerContent);
   1.762 +  if (mozbrowser) {
   1.763 +    bool isMozbrowser = false;
   1.764 +    mozbrowser->GetMozbrowser(&isMozbrowser);
   1.765 +    isContent |= isMozbrowser;
   1.766 +  }
   1.767 +
   1.768 +  if (isContent) {
   1.769 +    // The web shell's type is content.
   1.770 +
   1.771 +    aItem->SetItemType(nsIDocShellTreeItem::typeContent);
   1.772 +  } else {
   1.773 +    // Inherit our type from our parent docshell.  If it is
   1.774 +    // chrome, we'll be chrome.  If it is content, we'll be
   1.775 +    // content.
   1.776 +
   1.777 +    aItem->SetItemType(aParentType);
   1.778 +  }
   1.779 +
   1.780 +  // Now that we have our type set, add ourselves to the parent, as needed.
   1.781 +  if (aParentNode) {
   1.782 +    aParentNode->AddChild(aItem);
   1.783 +  }
   1.784 +
   1.785 +  bool retval = false;
   1.786 +  if (aParentType == nsIDocShellTreeItem::typeChrome && isContent) {
   1.787 +    retval = true;
   1.788 +
   1.789 +    bool is_primary = value.LowerCaseEqualsLiteral("content-primary");
   1.790 +
   1.791 +    if (aOwner) {
   1.792 +      bool is_targetable = is_primary ||
   1.793 +        value.LowerCaseEqualsLiteral("content-targetable");
   1.794 +      mOwnerContent->AddMutationObserver(this);
   1.795 +      mObservingOwnerContent = true;
   1.796 +      aOwner->ContentShellAdded(aItem, is_primary, is_targetable, value);
   1.797 +    }
   1.798 +  }
   1.799 +
   1.800 +  return retval;
   1.801 +}
   1.802 +
   1.803 +static bool
   1.804 +AllDescendantsOfType(nsIDocShellTreeItem* aParentItem, int32_t aType)
   1.805 +{
   1.806 +  int32_t childCount = 0;
   1.807 +  aParentItem->GetChildCount(&childCount);
   1.808 +
   1.809 +  for (int32_t i = 0; i < childCount; ++i) {
   1.810 +    nsCOMPtr<nsIDocShellTreeItem> kid;
   1.811 +    aParentItem->GetChildAt(i, getter_AddRefs(kid));
   1.812 +
   1.813 +    if (kid->ItemType() != aType || !AllDescendantsOfType(kid, aType)) {
   1.814 +      return false;
   1.815 +    }
   1.816 +  }
   1.817 +
   1.818 +  return true;
   1.819 +}
   1.820 +
   1.821 +/**
   1.822 + * A class that automatically sets mInShow to false when it goes
   1.823 + * out of scope.
   1.824 + */
   1.825 +class MOZ_STACK_CLASS AutoResetInShow {
   1.826 +  private:
   1.827 +    nsFrameLoader* mFrameLoader;
   1.828 +    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   1.829 +  public:
   1.830 +    AutoResetInShow(nsFrameLoader* aFrameLoader MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
   1.831 +      : mFrameLoader(aFrameLoader)
   1.832 +    {
   1.833 +      MOZ_GUARD_OBJECT_NOTIFIER_INIT;
   1.834 +    }
   1.835 +    ~AutoResetInShow() { mFrameLoader->mInShow = false; }
   1.836 +};
   1.837 +
   1.838 +
   1.839 +bool
   1.840 +nsFrameLoader::Show(int32_t marginWidth, int32_t marginHeight,
   1.841 +                    int32_t scrollbarPrefX, int32_t scrollbarPrefY,
   1.842 +                    nsSubDocumentFrame* frame)
   1.843 +{
   1.844 +  if (mInShow) {
   1.845 +    return false;
   1.846 +  }
   1.847 +  // Reset mInShow if we exit early.
   1.848 +  AutoResetInShow resetInShow(this);
   1.849 +  mInShow = true;
   1.850 +
   1.851 +  nsresult rv = MaybeCreateDocShell();
   1.852 +  if (NS_FAILED(rv)) {
   1.853 +    return false;
   1.854 +  }
   1.855 +
   1.856 +  if (!mRemoteFrame) {
   1.857 +    if (!mDocShell)
   1.858 +      return false;
   1.859 +
   1.860 +    mDocShell->SetMarginWidth(marginWidth);
   1.861 +    mDocShell->SetMarginHeight(marginHeight);
   1.862 +
   1.863 +    nsCOMPtr<nsIScrollable> sc = do_QueryInterface(mDocShell);
   1.864 +    if (sc) {
   1.865 +      sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X,
   1.866 +                                         scrollbarPrefX);
   1.867 +      sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y,
   1.868 +                                         scrollbarPrefY);
   1.869 +    }
   1.870 +
   1.871 +    nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
   1.872 +    if (presShell) {
   1.873 +      // Ensure root scroll frame is reflowed in case scroll preferences or
   1.874 +      // margins have changed
   1.875 +      nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
   1.876 +      if (rootScrollFrame) {
   1.877 +        presShell->FrameNeedsReflow(rootScrollFrame, nsIPresShell::eResize,
   1.878 +                                    NS_FRAME_IS_DIRTY);
   1.879 +      }
   1.880 +      return true;
   1.881 +    }
   1.882 +  }
   1.883 +
   1.884 +  nsIntSize size = frame->GetSubdocumentSize();
   1.885 +  if (mRemoteFrame) {
   1.886 +    return ShowRemoteFrame(size, frame);
   1.887 +  }
   1.888 +
   1.889 +  nsView* view = frame->EnsureInnerView();
   1.890 +  if (!view)
   1.891 +    return false;
   1.892 +
   1.893 +  nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mDocShell);
   1.894 +  NS_ASSERTION(baseWindow, "Found a nsIDocShell that isn't a nsIBaseWindow.");
   1.895 +  baseWindow->InitWindow(nullptr, view->GetWidget(), 0, 0,
   1.896 +                         size.width, size.height);
   1.897 +  // This is kinda whacky, this "Create()" call doesn't really
   1.898 +  // create anything, one starts to wonder why this was named
   1.899 +  // "Create"...
   1.900 +  baseWindow->Create();
   1.901 +  baseWindow->SetVisibility(true);
   1.902 +  NS_ENSURE_TRUE(mDocShell, false);
   1.903 +
   1.904 +  // Trigger editor re-initialization if midas is turned on in the
   1.905 +  // sub-document. This shouldn't be necessary, but given the way our
   1.906 +  // editor works, it is. See
   1.907 +  // https://bugzilla.mozilla.org/show_bug.cgi?id=284245
   1.908 +  nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
   1.909 +  if (presShell) {
   1.910 +    nsCOMPtr<nsIDOMHTMLDocument> doc =
   1.911 +      do_QueryInterface(presShell->GetDocument());
   1.912 +
   1.913 +    if (doc) {
   1.914 +      nsAutoString designMode;
   1.915 +      doc->GetDesignMode(designMode);
   1.916 +
   1.917 +      if (designMode.EqualsLiteral("on")) {
   1.918 +        // Hold on to the editor object to let the document reattach to the
   1.919 +        // same editor object, instead of creating a new one.
   1.920 +        nsCOMPtr<nsIEditor> editor;
   1.921 +        nsresult rv = mDocShell->GetEditor(getter_AddRefs(editor));
   1.922 +        NS_ENSURE_SUCCESS(rv, false);
   1.923 +
   1.924 +        doc->SetDesignMode(NS_LITERAL_STRING("off"));
   1.925 +        doc->SetDesignMode(NS_LITERAL_STRING("on"));
   1.926 +      } else {
   1.927 +        // Re-initialize the presentation for contenteditable documents
   1.928 +        bool editable = false,
   1.929 +             hasEditingSession = false;
   1.930 +        mDocShell->GetEditable(&editable);
   1.931 +        mDocShell->GetHasEditingSession(&hasEditingSession);
   1.932 +        nsCOMPtr<nsIEditor> editor;
   1.933 +        mDocShell->GetEditor(getter_AddRefs(editor));
   1.934 +        if (editable && hasEditingSession && editor) {
   1.935 +          editor->PostCreate();
   1.936 +        }
   1.937 +      }
   1.938 +    }
   1.939 +  }
   1.940 +
   1.941 +  mInShow = false;
   1.942 +  if (mHideCalled) {
   1.943 +    mHideCalled = false;
   1.944 +    Hide();
   1.945 +    return false;
   1.946 +  }
   1.947 +  return true;
   1.948 +}
   1.949 +
   1.950 +void
   1.951 +nsFrameLoader::MarginsChanged(uint32_t aMarginWidth,
   1.952 +                              uint32_t aMarginHeight)
   1.953 +{
   1.954 +  // We assume that the margins are always zero for remote frames.
   1.955 +  if (mRemoteFrame)
   1.956 +    return;
   1.957 +
   1.958 +  // If there's no docshell, we're probably not up and running yet.
   1.959 +  // nsFrameLoader::Show() will take care of setting the right
   1.960 +  // margins.
   1.961 +  if (!mDocShell)
   1.962 +    return;
   1.963 +
   1.964 +  // Set the margins
   1.965 +  mDocShell->SetMarginWidth(aMarginWidth);
   1.966 +  mDocShell->SetMarginHeight(aMarginHeight);
   1.967 +
   1.968 +  // Trigger a restyle if there's a prescontext
   1.969 +  nsRefPtr<nsPresContext> presContext;
   1.970 +  mDocShell->GetPresContext(getter_AddRefs(presContext));
   1.971 +  if (presContext)
   1.972 +    presContext->RebuildAllStyleData(nsChangeHint(0));
   1.973 +}
   1.974 +
   1.975 +bool
   1.976 +nsFrameLoader::ShowRemoteFrame(const nsIntSize& size,
   1.977 +                               nsSubDocumentFrame *aFrame)
   1.978 +{
   1.979 +  NS_ASSERTION(mRemoteFrame, "ShowRemote only makes sense on remote frames.");
   1.980 +
   1.981 +  if (!mRemoteBrowser) {
   1.982 +    TryRemoteBrowser();
   1.983 +
   1.984 +    if (!mRemoteBrowser) {
   1.985 +      NS_ERROR("Couldn't create child process.");
   1.986 +      return false;
   1.987 +    }
   1.988 +  }
   1.989 +
   1.990 +  // FIXME/bug 589337: Show()/Hide() is pretty expensive for
   1.991 +  // cross-process layers; need to figure out what behavior we really
   1.992 +  // want here.  For now, hack.
   1.993 +  if (!mRemoteBrowserShown) {
   1.994 +    if (!mOwnerContent ||
   1.995 +        !mOwnerContent->GetCurrentDoc()) {
   1.996 +      return false;
   1.997 +    }
   1.998 +
   1.999 +    nsRefPtr<layers::LayerManager> layerManager =
  1.1000 +      nsContentUtils::LayerManagerForDocument(mOwnerContent->GetCurrentDoc());
  1.1001 +    if (!layerManager) {
  1.1002 +      // This is just not going to work.
  1.1003 +      return false;
  1.1004 +    }
  1.1005 +
  1.1006 +    mRemoteBrowser->Show(size);
  1.1007 +    mRemoteBrowserShown = true;
  1.1008 +
  1.1009 +    EnsureMessageManager();
  1.1010 +
  1.1011 +    nsCOMPtr<nsIObserverService> os = services::GetObserverService();
  1.1012 +    if (os && !mRemoteBrowserInitialized) {
  1.1013 +      if (!mPendingFrameSent) {
  1.1014 +        os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
  1.1015 +                            "remote-browser-pending", nullptr);
  1.1016 +        mPendingFrameSent = true;
  1.1017 +      }
  1.1018 +      os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
  1.1019 +                          "remote-browser-shown", nullptr);
  1.1020 +      mRemoteBrowserInitialized = true;
  1.1021 +    }
  1.1022 +  } else {
  1.1023 +    nsRect dimensions;
  1.1024 +    NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), false);
  1.1025 +
  1.1026 +    // Don't show remote iframe if we are waiting for the completion of reflow.
  1.1027 +    if (!aFrame || !(aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
  1.1028 +      mRemoteBrowser->UpdateDimensions(dimensions, size);
  1.1029 +    }
  1.1030 +  }
  1.1031 +
  1.1032 +  return true;
  1.1033 +}
  1.1034 +
  1.1035 +void
  1.1036 +nsFrameLoader::Hide()
  1.1037 +{
  1.1038 +  if (mHideCalled) {
  1.1039 +    return;
  1.1040 +  }
  1.1041 +  if (mInShow) {
  1.1042 +    mHideCalled = true;
  1.1043 +    return;
  1.1044 +  }
  1.1045 +
  1.1046 +  if (!mDocShell)
  1.1047 +    return;
  1.1048 +
  1.1049 +  nsCOMPtr<nsIContentViewer> contentViewer;
  1.1050 +  mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
  1.1051 +  if (contentViewer)
  1.1052 +    contentViewer->SetSticky(false);
  1.1053 +
  1.1054 +  nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
  1.1055 +  NS_ASSERTION(baseWin,
  1.1056 +               "Found an nsIDocShell which doesn't implement nsIBaseWindow.");
  1.1057 +  baseWin->SetVisibility(false);
  1.1058 +  baseWin->SetParentWidget(nullptr);
  1.1059 +}
  1.1060 +
  1.1061 +nsresult
  1.1062 +nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
  1.1063 +                                   nsRefPtr<nsFrameLoader>& aFirstToSwap,
  1.1064 +                                   nsRefPtr<nsFrameLoader>& aSecondToSwap)
  1.1065 +{
  1.1066 +  NS_PRECONDITION((aFirstToSwap == this && aSecondToSwap == aOther) ||
  1.1067 +                  (aFirstToSwap == aOther && aSecondToSwap == this),
  1.1068 +                  "Swapping some sort of random loaders?");
  1.1069 +  NS_ENSURE_STATE(!mInShow && !aOther->mInShow);
  1.1070 +
  1.1071 +  Element* ourContent = mOwnerContent;
  1.1072 +  Element* otherContent = aOther->mOwnerContent;
  1.1073 +
  1.1074 +  if (!ourContent || !otherContent) {
  1.1075 +    // Can't handle this
  1.1076 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1077 +  }
  1.1078 +
  1.1079 +  // Make sure there are no same-origin issues
  1.1080 +  bool equal;
  1.1081 +  nsresult rv =
  1.1082 +    ourContent->NodePrincipal()->Equals(otherContent->NodePrincipal(), &equal);
  1.1083 +  if (NS_FAILED(rv) || !equal) {
  1.1084 +    // Security problems loom.  Just bail on it all
  1.1085 +    return NS_ERROR_DOM_SECURITY_ERR;
  1.1086 +  }
  1.1087 +
  1.1088 +  nsCOMPtr<nsIDocShell> ourDocshell = GetExistingDocShell();
  1.1089 +  nsCOMPtr<nsIDocShell> otherDocshell = aOther->GetExistingDocShell();
  1.1090 +  if (!ourDocshell || !otherDocshell) {
  1.1091 +    // How odd
  1.1092 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1093 +  }
  1.1094 +
  1.1095 +  // To avoid having to mess with session history, avoid swapping
  1.1096 +  // frameloaders that don't correspond to root same-type docshells,
  1.1097 +  // unless both roots have session history disabled.
  1.1098 +  nsCOMPtr<nsIDocShellTreeItem> ourRootTreeItem, otherRootTreeItem;
  1.1099 +  ourDocshell->GetSameTypeRootTreeItem(getter_AddRefs(ourRootTreeItem));
  1.1100 +  otherDocshell->GetSameTypeRootTreeItem(getter_AddRefs(otherRootTreeItem));
  1.1101 +  nsCOMPtr<nsIWebNavigation> ourRootWebnav =
  1.1102 +    do_QueryInterface(ourRootTreeItem);
  1.1103 +  nsCOMPtr<nsIWebNavigation> otherRootWebnav =
  1.1104 +    do_QueryInterface(otherRootTreeItem);
  1.1105 +
  1.1106 +  if (!ourRootWebnav || !otherRootWebnav) {
  1.1107 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1108 +  }
  1.1109 +
  1.1110 +  nsCOMPtr<nsISHistory> ourHistory;
  1.1111 +  nsCOMPtr<nsISHistory> otherHistory;
  1.1112 +  ourRootWebnav->GetSessionHistory(getter_AddRefs(ourHistory));
  1.1113 +  otherRootWebnav->GetSessionHistory(getter_AddRefs(otherHistory));
  1.1114 +
  1.1115 +  if ((ourRootTreeItem != ourDocshell || otherRootTreeItem != otherDocshell) &&
  1.1116 +      (ourHistory || otherHistory)) {
  1.1117 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1118 +  }
  1.1119 +
  1.1120 +  // Also make sure that the two docshells are the same type. Otherwise
  1.1121 +  // swapping is certainly not safe. If this needs to be changed then
  1.1122 +  // the code below needs to be audited as it assumes identical types.
  1.1123 +  int32_t ourType = ourDocshell->ItemType();
  1.1124 +  int32_t otherType = otherDocshell->ItemType();
  1.1125 +  if (ourType != otherType) {
  1.1126 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1127 +  }
  1.1128 +
  1.1129 +  // One more twist here.  Setting up the right treeowners in a heterogeneous
  1.1130 +  // tree is a bit of a pain.  So make sure that if ourType is not
  1.1131 +  // nsIDocShellTreeItem::typeContent then all of our descendants are the same
  1.1132 +  // type as us.
  1.1133 +  if (ourType != nsIDocShellTreeItem::typeContent &&
  1.1134 +      (!AllDescendantsOfType(ourDocshell, ourType) ||
  1.1135 +       !AllDescendantsOfType(otherDocshell, otherType))) {
  1.1136 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1137 +  }
  1.1138 +  
  1.1139 +  // Save off the tree owners, frame elements, chrome event handlers, and
  1.1140 +  // docshell and document parents before doing anything else.
  1.1141 +  nsCOMPtr<nsIDocShellTreeOwner> ourOwner, otherOwner;
  1.1142 +  ourDocshell->GetTreeOwner(getter_AddRefs(ourOwner));
  1.1143 +  otherDocshell->GetTreeOwner(getter_AddRefs(otherOwner));
  1.1144 +  // Note: it's OK to have null treeowners.
  1.1145 +
  1.1146 +  nsCOMPtr<nsIDocShellTreeItem> ourParentItem, otherParentItem;
  1.1147 +  ourDocshell->GetParent(getter_AddRefs(ourParentItem));
  1.1148 +  otherDocshell->GetParent(getter_AddRefs(otherParentItem));
  1.1149 +  if (!ourParentItem || !otherParentItem) {
  1.1150 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1151 +  }
  1.1152 +
  1.1153 +  // Make sure our parents are the same type too
  1.1154 +  int32_t ourParentType = ourParentItem->ItemType();
  1.1155 +  int32_t otherParentType = otherParentItem->ItemType();
  1.1156 +  if (ourParentType != otherParentType) {
  1.1157 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1158 +  }
  1.1159 +
  1.1160 +  nsCOMPtr<nsPIDOMWindow> ourWindow = do_GetInterface(ourDocshell);
  1.1161 +  nsCOMPtr<nsPIDOMWindow> otherWindow = do_GetInterface(otherDocshell);
  1.1162 +
  1.1163 +  nsCOMPtr<Element> ourFrameElement =
  1.1164 +    ourWindow->GetFrameElementInternal();
  1.1165 +  nsCOMPtr<Element> otherFrameElement =
  1.1166 +    otherWindow->GetFrameElementInternal();
  1.1167 +
  1.1168 +  nsCOMPtr<EventTarget> ourChromeEventHandler =
  1.1169 +    do_QueryInterface(ourWindow->GetChromeEventHandler());
  1.1170 +  nsCOMPtr<EventTarget> otherChromeEventHandler =
  1.1171 +    do_QueryInterface(otherWindow->GetChromeEventHandler());
  1.1172 +
  1.1173 +  NS_ASSERTION(SameCOMIdentity(ourFrameElement, ourContent) &&
  1.1174 +               SameCOMIdentity(otherFrameElement, otherContent) &&
  1.1175 +               SameCOMIdentity(ourChromeEventHandler, ourContent) &&
  1.1176 +               SameCOMIdentity(otherChromeEventHandler, otherContent),
  1.1177 +               "How did that happen, exactly?");
  1.1178 +
  1.1179 +  nsCOMPtr<nsIDocument> ourChildDocument = ourWindow->GetExtantDoc();
  1.1180 +  nsCOMPtr<nsIDocument> otherChildDocument = otherWindow ->GetExtantDoc();
  1.1181 +  if (!ourChildDocument || !otherChildDocument) {
  1.1182 +    // This shouldn't be happening
  1.1183 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1184 +  }
  1.1185 +
  1.1186 +  nsCOMPtr<nsIDocument> ourParentDocument =
  1.1187 +    ourChildDocument->GetParentDocument();
  1.1188 +  nsCOMPtr<nsIDocument> otherParentDocument =
  1.1189 +    otherChildDocument->GetParentDocument();
  1.1190 +
  1.1191 +  // Make sure to swap docshells between the two frames.
  1.1192 +  nsIDocument* ourDoc = ourContent->GetCurrentDoc();
  1.1193 +  nsIDocument* otherDoc = otherContent->GetCurrentDoc();
  1.1194 +  if (!ourDoc || !otherDoc) {
  1.1195 +    // Again, how odd, given that we had docshells
  1.1196 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1197 +  }
  1.1198 +
  1.1199 +  NS_ASSERTION(ourDoc == ourParentDocument, "Unexpected parent document");
  1.1200 +  NS_ASSERTION(otherDoc == otherParentDocument, "Unexpected parent document");
  1.1201 +
  1.1202 +  nsIPresShell* ourShell = ourDoc->GetShell();
  1.1203 +  nsIPresShell* otherShell = otherDoc->GetShell();
  1.1204 +  if (!ourShell || !otherShell) {
  1.1205 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1206 +  }
  1.1207 +
  1.1208 +  if (ourDocshell->GetIsBrowserElement() !=
  1.1209 +      otherDocshell->GetIsBrowserElement() ||
  1.1210 +      ourDocshell->GetIsApp() != otherDocshell->GetIsApp()) {
  1.1211 +      return NS_ERROR_NOT_IMPLEMENTED;
  1.1212 +  }
  1.1213 +
  1.1214 +  if (mInSwap || aOther->mInSwap) {
  1.1215 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1216 +  }
  1.1217 +  mInSwap = aOther->mInSwap = true;
  1.1218 +
  1.1219 +  // Fire pageshow events on still-loading pages, and then fire pagehide
  1.1220 +  // events.  Note that we do NOT fire these in the normal way, but just fire
  1.1221 +  // them on the chrome event handlers.
  1.1222 +  FirePageShowEvent(ourDocshell, ourChromeEventHandler, false);
  1.1223 +  FirePageShowEvent(otherDocshell, otherChromeEventHandler, false);
  1.1224 +  FirePageHideEvent(ourDocshell, ourChromeEventHandler);
  1.1225 +  FirePageHideEvent(otherDocshell, otherChromeEventHandler);
  1.1226 +  
  1.1227 +  nsIFrame* ourFrame = ourContent->GetPrimaryFrame();
  1.1228 +  nsIFrame* otherFrame = otherContent->GetPrimaryFrame();
  1.1229 +  if (!ourFrame || !otherFrame) {
  1.1230 +    mInSwap = aOther->mInSwap = false;
  1.1231 +    FirePageShowEvent(ourDocshell, ourChromeEventHandler, true);
  1.1232 +    FirePageShowEvent(otherDocshell, otherChromeEventHandler, true);
  1.1233 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1234 +  }
  1.1235 +
  1.1236 +  nsSubDocumentFrame* ourFrameFrame = do_QueryFrame(ourFrame);
  1.1237 +  if (!ourFrameFrame) {
  1.1238 +    mInSwap = aOther->mInSwap = false;
  1.1239 +    FirePageShowEvent(ourDocshell, ourChromeEventHandler, true);
  1.1240 +    FirePageShowEvent(otherDocshell, otherChromeEventHandler, true);
  1.1241 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1242 +  }
  1.1243 +
  1.1244 +  // OK.  First begin to swap the docshells in the two nsIFrames
  1.1245 +  rv = ourFrameFrame->BeginSwapDocShells(otherFrame);
  1.1246 +  if (NS_FAILED(rv)) {
  1.1247 +    mInSwap = aOther->mInSwap = false;
  1.1248 +    FirePageShowEvent(ourDocshell, ourChromeEventHandler, true);
  1.1249 +    FirePageShowEvent(otherDocshell, otherChromeEventHandler, true);
  1.1250 +    return rv;
  1.1251 +  }
  1.1252 +
  1.1253 +  // Now move the docshells to the right docshell trees.  Note that this
  1.1254 +  // resets their treeowners to null.
  1.1255 +  ourParentItem->RemoveChild(ourDocshell);
  1.1256 +  otherParentItem->RemoveChild(otherDocshell);
  1.1257 +  if (ourType == nsIDocShellTreeItem::typeContent) {
  1.1258 +    ourOwner->ContentShellRemoved(ourDocshell);
  1.1259 +    otherOwner->ContentShellRemoved(otherDocshell);
  1.1260 +  }
  1.1261 +  
  1.1262 +  ourParentItem->AddChild(otherDocshell);
  1.1263 +  otherParentItem->AddChild(ourDocshell);
  1.1264 +
  1.1265 +  // Restore the correct chrome event handlers.
  1.1266 +  ourDocshell->SetChromeEventHandler(otherChromeEventHandler);
  1.1267 +  otherDocshell->SetChromeEventHandler(ourChromeEventHandler);
  1.1268 +  // Restore the correct treeowners
  1.1269 +  // (and also chrome event handlers for content frames only).
  1.1270 +  SetTreeOwnerAndChromeEventHandlerOnDocshellTree(ourDocshell, otherOwner,
  1.1271 +    ourType == nsIDocShellTreeItem::typeContent ? otherChromeEventHandler : nullptr);
  1.1272 +  SetTreeOwnerAndChromeEventHandlerOnDocshellTree(otherDocshell, ourOwner,
  1.1273 +    ourType == nsIDocShellTreeItem::typeContent ? ourChromeEventHandler : nullptr);
  1.1274 +
  1.1275 +  // Switch the owner content before we start calling AddTreeItemToTreeOwner.
  1.1276 +  // Note that we rely on this to deal with setting mObservingOwnerContent to
  1.1277 +  // false and calling RemoveMutationObserver as needed.
  1.1278 +  SetOwnerContent(otherContent);
  1.1279 +  aOther->SetOwnerContent(ourContent);
  1.1280 +
  1.1281 +  AddTreeItemToTreeOwner(ourDocshell, otherOwner, otherParentType, nullptr);
  1.1282 +  aOther->AddTreeItemToTreeOwner(otherDocshell, ourOwner, ourParentType,
  1.1283 +                                 nullptr);
  1.1284 +
  1.1285 +  // SetSubDocumentFor nulls out parent documents on the old child doc if a
  1.1286 +  // new non-null document is passed in, so just go ahead and remove both
  1.1287 +  // kids before reinserting in the parent subdoc maps, to avoid
  1.1288 +  // complications.
  1.1289 +  ourParentDocument->SetSubDocumentFor(ourContent, nullptr);
  1.1290 +  otherParentDocument->SetSubDocumentFor(otherContent, nullptr);
  1.1291 +  ourParentDocument->SetSubDocumentFor(ourContent, otherChildDocument);
  1.1292 +  otherParentDocument->SetSubDocumentFor(otherContent, ourChildDocument);
  1.1293 +
  1.1294 +  ourWindow->SetFrameElementInternal(otherFrameElement);
  1.1295 +  otherWindow->SetFrameElementInternal(ourFrameElement);
  1.1296 +
  1.1297 +  nsRefPtr<nsFrameMessageManager> ourMessageManager = mMessageManager;
  1.1298 +  nsRefPtr<nsFrameMessageManager> otherMessageManager = aOther->mMessageManager;
  1.1299 +  // Swap pointers in child message managers.
  1.1300 +  if (mChildMessageManager) {
  1.1301 +    nsInProcessTabChildGlobal* tabChild =
  1.1302 +      static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get());
  1.1303 +    tabChild->SetOwner(otherContent);
  1.1304 +    tabChild->SetChromeMessageManager(otherMessageManager);
  1.1305 +  }
  1.1306 +  if (aOther->mChildMessageManager) {
  1.1307 +    nsInProcessTabChildGlobal* otherTabChild =
  1.1308 +      static_cast<nsInProcessTabChildGlobal*>(aOther->mChildMessageManager.get());
  1.1309 +    otherTabChild->SetOwner(ourContent);
  1.1310 +    otherTabChild->SetChromeMessageManager(ourMessageManager);
  1.1311 +  }
  1.1312 +  // Swap and setup things in parent message managers.
  1.1313 +  if (mMessageManager) {
  1.1314 +    mMessageManager->SetCallback(aOther);
  1.1315 +  }
  1.1316 +  if (aOther->mMessageManager) {
  1.1317 +    aOther->mMessageManager->SetCallback(this);
  1.1318 +  }
  1.1319 +  mMessageManager.swap(aOther->mMessageManager);
  1.1320 +
  1.1321 +  aFirstToSwap.swap(aSecondToSwap);
  1.1322 +
  1.1323 +  // Drop any cached content viewers in the two session histories.
  1.1324 +  nsCOMPtr<nsISHistoryInternal> ourInternalHistory =
  1.1325 +    do_QueryInterface(ourHistory);
  1.1326 +  nsCOMPtr<nsISHistoryInternal> otherInternalHistory =
  1.1327 +    do_QueryInterface(otherHistory);
  1.1328 +  if (ourInternalHistory) {
  1.1329 +    ourInternalHistory->EvictAllContentViewers();
  1.1330 +  }
  1.1331 +  if (otherInternalHistory) {
  1.1332 +    otherInternalHistory->EvictAllContentViewers();
  1.1333 +  }
  1.1334 +
  1.1335 +  NS_ASSERTION(ourFrame == ourContent->GetPrimaryFrame() &&
  1.1336 +               otherFrame == otherContent->GetPrimaryFrame(),
  1.1337 +               "changed primary frame");
  1.1338 +
  1.1339 +  ourFrameFrame->EndSwapDocShells(otherFrame);
  1.1340 +
  1.1341 +  // If the content being swapped came from windows on two screens with
  1.1342 +  // incompatible backing resolution (e.g. dragging a tab between windows on
  1.1343 +  // hi-dpi and low-dpi screens), it will have style data that is based on
  1.1344 +  // the wrong appUnitsPerDevPixel value. So we tell the PresShells that their
  1.1345 +  // backing scale factor may have changed. (Bug 822266)
  1.1346 +  ourShell->BackingScaleFactorChanged();
  1.1347 +  otherShell->BackingScaleFactorChanged();
  1.1348 +
  1.1349 +  ourParentDocument->FlushPendingNotifications(Flush_Layout);
  1.1350 +  otherParentDocument->FlushPendingNotifications(Flush_Layout);
  1.1351 +
  1.1352 +  FirePageShowEvent(ourDocshell, otherChromeEventHandler, true);
  1.1353 +  FirePageShowEvent(otherDocshell, ourChromeEventHandler, true);
  1.1354 +
  1.1355 +  mInSwap = aOther->mInSwap = false;
  1.1356 +  return NS_OK;
  1.1357 +}
  1.1358 +
  1.1359 +void
  1.1360 +nsFrameLoader::DestroyChild()
  1.1361 +{
  1.1362 +  if (mRemoteBrowser) {
  1.1363 +    mRemoteBrowser->SetOwnerElement(nullptr);
  1.1364 +    mRemoteBrowser->Destroy();
  1.1365 +    mRemoteBrowser = nullptr;
  1.1366 +  }
  1.1367 +}
  1.1368 +
  1.1369 +NS_IMETHODIMP
  1.1370 +nsFrameLoader::Destroy()
  1.1371 +{
  1.1372 +  if (mDestroyCalled) {
  1.1373 +    return NS_OK;
  1.1374 +  }
  1.1375 +  mDestroyCalled = true;
  1.1376 +
  1.1377 +  if (mMessageManager) {
  1.1378 +    mMessageManager->Disconnect();
  1.1379 +  }
  1.1380 +  if (mChildMessageManager) {
  1.1381 +    static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get())->Disconnect();
  1.1382 +  }
  1.1383 +
  1.1384 +  nsCOMPtr<nsIDocument> doc;
  1.1385 +  bool dynamicSubframeRemoval = false;
  1.1386 +  if (mOwnerContent) {
  1.1387 +    doc = mOwnerContent->OwnerDoc();
  1.1388 +    dynamicSubframeRemoval = !mIsTopLevelContent && !doc->InUnlinkOrDeletion();
  1.1389 +    doc->SetSubDocumentFor(mOwnerContent, nullptr);
  1.1390 +
  1.1391 +    SetOwnerContent(nullptr);
  1.1392 +  }
  1.1393 +  DestroyChild();
  1.1394 +
  1.1395 +  // Seems like this is a dynamic frame removal.
  1.1396 +  if (dynamicSubframeRemoval) {
  1.1397 +    if (mDocShell) {
  1.1398 +      mDocShell->RemoveFromSessionHistory();
  1.1399 +    }
  1.1400 +  }
  1.1401 +
  1.1402 +  // Let the tree owner know we're gone.
  1.1403 +  if (mIsTopLevelContent) {
  1.1404 +    if (mDocShell) {
  1.1405 +      nsCOMPtr<nsIDocShellTreeItem> parentItem;
  1.1406 +      mDocShell->GetParent(getter_AddRefs(parentItem));
  1.1407 +      nsCOMPtr<nsIDocShellTreeOwner> owner = do_GetInterface(parentItem);
  1.1408 +      if (owner) {
  1.1409 +        owner->ContentShellRemoved(mDocShell);
  1.1410 +      }
  1.1411 +    }
  1.1412 +  }
  1.1413 +  
  1.1414 +  // Let our window know that we are gone
  1.1415 +  nsCOMPtr<nsPIDOMWindow> win_private(do_GetInterface(mDocShell));
  1.1416 +  if (win_private) {
  1.1417 +    win_private->SetFrameElementInternal(nullptr);
  1.1418 +  }
  1.1419 +
  1.1420 +  if ((mNeedsAsyncDestroy || !doc ||
  1.1421 +       NS_FAILED(doc->FinalizeFrameLoader(this))) && mDocShell) {
  1.1422 +    nsCOMPtr<nsIRunnable> event = new nsAsyncDocShellDestroyer(mDocShell);
  1.1423 +    NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
  1.1424 +    NS_DispatchToCurrentThread(event);
  1.1425 +
  1.1426 +    // Let go of our docshell now that the async destroyer holds on to
  1.1427 +    // the docshell.
  1.1428 +
  1.1429 +    mDocShell = nullptr;
  1.1430 +  }
  1.1431 +
  1.1432 +  // NOTE: 'this' may very well be gone by now.
  1.1433 +
  1.1434 +  return NS_OK;
  1.1435 +}
  1.1436 +
  1.1437 +NS_IMETHODIMP
  1.1438 +nsFrameLoader::GetDepthTooGreat(bool* aDepthTooGreat)
  1.1439 +{
  1.1440 +  *aDepthTooGreat = mDepthTooGreat;
  1.1441 +  return NS_OK;
  1.1442 +}
  1.1443 +
  1.1444 +void
  1.1445 +nsFrameLoader::SetOwnerContent(Element* aContent)
  1.1446 +{
  1.1447 +  if (mObservingOwnerContent) {
  1.1448 +    mObservingOwnerContent = false;
  1.1449 +    mOwnerContent->RemoveMutationObserver(this);
  1.1450 +  }
  1.1451 +  mOwnerContent = aContent;
  1.1452 +  if (RenderFrameParent* rfp = GetCurrentRemoteFrame()) {
  1.1453 +    rfp->OwnerContentChanged(aContent);
  1.1454 +  }
  1.1455 +
  1.1456 +  ResetPermissionManagerStatus();
  1.1457 +}
  1.1458 +
  1.1459 +bool
  1.1460 +nsFrameLoader::OwnerIsBrowserOrAppFrame()
  1.1461 +{
  1.1462 +  nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
  1.1463 +  return browserFrame ? browserFrame->GetReallyIsBrowserOrApp() : false;
  1.1464 +}
  1.1465 +
  1.1466 +// The xpcom getter version
  1.1467 +NS_IMETHODIMP
  1.1468 +nsFrameLoader::GetOwnerIsBrowserOrAppFrame(bool* aResult)
  1.1469 +{
  1.1470 +  *aResult = OwnerIsBrowserOrAppFrame();
  1.1471 +  return NS_OK;
  1.1472 +}
  1.1473 +
  1.1474 +bool
  1.1475 +nsFrameLoader::OwnerIsAppFrame()
  1.1476 +{
  1.1477 +  nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
  1.1478 +  return browserFrame ? browserFrame->GetReallyIsApp() : false;
  1.1479 +}
  1.1480 +
  1.1481 +bool
  1.1482 +nsFrameLoader::OwnerIsBrowserFrame()
  1.1483 +{
  1.1484 +  return OwnerIsBrowserOrAppFrame() && !OwnerIsAppFrame();
  1.1485 +}
  1.1486 +
  1.1487 +void
  1.1488 +nsFrameLoader::GetOwnerAppManifestURL(nsAString& aOut)
  1.1489 +{
  1.1490 +  aOut.Truncate();
  1.1491 +  nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
  1.1492 +  if (browserFrame) {
  1.1493 +    browserFrame->GetAppManifestURL(aOut);
  1.1494 +  }
  1.1495 +}
  1.1496 +
  1.1497 +already_AddRefed<mozIApplication>
  1.1498 +nsFrameLoader::GetOwnApp()
  1.1499 +{
  1.1500 +  nsAutoString manifest;
  1.1501 +  GetOwnerAppManifestURL(manifest);
  1.1502 +  if (manifest.IsEmpty()) {
  1.1503 +    return nullptr;
  1.1504 +  }
  1.1505 +
  1.1506 +  nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
  1.1507 +  NS_ENSURE_TRUE(appsService, nullptr);
  1.1508 +
  1.1509 +  nsCOMPtr<mozIApplication> app;
  1.1510 +  appsService->GetAppByManifestURL(manifest, getter_AddRefs(app));
  1.1511 +
  1.1512 +  return app.forget();
  1.1513 +}
  1.1514 +
  1.1515 +already_AddRefed<mozIApplication>
  1.1516 +nsFrameLoader::GetContainingApp()
  1.1517 +{
  1.1518 +  // See if our owner content's principal has an associated app.
  1.1519 +  uint32_t appId = mOwnerContent->NodePrincipal()->GetAppId();
  1.1520 +  MOZ_ASSERT(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
  1.1521 +
  1.1522 +  if (appId == nsIScriptSecurityManager::NO_APP_ID ||
  1.1523 +      appId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
  1.1524 +    return nullptr;
  1.1525 +  }
  1.1526 +
  1.1527 +  nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
  1.1528 +  NS_ENSURE_TRUE(appsService, nullptr);
  1.1529 +
  1.1530 +  nsCOMPtr<mozIApplication> app;
  1.1531 +  appsService->GetAppByLocalId(appId, getter_AddRefs(app));
  1.1532 +
  1.1533 +  return app.forget();
  1.1534 +}
  1.1535 +
  1.1536 +bool
  1.1537 +nsFrameLoader::ShouldUseRemoteProcess()
  1.1538 +{
  1.1539 +  if (PR_GetEnv("MOZ_DISABLE_OOP_TABS") ||
  1.1540 +      Preferences::GetBool("dom.ipc.tabs.disabled", false)) {
  1.1541 +    return false;
  1.1542 +  }
  1.1543 +
  1.1544 +  // If we're inside a content process, don't use a remote process for this
  1.1545 +  // frame; it won't work properly until bug 761935 is fixed.
  1.1546 +  if (XRE_GetProcessType() == GeckoProcessType_Content) {
  1.1547 +    return false;
  1.1548 +  }
  1.1549 +
  1.1550 +  // If we're an <iframe mozbrowser> and we don't have a "remote" attribute,
  1.1551 +  // fall back to the default.
  1.1552 +  if (OwnerIsBrowserOrAppFrame() &&
  1.1553 +      !mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::Remote)) {
  1.1554 +
  1.1555 +    return Preferences::GetBool("dom.ipc.browser_frames.oop_by_default", false);
  1.1556 +  }
  1.1557 +
  1.1558 +  // Otherwise, we're remote if we have "remote=true" and we're either a
  1.1559 +  // browser frame or a XUL element.
  1.1560 +  return (OwnerIsBrowserOrAppFrame() ||
  1.1561 +          mOwnerContent->GetNameSpaceID() == kNameSpaceID_XUL) &&
  1.1562 +         mOwnerContent->AttrValueIs(kNameSpaceID_None,
  1.1563 +                                    nsGkAtoms::Remote,
  1.1564 +                                    nsGkAtoms::_true,
  1.1565 +                                    eCaseMatters);
  1.1566 +}
  1.1567 +
  1.1568 +nsresult
  1.1569 +nsFrameLoader::MaybeCreateDocShell()
  1.1570 +{
  1.1571 +  if (mDocShell) {
  1.1572 +    return NS_OK;
  1.1573 +  }
  1.1574 +  if (mRemoteFrame) {
  1.1575 +    return NS_OK;
  1.1576 +  }
  1.1577 +  NS_ENSURE_STATE(!mDestroyCalled);
  1.1578 +
  1.1579 +  if (ShouldUseRemoteProcess()) {
  1.1580 +    mRemoteFrame = true;
  1.1581 +    return NS_OK;
  1.1582 +  }
  1.1583 +
  1.1584 +  // Get our parent docshell off the document of mOwnerContent
  1.1585 +  // XXXbz this is such a total hack.... We really need to have a
  1.1586 +  // better setup for doing this.
  1.1587 +  nsIDocument* doc = mOwnerContent->OwnerDoc();
  1.1588 +  if (!(doc->IsStaticDocument() || mOwnerContent->IsInDoc())) {
  1.1589 +    return NS_ERROR_UNEXPECTED;
  1.1590 +  }
  1.1591 +
  1.1592 +  if (doc->IsResourceDoc() || !doc->IsActive()) {
  1.1593 +    // Don't allow subframe loads in resource documents, nor
  1.1594 +    // in non-active documents.
  1.1595 +    return NS_ERROR_NOT_AVAILABLE;
  1.1596 +  }
  1.1597 +
  1.1598 +  nsCOMPtr<nsIDocShell> docShell = doc->GetDocShell();
  1.1599 +  nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_QueryInterface(docShell);
  1.1600 +  NS_ENSURE_STATE(parentAsWebNav);
  1.1601 +
  1.1602 +  // Create the docshell...
  1.1603 +  mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
  1.1604 +  NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
  1.1605 +
  1.1606 +  // Apply sandbox flags even if our owner is not an iframe, as this copies
  1.1607 +  // flags from our owning content's owning document.
  1.1608 +  uint32_t sandboxFlags = 0;
  1.1609 +  HTMLIFrameElement* iframe = HTMLIFrameElement::FromContent(mOwnerContent);
  1.1610 +  if (iframe) {
  1.1611 +    sandboxFlags = iframe->GetSandboxFlags();
  1.1612 +  }
  1.1613 +  ApplySandboxFlags(sandboxFlags);
  1.1614 +
  1.1615 +  if (!mNetworkCreated) {
  1.1616 +    if (mDocShell) {
  1.1617 +      mDocShell->SetCreatedDynamically(true);
  1.1618 +    }
  1.1619 +  }
  1.1620 +
  1.1621 +  // Get the frame name and tell the docshell about it.
  1.1622 +  NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
  1.1623 +  nsAutoString frameName;
  1.1624 +
  1.1625 +  int32_t namespaceID = mOwnerContent->GetNameSpaceID();
  1.1626 +  if (namespaceID == kNameSpaceID_XHTML && !mOwnerContent->IsInHTMLDocument()) {
  1.1627 +    mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
  1.1628 +  } else {
  1.1629 +    mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, frameName);
  1.1630 +    // XXX if no NAME then use ID, after a transition period this will be
  1.1631 +    // changed so that XUL only uses ID too (bug 254284).
  1.1632 +    if (frameName.IsEmpty() && namespaceID == kNameSpaceID_XUL) {
  1.1633 +      mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
  1.1634 +    }
  1.1635 +  }
  1.1636 +
  1.1637 +  if (!frameName.IsEmpty()) {
  1.1638 +    mDocShell->SetName(frameName);
  1.1639 +  }
  1.1640 +
  1.1641 +  // Inform our docShell that it has a new child.
  1.1642 +  // Note: This logic duplicates a lot of logic in
  1.1643 +  // nsSubDocumentFrame::AttributeChanged.  We should fix that.
  1.1644 +
  1.1645 +  int32_t parentType = docShell->ItemType();
  1.1646 +
  1.1647 +  // XXXbz why is this in content code, exactly?  We should handle
  1.1648 +  // this some other way.....  Not sure how yet.
  1.1649 +  nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
  1.1650 +  docShell->GetTreeOwner(getter_AddRefs(parentTreeOwner));
  1.1651 +  NS_ENSURE_STATE(parentTreeOwner);
  1.1652 +  mIsTopLevelContent =
  1.1653 +    AddTreeItemToTreeOwner(mDocShell, parentTreeOwner, parentType, docShell);
  1.1654 +
  1.1655 +  // Make sure all shells have links back to the content element
  1.1656 +  // in the nearest enclosing chrome shell.
  1.1657 +  nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
  1.1658 +
  1.1659 +  if (parentType == nsIDocShellTreeItem::typeChrome) {
  1.1660 +    // Our parent shell is a chrome shell. It is therefore our nearest
  1.1661 +    // enclosing chrome shell.
  1.1662 +
  1.1663 +    chromeEventHandler = do_QueryInterface(mOwnerContent);
  1.1664 +    NS_ASSERTION(chromeEventHandler,
  1.1665 +                 "This mContent should implement this.");
  1.1666 +  } else {
  1.1667 +    // Our parent shell is a content shell. Get the chrome event
  1.1668 +    // handler from it and use that for our shell as well.
  1.1669 +
  1.1670 +    docShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
  1.1671 +  }
  1.1672 +
  1.1673 +  mDocShell->SetChromeEventHandler(chromeEventHandler);
  1.1674 +
  1.1675 +  // This is nasty, this code (the do_GetInterface(mDocShell) below)
  1.1676 +  // *must* come *after* the above call to
  1.1677 +  // mDocShell->SetChromeEventHandler() for the global window to get
  1.1678 +  // the right chrome event handler.
  1.1679 +
  1.1680 +  // Tell the window about the frame that hosts it.
  1.1681 +  nsCOMPtr<Element> frame_element = mOwnerContent;
  1.1682 +  NS_ASSERTION(frame_element, "frame loader owner element not a DOM element!");
  1.1683 +
  1.1684 +  nsCOMPtr<nsPIDOMWindow> win_private(do_GetInterface(mDocShell));
  1.1685 +  nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell));
  1.1686 +  if (win_private) {
  1.1687 +    win_private->SetFrameElementInternal(frame_element);
  1.1688 +  }
  1.1689 +
  1.1690 +  // This is kinda whacky, this call doesn't really create anything,
  1.1691 +  // but it must be called to make sure things are properly
  1.1692 +  // initialized.
  1.1693 +  if (NS_FAILED(base_win->Create()) || !win_private) {
  1.1694 +    // Do not call Destroy() here. See bug 472312.
  1.1695 +    NS_WARNING("Something wrong when creating the docshell for a frameloader!");
  1.1696 +    return NS_ERROR_FAILURE;
  1.1697 +  }
  1.1698 +
  1.1699 +  if (mIsTopLevelContent &&
  1.1700 +      mOwnerContent->IsXUL(nsGkAtoms::browser) &&
  1.1701 +      !mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::disablehistory)) {
  1.1702 +    nsresult rv;
  1.1703 +    nsCOMPtr<nsISHistory> sessionHistory =
  1.1704 +      do_CreateInstance(NS_SHISTORY_CONTRACTID, &rv);
  1.1705 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1706 +
  1.1707 +    nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
  1.1708 +    webNav->SetSessionHistory(sessionHistory);
  1.1709 +  }
  1.1710 +
  1.1711 +  EnsureMessageManager();
  1.1712 +
  1.1713 +  if (OwnerIsAppFrame()) {
  1.1714 +    // You can't be both an app and a browser frame.
  1.1715 +    MOZ_ASSERT(!OwnerIsBrowserFrame());
  1.1716 +
  1.1717 +    nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
  1.1718 +    MOZ_ASSERT(ownApp);
  1.1719 +    uint32_t ownAppId = nsIScriptSecurityManager::NO_APP_ID;
  1.1720 +    if (ownApp) {
  1.1721 +      NS_ENSURE_SUCCESS(ownApp->GetLocalId(&ownAppId), NS_ERROR_FAILURE);
  1.1722 +    }
  1.1723 +
  1.1724 +    mDocShell->SetIsApp(ownAppId);
  1.1725 +  }
  1.1726 +
  1.1727 +  if (OwnerIsBrowserFrame()) {
  1.1728 +    // You can't be both a browser and an app frame.
  1.1729 +    MOZ_ASSERT(!OwnerIsAppFrame());
  1.1730 +
  1.1731 +    nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
  1.1732 +    uint32_t containingAppId = nsIScriptSecurityManager::NO_APP_ID;
  1.1733 +    if (containingApp) {
  1.1734 +      NS_ENSURE_SUCCESS(containingApp->GetLocalId(&containingAppId),
  1.1735 +                        NS_ERROR_FAILURE);
  1.1736 +    }
  1.1737 +    mDocShell->SetIsBrowserInsideApp(containingAppId);
  1.1738 +  }
  1.1739 +
  1.1740 +  nsCOMPtr<nsIObserverService> os = services::GetObserverService();
  1.1741 +  if (os) {
  1.1742 +    os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
  1.1743 +                        "inprocess-browser-shown", nullptr);
  1.1744 +  }
  1.1745 +
  1.1746 +  if (OwnerIsBrowserOrAppFrame() && mMessageManager) {
  1.1747 +    mMessageManager->LoadFrameScript(
  1.1748 +      NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js"),
  1.1749 +      /* allowDelayedLoad = */ true,
  1.1750 +      /* aRunInGlobalScope */ true);
  1.1751 +  }
  1.1752 +
  1.1753 +  return NS_OK;
  1.1754 +}
  1.1755 +
  1.1756 +void
  1.1757 +nsFrameLoader::GetURL(nsString& aURI)
  1.1758 +{
  1.1759 +  aURI.Truncate();
  1.1760 +
  1.1761 +  if (mOwnerContent->Tag() == nsGkAtoms::object) {
  1.1762 +    mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, aURI);
  1.1763 +  } else {
  1.1764 +    mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, aURI);
  1.1765 +  }
  1.1766 +}
  1.1767 +
  1.1768 +nsresult
  1.1769 +nsFrameLoader::CheckForRecursiveLoad(nsIURI* aURI)
  1.1770 +{
  1.1771 +  nsresult rv;
  1.1772 +
  1.1773 +  mDepthTooGreat = false;
  1.1774 +  rv = MaybeCreateDocShell();
  1.1775 +  if (NS_FAILED(rv)) {
  1.1776 +    return rv;
  1.1777 +  }
  1.1778 +  NS_ASSERTION(!mRemoteFrame,
  1.1779 +               "Shouldn't call CheckForRecursiveLoad on remote frames.");
  1.1780 +  if (!mDocShell) {
  1.1781 +    return NS_ERROR_FAILURE;
  1.1782 +  }
  1.1783 +
  1.1784 +  // Check that we're still in the docshell tree.
  1.1785 +  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
  1.1786 +  mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
  1.1787 +  NS_WARN_IF_FALSE(treeOwner,
  1.1788 +                   "Trying to load a new url to a docshell without owner!");
  1.1789 +  NS_ENSURE_STATE(treeOwner);
  1.1790 +  
  1.1791 +  if (mDocShell->ItemType() != nsIDocShellTreeItem::typeContent) {
  1.1792 +    // No need to do recursion-protection here XXXbz why not??  Do we really
  1.1793 +    // trust people not to screw up with non-content docshells?
  1.1794 +    return NS_OK;
  1.1795 +  }
  1.1796 +
  1.1797 +  // Bug 8065: Don't exceed some maximum depth in content frames
  1.1798 +  // (MAX_DEPTH_CONTENT_FRAMES)
  1.1799 +  nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
  1.1800 +  mDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem));
  1.1801 +  int32_t depth = 0;
  1.1802 +  while (parentAsItem) {
  1.1803 +    ++depth;
  1.1804 +    
  1.1805 +    if (depth >= MAX_DEPTH_CONTENT_FRAMES) {
  1.1806 +      mDepthTooGreat = true;
  1.1807 +      NS_WARNING("Too many nested content frames so giving up");
  1.1808 +
  1.1809 +      return NS_ERROR_UNEXPECTED; // Too deep, give up!  (silently?)
  1.1810 +    }
  1.1811 +
  1.1812 +    nsCOMPtr<nsIDocShellTreeItem> temp;
  1.1813 +    temp.swap(parentAsItem);
  1.1814 +    temp->GetSameTypeParent(getter_AddRefs(parentAsItem));
  1.1815 +  }
  1.1816 +
  1.1817 +  // Bug 136580: Check for recursive frame loading excluding about:srcdoc URIs.
  1.1818 +  // srcdoc URIs require their contents to be specified inline, so it isn't
  1.1819 +  // possible for undesirable recursion to occur without the aid of a
  1.1820 +  // non-srcdoc URI,  which this method will block normally.
  1.1821 +  // Besides, URI is not enough to guarantee uniqueness of srcdoc documents.
  1.1822 +  nsAutoCString buffer;
  1.1823 +  rv = aURI->GetScheme(buffer);
  1.1824 +  if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("about")) {
  1.1825 +    rv = aURI->GetPath(buffer);
  1.1826 +    if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("srcdoc")) {
  1.1827 +      // Duplicates allowed up to depth limits
  1.1828 +      return NS_OK;
  1.1829 +    }
  1.1830 +  }
  1.1831 +  int32_t matchCount = 0;
  1.1832 +  mDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem));
  1.1833 +  while (parentAsItem) {
  1.1834 +    // Check the parent URI with the URI we're loading
  1.1835 +    nsCOMPtr<nsIWebNavigation> parentAsNav(do_QueryInterface(parentAsItem));
  1.1836 +    if (parentAsNav) {
  1.1837 +      // Does the URI match the one we're about to load?
  1.1838 +      nsCOMPtr<nsIURI> parentURI;
  1.1839 +      parentAsNav->GetCurrentURI(getter_AddRefs(parentURI));
  1.1840 +      if (parentURI) {
  1.1841 +        // Bug 98158/193011: We need to ignore data after the #
  1.1842 +        bool equal;
  1.1843 +        rv = aURI->EqualsExceptRef(parentURI, &equal);
  1.1844 +        NS_ENSURE_SUCCESS(rv, rv);
  1.1845 +        
  1.1846 +        if (equal) {
  1.1847 +          matchCount++;
  1.1848 +          if (matchCount >= MAX_SAME_URL_CONTENT_FRAMES) {
  1.1849 +            NS_WARNING("Too many nested content frames have the same url (recursion?) so giving up");
  1.1850 +            return NS_ERROR_UNEXPECTED;
  1.1851 +          }
  1.1852 +        }
  1.1853 +      }
  1.1854 +    }
  1.1855 +    nsCOMPtr<nsIDocShellTreeItem> temp;
  1.1856 +    temp.swap(parentAsItem);
  1.1857 +    temp->GetSameTypeParent(getter_AddRefs(parentAsItem));
  1.1858 +  }
  1.1859 +
  1.1860 +  return NS_OK;
  1.1861 +}
  1.1862 +
  1.1863 +nsresult
  1.1864 +nsFrameLoader::GetWindowDimensions(nsRect& aRect)
  1.1865 +{
  1.1866 +  // Need to get outer window position here
  1.1867 +  nsIDocument* doc = mOwnerContent->GetDocument();
  1.1868 +  if (!doc) {
  1.1869 +    return NS_ERROR_FAILURE;
  1.1870 +  }
  1.1871 +
  1.1872 +  if (doc->IsResourceDoc()) {
  1.1873 +    return NS_ERROR_FAILURE;
  1.1874 +  }
  1.1875 +
  1.1876 +  nsCOMPtr<nsIWebNavigation> parentAsWebNav =
  1.1877 +    do_GetInterface(doc->GetWindow());
  1.1878 +
  1.1879 +  if (!parentAsWebNav) {
  1.1880 +    return NS_ERROR_FAILURE;
  1.1881 +  }
  1.1882 +
  1.1883 +  nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsWebNav));
  1.1884 +
  1.1885 +  nsCOMPtr<nsIDocShellTreeOwner> parentOwner;
  1.1886 +  if (NS_FAILED(parentAsItem->GetTreeOwner(getter_AddRefs(parentOwner))) ||
  1.1887 +      !parentOwner) {
  1.1888 +    return NS_ERROR_FAILURE;
  1.1889 +  }
  1.1890 +
  1.1891 +  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_GetInterface(parentOwner));
  1.1892 +  treeOwnerAsWin->GetPosition(&aRect.x, &aRect.y);
  1.1893 +  treeOwnerAsWin->GetSize(&aRect.width, &aRect.height);
  1.1894 +  return NS_OK;
  1.1895 +}
  1.1896 +
  1.1897 +NS_IMETHODIMP
  1.1898 +nsFrameLoader::UpdatePositionAndSize(nsSubDocumentFrame *aIFrame)
  1.1899 +{
  1.1900 +  if (mRemoteFrame) {
  1.1901 +    if (mRemoteBrowser) {
  1.1902 +      nsIntSize size = aIFrame->GetSubdocumentSize();
  1.1903 +      nsRect dimensions;
  1.1904 +      NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), NS_ERROR_FAILURE);
  1.1905 +      mRemoteBrowser->UpdateDimensions(dimensions, size);
  1.1906 +    }
  1.1907 +    return NS_OK;
  1.1908 +  }
  1.1909 +  return UpdateBaseWindowPositionAndSize(aIFrame);
  1.1910 +}
  1.1911 +
  1.1912 +nsresult
  1.1913 +nsFrameLoader::UpdateBaseWindowPositionAndSize(nsSubDocumentFrame *aIFrame)
  1.1914 +{
  1.1915 +  nsCOMPtr<nsIDocShell> docShell;
  1.1916 +  GetDocShell(getter_AddRefs(docShell));
  1.1917 +  nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
  1.1918 +
  1.1919 +  // resize the sub document
  1.1920 +  if (baseWindow) {
  1.1921 +    int32_t x = 0;
  1.1922 +    int32_t y = 0;
  1.1923 +
  1.1924 +    nsWeakFrame weakFrame(aIFrame);
  1.1925 +
  1.1926 +    baseWindow->GetPositionAndSize(&x, &y, nullptr, nullptr);
  1.1927 +
  1.1928 +    if (!weakFrame.IsAlive()) {
  1.1929 +      // GetPositionAndSize() killed us
  1.1930 +      return NS_OK;
  1.1931 +    }
  1.1932 +
  1.1933 +    nsIntSize size = aIFrame->GetSubdocumentSize();
  1.1934 +
  1.1935 +    baseWindow->SetPositionAndSize(x, y, size.width, size.height, false);
  1.1936 +  }
  1.1937 +
  1.1938 +  return NS_OK;
  1.1939 +}
  1.1940 +
  1.1941 +NS_IMETHODIMP
  1.1942 +nsFrameLoader::GetRenderMode(uint32_t* aRenderMode)
  1.1943 +{
  1.1944 +  *aRenderMode = mRenderMode;
  1.1945 +  return NS_OK;
  1.1946 +}
  1.1947 +
  1.1948 +NS_IMETHODIMP
  1.1949 +nsFrameLoader::SetRenderMode(uint32_t aRenderMode)
  1.1950 +{
  1.1951 +  if (aRenderMode == mRenderMode) {
  1.1952 +    return NS_OK;
  1.1953 +  }
  1.1954 +
  1.1955 +  mRenderMode = aRenderMode;
  1.1956 +  return NS_OK;
  1.1957 +}
  1.1958 +
  1.1959 +NS_IMETHODIMP
  1.1960 +nsFrameLoader::GetEventMode(uint32_t* aEventMode)
  1.1961 +{
  1.1962 +  *aEventMode = mEventMode;
  1.1963 +  return NS_OK;
  1.1964 +}
  1.1965 +
  1.1966 +NS_IMETHODIMP
  1.1967 +nsFrameLoader::SetEventMode(uint32_t aEventMode)
  1.1968 +{
  1.1969 +  mEventMode = aEventMode;
  1.1970 +  return NS_OK;
  1.1971 +}
  1.1972 +
  1.1973 +NS_IMETHODIMP
  1.1974 +nsFrameLoader::GetClipSubdocument(bool* aResult)
  1.1975 +{
  1.1976 +  *aResult = mClipSubdocument;
  1.1977 +  return NS_OK;
  1.1978 +}
  1.1979 +
  1.1980 +NS_IMETHODIMP
  1.1981 +nsFrameLoader::SetClipSubdocument(bool aClip)
  1.1982 +{
  1.1983 +  mClipSubdocument = aClip;
  1.1984 +  nsIFrame* frame = GetPrimaryFrameOfOwningContent();
  1.1985 +  if (frame) {
  1.1986 +    frame->InvalidateFrame();
  1.1987 +    frame->PresContext()->PresShell()->
  1.1988 +      FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
  1.1989 +    nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);
  1.1990 +    if (subdocFrame) {
  1.1991 +      nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame();
  1.1992 +      if (subdocRootFrame) {
  1.1993 +        nsIFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()->
  1.1994 +          GetRootScrollFrame();
  1.1995 +        if (subdocRootScrollFrame) {
  1.1996 +          frame->PresContext()->PresShell()->
  1.1997 +            FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
  1.1998 +        }
  1.1999 +      }
  1.2000 +    }
  1.2001 +  }
  1.2002 +  return NS_OK;
  1.2003 +}
  1.2004 +
  1.2005 +NS_IMETHODIMP
  1.2006 +nsFrameLoader::GetClampScrollPosition(bool* aResult)
  1.2007 +{
  1.2008 +  *aResult = mClampScrollPosition;
  1.2009 +  return NS_OK;
  1.2010 +}
  1.2011 +
  1.2012 +NS_IMETHODIMP
  1.2013 +nsFrameLoader::SetClampScrollPosition(bool aClamp)
  1.2014 +{
  1.2015 +  mClampScrollPosition = aClamp;
  1.2016 +
  1.2017 +  // When turning clamping on, make sure the current position is clamped.
  1.2018 +  if (aClamp) {
  1.2019 +    nsIFrame* frame = GetPrimaryFrameOfOwningContent();
  1.2020 +    nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);
  1.2021 +    if (subdocFrame) {
  1.2022 +      nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame();
  1.2023 +      if (subdocRootFrame) {
  1.2024 +        nsIScrollableFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()->
  1.2025 +          GetRootScrollFrameAsScrollable();
  1.2026 +        if (subdocRootScrollFrame) {
  1.2027 +          subdocRootScrollFrame->ScrollTo(subdocRootScrollFrame->GetScrollPosition(), nsIScrollableFrame::INSTANT);
  1.2028 +        }
  1.2029 +      }
  1.2030 +    }
  1.2031 +  }
  1.2032 +  return NS_OK;
  1.2033 +}
  1.2034 +
  1.2035 +bool
  1.2036 +nsFrameLoader::TryRemoteBrowser()
  1.2037 +{
  1.2038 +  NS_ASSERTION(!mRemoteBrowser, "TryRemoteBrowser called with a remote browser already?");
  1.2039 +
  1.2040 +  nsIDocument* doc = mOwnerContent->GetDocument();
  1.2041 +  if (!doc) {
  1.2042 +    return false;
  1.2043 +  }
  1.2044 +
  1.2045 +  if (doc->IsResourceDoc()) {
  1.2046 +    // Don't allow subframe loads in external reference documents
  1.2047 +    return false;
  1.2048 +  }
  1.2049 +
  1.2050 +  nsCOMPtr<nsIWebNavigation> parentAsWebNav =
  1.2051 +    do_GetInterface(doc->GetWindow());
  1.2052 +
  1.2053 +  if (!parentAsWebNav) {
  1.2054 +    return false;
  1.2055 +  }
  1.2056 +
  1.2057 +  nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsWebNav));
  1.2058 +
  1.2059 +  // <iframe mozbrowser> gets to skip these checks.
  1.2060 +  if (!OwnerIsBrowserOrAppFrame()) {
  1.2061 +    if (parentAsItem->ItemType() != nsIDocShellTreeItem::typeChrome) {
  1.2062 +      return false;
  1.2063 +    }
  1.2064 +
  1.2065 +    if (!mOwnerContent->IsXUL()) {
  1.2066 +      return false;
  1.2067 +    }
  1.2068 +
  1.2069 +    nsAutoString value;
  1.2070 +    mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
  1.2071 +
  1.2072 +    if (!value.LowerCaseEqualsLiteral("content") &&
  1.2073 +        !StringBeginsWith(value, NS_LITERAL_STRING("content-"),
  1.2074 +                          nsCaseInsensitiveStringComparator())) {
  1.2075 +      return false;
  1.2076 +    }
  1.2077 +  }
  1.2078 +
  1.2079 +  uint32_t chromeFlags = 0;
  1.2080 +  nsCOMPtr<nsIDocShellTreeOwner> parentOwner;
  1.2081 +  if (NS_FAILED(parentAsItem->GetTreeOwner(getter_AddRefs(parentOwner))) ||
  1.2082 +      !parentOwner) {
  1.2083 +    return false;
  1.2084 +  }
  1.2085 +  nsCOMPtr<nsIXULWindow> window(do_GetInterface(parentOwner));
  1.2086 +  if (!window) {
  1.2087 +    return false;
  1.2088 +  }
  1.2089 +  if (NS_FAILED(window->GetChromeFlags(&chromeFlags))) {
  1.2090 +    return false;
  1.2091 +  }
  1.2092 +
  1.2093 +  PROFILER_LABEL("nsFrameLoader", "CreateRemoteBrowser");
  1.2094 +
  1.2095 +  MutableTabContext context;
  1.2096 +  nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
  1.2097 +  nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
  1.2098 +  ScrollingBehavior scrollingBehavior = DEFAULT_SCROLLING;
  1.2099 +
  1.2100 +  if (Preferences::GetBool("dom.browser_frames.useAsyncPanZoom", false) ||
  1.2101 +      mOwnerContent->AttrValueIs(kNameSpaceID_None,
  1.2102 +                                 nsGkAtoms::mozasyncpanzoom,
  1.2103 +                                 nsGkAtoms::_true,
  1.2104 +                                 eCaseMatters)) {
  1.2105 +    scrollingBehavior = ASYNC_PAN_ZOOM;
  1.2106 +  }
  1.2107 +
  1.2108 +  bool rv = true;
  1.2109 +  if (ownApp) {
  1.2110 +    rv = context.SetTabContextForAppFrame(ownApp, containingApp, scrollingBehavior);
  1.2111 +  } else if (OwnerIsBrowserFrame()) {
  1.2112 +    // The |else| above is unnecessary; OwnerIsBrowserFrame() implies !ownApp.
  1.2113 +    rv = context.SetTabContextForBrowserFrame(containingApp, scrollingBehavior);
  1.2114 +  } else {
  1.2115 +    rv = context.SetTabContextForNormalFrame(scrollingBehavior);
  1.2116 +  }
  1.2117 +  NS_ENSURE_TRUE(rv, false);
  1.2118 +
  1.2119 +  nsCOMPtr<Element> ownerElement = mOwnerContent;
  1.2120 +  mRemoteBrowser = ContentParent::CreateBrowserOrApp(context, ownerElement);
  1.2121 +  if (mRemoteBrowser) {
  1.2122 +    mChildID = mRemoteBrowser->Manager()->ChildID();
  1.2123 +    nsCOMPtr<nsIDocShellTreeItem> rootItem;
  1.2124 +    parentAsItem->GetRootTreeItem(getter_AddRefs(rootItem));
  1.2125 +    nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
  1.2126 +    nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin);
  1.2127 +    NS_ABORT_IF_FALSE(rootChromeWin, "How did we not get a chrome window here?");
  1.2128 +
  1.2129 +    nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
  1.2130 +    rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
  1.2131 +    mRemoteBrowser->SetBrowserDOMWindow(browserDOMWin);
  1.2132 +
  1.2133 +    mContentParent = mRemoteBrowser->Manager();
  1.2134 +
  1.2135 +    if (mOwnerContent->AttrValueIs(kNameSpaceID_None,
  1.2136 +                                   nsGkAtoms::mozpasspointerevents,
  1.2137 +                                   nsGkAtoms::_true,
  1.2138 +                                   eCaseMatters)) {
  1.2139 +      unused << mRemoteBrowser->SendSetUpdateHitRegion(true);
  1.2140 +    }
  1.2141 +  }
  1.2142 +  return true;
  1.2143 +}
  1.2144 +
  1.2145 +mozilla::dom::PBrowserParent*
  1.2146 +nsFrameLoader::GetRemoteBrowser()
  1.2147 +{
  1.2148 +  return mRemoteBrowser;
  1.2149 +}
  1.2150 +
  1.2151 +NS_IMETHODIMP
  1.2152 +nsFrameLoader::ActivateRemoteFrame() {
  1.2153 +  if (mRemoteBrowser) {
  1.2154 +    mRemoteBrowser->Activate();
  1.2155 +    return NS_OK;
  1.2156 +  }
  1.2157 +  return NS_ERROR_UNEXPECTED;
  1.2158 +}
  1.2159 +
  1.2160 +NS_IMETHODIMP
  1.2161 +nsFrameLoader::DeactivateRemoteFrame() {
  1.2162 +  if (mRemoteBrowser) {
  1.2163 +    mRemoteBrowser->Deactivate();
  1.2164 +    return NS_OK;
  1.2165 +  }
  1.2166 +  return NS_ERROR_UNEXPECTED;
  1.2167 +}
  1.2168 +
  1.2169 +NS_IMETHODIMP
  1.2170 +nsFrameLoader::SendCrossProcessMouseEvent(const nsAString& aType,
  1.2171 +                                          float aX,
  1.2172 +                                          float aY,
  1.2173 +                                          int32_t aButton,
  1.2174 +                                          int32_t aClickCount,
  1.2175 +                                          int32_t aModifiers,
  1.2176 +                                          bool aIgnoreRootScrollFrame)
  1.2177 +{
  1.2178 +  if (mRemoteBrowser) {
  1.2179 +    mRemoteBrowser->SendMouseEvent(aType, aX, aY, aButton,
  1.2180 +                                   aClickCount, aModifiers,
  1.2181 +                                   aIgnoreRootScrollFrame);
  1.2182 +    return NS_OK;
  1.2183 +  }
  1.2184 +  return NS_ERROR_FAILURE;
  1.2185 +}
  1.2186 +
  1.2187 +NS_IMETHODIMP
  1.2188 +nsFrameLoader::ActivateFrameEvent(const nsAString& aType,
  1.2189 +                                  bool aCapture)
  1.2190 +{
  1.2191 +  if (mRemoteBrowser) {
  1.2192 +    return mRemoteBrowser->SendActivateFrameEvent(nsString(aType), aCapture) ?
  1.2193 +      NS_OK : NS_ERROR_NOT_AVAILABLE;
  1.2194 +  }
  1.2195 +  return NS_ERROR_FAILURE;
  1.2196 +}
  1.2197 +
  1.2198 +NS_IMETHODIMP
  1.2199 +nsFrameLoader::SendCrossProcessKeyEvent(const nsAString& aType,
  1.2200 +                                        int32_t aKeyCode,
  1.2201 +                                        int32_t aCharCode,
  1.2202 +                                        int32_t aModifiers,
  1.2203 +                                        bool aPreventDefault)
  1.2204 +{
  1.2205 +  if (mRemoteBrowser) {
  1.2206 +    mRemoteBrowser->SendKeyEvent(aType, aKeyCode, aCharCode, aModifiers,
  1.2207 +                                 aPreventDefault);
  1.2208 +    return NS_OK;
  1.2209 +  }
  1.2210 +  return NS_ERROR_FAILURE;
  1.2211 +}
  1.2212 +
  1.2213 +nsresult
  1.2214 +nsFrameLoader::CreateStaticClone(nsIFrameLoader* aDest)
  1.2215 +{
  1.2216 +  nsFrameLoader* dest = static_cast<nsFrameLoader*>(aDest);
  1.2217 +  dest->MaybeCreateDocShell();
  1.2218 +  NS_ENSURE_STATE(dest->mDocShell);
  1.2219 +
  1.2220 +  nsCOMPtr<nsIDocument> dummy = do_GetInterface(dest->mDocShell);
  1.2221 +  nsCOMPtr<nsIContentViewer> viewer;
  1.2222 +  dest->mDocShell->GetContentViewer(getter_AddRefs(viewer));
  1.2223 +  NS_ENSURE_STATE(viewer);
  1.2224 +
  1.2225 +  nsCOMPtr<nsIDocShell> origDocShell;
  1.2226 +  GetDocShell(getter_AddRefs(origDocShell));
  1.2227 +  nsCOMPtr<nsIDocument> doc = do_GetInterface(origDocShell);
  1.2228 +  NS_ENSURE_STATE(doc);
  1.2229 +  nsCOMPtr<nsIDocument> clonedDoc = doc->CreateStaticClone(dest->mDocShell);
  1.2230 +  nsCOMPtr<nsIDOMDocument> clonedDOMDoc = do_QueryInterface(clonedDoc);
  1.2231 +
  1.2232 +  viewer->SetDOMDocument(clonedDOMDoc);
  1.2233 +  return NS_OK;
  1.2234 +}
  1.2235 +
  1.2236 +bool
  1.2237 +nsFrameLoader::DoLoadFrameScript(const nsAString& aURL, bool aRunInGlobalScope)
  1.2238 +{
  1.2239 +  mozilla::dom::PBrowserParent* tabParent = GetRemoteBrowser();
  1.2240 +  if (tabParent) {
  1.2241 +    return tabParent->SendLoadRemoteScript(nsString(aURL), aRunInGlobalScope);
  1.2242 +  }
  1.2243 +  nsRefPtr<nsInProcessTabChildGlobal> tabChild =
  1.2244 +    static_cast<nsInProcessTabChildGlobal*>(GetTabChildGlobalAsEventTarget());
  1.2245 +  if (tabChild) {
  1.2246 +    tabChild->LoadFrameScript(aURL, aRunInGlobalScope);
  1.2247 +  }
  1.2248 +  return true;
  1.2249 +}
  1.2250 +
  1.2251 +class nsAsyncMessageToChild : public nsSameProcessAsyncMessageBase,
  1.2252 +                              public nsRunnable
  1.2253 +{
  1.2254 +public:
  1.2255 +  nsAsyncMessageToChild(JSContext* aCx,
  1.2256 +                        nsFrameLoader* aFrameLoader,
  1.2257 +                        const nsAString& aMessage,
  1.2258 +                        const StructuredCloneData& aData,
  1.2259 +                        JS::Handle<JSObject *> aCpows,
  1.2260 +                        nsIPrincipal* aPrincipal)
  1.2261 +    : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal)
  1.2262 +    , mFrameLoader(aFrameLoader)
  1.2263 +  {
  1.2264 +  }
  1.2265 +
  1.2266 +  NS_IMETHOD Run()
  1.2267 +  {
  1.2268 +    nsInProcessTabChildGlobal* tabChild =
  1.2269 +      static_cast<nsInProcessTabChildGlobal*>(mFrameLoader->mChildMessageManager.get());
  1.2270 +    if (tabChild && tabChild->GetInnerManager()) {
  1.2271 +      nsCOMPtr<nsIXPConnectJSObjectHolder> kungFuDeathGrip(tabChild->GetGlobal());
  1.2272 +      ReceiveMessage(static_cast<EventTarget*>(tabChild),
  1.2273 +                     tabChild->GetInnerManager());
  1.2274 +    }
  1.2275 +    return NS_OK;
  1.2276 +  }
  1.2277 +  nsRefPtr<nsFrameLoader> mFrameLoader;
  1.2278 +};
  1.2279 +
  1.2280 +bool
  1.2281 +nsFrameLoader::DoSendAsyncMessage(JSContext* aCx,
  1.2282 +                                  const nsAString& aMessage,
  1.2283 +                                  const StructuredCloneData& aData,
  1.2284 +                                  JS::Handle<JSObject *> aCpows,
  1.2285 +                                  nsIPrincipal* aPrincipal)
  1.2286 +{
  1.2287 +  TabParent* tabParent = mRemoteBrowser;
  1.2288 +  if (tabParent) {
  1.2289 +    ClonedMessageData data;
  1.2290 +    ContentParent* cp = tabParent->Manager();
  1.2291 +    if (!BuildClonedMessageDataForParent(cp, aData, data)) {
  1.2292 +      return false;
  1.2293 +    }
  1.2294 +    InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
  1.2295 +    if (aCpows && !cp->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
  1.2296 +      return false;
  1.2297 +    }
  1.2298 +    return tabParent->SendAsyncMessage(nsString(aMessage), data, cpows,
  1.2299 +                                       aPrincipal);
  1.2300 +  }
  1.2301 +
  1.2302 +  if (mChildMessageManager) {
  1.2303 +    nsRefPtr<nsIRunnable> ev = new nsAsyncMessageToChild(aCx, this, aMessage,
  1.2304 +                                                         aData, aCpows,
  1.2305 +                                                         aPrincipal);
  1.2306 +    NS_DispatchToCurrentThread(ev);
  1.2307 +    return true;
  1.2308 +  }
  1.2309 +
  1.2310 +  // We don't have any targets to send our asynchronous message to.
  1.2311 +  return false;
  1.2312 +}
  1.2313 +
  1.2314 +bool
  1.2315 +nsFrameLoader::CheckPermission(const nsAString& aPermission)
  1.2316 +{
  1.2317 +  return AssertAppProcessPermission(GetRemoteBrowser(),
  1.2318 +                                    NS_ConvertUTF16toUTF8(aPermission).get());
  1.2319 +}
  1.2320 +
  1.2321 +bool
  1.2322 +nsFrameLoader::CheckManifestURL(const nsAString& aManifestURL)
  1.2323 +{
  1.2324 +  return AssertAppProcessManifestURL(GetRemoteBrowser(),
  1.2325 +                                     NS_ConvertUTF16toUTF8(aManifestURL).get());
  1.2326 +}
  1.2327 +
  1.2328 +bool
  1.2329 +nsFrameLoader::CheckAppHasPermission(const nsAString& aPermission)
  1.2330 +{
  1.2331 +  return AssertAppHasPermission(GetRemoteBrowser(),
  1.2332 +                                NS_ConvertUTF16toUTF8(aPermission).get());
  1.2333 +}
  1.2334 +
  1.2335 +NS_IMETHODIMP
  1.2336 +nsFrameLoader::GetMessageManager(nsIMessageSender** aManager)
  1.2337 +{
  1.2338 +  EnsureMessageManager();
  1.2339 +  if (mMessageManager) {
  1.2340 +    CallQueryInterface(mMessageManager, aManager);
  1.2341 +  }
  1.2342 +  return NS_OK;
  1.2343 +}
  1.2344 +
  1.2345 +NS_IMETHODIMP
  1.2346 +nsFrameLoader::GetContentViewsIn(float aXPx, float aYPx,
  1.2347 +                                 float aTopSize, float aRightSize,
  1.2348 +                                 float aBottomSize, float aLeftSize,
  1.2349 +                                 uint32_t* aLength,
  1.2350 +                                 nsIContentView*** aResult)
  1.2351 +{
  1.2352 +  nscoord x = nsPresContext::CSSPixelsToAppUnits(aXPx - aLeftSize);
  1.2353 +  nscoord y = nsPresContext::CSSPixelsToAppUnits(aYPx - aTopSize);
  1.2354 +  nscoord w = nsPresContext::CSSPixelsToAppUnits(aLeftSize + aRightSize) + 1;
  1.2355 +  nscoord h = nsPresContext::CSSPixelsToAppUnits(aTopSize + aBottomSize) + 1;
  1.2356 +  nsRect target(x, y, w, h);
  1.2357 +
  1.2358 +  nsIFrame* frame = GetPrimaryFrameOfOwningContent();
  1.2359 +
  1.2360 +  nsTArray<ViewID> ids;
  1.2361 +  nsLayoutUtils::GetRemoteContentIds(frame, target, ids, true);
  1.2362 +  if (ids.Length() == 0 || !GetCurrentRemoteFrame()) {
  1.2363 +    *aResult = nullptr;
  1.2364 +    *aLength = 0;
  1.2365 +    return NS_OK;
  1.2366 +  }
  1.2367 +
  1.2368 +  nsIContentView** result = reinterpret_cast<nsIContentView**>(
  1.2369 +    NS_Alloc(ids.Length() * sizeof(nsIContentView*)));
  1.2370 +
  1.2371 +  for (uint32_t i = 0; i < ids.Length(); i++) {
  1.2372 +    nsIContentView* view = GetCurrentRemoteFrame()->GetContentView(ids[i]);
  1.2373 +    NS_ABORT_IF_FALSE(view, "Retrieved ID from RenderFrameParent, it should be valid!");
  1.2374 +    nsRefPtr<nsIContentView>(view).forget(&result[i]);
  1.2375 +  }
  1.2376 +
  1.2377 +  *aResult = result;
  1.2378 +  *aLength = ids.Length();
  1.2379 +
  1.2380 +  return NS_OK;
  1.2381 +}
  1.2382 +
  1.2383 +NS_IMETHODIMP
  1.2384 +nsFrameLoader::GetRootContentView(nsIContentView** aContentView)
  1.2385 +{
  1.2386 +  RenderFrameParent* rfp = GetCurrentRemoteFrame();
  1.2387 +  if (!rfp) {
  1.2388 +    *aContentView = nullptr;
  1.2389 +    return NS_OK;
  1.2390 +  }
  1.2391 +
  1.2392 +  nsContentView* view = rfp->GetRootContentView();
  1.2393 +  NS_ABORT_IF_FALSE(view, "Should always be able to create root scrollable!");
  1.2394 +  nsRefPtr<nsIContentView>(view).forget(aContentView);
  1.2395 +
  1.2396 +  return NS_OK;
  1.2397 +}
  1.2398 +
  1.2399 +nsresult
  1.2400 +nsFrameLoader::EnsureMessageManager()
  1.2401 +{
  1.2402 +  NS_ENSURE_STATE(mOwnerContent);
  1.2403 +
  1.2404 +  nsresult rv = MaybeCreateDocShell();
  1.2405 +  if (NS_FAILED(rv)) {
  1.2406 +    return rv;
  1.2407 +  }
  1.2408 +
  1.2409 +  if (!mIsTopLevelContent && !OwnerIsBrowserOrAppFrame() && !mRemoteFrame) {
  1.2410 +    return NS_OK;
  1.2411 +  }
  1.2412 +
  1.2413 +  if (mMessageManager) {
  1.2414 +    if (ShouldUseRemoteProcess() && mRemoteBrowserShown) {
  1.2415 +      mMessageManager->InitWithCallback(this);
  1.2416 +    }
  1.2417 +    return NS_OK;
  1.2418 +  }
  1.2419 +
  1.2420 +  nsIScriptContext* sctx = mOwnerContent->GetContextForEventHandlers(&rv);
  1.2421 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2422 +  NS_ENSURE_STATE(sctx);
  1.2423 +  AutoPushJSContext cx(sctx->GetNativeContext());
  1.2424 +  NS_ENSURE_STATE(cx);
  1.2425 +
  1.2426 +  nsCOMPtr<nsIDOMChromeWindow> chromeWindow =
  1.2427 +    do_QueryInterface(GetOwnerDoc()->GetWindow());
  1.2428 +  nsCOMPtr<nsIMessageBroadcaster> parentManager;
  1.2429 +  if (chromeWindow) {
  1.2430 +    chromeWindow->GetMessageManager(getter_AddRefs(parentManager));
  1.2431 +  }
  1.2432 +
  1.2433 +  if (ShouldUseRemoteProcess()) {
  1.2434 +    mMessageManager = new nsFrameMessageManager(mRemoteBrowserShown ? this : nullptr,
  1.2435 +                                                static_cast<nsFrameMessageManager*>(parentManager.get()),
  1.2436 +                                                MM_CHROME);
  1.2437 +  } else {
  1.2438 +    mMessageManager = new nsFrameMessageManager(nullptr,
  1.2439 +                                                static_cast<nsFrameMessageManager*>(parentManager.get()),
  1.2440 +                                                MM_CHROME);
  1.2441 +
  1.2442 +    mChildMessageManager =
  1.2443 +      new nsInProcessTabChildGlobal(mDocShell, mOwnerContent, mMessageManager);
  1.2444 +    // Force pending frame scripts to be loaded.
  1.2445 +    mMessageManager->InitWithCallback(this);
  1.2446 +  }
  1.2447 +  return NS_OK;
  1.2448 +}
  1.2449 +
  1.2450 +EventTarget*
  1.2451 +nsFrameLoader::GetTabChildGlobalAsEventTarget()
  1.2452 +{
  1.2453 +  return static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get());
  1.2454 +}
  1.2455 +
  1.2456 +NS_IMETHODIMP
  1.2457 +nsFrameLoader::GetOwnerElement(nsIDOMElement **aElement)
  1.2458 +{
  1.2459 +  nsCOMPtr<nsIDOMElement> ownerElement = do_QueryInterface(mOwnerContent);
  1.2460 +  ownerElement.forget(aElement);
  1.2461 +  return NS_OK;
  1.2462 +}
  1.2463 +
  1.2464 +NS_IMETHODIMP
  1.2465 +nsFrameLoader::GetChildID(uint64_t* aChildID)
  1.2466 +{
  1.2467 +  *aChildID = mChildID;
  1.2468 +  return NS_OK;
  1.2469 +}
  1.2470 +
  1.2471 +void
  1.2472 +nsFrameLoader::SetRemoteBrowser(nsITabParent* aTabParent)
  1.2473 +{
  1.2474 +  MOZ_ASSERT(!mRemoteBrowser);
  1.2475 +  MOZ_ASSERT(!mCurrentRemoteFrame);
  1.2476 +  mRemoteFrame = true;
  1.2477 +  mRemoteBrowser = static_cast<TabParent*>(aTabParent);
  1.2478 +  mChildID = mRemoteBrowser ? mRemoteBrowser->Manager()->ChildID() : 0;
  1.2479 +  ShowRemoteFrame(nsIntSize(0, 0));
  1.2480 +}
  1.2481 +
  1.2482 +void
  1.2483 +nsFrameLoader::SetDetachedSubdocView(nsView* aDetachedViews,
  1.2484 +                                     nsIDocument* aContainerDoc)
  1.2485 +{
  1.2486 +  mDetachedSubdocViews = aDetachedViews;
  1.2487 +  mContainerDocWhileDetached = aContainerDoc;
  1.2488 +}
  1.2489 +
  1.2490 +nsView*
  1.2491 +nsFrameLoader::GetDetachedSubdocView(nsIDocument** aContainerDoc) const
  1.2492 +{
  1.2493 +  NS_IF_ADDREF(*aContainerDoc = mContainerDocWhileDetached);
  1.2494 +  return mDetachedSubdocViews;
  1.2495 +}
  1.2496 +
  1.2497 +void
  1.2498 +nsFrameLoader::ApplySandboxFlags(uint32_t sandboxFlags)
  1.2499 +{
  1.2500 +  if (mDocShell) {
  1.2501 +    uint32_t parentSandboxFlags = mOwnerContent->OwnerDoc()->GetSandboxFlags();
  1.2502 +
  1.2503 +    // The child can only add restrictions, never remove them.
  1.2504 +    sandboxFlags |= parentSandboxFlags;
  1.2505 +    mDocShell->SetSandboxFlags(sandboxFlags);
  1.2506 +  }
  1.2507 +}
  1.2508 +
  1.2509 +/* virtual */ void
  1.2510 +nsFrameLoader::AttributeChanged(nsIDocument* aDocument,
  1.2511 +                                mozilla::dom::Element* aElement,
  1.2512 +                                int32_t      aNameSpaceID,
  1.2513 +                                nsIAtom*     aAttribute,
  1.2514 +                                int32_t      aModType)
  1.2515 +{
  1.2516 +  MOZ_ASSERT(mObservingOwnerContent);
  1.2517 +  // TODO: Implement ContentShellAdded for remote browsers (bug 658304)
  1.2518 +  MOZ_ASSERT(!mRemoteBrowser);
  1.2519 +
  1.2520 +  if (aNameSpaceID != kNameSpaceID_None || aAttribute != TypeAttrName()) {
  1.2521 +    return;
  1.2522 +  }
  1.2523 +
  1.2524 +  if (aElement != mOwnerContent) {
  1.2525 +    return;
  1.2526 +  }
  1.2527 +
  1.2528 +  // Note: This logic duplicates a lot of logic in
  1.2529 +  // MaybeCreateDocshell.  We should fix that.
  1.2530 +
  1.2531 +  // Notify our enclosing chrome that our type has changed.  We only do this
  1.2532 +  // if our parent is chrome, since in all other cases we're random content
  1.2533 +  // subframes and the treeowner shouldn't worry about us.
  1.2534 +  if (!mDocShell) {
  1.2535 +    return;
  1.2536 +  }
  1.2537 +
  1.2538 +  nsCOMPtr<nsIDocShellTreeItem> parentItem;
  1.2539 +  mDocShell->GetParent(getter_AddRefs(parentItem));
  1.2540 +  if (!parentItem) {
  1.2541 +    return;
  1.2542 +  }
  1.2543 +
  1.2544 +  if (parentItem->ItemType() != nsIDocShellTreeItem::typeChrome) {
  1.2545 +    return;
  1.2546 +  }
  1.2547 +
  1.2548 +  nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
  1.2549 +  parentItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
  1.2550 +  if (!parentTreeOwner) {
  1.2551 +    return;
  1.2552 +  }
  1.2553 +
  1.2554 +  nsAutoString value;
  1.2555 +  aElement->GetAttr(kNameSpaceID_None, TypeAttrName(), value);
  1.2556 +
  1.2557 +  bool is_primary = value.LowerCaseEqualsLiteral("content-primary");
  1.2558 +
  1.2559 +#ifdef MOZ_XUL
  1.2560 +  // when a content panel is no longer primary, hide any open popups it may have
  1.2561 +  if (!is_primary) {
  1.2562 +    nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
  1.2563 +    if (pm)
  1.2564 +      pm->HidePopupsInDocShell(mDocShell);
  1.2565 +  }
  1.2566 +#endif
  1.2567 +
  1.2568 +  parentTreeOwner->ContentShellRemoved(mDocShell);
  1.2569 +  if (value.LowerCaseEqualsLiteral("content") ||
  1.2570 +      StringBeginsWith(value, NS_LITERAL_STRING("content-"),
  1.2571 +                       nsCaseInsensitiveStringComparator())) {
  1.2572 +    bool is_targetable = is_primary ||
  1.2573 +      value.LowerCaseEqualsLiteral("content-targetable");
  1.2574 +
  1.2575 +    parentTreeOwner->ContentShellAdded(mDocShell, is_primary,
  1.2576 +                                       is_targetable, value);
  1.2577 +  }
  1.2578 +}
  1.2579 +
  1.2580 +void
  1.2581 +nsFrameLoader::ResetPermissionManagerStatus()
  1.2582 +{
  1.2583 +  // The resetting of the permissions status can run only
  1.2584 +  // in the main process.
  1.2585 +  if (XRE_GetProcessType() == GeckoProcessType_Content) {
  1.2586 +    return;
  1.2587 +  }
  1.2588 +
  1.2589 +  // Finding the new app Id:
  1.2590 +  // . first we check if the owner is an app frame
  1.2591 +  // . second, we check if the owner is a browser frame
  1.2592 +  // in both cases we populate the appId variable.
  1.2593 +  uint32_t appId = nsIScriptSecurityManager::NO_APP_ID;
  1.2594 +  if (OwnerIsAppFrame()) {
  1.2595 +    // You can't be both an app and a browser frame.
  1.2596 +    MOZ_ASSERT(!OwnerIsBrowserFrame());
  1.2597 +
  1.2598 +    nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
  1.2599 +    MOZ_ASSERT(ownApp);
  1.2600 +    uint32_t ownAppId = nsIScriptSecurityManager::NO_APP_ID;
  1.2601 +    if (ownApp && NS_SUCCEEDED(ownApp->GetLocalId(&ownAppId))) {
  1.2602 +      appId = ownAppId;
  1.2603 +    }
  1.2604 +  }
  1.2605 +
  1.2606 +  if (OwnerIsBrowserFrame()) {
  1.2607 +    // You can't be both a browser and an app frame.
  1.2608 +    MOZ_ASSERT(!OwnerIsAppFrame());
  1.2609 +
  1.2610 +    nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
  1.2611 +    uint32_t containingAppId = nsIScriptSecurityManager::NO_APP_ID;
  1.2612 +    if (containingApp && NS_SUCCEEDED(containingApp->GetLocalId(&containingAppId))) {
  1.2613 +      appId = containingAppId;
  1.2614 +    }
  1.2615 +  }
  1.2616 +
  1.2617 +  // Nothing changed.
  1.2618 +  if (appId == mAppIdSentToPermissionManager) {
  1.2619 +    return;
  1.2620 +  }
  1.2621 +
  1.2622 +  nsCOMPtr<nsIPermissionManager> permMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
  1.2623 +  if (!permMgr) {
  1.2624 +    NS_ERROR("No PermissionManager available!");
  1.2625 +    return;
  1.2626 +  }
  1.2627 +
  1.2628 +  // If previously we registered an appId, we have to unregister it.
  1.2629 +  if (mAppIdSentToPermissionManager != nsIScriptSecurityManager::NO_APP_ID) {
  1.2630 +    permMgr->ReleaseAppId(mAppIdSentToPermissionManager);
  1.2631 +    mAppIdSentToPermissionManager = nsIScriptSecurityManager::NO_APP_ID;
  1.2632 +  }
  1.2633 +
  1.2634 +  // Register the new AppId.
  1.2635 +  if (appId != nsIScriptSecurityManager::NO_APP_ID) {
  1.2636 +    mAppIdSentToPermissionManager = appId;
  1.2637 +    permMgr->AddrefAppId(mAppIdSentToPermissionManager);
  1.2638 +  }
  1.2639 +}
  1.2640 +
  1.2641 +/* [infallible] */ NS_IMETHODIMP
  1.2642 +nsFrameLoader::SetVisible(bool aVisible)
  1.2643 +{
  1.2644 +  if (mVisible == aVisible) {
  1.2645 +    return NS_OK;
  1.2646 +  }
  1.2647 +
  1.2648 +  mVisible = aVisible;
  1.2649 +  nsCOMPtr<nsIObserverService> os = services::GetObserverService();
  1.2650 +  if (os) {
  1.2651 +    os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
  1.2652 +                        "frameloader-visible-changed", nullptr);
  1.2653 +  }
  1.2654 +  return NS_OK;
  1.2655 +}
  1.2656 +
  1.2657 +/* [infallible] */ NS_IMETHODIMP
  1.2658 +nsFrameLoader::GetVisible(bool* aVisible)
  1.2659 +{
  1.2660 +  *aVisible = mVisible;
  1.2661 +  return NS_OK;
  1.2662 +}
  1.2663 +
  1.2664 +NS_IMETHODIMP
  1.2665 +nsFrameLoader::GetTabParent(nsITabParent** aTabParent)
  1.2666 +{
  1.2667 +  nsCOMPtr<nsITabParent> tp = mRemoteBrowser;
  1.2668 +  tp.forget(aTabParent);
  1.2669 +  return NS_OK;
  1.2670 +}
  1.2671 +
  1.2672 +NS_IMETHODIMP
  1.2673 +nsFrameLoader::GetLoadContext(nsILoadContext** aLoadContext)
  1.2674 +{
  1.2675 +  nsCOMPtr<nsILoadContext> loadContext;
  1.2676 +  if (mRemoteBrowser) {
  1.2677 +    loadContext = mRemoteBrowser->GetLoadContext();
  1.2678 +  } else {
  1.2679 +    nsCOMPtr<nsIDocShell> docShell;
  1.2680 +    GetDocShell(getter_AddRefs(docShell));
  1.2681 +    loadContext = do_GetInterface(docShell);
  1.2682 +  }
  1.2683 +  loadContext.forget(aLoadContext);
  1.2684 +  return NS_OK;
  1.2685 +}

mercurial