content/base/src/nsFrameLoader.cpp

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

mercurial