content/base/src/nsFrameLoader.cpp

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

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

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

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

mercurial