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 +}