Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 "nsDocShell.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 "nsPIDOMWindow.h"
27 : #include "nsIWebNavigation.h"
28 : #include "nsIWebProgress.h"
29 : #include "nsIDocShell.h"
30 : #include "nsIDocShellTreeOwner.h"
31 : #include "nsIDocShellLoadInfo.h"
32 : #include "nsIBaseWindow.h"
33 : #include "nsIBrowser.h"
34 : #include "nsContentUtils.h"
35 : #include "nsIXPConnect.h"
36 : #include "nsUnicharUtils.h"
37 : #include "nsIScriptGlobalObject.h"
38 : #include "nsIScriptSecurityManager.h"
39 : #include "nsIScrollable.h"
40 : #include "nsFrameLoader.h"
41 : #include "nsIDOMEventTarget.h"
42 : #include "nsIFrame.h"
43 : #include "nsIScrollableFrame.h"
44 : #include "nsSubDocumentFrame.h"
45 : #include "nsError.h"
46 : #include "nsISHistory.h"
47 : #include "nsISHistoryInternal.h"
48 : #include "nsIDOMHTMLDocument.h"
49 : #include "nsIXULWindow.h"
50 : #include "nsIEditor.h"
51 : #include "nsIMozBrowserFrame.h"
52 : #include "nsISHistory.h"
53 : #include "NullPrincipal.h"
54 : #include "nsIScriptError.h"
55 : #include "nsGlobalWindow.h"
56 : #include "nsPIWindowRoot.h"
57 : #include "nsLayoutUtils.h"
58 : #include "nsMappedAttributes.h"
59 : #include "nsView.h"
60 : #include "nsBaseWidget.h"
61 : #include "GroupedSHistory.h"
62 : #include "PartialSHistory.h"
63 :
64 : #include "nsIURI.h"
65 : #include "nsIURL.h"
66 : #include "nsNetUtil.h"
67 :
68 : #include "nsGkAtoms.h"
69 : #include "nsNameSpaceManager.h"
70 :
71 : #include "nsThreadUtils.h"
72 :
73 : #include "nsIDOMChromeWindow.h"
74 : #include "nsInProcessTabChildGlobal.h"
75 :
76 : #include "Layers.h"
77 : #include "ClientLayerManager.h"
78 :
79 : #include "ContentParent.h"
80 : #include "TabParent.h"
81 : #include "mozilla/AsyncEventDispatcher.h"
82 : #include "mozilla/BasePrincipal.h"
83 : #include "mozilla/GuardObjects.h"
84 : #include "mozilla/Preferences.h"
85 : #include "mozilla/Unused.h"
86 : #include "mozilla/dom/Element.h"
87 : #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
88 : #include "mozilla/layout/RenderFrameParent.h"
89 : #include "GeckoProfiler.h"
90 :
91 : #include "jsapi.h"
92 : #include "mozilla/dom/HTMLIFrameElement.h"
93 : #include "nsSandboxFlags.h"
94 : #include "mozilla/layers/CompositorBridgeChild.h"
95 : #include "mozilla/dom/CustomEvent.h"
96 :
97 : #include "mozilla/dom/ipc/StructuredCloneData.h"
98 : #include "mozilla/WebBrowserPersistLocalDocument.h"
99 : #include "mozilla/dom/GroupedHistoryEvent.h"
100 : #include "mozilla/dom/Promise.h"
101 : #include "mozilla/dom/PromiseNativeHandler.h"
102 :
103 : #include "mozilla/dom/HTMLBodyElement.h"
104 :
105 : #include "ContentPrincipal.h"
106 :
107 : #ifdef XP_WIN
108 : #include "mozilla/plugins/PPluginWidgetParent.h"
109 : #include "../plugins/ipc/PluginWidgetParent.h"
110 : #endif
111 :
112 : #ifdef MOZ_XUL
113 : #include "nsXULPopupManager.h"
114 : #endif
115 :
116 : #ifdef NS_PRINTING
117 : #include "mozilla/embedding/printingui/PrintingParent.h"
118 : #include "nsIWebBrowserPrint.h"
119 : #endif
120 :
121 : using namespace mozilla;
122 : using namespace mozilla::hal;
123 : using namespace mozilla::dom;
124 : using namespace mozilla::dom::ipc;
125 : using namespace mozilla::layers;
126 : using namespace mozilla::layout;
127 : typedef FrameMetrics::ViewID ViewID;
128 :
129 : // Bug 136580: Limit to the number of nested content frames that can have the
130 : // same URL. This is to stop content that is recursively loading
131 : // itself. Note that "#foo" on the end of URL doesn't affect
132 : // whether it's considered identical, but "?foo" or ";foo" are
133 : // considered and compared.
134 : // Bug 228829: Limit this to 1, like IE does.
135 : #define MAX_SAME_URL_CONTENT_FRAMES 1
136 :
137 : // Bug 8065: Limit content frame depth to some reasonable level. This
138 : // does not count chrome frames when determining depth, nor does it
139 : // prevent chrome recursion. Number is fairly arbitrary, but meant to
140 : // keep number of shells to a reasonable number on accidental recursion with a
141 : // small (but not 1) branching factor. With large branching factors the number
142 : // of shells can rapidly become huge and run us out of memory. To solve that,
143 : // we'd need to re-institute a fixed version of bug 98158.
144 : #define MAX_DEPTH_CONTENT_FRAMES 10
145 :
146 0 : NS_IMPL_CYCLE_COLLECTION(nsFrameLoader,
147 : mDocShell,
148 : mMessageManager,
149 : mChildMessageManager,
150 : mOpener,
151 : mPartialSHistory)
152 362 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameLoader)
153 343 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameLoader)
154 :
155 650 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader)
156 646 : NS_INTERFACE_MAP_ENTRY(nsIFrameLoader)
157 456 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFrameLoader)
158 320 : NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPersistable)
159 320 : NS_INTERFACE_MAP_END
160 :
161 4 : nsFrameLoader::nsFrameLoader(Element* aOwner, nsPIDOMWindowOuter* aOpener,
162 4 : bool aNetworkCreated, int32_t aJSPluginID)
163 : : mOwnerContent(aOwner)
164 : , mDetachedSubdocFrame(nullptr)
165 : , mOpener(aOpener)
166 : , mRemoteBrowser(nullptr)
167 : , mChildID(0)
168 : , mJSPluginID(aJSPluginID)
169 : , mEventMode(EVENT_MODE_NORMAL_DISPATCH)
170 : , mBrowserChangingProcessBlockers(nullptr)
171 : , mIsPrerendered(false)
172 : , mDepthTooGreat(false)
173 : , mIsTopLevelContent(false)
174 : , mDestroyCalled(false)
175 : , mNeedsAsyncDestroy(false)
176 : , mInSwap(false)
177 : , mInShow(false)
178 : , mHideCalled(false)
179 : , mNetworkCreated(aNetworkCreated)
180 : , mRemoteBrowserShown(false)
181 : , mRemoteFrame(false)
182 : , mClipSubdocument(true)
183 : , mClampScrollPosition(true)
184 4 : , mObservingOwnerContent(false)
185 : {
186 4 : mRemoteFrame = ShouldUseRemoteProcess();
187 4 : MOZ_ASSERT(!mRemoteFrame || !aOpener,
188 : "Cannot pass aOpener for a remote frame!");
189 4 : }
190 :
191 0 : nsFrameLoader::~nsFrameLoader()
192 : {
193 0 : if (mMessageManager) {
194 0 : mMessageManager->Disconnect();
195 : }
196 0 : MOZ_RELEASE_ASSERT(mDestroyCalled);
197 0 : }
198 :
199 : nsFrameLoader*
200 4 : nsFrameLoader::Create(Element* aOwner, nsPIDOMWindowOuter* aOpener, bool aNetworkCreated,
201 : int32_t aJSPluginId)
202 : {
203 4 : NS_ENSURE_TRUE(aOwner, nullptr);
204 4 : nsIDocument* doc = aOwner->OwnerDoc();
205 :
206 : // We never create nsFrameLoaders for elements in resource documents.
207 : //
208 : // We never create nsFrameLoaders for elements in data documents, unless the
209 : // document is a static document.
210 : // Static documents are an exception because any sub-documents need an
211 : // nsFrameLoader to keep the relevant docShell alive, even though the
212 : // nsFrameLoader isn't used to load anything (the sub-document is created by
213 : // the static clone process).
214 : //
215 : // We never create nsFrameLoaders for elements that are not
216 : // in-composed-document, unless the element belongs to a static document.
217 : // Static documents are an exception because this method is called at a point
218 : // in the static clone process before aOwner has been inserted into its
219 : // document. For other types of documents this wouldn't be a problem since
220 : // we'd create the nsFrameLoader as necessary after aOwner is inserted into a
221 : // document, but the mechanisms that take care of that don't apply for static
222 : // documents so we need to create the nsFrameLoader now. (This isn't wasteful
223 : // since for a static document we know aOwner will end up in a document and
224 : // the nsFrameLoader will be used for its docShell.)
225 : //
226 4 : NS_ENSURE_TRUE(!doc->IsResourceDoc() &&
227 : ((!doc->IsLoadedAsData() && aOwner->IsInComposedDoc()) ||
228 : doc->IsStaticDocument()),
229 : nullptr);
230 :
231 4 : return new nsFrameLoader(aOwner, aOpener, aNetworkCreated, aJSPluginId);
232 : }
233 :
234 : NS_IMETHODIMP
235 4 : nsFrameLoader::LoadFrame()
236 : {
237 4 : NS_ENSURE_TRUE(mOwnerContent, NS_ERROR_NOT_INITIALIZED);
238 :
239 8 : nsAutoString src;
240 :
241 4 : bool isSrcdoc = mOwnerContent->IsHTMLElement(nsGkAtoms::iframe) &&
242 4 : mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc);
243 4 : if (isSrcdoc) {
244 0 : src.AssignLiteral("about:srcdoc");
245 : }
246 : else {
247 4 : GetURL(src);
248 :
249 4 : src.Trim(" \t\n\r");
250 :
251 4 : if (src.IsEmpty()) {
252 : // If the frame is a XUL element and has the attribute 'nodefaultsrc=true'
253 : // then we will not use 'about:blank' as fallback but return early without
254 : // starting a load if no 'src' attribute is given (or it's empty).
255 8 : if (mOwnerContent->IsXULElement() &&
256 4 : mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::nodefaultsrc,
257 : nsGkAtoms::_true, eCaseMatters)) {
258 0 : return NS_OK;
259 : }
260 4 : src.AssignLiteral("about:blank");
261 : }
262 : }
263 :
264 4 : nsIDocument* doc = mOwnerContent->OwnerDoc();
265 4 : if (doc->IsStaticDocument()) {
266 0 : return NS_OK;
267 : }
268 :
269 4 : if (doc->IsLoadedAsInteractiveData()) {
270 : // XBL bindings doc shouldn't load sub-documents.
271 1 : return NS_OK;
272 : }
273 :
274 6 : nsCOMPtr<nsIURI> base_uri = mOwnerContent->GetBaseURI();
275 3 : auto encoding = doc->GetDocumentCharacterSet();
276 :
277 6 : nsCOMPtr<nsIURI> uri;
278 3 : nsresult rv = NS_NewURI(getter_AddRefs(uri), src, encoding, base_uri);
279 :
280 : // If the URI was malformed, try to recover by loading about:blank.
281 3 : if (rv == NS_ERROR_MALFORMED_URI) {
282 0 : rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("about:blank"),
283 0 : encoding, base_uri);
284 : }
285 :
286 3 : if (NS_SUCCEEDED(rv)) {
287 3 : rv = LoadURI(uri);
288 : }
289 :
290 3 : if (NS_FAILED(rv)) {
291 0 : FireErrorEvent();
292 :
293 0 : return rv;
294 : }
295 :
296 3 : return NS_OK;
297 : }
298 :
299 : void
300 0 : nsFrameLoader::FireErrorEvent()
301 : {
302 0 : if (!mOwnerContent) {
303 0 : return;
304 : }
305 : RefPtr<AsyncEventDispatcher > loadBlockingAsyncDispatcher =
306 0 : new LoadBlockingAsyncEventDispatcher(mOwnerContent,
307 0 : NS_LITERAL_STRING("error"),
308 0 : false, false);
309 0 : loadBlockingAsyncDispatcher->PostDOMEvent();
310 : }
311 :
312 : NS_IMETHODIMP
313 3 : nsFrameLoader::LoadURI(nsIURI* aURI)
314 : {
315 3 : if (!aURI)
316 0 : return NS_ERROR_INVALID_POINTER;
317 3 : NS_ENSURE_STATE(!mDestroyCalled && mOwnerContent);
318 :
319 6 : nsCOMPtr<nsIDocument> doc = mOwnerContent->OwnerDoc();
320 :
321 : nsresult rv;
322 : // If IsForJSPlugin() returns true then we want to allow the load. We're just
323 : // loading the source for the implementation of the JS plugin from a URI
324 : // that's under our control. We will already have done the security checks for
325 : // loading the plugin content itself in the object/embed loading code.
326 3 : if (!IsForJSPlugin()) {
327 3 : rv = CheckURILoad(aURI);
328 3 : NS_ENSURE_SUCCESS(rv, rv);
329 : }
330 :
331 3 : mURIToLoad = aURI;
332 3 : rv = doc->InitializeFrameLoader(this);
333 3 : if (NS_FAILED(rv)) {
334 0 : mURIToLoad = nullptr;
335 : }
336 3 : return rv;
337 : }
338 :
339 : NS_IMETHODIMP
340 0 : nsFrameLoader::SetIsPrerendered()
341 : {
342 0 : MOZ_ASSERT(!mDocShell, "Please call SetIsPrerendered before docShell is created");
343 0 : mIsPrerendered = true;
344 :
345 0 : return NS_OK;
346 : }
347 :
348 : NS_IMETHODIMP
349 0 : nsFrameLoader::MakePrerenderedLoaderActive()
350 : {
351 0 : MOZ_ASSERT(mIsPrerendered, "This frameloader was not in prerendered mode.");
352 :
353 0 : mIsPrerendered = false;
354 0 : if (IsRemoteFrame()) {
355 0 : if (!mRemoteBrowser) {
356 0 : NS_WARNING("Missing remote browser.");
357 0 : return NS_ERROR_FAILURE;
358 : }
359 :
360 0 : mRemoteBrowser->SetDocShellIsActive(true);
361 : } else {
362 0 : if (!mDocShell) {
363 0 : NS_WARNING("Missing docshell.");
364 0 : return NS_ERROR_FAILURE;
365 : }
366 :
367 0 : nsresult rv = mDocShell->SetIsActive(true);
368 0 : NS_ENSURE_SUCCESS(rv, rv);
369 : }
370 :
371 0 : return NS_OK;
372 : }
373 :
374 : NS_IMETHODIMP
375 0 : nsFrameLoader::GetPartialSHistory(nsIPartialSHistory** aResult)
376 : {
377 0 : if (mRemoteBrowser && !mPartialSHistory) {
378 : // For remote case we can lazy initialize PartialSHistory since
379 : // it doens't need to be registered as a listener to nsISHistory directly.
380 0 : mPartialSHistory = new PartialSHistory(this);
381 : }
382 :
383 0 : nsCOMPtr<nsIPartialSHistory> partialHistory(mPartialSHistory);
384 0 : partialHistory.forget(aResult);
385 0 : return NS_OK;
386 : }
387 :
388 : NS_IMETHODIMP
389 0 : nsFrameLoader::EnsureGroupedSHistory(nsIGroupedSHistory** aResult)
390 : {
391 0 : nsCOMPtr<nsIPartialSHistory> partialHistory;
392 0 : GetPartialSHistory(getter_AddRefs(partialHistory));
393 0 : MOZ_ASSERT(partialHistory);
394 :
395 0 : nsCOMPtr<nsIGroupedSHistory> groupedHistory;
396 0 : partialHistory->GetGroupedSHistory(getter_AddRefs(groupedHistory));
397 0 : if (!groupedHistory) {
398 0 : groupedHistory = new GroupedSHistory();
399 0 : groupedHistory->AppendPartialSHistory(partialHistory);
400 :
401 : #ifdef DEBUG
402 0 : nsCOMPtr<nsIGroupedSHistory> test;
403 0 : GetGroupedSHistory(getter_AddRefs(test));
404 0 : MOZ_ASSERT(test == groupedHistory, "GroupedHistory must match");
405 : #endif
406 : }
407 :
408 0 : groupedHistory.forget(aResult);
409 0 : return NS_OK;
410 : }
411 :
412 : NS_IMETHODIMP
413 0 : nsFrameLoader::GetGroupedSHistory(nsIGroupedSHistory** aResult)
414 : {
415 0 : nsCOMPtr<nsIGroupedSHistory> groupedSHistory;
416 0 : if (mPartialSHistory) {
417 0 : mPartialSHistory->GetGroupedSHistory(getter_AddRefs(groupedSHistory));
418 : }
419 0 : groupedSHistory.forget(aResult);
420 0 : return NS_OK;
421 : }
422 :
423 : bool
424 0 : nsFrameLoader::SwapBrowsersAndNotify(nsFrameLoader* aOther)
425 : {
426 : // Cache the owner content before calling SwapBrowsers, which will change
427 : // these member variables.
428 0 : RefPtr<mozilla::dom::Element> primaryContent = mOwnerContent;
429 0 : RefPtr<mozilla::dom::Element> secondaryContent = aOther->mOwnerContent;
430 :
431 : // Swap loaders through our owner, so the owner's listeners will be correctly
432 : // setup.
433 0 : nsCOMPtr<nsIBrowser> ourBrowser = do_QueryInterface(primaryContent);
434 0 : nsCOMPtr<nsIBrowser> otherBrowser = do_QueryInterface(secondaryContent);
435 0 : if (NS_WARN_IF(!ourBrowser || !otherBrowser)) {
436 0 : return false;
437 : }
438 0 : nsresult rv = ourBrowser->SwapBrowsers(otherBrowser, nsIBrowser::SWAP_KEEP_PERMANENT_KEY);
439 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
440 0 : return false;
441 : }
442 :
443 : // Dispatch the BrowserChangedProcess event to tell JS that the process swap
444 : // has occurred.
445 0 : GroupedHistoryEventInit eventInit;
446 0 : eventInit.mBubbles = true;
447 0 : eventInit.mCancelable= false;
448 0 : eventInit.mOtherBrowser = secondaryContent;
449 : RefPtr<GroupedHistoryEvent> event =
450 0 : GroupedHistoryEvent::Constructor(primaryContent,
451 0 : NS_LITERAL_STRING("BrowserChangedProcess"),
452 0 : eventInit);
453 0 : event->SetTrusted(true);
454 : bool dummy;
455 0 : primaryContent->DispatchEvent(event, &dummy);
456 :
457 0 : return true;
458 : }
459 :
460 : class AppendPartialSHistoryAndSwapHelper : public PromiseNativeHandler
461 : {
462 : public:
463 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
464 0 : NS_DECL_CYCLE_COLLECTION_CLASS(AppendPartialSHistoryAndSwapHelper)
465 :
466 0 : AppendPartialSHistoryAndSwapHelper(nsFrameLoader* aThis,
467 : nsFrameLoader* aOther,
468 : Promise* aPromise)
469 0 : : mThis(aThis), mOther(aOther), mPromise(aPromise) {}
470 :
471 : void
472 0 : ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
473 : {
474 0 : nsCOMPtr<nsIGroupedSHistory> otherGroupedHistory;
475 0 : mOther->GetGroupedSHistory(getter_AddRefs(otherGroupedHistory));
476 0 : MOZ_ASSERT(!otherGroupedHistory,
477 : "Cannot append a GroupedSHistory owner to another.");
478 0 : if (otherGroupedHistory) {
479 0 : mPromise->MaybeRejectWithUndefined();
480 0 : return;
481 : }
482 :
483 : // Append ourselves.
484 : nsresult rv;
485 0 : nsCOMPtr<nsIGroupedSHistory> groupedSHistory;
486 0 : rv = mThis->EnsureGroupedSHistory(getter_AddRefs(groupedSHistory));
487 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
488 0 : mPromise->MaybeRejectWithUndefined();
489 0 : return;
490 : }
491 :
492 : // Append the other.
493 0 : nsCOMPtr<nsIPartialSHistory> otherPartialSHistory;
494 0 : MOZ_ALWAYS_SUCCEEDS(mOther->GetPartialSHistory(getter_AddRefs(otherPartialSHistory)));
495 0 : rv = groupedSHistory->AppendPartialSHistory(otherPartialSHistory);
496 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
497 0 : mPromise->MaybeRejectWithUndefined();
498 0 : return;
499 : }
500 :
501 : // Swap the browsers and fire the BrowserChangedProcess event.
502 0 : if (mThis->SwapBrowsersAndNotify(mOther)) {
503 0 : mPromise->MaybeResolveWithUndefined();
504 : } else {
505 0 : mPromise->MaybeRejectWithUndefined();
506 : }
507 : }
508 :
509 : void
510 0 : RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
511 : {
512 0 : mPromise->MaybeRejectWithUndefined();
513 0 : }
514 :
515 : private:
516 0 : ~AppendPartialSHistoryAndSwapHelper() {}
517 : RefPtr<nsFrameLoader> mThis;
518 : RefPtr<nsFrameLoader> mOther;
519 : RefPtr<Promise> mPromise;
520 : };
521 :
522 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(AppendPartialSHistoryAndSwapHelper)
523 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(AppendPartialSHistoryAndSwapHelper)
524 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AppendPartialSHistoryAndSwapHelper)
525 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
526 0 : NS_INTERFACE_MAP_END
527 0 : NS_IMPL_CYCLE_COLLECTION(AppendPartialSHistoryAndSwapHelper,
528 : mThis, mPromise)
529 :
530 : class RequestGroupedHistoryNavigationHelper : public PromiseNativeHandler
531 : {
532 : public:
533 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
534 0 : NS_DECL_CYCLE_COLLECTION_CLASS(RequestGroupedHistoryNavigationHelper)
535 :
536 0 : RequestGroupedHistoryNavigationHelper(nsFrameLoader* aThis,
537 : uint32_t aGlobalIndex,
538 : Promise* aPromise)
539 0 : : mThis(aThis), mGlobalIndex(aGlobalIndex), mPromise(aPromise) {}
540 :
541 : void
542 0 : ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
543 : {
544 0 : if (NS_WARN_IF(!mThis->mOwnerContent)) {
545 0 : mPromise->MaybeRejectWithUndefined();
546 0 : return;
547 : }
548 :
549 0 : nsCOMPtr<nsIGroupedSHistory> groupedSHistory;
550 0 : mThis->GetGroupedSHistory(getter_AddRefs(groupedSHistory));
551 0 : if (NS_WARN_IF(!groupedSHistory)) {
552 0 : mPromise->MaybeRejectWithUndefined();
553 0 : return;
554 : }
555 :
556 : // Navigate the loader to the new index
557 0 : nsCOMPtr<nsIFrameLoader> otherLoader;
558 0 : nsresult rv = groupedSHistory->GotoIndex(mGlobalIndex, getter_AddRefs(otherLoader));
559 :
560 : // Check if the gotoIndex failed because the target frameloader is dead. We
561 : // need to perform a navigateAndRestoreByIndex and then return to recover.
562 0 : if (rv == NS_ERROR_NOT_AVAILABLE) {
563 : // Get the nsIXULBrowserWindow so that we can call NavigateAndRestoreByIndex on it.
564 0 : nsCOMPtr<nsIDocShell> docShell = mThis->mOwnerContent->OwnerDoc()->GetDocShell();
565 0 : if (NS_WARN_IF(!docShell)) {
566 0 : mPromise->MaybeRejectWithUndefined();
567 0 : return;
568 : }
569 :
570 0 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
571 0 : docShell->GetTreeOwner(getter_AddRefs(treeOwner));
572 0 : if (NS_WARN_IF(!treeOwner)) {
573 0 : mPromise->MaybeRejectWithUndefined();
574 0 : return;
575 : }
576 :
577 0 : nsCOMPtr<nsIXULWindow> window = do_GetInterface(treeOwner);
578 0 : if (NS_WARN_IF(!window)) {
579 0 : mPromise->MaybeRejectWithUndefined();
580 0 : return;
581 : }
582 :
583 0 : nsCOMPtr<nsIXULBrowserWindow> xbw;
584 0 : window->GetXULBrowserWindow(getter_AddRefs(xbw));
585 0 : if (NS_WARN_IF(!xbw)) {
586 0 : mPromise->MaybeRejectWithUndefined();
587 0 : return;
588 : }
589 :
590 0 : nsCOMPtr<nsIBrowser> ourBrowser = do_QueryInterface(mThis->mOwnerContent);
591 0 : if (NS_WARN_IF(!ourBrowser)) {
592 0 : mPromise->MaybeRejectWithUndefined();
593 0 : return;
594 : }
595 :
596 0 : rv = xbw->NavigateAndRestoreByIndex(ourBrowser, mGlobalIndex);
597 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
598 0 : mPromise->MaybeRejectWithUndefined();
599 0 : return;
600 : }
601 0 : mPromise->MaybeResolveWithUndefined();
602 0 : return;
603 : }
604 :
605 : // Check for any other type of failure
606 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
607 0 : mPromise->MaybeRejectWithUndefined();
608 0 : return;
609 : }
610 :
611 : // Perform the swap.
612 0 : nsFrameLoader* other = static_cast<nsFrameLoader*>(otherLoader.get());
613 0 : if (!other || other == mThis) {
614 0 : mPromise->MaybeRejectWithUndefined();
615 0 : return;
616 : }
617 :
618 : // Swap the browsers and fire the BrowserChangedProcess event.
619 0 : if (mThis->SwapBrowsersAndNotify(other)) {
620 0 : mPromise->MaybeResolveWithUndefined();
621 : } else {
622 0 : mPromise->MaybeRejectWithUndefined();
623 : }
624 : }
625 :
626 : void
627 0 : RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
628 : {
629 0 : mPromise->MaybeRejectWithUndefined();
630 0 : }
631 :
632 : private:
633 0 : ~RequestGroupedHistoryNavigationHelper() {}
634 : RefPtr<nsFrameLoader> mThis;
635 : uint32_t mGlobalIndex;
636 : RefPtr<Promise> mPromise;
637 : };
638 :
639 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(RequestGroupedHistoryNavigationHelper)
640 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(RequestGroupedHistoryNavigationHelper)
641 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RequestGroupedHistoryNavigationHelper)
642 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
643 0 : NS_INTERFACE_MAP_END
644 0 : NS_IMPL_CYCLE_COLLECTION(RequestGroupedHistoryNavigationHelper,
645 : mThis, mPromise)
646 :
647 : already_AddRefed<Promise>
648 0 : nsFrameLoader::FireWillChangeProcessEvent()
649 : {
650 0 : AutoJSAPI jsapi;
651 0 : if (NS_WARN_IF(!jsapi.Init(mOwnerContent->GetOwnerGlobal()))) {
652 0 : return nullptr;
653 : }
654 0 : JSContext* cx = jsapi.cx();
655 0 : GlobalObject global(cx, mOwnerContent->GetOwnerGlobal()->GetGlobalJSObject());
656 0 : MOZ_ASSERT(!global.Failed());
657 :
658 : // Set our mBrowserChangingProcessBlockers property to refer to the blockers
659 : // list. We will synchronously dispatch a DOM event to collect this list of
660 : // blockers.
661 0 : nsTArray<RefPtr<Promise>> blockers;
662 0 : mBrowserChangingProcessBlockers = &blockers;
663 :
664 0 : GroupedHistoryEventInit eventInit;
665 0 : eventInit.mBubbles = true;
666 0 : eventInit.mCancelable = false;
667 0 : eventInit.mOtherBrowser = nullptr;
668 : RefPtr<GroupedHistoryEvent> event =
669 0 : GroupedHistoryEvent::Constructor(mOwnerContent,
670 0 : NS_LITERAL_STRING("BrowserWillChangeProcess"),
671 0 : eventInit);
672 0 : event->SetTrusted(true);
673 : bool dummy;
674 0 : mOwnerContent->DispatchEvent(event, &dummy);
675 :
676 0 : mBrowserChangingProcessBlockers = nullptr;
677 :
678 0 : ErrorResult rv;
679 0 : RefPtr<Promise> allPromise = Promise::All(global, blockers, rv);
680 0 : return allPromise.forget();
681 : }
682 :
683 : NS_IMETHODIMP
684 0 : nsFrameLoader::AppendPartialSHistoryAndSwap(nsIFrameLoader* aOther, nsISupports** aPromise)
685 : {
686 0 : if (!aOther) {
687 0 : return NS_ERROR_INVALID_POINTER;
688 : }
689 :
690 0 : if (aOther == this) {
691 0 : return NS_OK;
692 : }
693 :
694 0 : RefPtr<nsFrameLoader> otherLoader = static_cast<nsFrameLoader*>(aOther);
695 :
696 0 : RefPtr<Promise> ready = FireWillChangeProcessEvent();
697 0 : if (NS_WARN_IF(!ready)) {
698 0 : return NS_ERROR_FAILURE;
699 : }
700 :
701 : // This promise will be resolved when the swap has finished, we return it now
702 : // and pass it to our helper so our helper can resolve it.
703 0 : ErrorResult rv;
704 0 : RefPtr<Promise> complete = Promise::Create(mOwnerContent->GetOwnerGlobal(), rv);
705 0 : if (NS_WARN_IF(rv.Failed())) {
706 0 : return rv.StealNSResult();
707 : }
708 :
709 : // Attach our handler to the ready promise, and make it fulfil the complete
710 : // promise when we are done.
711 : RefPtr<AppendPartialSHistoryAndSwapHelper> helper =
712 0 : new AppendPartialSHistoryAndSwapHelper(this, otherLoader, complete);
713 0 : ready->AppendNativeHandler(helper);
714 0 : complete.forget(aPromise);
715 0 : return NS_OK;
716 : }
717 :
718 : NS_IMETHODIMP
719 0 : nsFrameLoader::RequestGroupedHistoryNavigation(uint32_t aGlobalIndex, nsISupports** aPromise)
720 : {
721 :
722 0 : RefPtr<Promise> ready = FireWillChangeProcessEvent();
723 0 : if (NS_WARN_IF(!ready)) {
724 0 : return NS_ERROR_FAILURE;
725 : }
726 :
727 : // This promise will be resolved when the swap has finished, we return it now
728 : // and pass it to our helper so our helper can resolve it.
729 0 : ErrorResult rv;
730 0 : RefPtr<Promise> complete = Promise::Create(mOwnerContent->GetOwnerGlobal(), rv);
731 0 : if (NS_WARN_IF(rv.Failed())) {
732 0 : return rv.StealNSResult();
733 : }
734 :
735 : // Attach our handler to the ready promise, and make it fulfil the complete
736 : // promise when we are done.
737 : RefPtr<RequestGroupedHistoryNavigationHelper> helper =
738 0 : new RequestGroupedHistoryNavigationHelper(this, aGlobalIndex, complete);
739 0 : ready->AppendNativeHandler(helper);
740 0 : complete.forget(aPromise);
741 0 : return NS_OK;
742 : }
743 :
744 : NS_IMETHODIMP
745 0 : nsFrameLoader::AddProcessChangeBlockingPromise(js::Handle<js::Value> aPromise,
746 : JSContext* aCx)
747 : {
748 0 : nsCOMPtr<nsIGlobalObject> go = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
749 0 : if (!go) {
750 0 : return NS_ERROR_FAILURE;
751 : }
752 0 : ErrorResult rv;
753 0 : RefPtr<Promise> promise = Promise::Resolve(go, aCx, aPromise, rv);
754 0 : if (NS_WARN_IF(rv.Failed())) {
755 0 : return rv.StealNSResult();
756 : }
757 :
758 0 : if (NS_WARN_IF(!mBrowserChangingProcessBlockers)) {
759 0 : return NS_ERROR_DOM_INVALID_STATE_ERR;
760 : }
761 :
762 0 : mBrowserChangingProcessBlockers->AppendElement(promise);
763 0 : return NS_OK;
764 : }
765 :
766 : nsresult
767 3 : nsFrameLoader::ReallyStartLoading()
768 : {
769 3 : nsresult rv = ReallyStartLoadingInternal();
770 3 : if (NS_FAILED(rv)) {
771 0 : FireErrorEvent();
772 : }
773 :
774 3 : return rv;
775 : }
776 :
777 : nsresult
778 3 : nsFrameLoader::ReallyStartLoadingInternal()
779 : {
780 3 : NS_ENSURE_STATE(mURIToLoad && mOwnerContent && mOwnerContent->IsInComposedDoc());
781 :
782 6 : AUTO_PROFILER_LABEL("nsFrameLoader::ReallyStartLoadingInternal", OTHER);
783 :
784 3 : if (IsRemoteFrame()) {
785 1 : if (!mRemoteBrowser && !TryRemoteBrowser()) {
786 0 : NS_WARNING("Couldn't create child process for iframe.");
787 0 : return NS_ERROR_FAILURE;
788 : }
789 :
790 : // FIXME get error codes from child
791 1 : mRemoteBrowser->LoadURL(mURIToLoad);
792 :
793 1 : if (!mRemoteBrowserShown && !ShowRemoteFrame(ScreenIntSize(0, 0))) {
794 0 : NS_WARNING("[nsFrameLoader] ReallyStartLoadingInternal tried but couldn't show remote browser.\n");
795 : }
796 :
797 1 : return NS_OK;
798 : }
799 :
800 2 : nsresult rv = MaybeCreateDocShell();
801 2 : if (NS_FAILED(rv)) {
802 0 : return rv;
803 : }
804 2 : NS_ASSERTION(mDocShell,
805 : "MaybeCreateDocShell succeeded with a null mDocShell");
806 :
807 : // Just to be safe, recheck uri.
808 2 : rv = CheckURILoad(mURIToLoad);
809 2 : NS_ENSURE_SUCCESS(rv, rv);
810 :
811 4 : nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
812 2 : mDocShell->CreateLoadInfo(getter_AddRefs(loadInfo));
813 2 : NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
814 :
815 : // If this frame is sandboxed with respect to origin we will set it up with
816 : // a null principal later in nsDocShell::DoURILoad.
817 : // We do it there to correctly sandbox content that was loaded into
818 : // the frame via other methods than the src attribute.
819 : // We'll use our principal, not that of the document loaded inside us. This
820 : // is very important; needed to prevent XSS attacks on documents loaded in
821 : // subframes!
822 2 : loadInfo->SetTriggeringPrincipal(mOwnerContent->NodePrincipal());
823 :
824 4 : nsCOMPtr<nsIURI> referrer;
825 :
826 4 : nsAutoString srcdoc;
827 2 : bool isSrcdoc = mOwnerContent->IsHTMLElement(nsGkAtoms::iframe) &&
828 0 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::srcdoc,
829 2 : srcdoc);
830 :
831 2 : if (isSrcdoc) {
832 0 : nsAutoString referrerStr;
833 0 : mOwnerContent->OwnerDoc()->GetReferrer(referrerStr);
834 0 : rv = NS_NewURI(getter_AddRefs(referrer), referrerStr);
835 :
836 0 : loadInfo->SetSrcdocData(srcdoc);
837 0 : nsCOMPtr<nsIURI> baseURI = mOwnerContent->GetBaseURI();
838 0 : loadInfo->SetBaseURI(baseURI);
839 : }
840 : else {
841 2 : rv = mOwnerContent->NodePrincipal()->GetURI(getter_AddRefs(referrer));
842 2 : NS_ENSURE_SUCCESS(rv, rv);
843 : }
844 :
845 : // Use referrer as long as it is not an NullPrincipalURI.
846 : // We could add a method such as GetReferrerURI to principals to make this
847 : // cleaner, but given that we need to start using Source Browsing Context for
848 : // referrer (see Bug 960639) this may be wasted effort at this stage.
849 2 : if (referrer) {
850 : bool isNullPrincipalScheme;
851 0 : rv = referrer->SchemeIs(NS_NULLPRINCIPAL_SCHEME, &isNullPrincipalScheme);
852 0 : if (NS_SUCCEEDED(rv) && !isNullPrincipalScheme) {
853 0 : loadInfo->SetReferrer(referrer);
854 : }
855 : }
856 :
857 : // get referrer policy for this iframe:
858 : // first load document wide policy, then
859 : // load iframe referrer attribute if enabled in preferences
860 : // per element referrer overrules document wide referrer if enabled
861 2 : net::ReferrerPolicy referrerPolicy = mOwnerContent->OwnerDoc()->GetReferrerPolicy();
862 2 : HTMLIFrameElement* iframe = HTMLIFrameElement::FromContent(mOwnerContent);
863 2 : if (iframe) {
864 0 : net::ReferrerPolicy iframeReferrerPolicy = iframe->GetReferrerPolicyAsEnum();
865 0 : if (iframeReferrerPolicy != net::RP_Unset) {
866 0 : referrerPolicy = iframeReferrerPolicy;
867 : }
868 : }
869 2 : loadInfo->SetReferrerPolicy(referrerPolicy);
870 :
871 : // Default flags:
872 2 : int32_t flags = nsIWebNavigation::LOAD_FLAGS_NONE;
873 :
874 : // Flags for browser frame:
875 2 : if (OwnerIsMozBrowserFrame()) {
876 0 : flags = nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
877 : nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL;
878 : }
879 :
880 : // Kick off the load...
881 2 : bool tmpState = mNeedsAsyncDestroy;
882 2 : mNeedsAsyncDestroy = true;
883 4 : nsCOMPtr<nsIURI> uriToLoad = mURIToLoad;
884 2 : rv = mDocShell->LoadURI(uriToLoad, loadInfo, flags, false);
885 2 : mNeedsAsyncDestroy = tmpState;
886 2 : mURIToLoad = nullptr;
887 2 : NS_ENSURE_SUCCESS(rv, rv);
888 :
889 2 : return NS_OK;
890 : }
891 :
892 : nsresult
893 5 : nsFrameLoader::CheckURILoad(nsIURI* aURI)
894 : {
895 : // Check for security. The fun part is trying to figure out what principals
896 : // to use. The way I figure it, if we're doing a LoadFrame() accidentally
897 : // (eg someone created a frame/iframe node, we're being parsed, XUL iframes
898 : // are being reframed, etc.) then we definitely want to use the node
899 : // principal of mOwnerContent for security checks. If, on the other hand,
900 : // someone's setting the src on our owner content, or created it via script,
901 : // or whatever, then they can clearly access it... and we should still use
902 : // the principal of mOwnerContent. I don't think that leads to privilege
903 : // escalation, and it's reasonably guaranteed to not lead to XSS issues
904 : // (since caller can already access mOwnerContent in this case). So just use
905 : // the principal of mOwnerContent no matter what. If script wants to run
906 : // things with its own permissions, which differ from those of mOwnerContent
907 : // (which means the script is privileged in some way) it should set
908 : // window.location instead.
909 5 : nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
910 :
911 : // Get our principal
912 5 : nsIPrincipal* principal = mOwnerContent->NodePrincipal();
913 :
914 : // Check if we are allowed to load absURL
915 : nsresult rv =
916 : secMan->CheckLoadURIWithPrincipal(principal, aURI,
917 5 : nsIScriptSecurityManager::STANDARD);
918 5 : if (NS_FAILED(rv)) {
919 0 : return rv; // We're not
920 : }
921 :
922 : // Bail out if this is an infinite recursion scenario
923 5 : if (IsRemoteFrame()) {
924 1 : return NS_OK;
925 : }
926 4 : return CheckForRecursiveLoad(aURI);
927 : }
928 :
929 : NS_IMETHODIMP
930 5 : nsFrameLoader::GetDocShell(nsIDocShell **aDocShell)
931 : {
932 5 : *aDocShell = nullptr;
933 5 : nsresult rv = NS_OK;
934 :
935 5 : if (IsRemoteFrame()) {
936 3 : return rv;
937 : }
938 :
939 : // If we have an owner, make sure we have a docshell and return
940 : // that. If not, we're most likely in the middle of being torn down,
941 : // then we just return null.
942 2 : if (mOwnerContent) {
943 2 : nsresult rv = MaybeCreateDocShell();
944 2 : if (NS_FAILED(rv)) {
945 0 : return rv;
946 : }
947 2 : NS_ASSERTION(mDocShell,
948 : "MaybeCreateDocShell succeeded, but null mDocShell");
949 : }
950 :
951 2 : *aDocShell = mDocShell;
952 2 : NS_IF_ADDREF(*aDocShell);
953 :
954 2 : return rv;
955 : }
956 :
957 : static void
958 0 : SetTreeOwnerAndChromeEventHandlerOnDocshellTree(nsIDocShellTreeItem* aItem,
959 : nsIDocShellTreeOwner* aOwner,
960 : EventTarget* aHandler)
961 : {
962 0 : NS_PRECONDITION(aItem, "Must have item");
963 :
964 0 : aItem->SetTreeOwner(aOwner);
965 :
966 0 : int32_t childCount = 0;
967 0 : aItem->GetChildCount(&childCount);
968 0 : for (int32_t i = 0; i < childCount; ++i) {
969 0 : nsCOMPtr<nsIDocShellTreeItem> item;
970 0 : aItem->GetChildAt(i, getter_AddRefs(item));
971 0 : if (aHandler) {
972 0 : nsCOMPtr<nsIDocShell> shell(do_QueryInterface(item));
973 0 : shell->SetChromeEventHandler(aHandler);
974 : }
975 0 : SetTreeOwnerAndChromeEventHandlerOnDocshellTree(item, aOwner, aHandler);
976 : }
977 0 : }
978 :
979 : /**
980 : * Set the type of the treeitem and hook it up to the treeowner.
981 : * @param aItem the treeitem we're working with
982 : * @param aTreeOwner the relevant treeowner; might be null
983 : * @param aParentType the nsIDocShellTreeItem::GetType of our parent docshell
984 : * @param aParentNode if non-null, the docshell we should be added as a child to
985 : *
986 : * @return whether aItem is top-level content
987 : */
988 : bool
989 2 : nsFrameLoader::AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem,
990 : nsIDocShellTreeOwner* aOwner,
991 : int32_t aParentType,
992 : nsIDocShell* aParentNode)
993 : {
994 2 : NS_PRECONDITION(aItem, "Must have docshell treeitem");
995 2 : NS_PRECONDITION(mOwnerContent, "Must have owning content");
996 :
997 4 : nsAutoString value;
998 2 : bool isContent = false;
999 2 : mOwnerContent->GetAttr(kNameSpaceID_None, TypeAttrName(), value);
1000 :
1001 : // we accept "content" and "content-xxx" values.
1002 : // We ignore anything that comes after 'content-'.
1003 5 : isContent = value.LowerCaseEqualsLiteral("content") ||
1004 4 : StringBeginsWith(value, NS_LITERAL_STRING("content-"),
1005 4 : nsCaseInsensitiveStringComparator());
1006 :
1007 :
1008 : // Force mozbrowser frames to always be typeContent, even if the
1009 : // mozbrowser interfaces are disabled.
1010 : nsCOMPtr<nsIDOMMozBrowserFrame> mozbrowser =
1011 4 : do_QueryInterface(mOwnerContent);
1012 2 : if (mozbrowser) {
1013 0 : bool isMozbrowser = false;
1014 0 : mozbrowser->GetMozbrowser(&isMozbrowser);
1015 0 : isContent |= isMozbrowser;
1016 : }
1017 :
1018 2 : if (isContent) {
1019 : // The web shell's type is content.
1020 :
1021 1 : aItem->SetItemType(nsIDocShellTreeItem::typeContent);
1022 : } else {
1023 : // Inherit our type from our parent docshell. If it is
1024 : // chrome, we'll be chrome. If it is content, we'll be
1025 : // content.
1026 :
1027 1 : aItem->SetItemType(aParentType);
1028 : }
1029 :
1030 : // Now that we have our type set, add ourselves to the parent, as needed.
1031 2 : if (aParentNode) {
1032 2 : aParentNode->AddChild(aItem);
1033 : }
1034 :
1035 2 : bool retval = false;
1036 2 : if (aParentType == nsIDocShellTreeItem::typeChrome && isContent) {
1037 1 : retval = true;
1038 :
1039 : bool is_primary =
1040 1 : mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary,
1041 1 : nsGkAtoms::_true, eIgnoreCase);
1042 1 : if (aOwner) {
1043 1 : mOwnerContent->AddMutationObserver(this);
1044 1 : mObservingOwnerContent = true;
1045 1 : aOwner->ContentShellAdded(aItem, is_primary);
1046 : }
1047 : }
1048 :
1049 4 : return retval;
1050 : }
1051 :
1052 : static bool
1053 0 : AllDescendantsOfType(nsIDocShellTreeItem* aParentItem, int32_t aType)
1054 : {
1055 0 : int32_t childCount = 0;
1056 0 : aParentItem->GetChildCount(&childCount);
1057 :
1058 0 : for (int32_t i = 0; i < childCount; ++i) {
1059 0 : nsCOMPtr<nsIDocShellTreeItem> kid;
1060 0 : aParentItem->GetChildAt(i, getter_AddRefs(kid));
1061 :
1062 0 : if (kid->ItemType() != aType || !AllDescendantsOfType(kid, aType)) {
1063 0 : return false;
1064 : }
1065 : }
1066 :
1067 0 : return true;
1068 : }
1069 :
1070 : /**
1071 : * A class that automatically sets mInShow to false when it goes
1072 : * out of scope.
1073 : */
1074 : class MOZ_RAII AutoResetInShow {
1075 : private:
1076 : nsFrameLoader* mFrameLoader;
1077 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1078 : public:
1079 3 : explicit AutoResetInShow(nsFrameLoader* aFrameLoader MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1080 3 : : mFrameLoader(aFrameLoader)
1081 : {
1082 3 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1083 3 : }
1084 3 : ~AutoResetInShow() { mFrameLoader->mInShow = false; }
1085 : };
1086 :
1087 : static bool
1088 1 : ParentWindowIsActive(nsIDocument* aDoc)
1089 : {
1090 2 : nsCOMPtr<nsPIWindowRoot> root = nsContentUtils::GetWindowRoot(aDoc);
1091 1 : if (root) {
1092 1 : nsPIDOMWindowOuter* rootWin = root->GetWindow();
1093 1 : return rootWin && rootWin->IsActive();
1094 : }
1095 0 : return false;
1096 : }
1097 :
1098 : bool
1099 3 : nsFrameLoader::Show(int32_t marginWidth, int32_t marginHeight,
1100 : int32_t scrollbarPrefX, int32_t scrollbarPrefY,
1101 : nsSubDocumentFrame* frame)
1102 : {
1103 3 : if (mInShow) {
1104 0 : return false;
1105 : }
1106 : // Reset mInShow if we exit early.
1107 6 : AutoResetInShow resetInShow(this);
1108 3 : mInShow = true;
1109 :
1110 3 : ScreenIntSize size = frame->GetSubdocumentSize();
1111 3 : if (IsRemoteFrame()) {
1112 2 : return ShowRemoteFrame(size, frame);
1113 : }
1114 :
1115 1 : nsresult rv = MaybeCreateDocShell();
1116 1 : if (NS_FAILED(rv)) {
1117 0 : return false;
1118 : }
1119 1 : NS_ASSERTION(mDocShell,
1120 : "MaybeCreateDocShell succeeded, but null mDocShell");
1121 1 : if (!mDocShell) {
1122 0 : return false;
1123 : }
1124 :
1125 1 : mDocShell->SetMarginWidth(marginWidth);
1126 1 : mDocShell->SetMarginHeight(marginHeight);
1127 :
1128 2 : nsCOMPtr<nsIScrollable> sc = do_QueryInterface(mDocShell);
1129 1 : if (sc) {
1130 1 : sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X,
1131 1 : scrollbarPrefX);
1132 1 : sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y,
1133 1 : scrollbarPrefY);
1134 : }
1135 :
1136 2 : nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
1137 1 : if (presShell) {
1138 : // Ensure root scroll frame is reflowed in case scroll preferences or
1139 : // margins have changed
1140 1 : nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
1141 1 : if (rootScrollFrame) {
1142 0 : presShell->FrameNeedsReflow(rootScrollFrame, nsIPresShell::eResize,
1143 0 : NS_FRAME_IS_DIRTY);
1144 : }
1145 1 : return true;
1146 : }
1147 :
1148 0 : nsView* view = frame->EnsureInnerView();
1149 0 : if (!view)
1150 0 : return false;
1151 :
1152 0 : nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mDocShell);
1153 0 : NS_ASSERTION(baseWindow, "Found a nsIDocShell that isn't a nsIBaseWindow.");
1154 0 : baseWindow->InitWindow(nullptr, view->GetWidget(), 0, 0,
1155 0 : size.width, size.height);
1156 : // This is kinda whacky, this "Create()" call doesn't really
1157 : // create anything, one starts to wonder why this was named
1158 : // "Create"...
1159 0 : baseWindow->Create();
1160 0 : baseWindow->SetVisibility(true);
1161 0 : NS_ENSURE_TRUE(mDocShell, false);
1162 :
1163 : // Trigger editor re-initialization if midas is turned on in the
1164 : // sub-document. This shouldn't be necessary, but given the way our
1165 : // editor works, it is. See
1166 : // https://bugzilla.mozilla.org/show_bug.cgi?id=284245
1167 0 : presShell = mDocShell->GetPresShell();
1168 0 : if (presShell) {
1169 : nsCOMPtr<nsIDOMHTMLDocument> doc =
1170 0 : do_QueryInterface(presShell->GetDocument());
1171 :
1172 0 : if (doc) {
1173 0 : nsAutoString designMode;
1174 0 : doc->GetDesignMode(designMode);
1175 :
1176 0 : if (designMode.EqualsLiteral("on")) {
1177 : // Hold on to the editor object to let the document reattach to the
1178 : // same editor object, instead of creating a new one.
1179 0 : nsCOMPtr<nsIEditor> editor;
1180 0 : nsresult rv = mDocShell->GetEditor(getter_AddRefs(editor));
1181 0 : NS_ENSURE_SUCCESS(rv, false);
1182 :
1183 0 : doc->SetDesignMode(NS_LITERAL_STRING("off"));
1184 0 : doc->SetDesignMode(NS_LITERAL_STRING("on"));
1185 : } else {
1186 : // Re-initialize the presentation for contenteditable documents
1187 0 : bool editable = false,
1188 0 : hasEditingSession = false;
1189 0 : mDocShell->GetEditable(&editable);
1190 0 : mDocShell->GetHasEditingSession(&hasEditingSession);
1191 0 : nsCOMPtr<nsIEditor> editor;
1192 0 : mDocShell->GetEditor(getter_AddRefs(editor));
1193 0 : if (editable && hasEditingSession && editor) {
1194 0 : editor->PostCreate();
1195 : }
1196 : }
1197 : }
1198 : }
1199 :
1200 0 : mInShow = false;
1201 0 : if (mHideCalled) {
1202 0 : mHideCalled = false;
1203 0 : Hide();
1204 0 : return false;
1205 : }
1206 0 : return true;
1207 : }
1208 :
1209 : void
1210 0 : nsFrameLoader::MarginsChanged(uint32_t aMarginWidth,
1211 : uint32_t aMarginHeight)
1212 : {
1213 : // We assume that the margins are always zero for remote frames.
1214 0 : if (IsRemoteFrame())
1215 0 : return;
1216 :
1217 : // If there's no docshell, we're probably not up and running yet.
1218 : // nsFrameLoader::Show() will take care of setting the right
1219 : // margins.
1220 0 : if (!mDocShell)
1221 0 : return;
1222 :
1223 : // Set the margins
1224 0 : mDocShell->SetMarginWidth(aMarginWidth);
1225 0 : mDocShell->SetMarginHeight(aMarginHeight);
1226 :
1227 : // There's a cached property declaration block
1228 : // that needs to be updated
1229 0 : if (nsIDocument* doc = mDocShell->GetDocument()) {
1230 : // We don't need to do anything for Gecko here because
1231 : // we plan to RebuildAllStyleData anyway.
1232 0 : if (doc->GetStyleBackendType() == StyleBackendType::Servo) {
1233 0 : for (nsINode* cur = doc; cur; cur = cur->GetNextNode()) {
1234 0 : if (cur->IsHTMLElement(nsGkAtoms::body)) {
1235 0 : static_cast<HTMLBodyElement*>(cur)->ClearMappedServoStyle();
1236 : }
1237 : }
1238 : }
1239 : }
1240 :
1241 : // Trigger a restyle if there's a prescontext
1242 : // FIXME: This could do something much less expensive.
1243 0 : RefPtr<nsPresContext> presContext;
1244 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
1245 0 : if (presContext)
1246 : // rebuild, because now the same nsMappedAttributes* will produce
1247 : // a different style
1248 0 : presContext->RebuildAllStyleData(nsChangeHint(0), eRestyle_Subtree);
1249 : }
1250 :
1251 : bool
1252 2 : nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
1253 : nsSubDocumentFrame *aFrame)
1254 : {
1255 4 : AUTO_PROFILER_LABEL("nsFrameLoader::ShowRemoteFrame", GRAPHICS);
1256 2 : NS_ASSERTION(IsRemoteFrame(), "ShowRemote only makes sense on remote frames.");
1257 :
1258 2 : if (!mRemoteBrowser && !TryRemoteBrowser()) {
1259 0 : NS_ERROR("Couldn't create child process.");
1260 0 : return false;
1261 : }
1262 :
1263 : // FIXME/bug 589337: Show()/Hide() is pretty expensive for
1264 : // cross-process layers; need to figure out what behavior we really
1265 : // want here. For now, hack.
1266 2 : if (!mRemoteBrowserShown) {
1267 2 : if (!mOwnerContent ||
1268 1 : !mOwnerContent->GetComposedDoc()) {
1269 0 : return false;
1270 : }
1271 :
1272 : // We never want to host remote frameloaders in simple popups, like menus.
1273 1 : nsIWidget* widget = nsContentUtils::WidgetForContent(mOwnerContent);
1274 1 : if (!widget || static_cast<nsBaseWidget*>(widget)->IsSmallPopup()) {
1275 0 : return false;
1276 : }
1277 :
1278 1 : RenderFrameParent* rfp = GetCurrentRenderFrame();
1279 1 : if (!rfp) {
1280 0 : return false;
1281 : }
1282 :
1283 1 : if (!rfp->AttachLayerManager()) {
1284 : // This is just not going to work.
1285 0 : return false;
1286 : }
1287 :
1288 1 : mRemoteBrowser->Show(size, ParentWindowIsActive(mOwnerContent->OwnerDoc()));
1289 1 : mRemoteBrowserShown = true;
1290 :
1291 2 : nsCOMPtr<nsIObserverService> os = services::GetObserverService();
1292 1 : if (os) {
1293 2 : os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
1294 2 : "remote-browser-shown", nullptr);
1295 : }
1296 : } else {
1297 1 : nsIntRect dimensions;
1298 1 : NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), false);
1299 :
1300 : // Don't show remote iframe if we are waiting for the completion of reflow.
1301 1 : if (!aFrame || !(aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
1302 0 : mRemoteBrowser->UpdateDimensions(dimensions, size);
1303 : }
1304 : }
1305 :
1306 2 : return true;
1307 : }
1308 :
1309 : void
1310 2 : nsFrameLoader::Hide()
1311 : {
1312 2 : if (mHideCalled) {
1313 1 : return;
1314 : }
1315 2 : if (mInShow) {
1316 0 : mHideCalled = true;
1317 0 : return;
1318 : }
1319 :
1320 2 : if (!mDocShell)
1321 1 : return;
1322 :
1323 2 : nsCOMPtr<nsIContentViewer> contentViewer;
1324 1 : mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
1325 1 : if (contentViewer)
1326 1 : contentViewer->SetSticky(false);
1327 :
1328 2 : nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
1329 1 : NS_ASSERTION(baseWin,
1330 : "Found an nsIDocShell which doesn't implement nsIBaseWindow.");
1331 1 : baseWin->SetVisibility(false);
1332 1 : baseWin->SetParentWidget(nullptr);
1333 : }
1334 :
1335 : nsresult
1336 0 : nsFrameLoader::SwapWithOtherRemoteLoader(nsFrameLoader* aOther,
1337 : nsIFrameLoaderOwner* aThisOwner,
1338 : nsIFrameLoaderOwner* aOtherOwner)
1339 : {
1340 0 : MOZ_ASSERT(NS_IsMainThread());
1341 :
1342 : #ifdef DEBUG
1343 0 : RefPtr<nsFrameLoader> first = aThisOwner->GetFrameLoader();
1344 0 : RefPtr<nsFrameLoader> second = aOtherOwner->GetFrameLoader();
1345 0 : MOZ_ASSERT(first == this, "aThisOwner must own this");
1346 0 : MOZ_ASSERT(second == aOther, "aOtherOwner must own aOther");
1347 : #endif
1348 :
1349 0 : Element* ourContent = mOwnerContent;
1350 0 : Element* otherContent = aOther->mOwnerContent;
1351 :
1352 0 : if (!ourContent || !otherContent) {
1353 : // Can't handle this
1354 0 : return NS_ERROR_NOT_IMPLEMENTED;
1355 : }
1356 :
1357 : // Make sure there are no same-origin issues
1358 : bool equal;
1359 : nsresult rv =
1360 0 : ourContent->NodePrincipal()->Equals(otherContent->NodePrincipal(), &equal);
1361 0 : if (NS_FAILED(rv) || !equal) {
1362 : // Security problems loom. Just bail on it all
1363 0 : return NS_ERROR_DOM_SECURITY_ERR;
1364 : }
1365 :
1366 0 : nsIDocument* ourDoc = ourContent->GetComposedDoc();
1367 0 : nsIDocument* otherDoc = otherContent->GetComposedDoc();
1368 0 : if (!ourDoc || !otherDoc) {
1369 : // Again, how odd, given that we had docshells
1370 0 : return NS_ERROR_NOT_IMPLEMENTED;
1371 : }
1372 :
1373 0 : nsIPresShell* ourShell = ourDoc->GetShell();
1374 0 : nsIPresShell* otherShell = otherDoc->GetShell();
1375 0 : if (!ourShell || !otherShell) {
1376 0 : return NS_ERROR_NOT_IMPLEMENTED;
1377 : }
1378 :
1379 0 : if (!mRemoteBrowser || !aOther->mRemoteBrowser) {
1380 0 : return NS_ERROR_NOT_IMPLEMENTED;
1381 : }
1382 :
1383 0 : if (mRemoteBrowser->IsIsolatedMozBrowserElement() !=
1384 0 : aOther->mRemoteBrowser->IsIsolatedMozBrowserElement()) {
1385 0 : return NS_ERROR_NOT_IMPLEMENTED;
1386 : }
1387 :
1388 : // When we swap docShells, maybe we have to deal with a new page created just
1389 : // for this operation. In this case, the browser code should already have set
1390 : // the correct userContextId attribute value in the owning XULElement, but our
1391 : // docShell, that has been created way before) doesn't know that that
1392 : // happened.
1393 : // This is the reason why now we must retrieve the correct value from the
1394 : // usercontextid attribute before comparing our originAttributes with the
1395 : // other one.
1396 : OriginAttributes ourOriginAttributes =
1397 0 : mRemoteBrowser->OriginAttributesRef();
1398 0 : rv = PopulateUserContextIdFromAttribute(ourOriginAttributes);
1399 0 : NS_ENSURE_SUCCESS(rv,rv);
1400 :
1401 : OriginAttributes otherOriginAttributes =
1402 0 : aOther->mRemoteBrowser->OriginAttributesRef();
1403 0 : rv = aOther->PopulateUserContextIdFromAttribute(otherOriginAttributes);
1404 0 : NS_ENSURE_SUCCESS(rv,rv);
1405 :
1406 0 : if (ourOriginAttributes != otherOriginAttributes) {
1407 0 : return NS_ERROR_NOT_IMPLEMENTED;
1408 : }
1409 :
1410 : bool ourHasHistory =
1411 0 : mIsTopLevelContent &&
1412 0 : ourContent->IsXULElement(nsGkAtoms::browser) &&
1413 0 : !ourContent->HasAttr(kNameSpaceID_None, nsGkAtoms::disablehistory);
1414 : bool otherHasHistory =
1415 0 : aOther->mIsTopLevelContent &&
1416 0 : otherContent->IsXULElement(nsGkAtoms::browser) &&
1417 0 : !otherContent->HasAttr(kNameSpaceID_None, nsGkAtoms::disablehistory);
1418 0 : if (ourHasHistory != otherHasHistory) {
1419 0 : return NS_ERROR_NOT_IMPLEMENTED;
1420 : }
1421 :
1422 0 : if (mInSwap || aOther->mInSwap) {
1423 0 : return NS_ERROR_NOT_IMPLEMENTED;
1424 : }
1425 0 : mInSwap = aOther->mInSwap = true;
1426 :
1427 0 : nsIFrame* ourFrame = ourContent->GetPrimaryFrame();
1428 0 : nsIFrame* otherFrame = otherContent->GetPrimaryFrame();
1429 0 : if (!ourFrame || !otherFrame) {
1430 0 : mInSwap = aOther->mInSwap = false;
1431 0 : return NS_ERROR_NOT_IMPLEMENTED;
1432 : }
1433 :
1434 0 : nsSubDocumentFrame* ourFrameFrame = do_QueryFrame(ourFrame);
1435 0 : if (!ourFrameFrame) {
1436 0 : mInSwap = aOther->mInSwap = false;
1437 0 : return NS_ERROR_NOT_IMPLEMENTED;
1438 : }
1439 :
1440 0 : rv = ourFrameFrame->BeginSwapDocShells(otherFrame);
1441 0 : if (NS_FAILED(rv)) {
1442 0 : mInSwap = aOther->mInSwap = false;
1443 0 : return rv;
1444 : }
1445 :
1446 : nsCOMPtr<nsIBrowserDOMWindow> otherBrowserDOMWindow =
1447 0 : aOther->mRemoteBrowser->GetBrowserDOMWindow();
1448 : nsCOMPtr<nsIBrowserDOMWindow> browserDOMWindow =
1449 0 : mRemoteBrowser->GetBrowserDOMWindow();
1450 :
1451 0 : if (!!otherBrowserDOMWindow != !!browserDOMWindow) {
1452 0 : return NS_ERROR_NOT_IMPLEMENTED;
1453 : }
1454 :
1455 : // Destroy browser frame scripts for content leaving a frame with browser API
1456 0 : if (OwnerIsMozBrowserFrame() && !aOther->OwnerIsMozBrowserFrame()) {
1457 0 : DestroyBrowserFrameScripts();
1458 : }
1459 0 : if (!OwnerIsMozBrowserFrame() && aOther->OwnerIsMozBrowserFrame()) {
1460 0 : aOther->DestroyBrowserFrameScripts();
1461 : }
1462 :
1463 0 : aOther->mRemoteBrowser->SetBrowserDOMWindow(browserDOMWindow);
1464 0 : mRemoteBrowser->SetBrowserDOMWindow(otherBrowserDOMWindow);
1465 :
1466 : #ifdef XP_WIN
1467 : // Native plugin windows used by this remote content need to be reparented.
1468 : if (nsPIDOMWindowOuter* newWin = ourDoc->GetWindow()) {
1469 : RefPtr<nsIWidget> newParent = nsGlobalWindow::Cast(newWin)->GetMainWidget();
1470 : const ManagedContainer<mozilla::plugins::PPluginWidgetParent>& plugins =
1471 : aOther->mRemoteBrowser->ManagedPPluginWidgetParent();
1472 : for (auto iter = plugins.ConstIter(); !iter.Done(); iter.Next()) {
1473 : static_cast<mozilla::plugins::PluginWidgetParent*>(iter.Get()->GetKey())->SetParent(newParent);
1474 : }
1475 : }
1476 : #endif // XP_WIN
1477 :
1478 0 : MaybeUpdatePrimaryTabParent(eTabParentRemoved);
1479 0 : aOther->MaybeUpdatePrimaryTabParent(eTabParentRemoved);
1480 :
1481 0 : SetOwnerContent(otherContent);
1482 0 : aOther->SetOwnerContent(ourContent);
1483 :
1484 0 : mRemoteBrowser->SetOwnerElement(otherContent);
1485 0 : aOther->mRemoteBrowser->SetOwnerElement(ourContent);
1486 :
1487 : // Update window activation state for the swapped owner content.
1488 0 : Unused << mRemoteBrowser->Manager()->AsContentParent()->SendParentActivated(
1489 0 : mRemoteBrowser, ParentWindowIsActive(otherContent->OwnerDoc()));
1490 0 : Unused << aOther->mRemoteBrowser->Manager()->AsContentParent()->SendParentActivated(
1491 0 : aOther->mRemoteBrowser, ParentWindowIsActive(ourContent->OwnerDoc()));
1492 :
1493 0 : MaybeUpdatePrimaryTabParent(eTabParentChanged);
1494 0 : aOther->MaybeUpdatePrimaryTabParent(eTabParentChanged);
1495 :
1496 0 : RefPtr<nsFrameMessageManager> ourMessageManager = mMessageManager;
1497 0 : RefPtr<nsFrameMessageManager> otherMessageManager = aOther->mMessageManager;
1498 : // Swap and setup things in parent message managers.
1499 0 : if (ourMessageManager) {
1500 0 : ourMessageManager->SetCallback(aOther);
1501 : }
1502 0 : if (otherMessageManager) {
1503 0 : otherMessageManager->SetCallback(this);
1504 : }
1505 0 : mMessageManager.swap(aOther->mMessageManager);
1506 :
1507 : // Perform the actual swap of the internal refptrs. We keep a strong reference
1508 : // to ourselves to make sure we don't die while we overwrite our reference to
1509 : // ourself.
1510 0 : nsCOMPtr<nsIFrameLoader> kungFuDeathGrip(this);
1511 0 : aThisOwner->InternalSetFrameLoader(aOther);
1512 0 : aOtherOwner->InternalSetFrameLoader(kungFuDeathGrip);
1513 :
1514 0 : ourFrameFrame->EndSwapDocShells(otherFrame);
1515 :
1516 0 : ourShell->BackingScaleFactorChanged();
1517 0 : otherShell->BackingScaleFactorChanged();
1518 :
1519 : // Initialize browser API if needed now that owner content has changed.
1520 0 : InitializeBrowserAPI();
1521 0 : aOther->InitializeBrowserAPI();
1522 :
1523 0 : mInSwap = aOther->mInSwap = false;
1524 :
1525 : // Send an updated tab context since owner content type may have changed.
1526 0 : MutableTabContext ourContext;
1527 0 : rv = GetNewTabContext(&ourContext);
1528 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1529 0 : return rv;
1530 : }
1531 0 : MutableTabContext otherContext;
1532 0 : rv = aOther->GetNewTabContext(&otherContext);
1533 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1534 0 : return rv;
1535 : }
1536 :
1537 : // Swap the remoteType property as the frameloaders are being swapped
1538 0 : nsAutoString ourRemoteType;
1539 0 : if (!ourContent->GetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType,
1540 : ourRemoteType)) {
1541 0 : ourRemoteType.AssignLiteral(DEFAULT_REMOTE_TYPE);
1542 : }
1543 0 : nsAutoString otherRemoteType;
1544 0 : if (!otherContent->GetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType,
1545 : otherRemoteType)) {
1546 0 : otherRemoteType.AssignLiteral(DEFAULT_REMOTE_TYPE);
1547 : }
1548 0 : ourContent->SetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType, otherRemoteType, false);
1549 0 : otherContent->SetAttr(kNameSpaceID_None, nsGkAtoms::RemoteType, ourRemoteType, false);
1550 :
1551 0 : Unused << mRemoteBrowser->SendSwappedWithOtherRemoteLoader(
1552 0 : ourContext.AsIPCTabContext());
1553 0 : Unused << aOther->mRemoteBrowser->SendSwappedWithOtherRemoteLoader(
1554 0 : otherContext.AsIPCTabContext());
1555 0 : return NS_OK;
1556 : }
1557 :
1558 : class MOZ_RAII AutoResetInFrameSwap final
1559 : {
1560 : public:
1561 0 : AutoResetInFrameSwap(nsFrameLoader* aThisFrameLoader,
1562 : nsFrameLoader* aOtherFrameLoader,
1563 : nsDocShell* aThisDocShell,
1564 : nsDocShell* aOtherDocShell,
1565 : EventTarget* aThisEventTarget,
1566 : EventTarget* aOtherEventTarget
1567 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1568 0 : : mThisFrameLoader(aThisFrameLoader)
1569 : , mOtherFrameLoader(aOtherFrameLoader)
1570 : , mThisDocShell(aThisDocShell)
1571 : , mOtherDocShell(aOtherDocShell)
1572 : , mThisEventTarget(aThisEventTarget)
1573 0 : , mOtherEventTarget(aOtherEventTarget)
1574 : {
1575 0 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1576 :
1577 0 : mThisFrameLoader->mInSwap = true;
1578 0 : mOtherFrameLoader->mInSwap = true;
1579 0 : mThisDocShell->SetInFrameSwap(true);
1580 0 : mOtherDocShell->SetInFrameSwap(true);
1581 :
1582 : // Fire pageshow events on still-loading pages, and then fire pagehide
1583 : // events. Note that we do NOT fire these in the normal way, but just fire
1584 : // them on the chrome event handlers.
1585 0 : nsContentUtils::FirePageShowEvent(mThisDocShell, mThisEventTarget, false);
1586 0 : nsContentUtils::FirePageShowEvent(mOtherDocShell, mOtherEventTarget, false);
1587 0 : nsContentUtils::FirePageHideEvent(mThisDocShell, mThisEventTarget);
1588 0 : nsContentUtils::FirePageHideEvent(mOtherDocShell, mOtherEventTarget);
1589 0 : }
1590 :
1591 0 : ~AutoResetInFrameSwap()
1592 0 : {
1593 0 : nsContentUtils::FirePageShowEvent(mThisDocShell, mThisEventTarget, true);
1594 0 : nsContentUtils::FirePageShowEvent(mOtherDocShell, mOtherEventTarget, true);
1595 :
1596 0 : mThisFrameLoader->mInSwap = false;
1597 0 : mOtherFrameLoader->mInSwap = false;
1598 0 : mThisDocShell->SetInFrameSwap(false);
1599 0 : mOtherDocShell->SetInFrameSwap(false);
1600 0 : }
1601 :
1602 : private:
1603 : RefPtr<nsFrameLoader> mThisFrameLoader;
1604 : RefPtr<nsFrameLoader> mOtherFrameLoader;
1605 : RefPtr<nsDocShell> mThisDocShell;
1606 : RefPtr<nsDocShell> mOtherDocShell;
1607 : nsCOMPtr<EventTarget> mThisEventTarget;
1608 : nsCOMPtr<EventTarget> mOtherEventTarget;
1609 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1610 : };
1611 :
1612 : nsresult
1613 0 : nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
1614 : nsIFrameLoaderOwner* aThisOwner,
1615 : nsIFrameLoaderOwner* aOtherOwner)
1616 : {
1617 : #ifdef DEBUG
1618 0 : RefPtr<nsFrameLoader> first = aThisOwner->GetFrameLoader();
1619 0 : RefPtr<nsFrameLoader> second = aOtherOwner->GetFrameLoader();
1620 0 : MOZ_ASSERT(first == this, "aThisOwner must own this");
1621 0 : MOZ_ASSERT(second == aOther, "aOtherOwner must own aOther");
1622 : #endif
1623 :
1624 0 : NS_ENSURE_STATE(!mInShow && !aOther->mInShow);
1625 :
1626 0 : if (IsRemoteFrame() != aOther->IsRemoteFrame()) {
1627 0 : NS_WARNING("Swapping remote and non-remote frames is not currently supported");
1628 0 : return NS_ERROR_NOT_IMPLEMENTED;
1629 : }
1630 :
1631 0 : Element* ourContent = mOwnerContent;
1632 0 : Element* otherContent = aOther->mOwnerContent;
1633 :
1634 0 : if (!ourContent || !otherContent) {
1635 : // Can't handle this
1636 0 : return NS_ERROR_NOT_IMPLEMENTED;
1637 : }
1638 :
1639 0 : bool ourHasSrcdoc = ourContent->IsHTMLElement(nsGkAtoms::iframe) &&
1640 0 : ourContent->HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc);
1641 0 : bool otherHasSrcdoc = otherContent->IsHTMLElement(nsGkAtoms::iframe) &&
1642 0 : otherContent->HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc);
1643 0 : if (ourHasSrcdoc || otherHasSrcdoc) {
1644 : // Ignore this case entirely for now, since we support XUL <-> HTML swapping
1645 0 : return NS_ERROR_NOT_IMPLEMENTED;
1646 : }
1647 :
1648 : bool ourFullscreenAllowed =
1649 0 : ourContent->IsXULElement() ||
1650 0 : (OwnerIsMozBrowserFrame() &&
1651 0 : (ourContent->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) ||
1652 0 : ourContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen)));
1653 : bool otherFullscreenAllowed =
1654 0 : otherContent->IsXULElement() ||
1655 0 : (aOther->OwnerIsMozBrowserFrame() &&
1656 0 : (otherContent->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) ||
1657 0 : otherContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen)));
1658 0 : if (ourFullscreenAllowed != otherFullscreenAllowed) {
1659 0 : return NS_ERROR_NOT_IMPLEMENTED;
1660 : }
1661 :
1662 : // Divert to a separate path for the remaining steps in the remote case
1663 0 : if (IsRemoteFrame()) {
1664 0 : MOZ_ASSERT(aOther->IsRemoteFrame());
1665 0 : return SwapWithOtherRemoteLoader(aOther, aThisOwner, aOtherOwner);
1666 : }
1667 :
1668 : // Make sure there are no same-origin issues
1669 : bool equal;
1670 : nsresult rv =
1671 0 : ourContent->NodePrincipal()->Equals(otherContent->NodePrincipal(), &equal);
1672 0 : if (NS_FAILED(rv) || !equal) {
1673 : // Security problems loom. Just bail on it all
1674 0 : return NS_ERROR_DOM_SECURITY_ERR;
1675 : }
1676 :
1677 0 : RefPtr<nsDocShell> ourDocshell = static_cast<nsDocShell*>(GetExistingDocShell());
1678 0 : RefPtr<nsDocShell> otherDocshell = static_cast<nsDocShell*>(aOther->GetExistingDocShell());
1679 0 : if (!ourDocshell || !otherDocshell) {
1680 : // How odd
1681 0 : return NS_ERROR_NOT_IMPLEMENTED;
1682 : }
1683 :
1684 : // To avoid having to mess with session history, avoid swapping
1685 : // frameloaders that don't correspond to root same-type docshells,
1686 : // unless both roots have session history disabled.
1687 0 : nsCOMPtr<nsIDocShellTreeItem> ourRootTreeItem, otherRootTreeItem;
1688 0 : ourDocshell->GetSameTypeRootTreeItem(getter_AddRefs(ourRootTreeItem));
1689 0 : otherDocshell->GetSameTypeRootTreeItem(getter_AddRefs(otherRootTreeItem));
1690 : nsCOMPtr<nsIWebNavigation> ourRootWebnav =
1691 0 : do_QueryInterface(ourRootTreeItem);
1692 : nsCOMPtr<nsIWebNavigation> otherRootWebnav =
1693 0 : do_QueryInterface(otherRootTreeItem);
1694 :
1695 0 : if (!ourRootWebnav || !otherRootWebnav) {
1696 0 : return NS_ERROR_NOT_IMPLEMENTED;
1697 : }
1698 :
1699 0 : nsCOMPtr<nsISHistory> ourHistory;
1700 0 : nsCOMPtr<nsISHistory> otherHistory;
1701 0 : ourRootWebnav->GetSessionHistory(getter_AddRefs(ourHistory));
1702 0 : otherRootWebnav->GetSessionHistory(getter_AddRefs(otherHistory));
1703 :
1704 0 : if ((ourRootTreeItem != ourDocshell || otherRootTreeItem != otherDocshell) &&
1705 0 : (ourHistory || otherHistory)) {
1706 0 : return NS_ERROR_NOT_IMPLEMENTED;
1707 : }
1708 :
1709 : // Also make sure that the two docshells are the same type. Otherwise
1710 : // swapping is certainly not safe. If this needs to be changed then
1711 : // the code below needs to be audited as it assumes identical types.
1712 0 : int32_t ourType = ourDocshell->ItemType();
1713 0 : int32_t otherType = otherDocshell->ItemType();
1714 0 : if (ourType != otherType) {
1715 0 : return NS_ERROR_NOT_IMPLEMENTED;
1716 : }
1717 :
1718 : // One more twist here. Setting up the right treeowners in a heterogeneous
1719 : // tree is a bit of a pain. So make sure that if ourType is not
1720 : // nsIDocShellTreeItem::typeContent then all of our descendants are the same
1721 : // type as us.
1722 0 : if (ourType != nsIDocShellTreeItem::typeContent &&
1723 0 : (!AllDescendantsOfType(ourDocshell, ourType) ||
1724 0 : !AllDescendantsOfType(otherDocshell, otherType))) {
1725 0 : return NS_ERROR_NOT_IMPLEMENTED;
1726 : }
1727 :
1728 : // Save off the tree owners, frame elements, chrome event handlers, and
1729 : // docshell and document parents before doing anything else.
1730 0 : nsCOMPtr<nsIDocShellTreeOwner> ourOwner, otherOwner;
1731 0 : ourDocshell->GetTreeOwner(getter_AddRefs(ourOwner));
1732 0 : otherDocshell->GetTreeOwner(getter_AddRefs(otherOwner));
1733 : // Note: it's OK to have null treeowners.
1734 :
1735 0 : nsCOMPtr<nsIDocShellTreeItem> ourParentItem, otherParentItem;
1736 0 : ourDocshell->GetParent(getter_AddRefs(ourParentItem));
1737 0 : otherDocshell->GetParent(getter_AddRefs(otherParentItem));
1738 0 : if (!ourParentItem || !otherParentItem) {
1739 0 : return NS_ERROR_NOT_IMPLEMENTED;
1740 : }
1741 :
1742 : // Make sure our parents are the same type too
1743 0 : int32_t ourParentType = ourParentItem->ItemType();
1744 0 : int32_t otherParentType = otherParentItem->ItemType();
1745 0 : if (ourParentType != otherParentType) {
1746 0 : return NS_ERROR_NOT_IMPLEMENTED;
1747 : }
1748 :
1749 0 : nsCOMPtr<nsPIDOMWindowOuter> ourWindow = ourDocshell->GetWindow();
1750 0 : nsCOMPtr<nsPIDOMWindowOuter> otherWindow = otherDocshell->GetWindow();
1751 :
1752 : nsCOMPtr<Element> ourFrameElement =
1753 0 : ourWindow->GetFrameElementInternal();
1754 : nsCOMPtr<Element> otherFrameElement =
1755 0 : otherWindow->GetFrameElementInternal();
1756 :
1757 : nsCOMPtr<EventTarget> ourChromeEventHandler =
1758 0 : do_QueryInterface(ourWindow->GetChromeEventHandler());
1759 : nsCOMPtr<EventTarget> otherChromeEventHandler =
1760 0 : do_QueryInterface(otherWindow->GetChromeEventHandler());
1761 :
1762 0 : nsCOMPtr<EventTarget> ourEventTarget = ourWindow->GetParentTarget();
1763 0 : nsCOMPtr<EventTarget> otherEventTarget = otherWindow->GetParentTarget();
1764 :
1765 0 : NS_ASSERTION(SameCOMIdentity(ourFrameElement, ourContent) &&
1766 : SameCOMIdentity(otherFrameElement, otherContent) &&
1767 : SameCOMIdentity(ourChromeEventHandler, ourContent) &&
1768 : SameCOMIdentity(otherChromeEventHandler, otherContent),
1769 : "How did that happen, exactly?");
1770 :
1771 0 : nsCOMPtr<nsIDocument> ourChildDocument = ourWindow->GetExtantDoc();
1772 0 : nsCOMPtr<nsIDocument> otherChildDocument = otherWindow ->GetExtantDoc();
1773 0 : if (!ourChildDocument || !otherChildDocument) {
1774 : // This shouldn't be happening
1775 0 : return NS_ERROR_NOT_IMPLEMENTED;
1776 : }
1777 :
1778 : nsCOMPtr<nsIDocument> ourParentDocument =
1779 0 : ourChildDocument->GetParentDocument();
1780 : nsCOMPtr<nsIDocument> otherParentDocument =
1781 0 : otherChildDocument->GetParentDocument();
1782 :
1783 : // Make sure to swap docshells between the two frames.
1784 0 : nsIDocument* ourDoc = ourContent->GetComposedDoc();
1785 0 : nsIDocument* otherDoc = otherContent->GetComposedDoc();
1786 0 : if (!ourDoc || !otherDoc) {
1787 : // Again, how odd, given that we had docshells
1788 0 : return NS_ERROR_NOT_IMPLEMENTED;
1789 : }
1790 :
1791 0 : NS_ASSERTION(ourDoc == ourParentDocument, "Unexpected parent document");
1792 0 : NS_ASSERTION(otherDoc == otherParentDocument, "Unexpected parent document");
1793 :
1794 0 : nsIPresShell* ourShell = ourDoc->GetShell();
1795 0 : nsIPresShell* otherShell = otherDoc->GetShell();
1796 0 : if (!ourShell || !otherShell) {
1797 0 : return NS_ERROR_NOT_IMPLEMENTED;
1798 : }
1799 :
1800 0 : if (ourDocshell->GetIsIsolatedMozBrowserElement() !=
1801 0 : otherDocshell->GetIsIsolatedMozBrowserElement()) {
1802 0 : return NS_ERROR_NOT_IMPLEMENTED;
1803 : }
1804 :
1805 : // When we swap docShells, maybe we have to deal with a new page created just
1806 : // for this operation. In this case, the browser code should already have set
1807 : // the correct userContextId attribute value in the owning XULElement, but our
1808 : // docShell, that has been created way before) doesn't know that that
1809 : // happened.
1810 : // This is the reason why now we must retrieve the correct value from the
1811 : // usercontextid attribute before comparing our originAttributes with the
1812 : // other one.
1813 : OriginAttributes ourOriginAttributes =
1814 0 : ourDocshell->GetOriginAttributes();
1815 0 : rv = PopulateUserContextIdFromAttribute(ourOriginAttributes);
1816 0 : NS_ENSURE_SUCCESS(rv,rv);
1817 :
1818 : OriginAttributes otherOriginAttributes =
1819 0 : otherDocshell->GetOriginAttributes();
1820 0 : rv = aOther->PopulateUserContextIdFromAttribute(otherOriginAttributes);
1821 0 : NS_ENSURE_SUCCESS(rv,rv);
1822 :
1823 0 : if (ourOriginAttributes != otherOriginAttributes) {
1824 0 : return NS_ERROR_NOT_IMPLEMENTED;
1825 : }
1826 :
1827 0 : if (mInSwap || aOther->mInSwap) {
1828 0 : return NS_ERROR_NOT_IMPLEMENTED;
1829 : }
1830 : AutoResetInFrameSwap autoFrameSwap(this, aOther, ourDocshell, otherDocshell,
1831 0 : ourEventTarget, otherEventTarget);
1832 :
1833 0 : nsIFrame* ourFrame = ourContent->GetPrimaryFrame();
1834 0 : nsIFrame* otherFrame = otherContent->GetPrimaryFrame();
1835 0 : if (!ourFrame || !otherFrame) {
1836 0 : return NS_ERROR_NOT_IMPLEMENTED;
1837 : }
1838 :
1839 0 : nsSubDocumentFrame* ourFrameFrame = do_QueryFrame(ourFrame);
1840 0 : if (!ourFrameFrame) {
1841 0 : return NS_ERROR_NOT_IMPLEMENTED;
1842 : }
1843 :
1844 : // OK. First begin to swap the docshells in the two nsIFrames
1845 0 : rv = ourFrameFrame->BeginSwapDocShells(otherFrame);
1846 0 : if (NS_FAILED(rv)) {
1847 0 : return rv;
1848 : }
1849 :
1850 : // Destroy browser frame scripts for content leaving a frame with browser API
1851 0 : if (OwnerIsMozBrowserFrame() && !aOther->OwnerIsMozBrowserFrame()) {
1852 0 : DestroyBrowserFrameScripts();
1853 : }
1854 0 : if (!OwnerIsMozBrowserFrame() && aOther->OwnerIsMozBrowserFrame()) {
1855 0 : aOther->DestroyBrowserFrameScripts();
1856 : }
1857 :
1858 : // Now move the docshells to the right docshell trees. Note that this
1859 : // resets their treeowners to null.
1860 0 : ourParentItem->RemoveChild(ourDocshell);
1861 0 : otherParentItem->RemoveChild(otherDocshell);
1862 0 : if (ourType == nsIDocShellTreeItem::typeContent) {
1863 0 : ourOwner->ContentShellRemoved(ourDocshell);
1864 0 : otherOwner->ContentShellRemoved(otherDocshell);
1865 : }
1866 :
1867 0 : ourParentItem->AddChild(otherDocshell);
1868 0 : otherParentItem->AddChild(ourDocshell);
1869 :
1870 : // Restore the correct chrome event handlers.
1871 0 : ourDocshell->SetChromeEventHandler(otherChromeEventHandler);
1872 0 : otherDocshell->SetChromeEventHandler(ourChromeEventHandler);
1873 : // Restore the correct treeowners
1874 : // (and also chrome event handlers for content frames only).
1875 0 : SetTreeOwnerAndChromeEventHandlerOnDocshellTree(ourDocshell, otherOwner,
1876 0 : ourType == nsIDocShellTreeItem::typeContent ? otherChromeEventHandler.get() : nullptr);
1877 0 : SetTreeOwnerAndChromeEventHandlerOnDocshellTree(otherDocshell, ourOwner,
1878 0 : ourType == nsIDocShellTreeItem::typeContent ? ourChromeEventHandler.get() : nullptr);
1879 :
1880 : // Switch the owner content before we start calling AddTreeItemToTreeOwner.
1881 : // Note that we rely on this to deal with setting mObservingOwnerContent to
1882 : // false and calling RemoveMutationObserver as needed.
1883 0 : SetOwnerContent(otherContent);
1884 0 : aOther->SetOwnerContent(ourContent);
1885 :
1886 0 : AddTreeItemToTreeOwner(ourDocshell, otherOwner, otherParentType, nullptr);
1887 0 : aOther->AddTreeItemToTreeOwner(otherDocshell, ourOwner, ourParentType,
1888 0 : nullptr);
1889 :
1890 : // SetSubDocumentFor nulls out parent documents on the old child doc if a
1891 : // new non-null document is passed in, so just go ahead and remove both
1892 : // kids before reinserting in the parent subdoc maps, to avoid
1893 : // complications.
1894 0 : ourParentDocument->SetSubDocumentFor(ourContent, nullptr);
1895 0 : otherParentDocument->SetSubDocumentFor(otherContent, nullptr);
1896 0 : ourParentDocument->SetSubDocumentFor(ourContent, otherChildDocument);
1897 0 : otherParentDocument->SetSubDocumentFor(otherContent, ourChildDocument);
1898 :
1899 0 : ourWindow->SetFrameElementInternal(otherFrameElement);
1900 0 : otherWindow->SetFrameElementInternal(ourFrameElement);
1901 :
1902 0 : RefPtr<nsFrameMessageManager> ourMessageManager = mMessageManager;
1903 0 : RefPtr<nsFrameMessageManager> otherMessageManager = aOther->mMessageManager;
1904 : // Swap pointers in child message managers.
1905 0 : if (mChildMessageManager) {
1906 : nsInProcessTabChildGlobal* tabChild =
1907 0 : static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get());
1908 0 : tabChild->SetOwner(otherContent);
1909 0 : tabChild->SetChromeMessageManager(otherMessageManager);
1910 : }
1911 0 : if (aOther->mChildMessageManager) {
1912 : nsInProcessTabChildGlobal* otherTabChild =
1913 0 : static_cast<nsInProcessTabChildGlobal*>(aOther->mChildMessageManager.get());
1914 0 : otherTabChild->SetOwner(ourContent);
1915 0 : otherTabChild->SetChromeMessageManager(ourMessageManager);
1916 : }
1917 : // Swap and setup things in parent message managers.
1918 0 : if (mMessageManager) {
1919 0 : mMessageManager->SetCallback(aOther);
1920 : }
1921 0 : if (aOther->mMessageManager) {
1922 0 : aOther->mMessageManager->SetCallback(this);
1923 : }
1924 0 : mMessageManager.swap(aOther->mMessageManager);
1925 :
1926 : // Perform the actual swap of the internal refptrs. We keep a strong reference
1927 : // to ourselves to make sure we don't die while we overwrite our reference to
1928 : // ourself.
1929 0 : nsCOMPtr<nsIFrameLoader> kungFuDeathGrip(this);
1930 0 : aThisOwner->InternalSetFrameLoader(aOther);
1931 0 : aOtherOwner->InternalSetFrameLoader(kungFuDeathGrip);
1932 :
1933 : // Drop any cached content viewers in the two session histories.
1934 : nsCOMPtr<nsISHistoryInternal> ourInternalHistory =
1935 0 : do_QueryInterface(ourHistory);
1936 : nsCOMPtr<nsISHistoryInternal> otherInternalHistory =
1937 0 : do_QueryInterface(otherHistory);
1938 0 : if (ourInternalHistory) {
1939 0 : ourInternalHistory->EvictAllContentViewers();
1940 : }
1941 0 : if (otherInternalHistory) {
1942 0 : otherInternalHistory->EvictAllContentViewers();
1943 : }
1944 :
1945 0 : NS_ASSERTION(ourFrame == ourContent->GetPrimaryFrame() &&
1946 : otherFrame == otherContent->GetPrimaryFrame(),
1947 : "changed primary frame");
1948 :
1949 0 : ourFrameFrame->EndSwapDocShells(otherFrame);
1950 :
1951 : // If the content being swapped came from windows on two screens with
1952 : // incompatible backing resolution (e.g. dragging a tab between windows on
1953 : // hi-dpi and low-dpi screens), it will have style data that is based on
1954 : // the wrong appUnitsPerDevPixel value. So we tell the PresShells that their
1955 : // backing scale factor may have changed. (Bug 822266)
1956 0 : ourShell->BackingScaleFactorChanged();
1957 0 : otherShell->BackingScaleFactorChanged();
1958 :
1959 : // Initialize browser API if needed now that owner content has changed
1960 0 : InitializeBrowserAPI();
1961 0 : aOther->InitializeBrowserAPI();
1962 :
1963 0 : return NS_OK;
1964 : }
1965 :
1966 : NS_IMETHODIMP
1967 1 : nsFrameLoader::Destroy()
1968 : {
1969 1 : StartDestroy();
1970 1 : return NS_OK;
1971 : }
1972 :
1973 3 : class nsFrameLoaderDestroyRunnable : public Runnable
1974 : {
1975 : enum DestroyPhase
1976 : {
1977 : // See the implementation of Run for an explanation of these phases.
1978 : eDestroyDocShell,
1979 : eWaitForUnloadMessage,
1980 : eDestroyComplete
1981 : };
1982 :
1983 : RefPtr<nsFrameLoader> mFrameLoader;
1984 : DestroyPhase mPhase;
1985 :
1986 : public:
1987 1 : explicit nsFrameLoaderDestroyRunnable(nsFrameLoader* aFrameLoader)
1988 1 : : mozilla::Runnable("nsFrameLoaderDestroyRunnable")
1989 : , mFrameLoader(aFrameLoader)
1990 1 : , mPhase(eDestroyDocShell)
1991 : {
1992 1 : }
1993 :
1994 : NS_IMETHOD Run() override;
1995 : };
1996 :
1997 : void
1998 1 : nsFrameLoader::StartDestroy()
1999 : {
2000 : // nsFrameLoader::StartDestroy is called just before the frameloader is
2001 : // detached from the <browser> element. Destruction continues in phases via
2002 : // the nsFrameLoaderDestroyRunnable.
2003 :
2004 1 : if (mDestroyCalled) {
2005 0 : return;
2006 : }
2007 1 : mDestroyCalled = true;
2008 :
2009 : // After this point, we return an error when trying to send a message using
2010 : // the message manager on the frame.
2011 1 : if (mMessageManager) {
2012 1 : mMessageManager->Close();
2013 : }
2014 :
2015 : // Retain references to the <browser> element and the frameloader in case we
2016 : // receive any messages from the message manager on the frame. These
2017 : // references are dropped in DestroyComplete.
2018 1 : if (mChildMessageManager || mRemoteBrowser) {
2019 1 : mOwnerContentStrong = mOwnerContent;
2020 1 : if (mRemoteBrowser) {
2021 0 : mRemoteBrowser->CacheFrameLoader(this);
2022 : }
2023 1 : if (mChildMessageManager) {
2024 1 : mChildMessageManager->CacheFrameLoader(this);
2025 : }
2026 : }
2027 :
2028 : // If the TabParent has installed any event listeners on the window, this is
2029 : // its last chance to remove them while we're still in the document.
2030 1 : if (mRemoteBrowser) {
2031 0 : mRemoteBrowser->RemoveWindowListeners();
2032 : }
2033 :
2034 2 : nsCOMPtr<nsIDocument> doc;
2035 1 : bool dynamicSubframeRemoval = false;
2036 1 : if (mOwnerContent) {
2037 1 : doc = mOwnerContent->OwnerDoc();
2038 1 : dynamicSubframeRemoval = !mIsTopLevelContent && !doc->InUnlinkOrDeletion();
2039 1 : doc->SetSubDocumentFor(mOwnerContent, nullptr);
2040 1 : MaybeUpdatePrimaryTabParent(eTabParentRemoved);
2041 1 : SetOwnerContent(nullptr);
2042 : }
2043 :
2044 : // Seems like this is a dynamic frame removal.
2045 1 : if (dynamicSubframeRemoval) {
2046 0 : if (mDocShell) {
2047 0 : mDocShell->RemoveFromSessionHistory();
2048 : }
2049 : }
2050 :
2051 : // Let the tree owner know we're gone.
2052 1 : if (mIsTopLevelContent) {
2053 1 : if (mDocShell) {
2054 2 : nsCOMPtr<nsIDocShellTreeItem> parentItem;
2055 1 : mDocShell->GetParent(getter_AddRefs(parentItem));
2056 2 : nsCOMPtr<nsIDocShellTreeOwner> owner = do_GetInterface(parentItem);
2057 1 : if (owner) {
2058 1 : owner->ContentShellRemoved(mDocShell);
2059 : }
2060 : }
2061 : }
2062 :
2063 : // Let our window know that we are gone
2064 1 : if (mDocShell) {
2065 2 : nsCOMPtr<nsPIDOMWindowOuter> win_private(mDocShell->GetWindow());
2066 1 : if (win_private) {
2067 1 : win_private->SetFrameElementInternal(nullptr);
2068 : }
2069 : }
2070 :
2071 : // Destroy the other frame loader owners now that we are being destroyed.
2072 1 : if (mPartialSHistory &&
2073 1 : mPartialSHistory->GetActiveState() == nsIPartialSHistory::STATE_ACTIVE) {
2074 0 : nsCOMPtr<nsIGroupedSHistory> groupedSHistory;
2075 0 : GetGroupedSHistory(getter_AddRefs(groupedSHistory));
2076 0 : if (groupedSHistory) {
2077 0 : NS_DispatchToCurrentThread(NS_NewRunnableFunction(
2078 0 : "nsFrameLoader::StartDestroy", [groupedSHistory]() {
2079 0 : groupedSHistory->CloseInactiveFrameLoaderOwners();
2080 0 : }));
2081 : }
2082 : }
2083 :
2084 2 : nsCOMPtr<nsIRunnable> destroyRunnable = new nsFrameLoaderDestroyRunnable(this);
2085 2 : if (mNeedsAsyncDestroy || !doc ||
2086 1 : NS_FAILED(doc->FinalizeFrameLoader(this, destroyRunnable))) {
2087 0 : NS_DispatchToCurrentThread(destroyRunnable);
2088 : }
2089 : }
2090 :
2091 : nsresult
2092 3 : nsFrameLoaderDestroyRunnable::Run()
2093 : {
2094 3 : switch (mPhase) {
2095 : case eDestroyDocShell:
2096 1 : mFrameLoader->DestroyDocShell();
2097 :
2098 : // In the out-of-process case, TabParent will eventually call
2099 : // DestroyComplete once it receives a __delete__ message from the child. In
2100 : // the in-process case, we dispatch a series of runnables to ensure that
2101 : // DestroyComplete gets called at the right time. The frame loader is kept
2102 : // alive by mFrameLoader during this time.
2103 1 : if (mFrameLoader->mChildMessageManager) {
2104 : // When the docshell is destroyed, NotifyWindowIDDestroyed is called to
2105 : // asynchronously notify {outer,inner}-window-destroyed via a runnable. We
2106 : // don't want DestroyComplete to run until after those runnables have
2107 : // run. Since we're enqueueing ourselves after the window-destroyed
2108 : // runnables are enqueued, we're guaranteed to run after.
2109 1 : mPhase = eWaitForUnloadMessage;
2110 1 : NS_DispatchToCurrentThread(this);
2111 : }
2112 1 : break;
2113 :
2114 : case eWaitForUnloadMessage:
2115 : // The *-window-destroyed observers have finished running at this
2116 : // point. However, it's possible that a *-window-destroyed observer might
2117 : // have sent a message using the message manager. These messages might not
2118 : // have been processed yet. So we enqueue ourselves again to ensure that
2119 : // DestroyComplete runs after all messages sent by *-window-destroyed
2120 : // observers have been processed.
2121 1 : mPhase = eDestroyComplete;
2122 1 : NS_DispatchToCurrentThread(this);
2123 1 : break;
2124 :
2125 : case eDestroyComplete:
2126 : // Now that all messages sent by unload listeners and window destroyed
2127 : // observers have been processed, we disconnect the message manager and
2128 : // finish destruction.
2129 1 : mFrameLoader->DestroyComplete();
2130 1 : break;
2131 : }
2132 :
2133 3 : return NS_OK;
2134 : }
2135 :
2136 : void
2137 1 : nsFrameLoader::DestroyDocShell()
2138 : {
2139 : // This code runs after the frameloader has been detached from the <browser>
2140 : // element. We postpone this work because we may not be allowed to run
2141 : // script at that time.
2142 :
2143 : // Ask the TabChild to fire the frame script "unload" event, destroy its
2144 : // docshell, and finally destroy the PBrowser actor. This eventually leads to
2145 : // nsFrameLoader::DestroyComplete being called.
2146 1 : if (mRemoteBrowser) {
2147 0 : mRemoteBrowser->Destroy();
2148 : }
2149 :
2150 : // Fire the "unload" event if we're in-process.
2151 1 : if (mChildMessageManager) {
2152 1 : static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get())->FireUnloadEvent();
2153 : }
2154 :
2155 : // Destroy the docshell.
2156 2 : nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell));
2157 1 : if (base_win) {
2158 1 : base_win->Destroy();
2159 : }
2160 1 : mDocShell = nullptr;
2161 :
2162 1 : if (mChildMessageManager) {
2163 : // Stop handling events in the in-process frame script.
2164 1 : static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get())->DisconnectEventListeners();
2165 : }
2166 1 : }
2167 :
2168 : void
2169 1 : nsFrameLoader::DestroyComplete()
2170 : {
2171 : // We get here, as part of StartDestroy, after the docshell has been destroyed
2172 : // and all message manager messages sent during docshell destruction have been
2173 : // dispatched. We also get here if the child process crashes. In the latter
2174 : // case, StartDestroy might not have been called.
2175 :
2176 : // Drop the strong references created in StartDestroy.
2177 1 : if (mChildMessageManager || mRemoteBrowser) {
2178 1 : mOwnerContentStrong = nullptr;
2179 1 : if (mRemoteBrowser) {
2180 0 : mRemoteBrowser->CacheFrameLoader(nullptr);
2181 : }
2182 1 : if (mChildMessageManager) {
2183 1 : mChildMessageManager->CacheFrameLoader(nullptr);
2184 : }
2185 : }
2186 :
2187 : // Call TabParent::Destroy if we haven't already (in case of a crash).
2188 1 : if (mRemoteBrowser) {
2189 0 : mRemoteBrowser->SetOwnerElement(nullptr);
2190 0 : mRemoteBrowser->Destroy();
2191 0 : mRemoteBrowser = nullptr;
2192 : }
2193 :
2194 1 : if (mMessageManager) {
2195 1 : mMessageManager->Disconnect();
2196 : }
2197 :
2198 1 : if (mChildMessageManager) {
2199 1 : static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get())->Disconnect();
2200 : }
2201 :
2202 1 : mMessageManager = nullptr;
2203 1 : mChildMessageManager = nullptr;
2204 1 : }
2205 :
2206 : NS_IMETHODIMP
2207 0 : nsFrameLoader::GetDepthTooGreat(bool* aDepthTooGreat)
2208 : {
2209 0 : *aDepthTooGreat = mDepthTooGreat;
2210 0 : return NS_OK;
2211 : }
2212 :
2213 : void
2214 1 : nsFrameLoader::SetOwnerContent(Element* aContent)
2215 : {
2216 1 : if (mObservingOwnerContent) {
2217 1 : mObservingOwnerContent = false;
2218 1 : mOwnerContent->RemoveMutationObserver(this);
2219 : }
2220 1 : mOwnerContent = aContent;
2221 1 : if (RenderFrameParent* rfp = GetCurrentRenderFrame()) {
2222 0 : rfp->OwnerContentChanged(aContent);
2223 : }
2224 1 : }
2225 :
2226 : bool
2227 21 : nsFrameLoader::OwnerIsMozBrowserFrame()
2228 : {
2229 42 : nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
2230 42 : return browserFrame ? browserFrame->GetReallyIsBrowser() : false;
2231 : }
2232 :
2233 : // The xpcom getter version
2234 : NS_IMETHODIMP
2235 0 : nsFrameLoader::GetOwnerIsMozBrowserFrame(bool* aResult)
2236 : {
2237 0 : *aResult = OwnerIsMozBrowserFrame();
2238 0 : return NS_OK;
2239 : }
2240 :
2241 : bool
2242 1 : nsFrameLoader::OwnerIsIsolatedMozBrowserFrame()
2243 : {
2244 2 : nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
2245 1 : if (!browserFrame) {
2246 1 : return false;
2247 : }
2248 :
2249 0 : if (!OwnerIsMozBrowserFrame()) {
2250 0 : return false;
2251 : }
2252 :
2253 0 : bool isolated = browserFrame->GetIsolated();
2254 0 : if (isolated) {
2255 0 : return true;
2256 : }
2257 :
2258 0 : return false;
2259 : }
2260 :
2261 : bool
2262 4 : nsFrameLoader::ShouldUseRemoteProcess()
2263 : {
2264 4 : if (IsForJSPlugin()) {
2265 0 : return true;
2266 : }
2267 :
2268 8 : if (PR_GetEnv("MOZ_DISABLE_OOP_TABS") ||
2269 4 : Preferences::GetBool("dom.ipc.tabs.disabled", false)) {
2270 0 : return false;
2271 : }
2272 :
2273 : // Don't try to launch nested children if we don't have OMTC.
2274 : // They won't render!
2275 4 : if (XRE_IsContentProcess() &&
2276 0 : !CompositorBridgeChild::ChildProcessHasCompositorBridge()) {
2277 0 : return false;
2278 : }
2279 :
2280 4 : if (XRE_IsContentProcess() &&
2281 0 : !(PR_GetEnv("MOZ_NESTED_OOP_TABS") ||
2282 0 : Preferences::GetBool("dom.ipc.tabs.nested.enabled", false))) {
2283 0 : return false;
2284 : }
2285 :
2286 : // If we're an <iframe mozbrowser> and we don't have a "remote" attribute,
2287 : // fall back to the default.
2288 4 : if (OwnerIsMozBrowserFrame() &&
2289 0 : !mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::Remote)) {
2290 :
2291 0 : return Preferences::GetBool("dom.ipc.browser_frames.oop_by_default", false);
2292 : }
2293 :
2294 : // Otherwise, we're remote if we have "remote=true" and we're either a
2295 : // browser frame or a XUL element.
2296 8 : return (OwnerIsMozBrowserFrame() ||
2297 8 : mOwnerContent->GetNameSpaceID() == kNameSpaceID_XUL) &&
2298 4 : mOwnerContent->AttrValueIs(kNameSpaceID_None,
2299 : nsGkAtoms::Remote,
2300 : nsGkAtoms::_true,
2301 4 : eCaseMatters);
2302 : }
2303 :
2304 : bool
2305 32 : nsFrameLoader::IsRemoteFrame()
2306 : {
2307 32 : if (mRemoteFrame) {
2308 15 : MOZ_ASSERT(!mDocShell, "Found a remote frame with a DocShell");
2309 15 : return true;
2310 : }
2311 17 : return false;
2312 : }
2313 :
2314 : nsresult
2315 10 : nsFrameLoader::MaybeCreateDocShell()
2316 : {
2317 10 : if (mDocShell) {
2318 8 : return NS_OK;
2319 : }
2320 2 : if (IsRemoteFrame()) {
2321 0 : return NS_OK;
2322 : }
2323 2 : NS_ENSURE_STATE(!mDestroyCalled);
2324 :
2325 : // Get our parent docshell off the document of mOwnerContent
2326 : // XXXbz this is such a total hack.... We really need to have a
2327 : // better setup for doing this.
2328 2 : nsIDocument* doc = mOwnerContent->OwnerDoc();
2329 :
2330 2 : MOZ_RELEASE_ASSERT(!doc->IsResourceDoc(), "We shouldn't even exist");
2331 :
2332 2 : if (!(doc->IsStaticDocument() || mOwnerContent->IsInComposedDoc())) {
2333 0 : return NS_ERROR_UNEXPECTED;
2334 : }
2335 :
2336 2 : if (!doc->IsActive()) {
2337 : // Don't allow subframe loads in non-active documents.
2338 : // (See bug 610571 comment 5.)
2339 0 : return NS_ERROR_NOT_AVAILABLE;
2340 : }
2341 :
2342 4 : nsCOMPtr<nsIDocShell> docShell = doc->GetDocShell();
2343 4 : nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_QueryInterface(docShell);
2344 2 : NS_ENSURE_STATE(parentAsWebNav);
2345 :
2346 : // Create the docshell...
2347 2 : mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
2348 2 : NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
2349 :
2350 2 : if (mIsPrerendered) {
2351 0 : nsresult rv = mDocShell->SetIsPrerendered();
2352 0 : NS_ENSURE_SUCCESS(rv,rv);
2353 : }
2354 :
2355 2 : if (!mNetworkCreated) {
2356 2 : if (mDocShell) {
2357 2 : mDocShell->SetCreatedDynamically(true);
2358 : }
2359 : }
2360 :
2361 : // Get the frame name and tell the docshell about it.
2362 2 : NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
2363 4 : nsAutoString frameName;
2364 :
2365 2 : int32_t namespaceID = mOwnerContent->GetNameSpaceID();
2366 2 : if (namespaceID == kNameSpaceID_XHTML && !mOwnerContent->IsInHTMLDocument()) {
2367 0 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
2368 : } else {
2369 2 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, frameName);
2370 : // XXX if no NAME then use ID, after a transition period this will be
2371 : // changed so that XUL only uses ID too (bug 254284).
2372 2 : if (frameName.IsEmpty() && namespaceID == kNameSpaceID_XUL) {
2373 2 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
2374 : }
2375 : }
2376 :
2377 2 : if (!frameName.IsEmpty()) {
2378 1 : mDocShell->SetName(frameName);
2379 : }
2380 :
2381 : // Inform our docShell that it has a new child.
2382 : // Note: This logic duplicates a lot of logic in
2383 : // nsSubDocumentFrame::AttributeChanged. We should fix that.
2384 :
2385 2 : int32_t parentType = docShell->ItemType();
2386 :
2387 : // XXXbz why is this in content code, exactly? We should handle
2388 : // this some other way..... Not sure how yet.
2389 4 : nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
2390 2 : docShell->GetTreeOwner(getter_AddRefs(parentTreeOwner));
2391 2 : NS_ENSURE_STATE(parentTreeOwner);
2392 2 : mIsTopLevelContent =
2393 2 : AddTreeItemToTreeOwner(mDocShell, parentTreeOwner, parentType, docShell);
2394 :
2395 : // Make sure all shells have links back to the content element
2396 : // in the nearest enclosing chrome shell.
2397 4 : nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
2398 :
2399 2 : if (parentType == nsIDocShellTreeItem::typeChrome) {
2400 : // Our parent shell is a chrome shell. It is therefore our nearest
2401 : // enclosing chrome shell.
2402 :
2403 2 : chromeEventHandler = do_QueryInterface(mOwnerContent);
2404 2 : NS_ASSERTION(chromeEventHandler,
2405 : "This mContent should implement this.");
2406 : } else {
2407 : // Our parent shell is a content shell. Get the chrome event
2408 : // handler from it and use that for our shell as well.
2409 :
2410 0 : docShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
2411 : }
2412 :
2413 2 : mDocShell->SetChromeEventHandler(chromeEventHandler);
2414 :
2415 : // This is nasty, this code (the mDocShell->GetWindow() below)
2416 : // *must* come *after* the above call to
2417 : // mDocShell->SetChromeEventHandler() for the global window to get
2418 : // the right chrome event handler.
2419 :
2420 : // Tell the window about the frame that hosts it.
2421 4 : nsCOMPtr<Element> frame_element = mOwnerContent;
2422 2 : NS_ASSERTION(frame_element, "frame loader owner element not a DOM element!");
2423 :
2424 4 : nsCOMPtr<nsPIDOMWindowOuter> win_private(mDocShell->GetWindow());
2425 4 : nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell));
2426 2 : if (win_private) {
2427 2 : win_private->SetFrameElementInternal(frame_element);
2428 :
2429 : // Set the opener window if we have one provided here
2430 2 : if (mOpener) {
2431 0 : win_private->SetOpenerWindow(mOpener, true);
2432 0 : mOpener = nullptr;
2433 : }
2434 : }
2435 :
2436 : // This is kinda whacky, this call doesn't really create anything,
2437 : // but it must be called to make sure things are properly
2438 : // initialized.
2439 2 : if (NS_FAILED(base_win->Create()) || !win_private) {
2440 : // Do not call Destroy() here. See bug 472312.
2441 0 : NS_WARNING("Something wrong when creating the docshell for a frameloader!");
2442 0 : return NS_ERROR_FAILURE;
2443 : }
2444 :
2445 5 : if (mIsTopLevelContent &&
2446 3 : mOwnerContent->IsXULElement(nsGkAtoms::browser) &&
2447 1 : !mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::disablehistory)) {
2448 : nsresult rv;
2449 : nsCOMPtr<nsISHistory> sessionHistory =
2450 2 : do_CreateInstance(NS_SHISTORY_CONTRACTID, &rv);
2451 1 : NS_ENSURE_SUCCESS(rv, rv);
2452 :
2453 2 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
2454 1 : webNav->SetSessionHistory(sessionHistory);
2455 :
2456 :
2457 1 : if (GroupedSHistory::GroupedHistoryEnabled()) {
2458 0 : mPartialSHistory = new PartialSHistory(this);
2459 0 : nsCOMPtr<nsISHistoryListener> listener(do_QueryInterface(mPartialSHistory));
2460 0 : nsCOMPtr<nsIPartialSHistoryListener> partialListener(do_QueryInterface(mPartialSHistory));
2461 0 : sessionHistory->AddSHistoryListener(listener);
2462 0 : sessionHistory->SetPartialSHistoryListener(partialListener);
2463 : }
2464 : }
2465 :
2466 4 : OriginAttributes attrs;
2467 2 : if (docShell->ItemType() == mDocShell->ItemType()) {
2468 1 : attrs = nsDocShell::Cast(docShell)->GetOriginAttributes();
2469 : }
2470 :
2471 : // Inherit origin attributes from parent document if
2472 : // 1. It's in a content docshell.
2473 : // 2. its nodePrincipal is not a SystemPrincipal.
2474 : // 3. It's not a mozbrowser frame.
2475 : //
2476 : // For example, firstPartyDomain is computed from top-level document, it
2477 : // doesn't exist in the top-level docshell.
2478 2 : if (parentType == nsIDocShellTreeItem::typeContent &&
2479 2 : !nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()) &&
2480 0 : !OwnerIsMozBrowserFrame()) {
2481 0 : OriginAttributes oa = doc->NodePrincipal()->OriginAttributesRef();
2482 :
2483 : // Assert on the firstPartyDomain from top-level docshell should be empty
2484 0 : MOZ_ASSERT_IF(mIsTopLevelContent, attrs.mFirstPartyDomain.IsEmpty());
2485 :
2486 : // So far we want to make sure Inherit doesn't override any other origin
2487 : // attribute than firstPartyDomain.
2488 0 : MOZ_ASSERT(attrs.mAppId == oa.mAppId,
2489 : "docshell and document should have the same appId attribute.");
2490 0 : MOZ_ASSERT(attrs.mUserContextId == oa.mUserContextId,
2491 : "docshell and document should have the same userContextId attribute.");
2492 0 : MOZ_ASSERT(attrs.mInIsolatedMozBrowser == oa.mInIsolatedMozBrowser,
2493 : "docshell and document should have the same inIsolatedMozBrowser attribute.");
2494 0 : MOZ_ASSERT(attrs.mPrivateBrowsingId == oa.mPrivateBrowsingId,
2495 : "docshell and document should have the same privateBrowsingId attribute.");
2496 :
2497 0 : attrs = oa;
2498 : }
2499 :
2500 2 : if (OwnerIsMozBrowserFrame()) {
2501 0 : attrs.mAppId = nsIScriptSecurityManager::NO_APP_ID;
2502 0 : attrs.mInIsolatedMozBrowser = OwnerIsIsolatedMozBrowserFrame();
2503 0 : mDocShell->SetFrameType(nsIDocShell::FRAME_TYPE_BROWSER);
2504 : }
2505 :
2506 : // Apply sandbox flags even if our owner is not an iframe, as this copies
2507 : // flags from our owning content's owning document.
2508 : // Note: ApplySandboxFlags should be called after mDocShell->SetFrameType
2509 : // because we need to get the correct presentation URL in ApplySandboxFlags.
2510 2 : uint32_t sandboxFlags = 0;
2511 2 : HTMLIFrameElement* iframe = HTMLIFrameElement::FromContent(mOwnerContent);
2512 2 : if (iframe) {
2513 0 : sandboxFlags = iframe->GetSandboxFlags();
2514 : }
2515 2 : ApplySandboxFlags(sandboxFlags);
2516 :
2517 : // Grab the userContextId from owner if XUL
2518 2 : nsresult rv = PopulateUserContextIdFromAttribute(attrs);
2519 2 : if (NS_WARN_IF(NS_FAILED(rv))) {
2520 0 : return rv;
2521 : }
2522 :
2523 2 : bool isPrivate = false;
2524 4 : nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(docShell);
2525 2 : NS_ENSURE_STATE(parentContext);
2526 :
2527 2 : rv = parentContext->GetUsePrivateBrowsing(&isPrivate);
2528 2 : if (NS_WARN_IF(NS_FAILED(rv))) {
2529 0 : return rv;
2530 : }
2531 2 : attrs.SyncAttributesWithPrivateBrowsing(isPrivate);
2532 :
2533 2 : if (OwnerIsMozBrowserFrame()) {
2534 : // For inproc frames, set the docshell properties.
2535 0 : nsAutoString name;
2536 0 : if (mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name)) {
2537 0 : docShell->SetName(name);
2538 : }
2539 0 : mDocShell->SetFullscreenAllowed(
2540 0 : mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::allowfullscreen) ||
2541 0 : mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozallowfullscreen));
2542 0 : bool isPrivate = mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozprivatebrowsing);
2543 0 : if (isPrivate) {
2544 0 : if (mDocShell->GetHasLoadedNonBlankURI()) {
2545 0 : nsContentUtils::ReportToConsoleNonLocalized(
2546 0 : NS_LITERAL_STRING("We should not switch to Private Browsing after loading a document."),
2547 : nsIScriptError::warningFlag,
2548 0 : NS_LITERAL_CSTRING("mozprivatebrowsing"),
2549 0 : nullptr);
2550 : } else {
2551 : // This handles the case where a frames private browsing is set by chrome flags
2552 : // and not inherited by its parent.
2553 0 : attrs.SyncAttributesWithPrivateBrowsing(isPrivate);
2554 : }
2555 : }
2556 : }
2557 :
2558 2 : nsDocShell::Cast(mDocShell)->SetOriginAttributes(attrs);
2559 :
2560 2 : ReallyLoadFrameScripts();
2561 2 : InitializeBrowserAPI();
2562 :
2563 4 : nsCOMPtr<nsIObserverService> os = services::GetObserverService();
2564 2 : if (os) {
2565 4 : os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
2566 4 : "inprocess-browser-shown", nullptr);
2567 : }
2568 :
2569 2 : return NS_OK;
2570 : }
2571 :
2572 : void
2573 4 : nsFrameLoader::GetURL(nsString& aURI)
2574 : {
2575 4 : aURI.Truncate();
2576 :
2577 4 : if (mOwnerContent->IsHTMLElement(nsGkAtoms::object)) {
2578 0 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, aURI);
2579 : } else {
2580 4 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, aURI);
2581 : }
2582 4 : }
2583 :
2584 : nsresult
2585 4 : nsFrameLoader::CheckForRecursiveLoad(nsIURI* aURI)
2586 : {
2587 : nsresult rv;
2588 :
2589 4 : MOZ_ASSERT(!IsRemoteFrame(),
2590 : "Shouldn't call CheckForRecursiveLoad on remote frames.");
2591 :
2592 4 : mDepthTooGreat = false;
2593 4 : rv = MaybeCreateDocShell();
2594 4 : if (NS_FAILED(rv)) {
2595 0 : return rv;
2596 : }
2597 4 : NS_ASSERTION(mDocShell,
2598 : "MaybeCreateDocShell succeeded, but null mDocShell");
2599 4 : if (!mDocShell) {
2600 0 : return NS_ERROR_FAILURE;
2601 : }
2602 :
2603 : // Check that we're still in the docshell tree.
2604 8 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
2605 4 : mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
2606 4 : NS_WARNING_ASSERTION(treeOwner,
2607 : "Trying to load a new url to a docshell without owner!");
2608 4 : NS_ENSURE_STATE(treeOwner);
2609 :
2610 4 : if (mDocShell->ItemType() != nsIDocShellTreeItem::typeContent) {
2611 : // No need to do recursion-protection here XXXbz why not?? Do we really
2612 : // trust people not to screw up with non-content docshells?
2613 2 : return NS_OK;
2614 : }
2615 :
2616 : // Bug 8065: Don't exceed some maximum depth in content frames
2617 : // (MAX_DEPTH_CONTENT_FRAMES)
2618 4 : nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
2619 2 : mDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem));
2620 2 : int32_t depth = 0;
2621 2 : while (parentAsItem) {
2622 0 : ++depth;
2623 :
2624 0 : if (depth >= MAX_DEPTH_CONTENT_FRAMES) {
2625 0 : mDepthTooGreat = true;
2626 0 : NS_WARNING("Too many nested content frames so giving up");
2627 :
2628 0 : return NS_ERROR_UNEXPECTED; // Too deep, give up! (silently?)
2629 : }
2630 :
2631 0 : nsCOMPtr<nsIDocShellTreeItem> temp;
2632 0 : temp.swap(parentAsItem);
2633 0 : temp->GetSameTypeParent(getter_AddRefs(parentAsItem));
2634 : }
2635 :
2636 : // Bug 136580: Check for recursive frame loading excluding about:srcdoc URIs.
2637 : // srcdoc URIs require their contents to be specified inline, so it isn't
2638 : // possible for undesirable recursion to occur without the aid of a
2639 : // non-srcdoc URI, which this method will block normally.
2640 : // Besides, URI is not enough to guarantee uniqueness of srcdoc documents.
2641 4 : nsAutoCString buffer;
2642 2 : rv = aURI->GetScheme(buffer);
2643 2 : if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("about")) {
2644 2 : rv = aURI->GetPath(buffer);
2645 2 : if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("srcdoc")) {
2646 : // Duplicates allowed up to depth limits
2647 0 : return NS_OK;
2648 : }
2649 : }
2650 2 : int32_t matchCount = 0;
2651 2 : mDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem));
2652 2 : while (parentAsItem) {
2653 : // Check the parent URI with the URI we're loading
2654 0 : nsCOMPtr<nsIWebNavigation> parentAsNav(do_QueryInterface(parentAsItem));
2655 0 : if (parentAsNav) {
2656 : // Does the URI match the one we're about to load?
2657 0 : nsCOMPtr<nsIURI> parentURI;
2658 0 : parentAsNav->GetCurrentURI(getter_AddRefs(parentURI));
2659 0 : if (parentURI) {
2660 : // Bug 98158/193011: We need to ignore data after the #
2661 : bool equal;
2662 0 : rv = aURI->EqualsExceptRef(parentURI, &equal);
2663 0 : NS_ENSURE_SUCCESS(rv, rv);
2664 :
2665 0 : if (equal) {
2666 0 : matchCount++;
2667 0 : if (matchCount >= MAX_SAME_URL_CONTENT_FRAMES) {
2668 0 : NS_WARNING("Too many nested content frames have the same url (recursion?) so giving up");
2669 0 : return NS_ERROR_UNEXPECTED;
2670 : }
2671 : }
2672 : }
2673 : }
2674 0 : nsCOMPtr<nsIDocShellTreeItem> temp;
2675 0 : temp.swap(parentAsItem);
2676 0 : temp->GetSameTypeParent(getter_AddRefs(parentAsItem));
2677 : }
2678 :
2679 2 : return NS_OK;
2680 : }
2681 :
2682 : nsresult
2683 9 : nsFrameLoader::GetWindowDimensions(nsIntRect& aRect)
2684 : {
2685 : // Need to get outer window position here
2686 9 : nsIDocument* doc = mOwnerContent->GetComposedDoc();
2687 9 : if (!doc) {
2688 0 : return NS_ERROR_FAILURE;
2689 : }
2690 :
2691 9 : MOZ_RELEASE_ASSERT(!doc->IsResourceDoc(), "We shouldn't even exist");
2692 :
2693 18 : nsCOMPtr<nsPIDOMWindowOuter> win = doc->GetWindow();
2694 9 : if (!win) {
2695 0 : return NS_ERROR_FAILURE;
2696 : }
2697 :
2698 18 : nsCOMPtr<nsIDocShellTreeItem> parentAsItem(win->GetDocShell());
2699 9 : if (!parentAsItem) {
2700 0 : return NS_ERROR_FAILURE;
2701 : }
2702 :
2703 18 : nsCOMPtr<nsIDocShellTreeOwner> parentOwner;
2704 18 : if (NS_FAILED(parentAsItem->GetTreeOwner(getter_AddRefs(parentOwner))) ||
2705 9 : !parentOwner) {
2706 0 : return NS_ERROR_FAILURE;
2707 : }
2708 :
2709 18 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_GetInterface(parentOwner));
2710 9 : treeOwnerAsWin->GetPosition(&aRect.x, &aRect.y);
2711 9 : treeOwnerAsWin->GetSize(&aRect.width, &aRect.height);
2712 9 : return NS_OK;
2713 : }
2714 :
2715 : NS_IMETHODIMP
2716 3 : nsFrameLoader::UpdatePositionAndSize(nsSubDocumentFrame *aIFrame)
2717 : {
2718 3 : if (IsRemoteFrame()) {
2719 3 : if (mRemoteBrowser) {
2720 3 : ScreenIntSize size = aIFrame->GetSubdocumentSize();
2721 3 : nsIntRect dimensions;
2722 3 : NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), NS_ERROR_FAILURE);
2723 3 : mLazySize = size;
2724 3 : mRemoteBrowser->UpdateDimensions(dimensions, size);
2725 : }
2726 3 : return NS_OK;
2727 : }
2728 0 : UpdateBaseWindowPositionAndSize(aIFrame);
2729 0 : return NS_OK;
2730 : }
2731 :
2732 : void
2733 0 : nsFrameLoader::UpdateBaseWindowPositionAndSize(nsSubDocumentFrame *aIFrame)
2734 : {
2735 0 : nsCOMPtr<nsIDocShell> docShell;
2736 0 : GetDocShell(getter_AddRefs(docShell));
2737 0 : nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
2738 :
2739 : // resize the sub document
2740 0 : if (baseWindow) {
2741 0 : int32_t x = 0;
2742 0 : int32_t y = 0;
2743 :
2744 0 : AutoWeakFrame weakFrame(aIFrame);
2745 :
2746 0 : baseWindow->GetPosition(&x, &y);
2747 :
2748 0 : if (!weakFrame.IsAlive()) {
2749 : // GetPosition() killed us
2750 0 : return;
2751 : }
2752 :
2753 0 : ScreenIntSize size = aIFrame->GetSubdocumentSize();
2754 0 : mLazySize = size;
2755 :
2756 0 : baseWindow->SetPositionAndSize(x, y, size.width, size.height,
2757 0 : nsIBaseWindow::eDelayResize);
2758 : }
2759 : }
2760 :
2761 : NS_IMETHODIMP
2762 0 : nsFrameLoader::GetLazyWidth(uint32_t* aLazyWidth)
2763 : {
2764 0 : *aLazyWidth = mLazySize.width;
2765 :
2766 0 : nsIFrame* frame = GetPrimaryFrameOfOwningContent();
2767 0 : if (frame) {
2768 0 : *aLazyWidth = frame->PresContext()->DevPixelsToIntCSSPixels(*aLazyWidth);
2769 : }
2770 :
2771 0 : return NS_OK;
2772 : }
2773 :
2774 : NS_IMETHODIMP
2775 0 : nsFrameLoader::GetLazyHeight(uint32_t* aLazyHeight)
2776 : {
2777 0 : *aLazyHeight = mLazySize.height;
2778 :
2779 0 : nsIFrame* frame = GetPrimaryFrameOfOwningContent();
2780 0 : if (frame) {
2781 0 : *aLazyHeight = frame->PresContext()->DevPixelsToIntCSSPixels(*aLazyHeight);
2782 : }
2783 :
2784 0 : return NS_OK;
2785 : }
2786 :
2787 : NS_IMETHODIMP
2788 6 : nsFrameLoader::GetEventMode(uint32_t* aEventMode)
2789 : {
2790 6 : *aEventMode = mEventMode;
2791 6 : return NS_OK;
2792 : }
2793 :
2794 : NS_IMETHODIMP
2795 0 : nsFrameLoader::SetEventMode(uint32_t aEventMode)
2796 : {
2797 0 : mEventMode = aEventMode;
2798 0 : return NS_OK;
2799 : }
2800 :
2801 : NS_IMETHODIMP
2802 0 : nsFrameLoader::GetClipSubdocument(bool* aResult)
2803 : {
2804 0 : *aResult = mClipSubdocument;
2805 0 : return NS_OK;
2806 : }
2807 :
2808 : NS_IMETHODIMP
2809 0 : nsFrameLoader::SetClipSubdocument(bool aClip)
2810 : {
2811 0 : mClipSubdocument = aClip;
2812 0 : nsIFrame* frame = GetPrimaryFrameOfOwningContent();
2813 0 : if (frame) {
2814 0 : frame->InvalidateFrame();
2815 0 : frame->PresContext()->PresShell()->
2816 0 : FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
2817 0 : nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);
2818 0 : if (subdocFrame) {
2819 0 : nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame();
2820 0 : if (subdocRootFrame) {
2821 : nsIFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()->
2822 0 : GetRootScrollFrame();
2823 0 : if (subdocRootScrollFrame) {
2824 0 : frame->PresContext()->PresShell()->
2825 0 : FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
2826 : }
2827 : }
2828 : }
2829 : }
2830 0 : return NS_OK;
2831 : }
2832 :
2833 : NS_IMETHODIMP
2834 0 : nsFrameLoader::GetClampScrollPosition(bool* aResult)
2835 : {
2836 0 : *aResult = mClampScrollPosition;
2837 0 : return NS_OK;
2838 : }
2839 :
2840 : NS_IMETHODIMP
2841 0 : nsFrameLoader::SetClampScrollPosition(bool aClamp)
2842 : {
2843 0 : mClampScrollPosition = aClamp;
2844 :
2845 : // When turning clamping on, make sure the current position is clamped.
2846 0 : if (aClamp) {
2847 0 : nsIFrame* frame = GetPrimaryFrameOfOwningContent();
2848 0 : nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);
2849 0 : if (subdocFrame) {
2850 0 : nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame();
2851 0 : if (subdocRootFrame) {
2852 : nsIScrollableFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()->
2853 0 : GetRootScrollFrameAsScrollable();
2854 0 : if (subdocRootScrollFrame) {
2855 0 : subdocRootScrollFrame->ScrollTo(subdocRootScrollFrame->GetScrollPosition(), nsIScrollableFrame::INSTANT);
2856 : }
2857 : }
2858 : }
2859 : }
2860 0 : return NS_OK;
2861 : }
2862 :
2863 : static
2864 : Tuple<ContentParent*, TabParent*>
2865 1 : GetContentParent(Element* aBrowser)
2866 : {
2867 : using ReturnTuple = Tuple<ContentParent*, TabParent*>;
2868 :
2869 2 : nsCOMPtr<nsIBrowser> browser = do_QueryInterface(aBrowser);
2870 1 : if (!browser) {
2871 0 : return ReturnTuple(nullptr, nullptr);
2872 : }
2873 :
2874 2 : nsCOMPtr<nsIFrameLoader> otherLoader;
2875 1 : browser->GetSameProcessAsFrameLoader(getter_AddRefs(otherLoader));
2876 1 : if (!otherLoader) {
2877 1 : return ReturnTuple(nullptr, nullptr);
2878 : }
2879 :
2880 0 : TabParent* tabParent = TabParent::GetFrom(otherLoader);
2881 0 : if (tabParent &&
2882 0 : tabParent->Manager() &&
2883 0 : tabParent->Manager()->IsContentParent()) {
2884 0 : return MakeTuple(tabParent->Manager()->AsContentParent(), tabParent);
2885 : }
2886 :
2887 0 : return ReturnTuple(nullptr, nullptr);
2888 : }
2889 :
2890 : bool
2891 1 : nsFrameLoader::TryRemoteBrowser()
2892 : {
2893 1 : NS_ASSERTION(!mRemoteBrowser, "TryRemoteBrowser called with a remote browser already?");
2894 :
2895 : //XXXsmaug Per spec (2014/08/21) frameloader should not work in case the
2896 : // element isn't in document, only in shadow dom, but that will change
2897 : // https://www.w3.org/Bugs/Public/show_bug.cgi?id=26365#c0
2898 1 : nsIDocument* doc = mOwnerContent->GetComposedDoc();
2899 1 : if (!doc) {
2900 0 : return false;
2901 : }
2902 :
2903 1 : MOZ_RELEASE_ASSERT(!doc->IsResourceDoc(), "We shouldn't even exist");
2904 :
2905 1 : if (!doc->IsActive()) {
2906 : // Don't allow subframe loads in non-active documents.
2907 : // (See bug 610571 comment 5.)
2908 0 : return false;
2909 : }
2910 :
2911 2 : nsCOMPtr<nsPIDOMWindowOuter> parentWin = doc->GetWindow();
2912 1 : if (!parentWin) {
2913 0 : return false;
2914 : }
2915 :
2916 2 : nsCOMPtr<nsIDocShell> parentDocShell = parentWin->GetDocShell();
2917 1 : if (!parentDocShell) {
2918 0 : return false;
2919 : }
2920 :
2921 1 : TabParent* openingTab = TabParent::GetFrom(parentDocShell->GetOpener());
2922 2 : RefPtr<ContentParent> openerContentParent;
2923 2 : RefPtr<TabParent> sameTabGroupAs;
2924 :
2925 1 : if (openingTab &&
2926 1 : openingTab->Manager() &&
2927 0 : openingTab->Manager()->IsContentParent()) {
2928 0 : openerContentParent = openingTab->Manager()->AsContentParent();
2929 : }
2930 :
2931 : // <iframe mozbrowser> gets to skip these checks.
2932 : // iframes for JS plugins also get to skip these checks. We control the URL that gets
2933 : // loaded, but the load is triggered from the document containing the plugin.
2934 1 : if (!OwnerIsMozBrowserFrame() && !IsForJSPlugin()) {
2935 1 : if (parentDocShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
2936 : // Allow about:addon an exception to this rule so it can load remote
2937 : // extension options pages.
2938 : //
2939 : // Note that the new frame's message manager will not be a child of the
2940 : // chrome window message manager, and, the values of window.top and
2941 : // window.parent will be different than they would be for a non-remote
2942 : // frame.
2943 0 : nsCOMPtr<nsIWebNavigation> parentWebNav;
2944 0 : nsCOMPtr<nsIURI> aboutAddons;
2945 0 : nsCOMPtr<nsIURI> parentURI;
2946 : bool equals;
2947 0 : if (!((parentWebNav = do_GetInterface(parentDocShell)) &&
2948 0 : NS_SUCCEEDED(NS_NewURI(getter_AddRefs(aboutAddons), "about:addons")) &&
2949 0 : NS_SUCCEEDED(parentWebNav->GetCurrentURI(getter_AddRefs(parentURI))) &&
2950 0 : NS_SUCCEEDED(parentURI->EqualsExceptRef(aboutAddons, &equals)) && equals)) {
2951 0 : return false;
2952 : }
2953 : }
2954 :
2955 1 : if (!mOwnerContent->IsXULElement()) {
2956 0 : return false;
2957 : }
2958 :
2959 2 : nsAutoString value;
2960 1 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
2961 :
2962 3 : if (!value.LowerCaseEqualsLiteral("content") &&
2963 1 : !StringBeginsWith(value, NS_LITERAL_STRING("content-"),
2964 1 : nsCaseInsensitiveStringComparator())) {
2965 0 : return false;
2966 : }
2967 :
2968 : // Try to get the related content parent from our browser element.
2969 1 : Tie(openerContentParent, sameTabGroupAs) = GetContentParent(mOwnerContent);
2970 : }
2971 :
2972 1 : uint32_t chromeFlags = 0;
2973 2 : nsCOMPtr<nsIDocShellTreeOwner> parentOwner;
2974 2 : if (NS_FAILED(parentDocShell->GetTreeOwner(getter_AddRefs(parentOwner))) ||
2975 1 : !parentOwner) {
2976 0 : return false;
2977 : }
2978 2 : nsCOMPtr<nsIXULWindow> window(do_GetInterface(parentOwner));
2979 1 : if (window && NS_FAILED(window->GetChromeFlags(&chromeFlags))) {
2980 0 : return false;
2981 : }
2982 :
2983 2 : AUTO_PROFILER_LABEL("nsFrameLoader::TryRemoteBrowser:Create", OTHER);
2984 :
2985 2 : MutableTabContext context;
2986 1 : nsresult rv = GetNewTabContext(&context);
2987 1 : NS_ENSURE_SUCCESS(rv, false);
2988 :
2989 1 : uint64_t nextTabParentId = 0;
2990 1 : if (mOwnerContent) {
2991 2 : nsAutoString nextTabParentIdAttr;
2992 1 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nextTabParentId,
2993 2 : nextTabParentIdAttr);
2994 1 : nextTabParentId = strtoull(NS_ConvertUTF16toUTF8(nextTabParentIdAttr).get(),
2995 : nullptr, 10);
2996 :
2997 : // We may be in a window that was just opened, so try the
2998 : // nsIBrowserDOMWindow API as a backup.
2999 1 : if (!nextTabParentId && window) {
3000 1 : Unused << window->GetNextTabParentId(&nextTabParentId);
3001 : }
3002 : }
3003 :
3004 2 : nsCOMPtr<Element> ownerElement = mOwnerContent;
3005 1 : mRemoteBrowser = ContentParent::CreateBrowser(context, ownerElement,
3006 : openerContentParent,
3007 : sameTabGroupAs,
3008 : nextTabParentId);
3009 1 : if (!mRemoteBrowser) {
3010 0 : return false;
3011 : }
3012 : // Now that mRemoteBrowser is set, we can initialize the RenderFrameParent
3013 1 : mRemoteBrowser->InitRenderFrame();
3014 :
3015 1 : MaybeUpdatePrimaryTabParent(eTabParentChanged);
3016 :
3017 1 : mChildID = mRemoteBrowser->Manager()->ChildID();
3018 :
3019 2 : nsCOMPtr<nsIDocShellTreeItem> rootItem;
3020 1 : parentDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
3021 2 : nsCOMPtr<nsPIDOMWindowOuter> rootWin = rootItem->GetWindow();
3022 2 : nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin);
3023 :
3024 1 : if (rootChromeWin) {
3025 2 : nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
3026 1 : rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
3027 1 : mRemoteBrowser->SetBrowserDOMWindow(browserDOMWin);
3028 : }
3029 :
3030 : // Send down the name of the browser through mRemoteBrowser if it is set.
3031 : // Only do this on xul:browsers for now.
3032 1 : if (mOwnerContent->IsXULElement()) {
3033 2 : nsAutoString frameName;
3034 1 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, frameName);
3035 1 : if (nsContentUtils::IsOverridingWindowName(frameName)) {
3036 0 : Unused << mRemoteBrowser->SendSetWindowName(frameName);
3037 : }
3038 : }
3039 :
3040 1 : ReallyLoadFrameScripts();
3041 1 : InitializeBrowserAPI();
3042 :
3043 1 : return true;
3044 : }
3045 :
3046 : mozilla::dom::PBrowserParent*
3047 47 : nsFrameLoader::GetRemoteBrowser() const
3048 : {
3049 47 : return mRemoteBrowser;
3050 : }
3051 :
3052 : RenderFrameParent*
3053 35 : nsFrameLoader::GetCurrentRenderFrame() const
3054 : {
3055 35 : if (mRemoteBrowser) {
3056 34 : return mRemoteBrowser->GetRenderFrame();
3057 : }
3058 1 : return nullptr;
3059 : }
3060 :
3061 : NS_IMETHODIMP
3062 0 : nsFrameLoader::ActivateRemoteFrame() {
3063 0 : if (mRemoteBrowser) {
3064 0 : mRemoteBrowser->Activate();
3065 0 : return NS_OK;
3066 : }
3067 0 : return NS_ERROR_UNEXPECTED;
3068 : }
3069 :
3070 : NS_IMETHODIMP
3071 0 : nsFrameLoader::DeactivateRemoteFrame() {
3072 0 : if (mRemoteBrowser) {
3073 0 : mRemoteBrowser->Deactivate();
3074 0 : return NS_OK;
3075 : }
3076 0 : return NS_ERROR_UNEXPECTED;
3077 : }
3078 :
3079 : NS_IMETHODIMP
3080 0 : nsFrameLoader::SendCrossProcessMouseEvent(const nsAString& aType,
3081 : float aX,
3082 : float aY,
3083 : int32_t aButton,
3084 : int32_t aClickCount,
3085 : int32_t aModifiers,
3086 : bool aIgnoreRootScrollFrame)
3087 : {
3088 0 : if (mRemoteBrowser) {
3089 0 : mRemoteBrowser->SendMouseEvent(aType, aX, aY, aButton,
3090 : aClickCount, aModifiers,
3091 0 : aIgnoreRootScrollFrame);
3092 0 : return NS_OK;
3093 : }
3094 0 : return NS_ERROR_FAILURE;
3095 : }
3096 :
3097 : NS_IMETHODIMP
3098 0 : nsFrameLoader::ActivateFrameEvent(const nsAString& aType,
3099 : bool aCapture)
3100 : {
3101 0 : if (mRemoteBrowser) {
3102 0 : return mRemoteBrowser->SendActivateFrameEvent(nsString(aType), aCapture) ?
3103 0 : NS_OK : NS_ERROR_NOT_AVAILABLE;
3104 : }
3105 0 : return NS_ERROR_FAILURE;
3106 : }
3107 :
3108 : NS_IMETHODIMP
3109 0 : nsFrameLoader::SendCrossProcessKeyEvent(const nsAString& aType,
3110 : int32_t aKeyCode,
3111 : int32_t aCharCode,
3112 : int32_t aModifiers,
3113 : bool aPreventDefault)
3114 : {
3115 0 : if (mRemoteBrowser) {
3116 0 : mRemoteBrowser->SendKeyEvent(aType, aKeyCode, aCharCode, aModifiers,
3117 0 : aPreventDefault);
3118 0 : return NS_OK;
3119 : }
3120 0 : return NS_ERROR_FAILURE;
3121 : }
3122 :
3123 : nsresult
3124 0 : nsFrameLoader::CreateStaticClone(nsIFrameLoader* aDest)
3125 : {
3126 0 : nsFrameLoader* dest = static_cast<nsFrameLoader*>(aDest);
3127 0 : dest->MaybeCreateDocShell();
3128 0 : NS_ENSURE_STATE(dest->mDocShell);
3129 :
3130 0 : nsCOMPtr<nsIDocument> kungFuDeathGrip = dest->mDocShell->GetDocument();
3131 : Unused << kungFuDeathGrip;
3132 :
3133 0 : nsCOMPtr<nsIContentViewer> viewer;
3134 0 : dest->mDocShell->GetContentViewer(getter_AddRefs(viewer));
3135 0 : NS_ENSURE_STATE(viewer);
3136 :
3137 0 : nsCOMPtr<nsIDocShell> origDocShell;
3138 0 : GetDocShell(getter_AddRefs(origDocShell));
3139 0 : NS_ENSURE_STATE(origDocShell);
3140 :
3141 0 : nsCOMPtr<nsIDocument> doc = origDocShell->GetDocument();
3142 0 : NS_ENSURE_STATE(doc);
3143 :
3144 0 : nsCOMPtr<nsIDocument> clonedDoc = doc->CreateStaticClone(dest->mDocShell);
3145 0 : nsCOMPtr<nsIDOMDocument> clonedDOMDoc = do_QueryInterface(clonedDoc);
3146 :
3147 0 : viewer->SetDOMDocument(clonedDOMDoc);
3148 0 : return NS_OK;
3149 : }
3150 :
3151 : bool
3152 18 : nsFrameLoader::DoLoadMessageManagerScript(const nsAString& aURL, bool aRunInGlobalScope)
3153 : {
3154 18 : auto* tabParent = TabParent::GetFrom(GetRemoteBrowser());
3155 18 : if (tabParent) {
3156 12 : return tabParent->SendLoadRemoteScript(nsString(aURL), aRunInGlobalScope);
3157 : }
3158 : RefPtr<nsInProcessTabChildGlobal> tabChild =
3159 12 : static_cast<nsInProcessTabChildGlobal*>(GetTabChildGlobalAsEventTarget());
3160 6 : if (tabChild) {
3161 6 : tabChild->LoadFrameScript(aURL, aRunInGlobalScope);
3162 : }
3163 6 : return true;
3164 : }
3165 :
3166 0 : class nsAsyncMessageToChild : public nsSameProcessAsyncMessageBase,
3167 : public Runnable
3168 : {
3169 : public:
3170 0 : nsAsyncMessageToChild(JS::RootingContext* aRootingCx,
3171 : JS::Handle<JSObject*> aCpows,
3172 : nsFrameLoader* aFrameLoader)
3173 0 : : nsSameProcessAsyncMessageBase(aRootingCx, aCpows)
3174 : , mozilla::Runnable("nsAsyncMessageToChild")
3175 0 : , mFrameLoader(aFrameLoader)
3176 : {
3177 0 : }
3178 :
3179 0 : NS_IMETHOD Run() override
3180 : {
3181 : nsInProcessTabChildGlobal* tabChild =
3182 0 : static_cast<nsInProcessTabChildGlobal*>(mFrameLoader->mChildMessageManager.get());
3183 : // Since bug 1126089, messages can arrive even when the docShell is destroyed.
3184 : // Here we make sure that those messages are not delivered.
3185 0 : if (tabChild && tabChild->GetInnerManager() && mFrameLoader->GetExistingDocShell()) {
3186 0 : JS::Rooted<JSObject*> kungFuDeathGrip(dom::RootingCx(), tabChild->GetGlobal());
3187 0 : ReceiveMessage(static_cast<EventTarget*>(tabChild), mFrameLoader,
3188 0 : tabChild->GetInnerManager());
3189 : }
3190 0 : return NS_OK;
3191 : }
3192 : RefPtr<nsFrameLoader> mFrameLoader;
3193 : };
3194 :
3195 : nsresult
3196 8 : nsFrameLoader::DoSendAsyncMessage(JSContext* aCx,
3197 : const nsAString& aMessage,
3198 : StructuredCloneData& aData,
3199 : JS::Handle<JSObject *> aCpows,
3200 : nsIPrincipal* aPrincipal)
3201 : {
3202 8 : TabParent* tabParent = mRemoteBrowser;
3203 8 : if (tabParent) {
3204 16 : ClonedMessageData data;
3205 8 : nsIContentParent* cp = tabParent->Manager();
3206 8 : if (!BuildClonedMessageDataForParent(cp, aData, data)) {
3207 0 : MOZ_CRASH();
3208 : return NS_ERROR_DOM_DATA_CLONE_ERR;
3209 : }
3210 16 : InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
3211 8 : jsipc::CPOWManager* mgr = cp->GetCPOWManager();
3212 8 : if (aCpows && (!mgr || !mgr->Wrap(aCx, aCpows, &cpows))) {
3213 0 : return NS_ERROR_UNEXPECTED;
3214 : }
3215 16 : if (tabParent->SendAsyncMessage(nsString(aMessage), cpows,
3216 16 : IPC::Principal(aPrincipal), data)) {
3217 8 : return NS_OK;
3218 : } else {
3219 0 : return NS_ERROR_UNEXPECTED;
3220 : }
3221 : }
3222 :
3223 0 : if (mChildMessageManager) {
3224 0 : JS::RootingContext* rcx = JS::RootingContext::get(aCx);
3225 0 : RefPtr<nsAsyncMessageToChild> ev = new nsAsyncMessageToChild(rcx, aCpows, this);
3226 0 : nsresult rv = ev->Init(aMessage, aData, aPrincipal);
3227 0 : if (NS_FAILED(rv)) {
3228 0 : return rv;
3229 : }
3230 0 : rv = NS_DispatchToCurrentThread(ev);
3231 0 : if (NS_FAILED(rv)) {
3232 0 : return rv;
3233 : }
3234 0 : return rv;
3235 : }
3236 :
3237 : // We don't have any targets to send our asynchronous message to.
3238 0 : return NS_ERROR_UNEXPECTED;
3239 : }
3240 :
3241 : NS_IMETHODIMP
3242 44 : nsFrameLoader::GetMessageManager(nsIMessageSender** aManager)
3243 : {
3244 44 : EnsureMessageManager();
3245 44 : if (mMessageManager) {
3246 88 : RefPtr<nsFrameMessageManager> mm(mMessageManager);
3247 44 : mm.forget(aManager);
3248 44 : return NS_OK;
3249 : }
3250 0 : return NS_OK;
3251 : }
3252 :
3253 : nsresult
3254 47 : nsFrameLoader::EnsureMessageManager()
3255 : {
3256 47 : NS_ENSURE_STATE(mOwnerContent);
3257 :
3258 47 : if (mMessageManager) {
3259 44 : return NS_OK;
3260 : }
3261 :
3262 8 : if (!mIsTopLevelContent &&
3263 4 : !OwnerIsMozBrowserFrame() &&
3264 7 : !IsRemoteFrame() &&
3265 2 : !(mOwnerContent->IsXULElement() &&
3266 1 : mOwnerContent->AttrValueIs(kNameSpaceID_None,
3267 : nsGkAtoms::forcemessagemanager,
3268 : nsGkAtoms::_true, eCaseMatters))) {
3269 1 : return NS_OK;
3270 : }
3271 :
3272 : nsCOMPtr<nsIDOMChromeWindow> chromeWindow =
3273 4 : do_QueryInterface(GetOwnerDoc()->GetWindow());
3274 4 : nsCOMPtr<nsIMessageBroadcaster> parentManager;
3275 :
3276 2 : if (chromeWindow) {
3277 4 : nsAutoString messagemanagergroup;
3278 4 : if (mOwnerContent->IsXULElement() &&
3279 2 : mOwnerContent->GetAttr(kNameSpaceID_None,
3280 : nsGkAtoms::messagemanagergroup,
3281 : messagemanagergroup)) {
3282 2 : chromeWindow->GetGroupMessageManager(messagemanagergroup, getter_AddRefs(parentManager));
3283 : }
3284 :
3285 2 : if (!parentManager) {
3286 0 : chromeWindow->GetMessageManager(getter_AddRefs(parentManager));
3287 : }
3288 : } else {
3289 0 : parentManager = do_GetService("@mozilla.org/globalmessagemanager;1");
3290 : }
3291 :
3292 : mMessageManager = new nsFrameMessageManager(nullptr,
3293 2 : static_cast<nsFrameMessageManager*>(parentManager.get()),
3294 2 : MM_CHROME);
3295 2 : if (!IsRemoteFrame()) {
3296 1 : nsresult rv = MaybeCreateDocShell();
3297 1 : if (NS_FAILED(rv)) {
3298 0 : return rv;
3299 : }
3300 1 : NS_ASSERTION(mDocShell,
3301 : "MaybeCreateDocShell succeeded, but null mDocShell");
3302 1 : if (!mDocShell) {
3303 0 : return NS_ERROR_FAILURE;
3304 : }
3305 : mChildMessageManager =
3306 2 : new nsInProcessTabChildGlobal(mDocShell, mOwnerContent, mMessageManager);
3307 : }
3308 2 : return NS_OK;
3309 : }
3310 :
3311 : nsresult
3312 3 : nsFrameLoader::ReallyLoadFrameScripts()
3313 : {
3314 3 : nsresult rv = EnsureMessageManager();
3315 3 : if (NS_WARN_IF(NS_FAILED(rv))) {
3316 0 : return rv;
3317 : }
3318 3 : if (mMessageManager) {
3319 2 : mMessageManager->InitWithCallback(this);
3320 : }
3321 3 : return NS_OK;
3322 : }
3323 :
3324 : EventTarget*
3325 14 : nsFrameLoader::GetTabChildGlobalAsEventTarget()
3326 : {
3327 14 : return static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get());
3328 : }
3329 :
3330 : NS_IMETHODIMP
3331 0 : nsFrameLoader::GetOwnerElement(nsIDOMElement **aElement)
3332 : {
3333 0 : nsCOMPtr<nsIDOMElement> ownerElement = do_QueryInterface(mOwnerContent);
3334 0 : ownerElement.forget(aElement);
3335 0 : return NS_OK;
3336 : }
3337 :
3338 : NS_IMETHODIMP
3339 0 : nsFrameLoader::GetChildID(uint64_t* aChildID)
3340 : {
3341 0 : *aChildID = mChildID;
3342 0 : return NS_OK;
3343 : }
3344 :
3345 : void
3346 0 : nsFrameLoader::SetRemoteBrowser(nsITabParent* aTabParent)
3347 : {
3348 0 : MOZ_ASSERT(!mRemoteBrowser);
3349 0 : mRemoteFrame = true;
3350 0 : mRemoteBrowser = TabParent::GetFrom(aTabParent);
3351 0 : mChildID = mRemoteBrowser ? mRemoteBrowser->Manager()->ChildID() : 0;
3352 0 : MaybeUpdatePrimaryTabParent(eTabParentChanged);
3353 0 : ReallyLoadFrameScripts();
3354 0 : InitializeBrowserAPI();
3355 0 : ShowRemoteFrame(ScreenIntSize(0, 0));
3356 0 : }
3357 :
3358 : void
3359 5 : nsFrameLoader::SetDetachedSubdocFrame(nsIFrame* aDetachedFrame,
3360 : nsIDocument* aContainerDoc)
3361 : {
3362 5 : mDetachedSubdocFrame = aDetachedFrame;
3363 5 : mContainerDocWhileDetached = aContainerDoc;
3364 5 : }
3365 :
3366 : nsIFrame*
3367 6 : nsFrameLoader::GetDetachedSubdocFrame(nsIDocument** aContainerDoc) const
3368 : {
3369 6 : NS_IF_ADDREF(*aContainerDoc = mContainerDocWhileDetached);
3370 6 : return mDetachedSubdocFrame.GetFrame();
3371 : }
3372 :
3373 : void
3374 2 : nsFrameLoader::ApplySandboxFlags(uint32_t sandboxFlags)
3375 : {
3376 2 : if (mDocShell) {
3377 2 : uint32_t parentSandboxFlags = mOwnerContent->OwnerDoc()->GetSandboxFlags();
3378 :
3379 : // The child can only add restrictions, never remove them.
3380 2 : sandboxFlags |= parentSandboxFlags;
3381 :
3382 : // If this frame is a receiving browsing context, we should add
3383 : // sandboxed auxiliary navigation flag to sandboxFlags. See
3384 : // https://w3c.github.io/presentation-api/#creating-a-receiving-browsing-context
3385 4 : nsAutoString presentationURL;
3386 2 : nsContentUtils::GetPresentationURL(mDocShell, presentationURL);
3387 2 : if (!presentationURL.IsEmpty()) {
3388 0 : sandboxFlags |= SANDBOXED_AUXILIARY_NAVIGATION;
3389 : }
3390 2 : mDocShell->SetSandboxFlags(sandboxFlags);
3391 : }
3392 2 : }
3393 :
3394 : /* virtual */ void
3395 1 : nsFrameLoader::AttributeChanged(nsIDocument* aDocument,
3396 : mozilla::dom::Element* aElement,
3397 : int32_t aNameSpaceID,
3398 : nsIAtom* aAttribute,
3399 : int32_t aModType,
3400 : const nsAttrValue* aOldValue)
3401 : {
3402 1 : MOZ_ASSERT(mObservingOwnerContent);
3403 :
3404 3 : if (aNameSpaceID != kNameSpaceID_None ||
3405 2 : (aAttribute != TypeAttrName() && aAttribute != nsGkAtoms::primary)) {
3406 2 : return;
3407 : }
3408 :
3409 0 : if (aElement != mOwnerContent) {
3410 0 : return;
3411 : }
3412 :
3413 : // Note: This logic duplicates a lot of logic in
3414 : // MaybeCreateDocshell. We should fix that.
3415 :
3416 : // Notify our enclosing chrome that our type has changed. We only do this
3417 : // if our parent is chrome, since in all other cases we're random content
3418 : // subframes and the treeowner shouldn't worry about us.
3419 0 : if (!mDocShell) {
3420 0 : MaybeUpdatePrimaryTabParent(eTabParentChanged);
3421 0 : return;
3422 : }
3423 :
3424 0 : nsCOMPtr<nsIDocShellTreeItem> parentItem;
3425 0 : mDocShell->GetParent(getter_AddRefs(parentItem));
3426 0 : if (!parentItem) {
3427 0 : return;
3428 : }
3429 :
3430 0 : if (parentItem->ItemType() != nsIDocShellTreeItem::typeChrome) {
3431 0 : return;
3432 : }
3433 :
3434 0 : nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
3435 0 : parentItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
3436 0 : if (!parentTreeOwner) {
3437 0 : return;
3438 : }
3439 :
3440 : bool is_primary =
3441 0 : aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary, nsGkAtoms::_true, eIgnoreCase);
3442 :
3443 : #ifdef MOZ_XUL
3444 : // when a content panel is no longer primary, hide any open popups it may have
3445 0 : if (!is_primary) {
3446 0 : nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
3447 0 : if (pm)
3448 0 : pm->HidePopupsInDocShell(mDocShell);
3449 : }
3450 : #endif
3451 :
3452 0 : parentTreeOwner->ContentShellRemoved(mDocShell);
3453 :
3454 0 : nsAutoString value;
3455 0 : aElement->GetAttr(kNameSpaceID_None, TypeAttrName(), value);
3456 :
3457 0 : if (value.LowerCaseEqualsLiteral("content") ||
3458 0 : StringBeginsWith(value, NS_LITERAL_STRING("content-"),
3459 0 : nsCaseInsensitiveStringComparator())) {
3460 0 : parentTreeOwner->ContentShellAdded(mDocShell, is_primary);
3461 : }
3462 : }
3463 :
3464 : /**
3465 : * Send the RequestNotifyAfterRemotePaint message to the current Tab.
3466 : */
3467 : NS_IMETHODIMP
3468 0 : nsFrameLoader::RequestNotifyAfterRemotePaint()
3469 : {
3470 : // If remote browsing (e10s), handle this with the TabParent.
3471 0 : if (mRemoteBrowser) {
3472 0 : Unused << mRemoteBrowser->SendRequestNotifyAfterRemotePaint();
3473 : }
3474 :
3475 0 : return NS_OK;
3476 : }
3477 :
3478 : NS_IMETHODIMP
3479 0 : nsFrameLoader::RequestFrameLoaderClose()
3480 : {
3481 0 : nsCOMPtr<nsIBrowser> browser = do_QueryInterface(mOwnerContent);
3482 0 : if (NS_WARN_IF(!browser)) {
3483 : // OwnerElement other than nsIBrowser is not supported yet.
3484 0 : return NS_ERROR_NOT_IMPLEMENTED;
3485 : }
3486 :
3487 0 : return browser->CloseBrowser();
3488 : }
3489 :
3490 : NS_IMETHODIMP
3491 0 : nsFrameLoader::Print(uint64_t aOuterWindowID,
3492 : nsIPrintSettings* aPrintSettings,
3493 : nsIWebProgressListener* aProgressListener)
3494 : {
3495 : #if defined(NS_PRINTING)
3496 0 : if (mRemoteBrowser) {
3497 : RefPtr<embedding::PrintingParent> printingParent =
3498 0 : mRemoteBrowser->Manager()->AsContentParent()->GetPrintingParent();
3499 :
3500 0 : embedding::PrintData printData;
3501 0 : nsresult rv = printingParent->SerializeAndEnsureRemotePrintJob(
3502 0 : aPrintSettings, aProgressListener, nullptr, &printData);
3503 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
3504 0 : return rv;
3505 : }
3506 :
3507 0 : bool success = mRemoteBrowser->SendPrint(aOuterWindowID, printData);
3508 0 : return success ? NS_OK : NS_ERROR_FAILURE;
3509 : }
3510 :
3511 : nsGlobalWindow* outerWindow =
3512 0 : nsGlobalWindow::GetOuterWindowWithId(aOuterWindowID);
3513 0 : if (NS_WARN_IF(!outerWindow)) {
3514 0 : return NS_ERROR_FAILURE;
3515 : }
3516 :
3517 : nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint =
3518 0 : do_GetInterface(outerWindow->AsOuter());
3519 0 : if (NS_WARN_IF(!webBrowserPrint)) {
3520 0 : return NS_ERROR_FAILURE;
3521 : }
3522 :
3523 0 : return webBrowserPrint->Print(aPrintSettings, aProgressListener);
3524 : #endif
3525 : return NS_OK;
3526 : }
3527 :
3528 : NS_IMETHODIMP
3529 5 : nsFrameLoader::GetTabParent(nsITabParent** aTabParent)
3530 : {
3531 10 : nsCOMPtr<nsITabParent> tp = mRemoteBrowser;
3532 5 : tp.forget(aTabParent);
3533 10 : return NS_OK;
3534 : }
3535 :
3536 : NS_IMETHODIMP
3537 1 : nsFrameLoader::GetLoadContext(nsILoadContext** aLoadContext)
3538 : {
3539 2 : nsCOMPtr<nsILoadContext> loadContext;
3540 3 : if (IsRemoteFrame() &&
3541 1 : (mRemoteBrowser || TryRemoteBrowser())) {
3542 1 : loadContext = mRemoteBrowser->GetLoadContext();
3543 : } else {
3544 0 : nsCOMPtr<nsIDocShell> docShell;
3545 0 : GetDocShell(getter_AddRefs(docShell));
3546 0 : loadContext = do_GetInterface(docShell);
3547 : }
3548 1 : loadContext.forget(aLoadContext);
3549 2 : return NS_OK;
3550 : }
3551 :
3552 : void
3553 3 : nsFrameLoader::InitializeBrowserAPI()
3554 : {
3555 3 : if (!OwnerIsMozBrowserFrame()) {
3556 6 : return;
3557 : }
3558 0 : if (!IsRemoteFrame()) {
3559 0 : nsresult rv = EnsureMessageManager();
3560 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
3561 0 : return;
3562 : }
3563 0 : if (mMessageManager) {
3564 0 : mMessageManager->LoadFrameScript(
3565 0 : NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js"),
3566 : /* allowDelayedLoad = */ true,
3567 0 : /* aRunInGlobalScope */ true);
3568 : }
3569 : }
3570 0 : nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
3571 0 : if (browserFrame) {
3572 0 : browserFrame->InitializeBrowserAPI();
3573 : }
3574 : }
3575 :
3576 : void
3577 0 : nsFrameLoader::DestroyBrowserFrameScripts()
3578 : {
3579 0 : if (!OwnerIsMozBrowserFrame()) {
3580 0 : return;
3581 : }
3582 0 : nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
3583 0 : if (browserFrame) {
3584 0 : browserFrame->DestroyBrowserFrameScripts();
3585 : }
3586 : }
3587 :
3588 : NS_IMETHODIMP
3589 0 : nsFrameLoader::StartPersistence(uint64_t aOuterWindowID,
3590 : nsIWebBrowserPersistDocumentReceiver* aRecv)
3591 : {
3592 0 : if (!aRecv) {
3593 0 : return NS_ERROR_INVALID_POINTER;
3594 : }
3595 :
3596 0 : if (mRemoteBrowser) {
3597 0 : return mRemoteBrowser->StartPersistence(aOuterWindowID, aRecv);
3598 : }
3599 :
3600 : nsCOMPtr<nsIDocument> rootDoc =
3601 0 : mDocShell ? mDocShell->GetDocument() : nullptr;
3602 0 : nsCOMPtr<nsIDocument> foundDoc;
3603 0 : if (aOuterWindowID) {
3604 0 : foundDoc = nsContentUtils::GetSubdocumentWithOuterWindowId(rootDoc, aOuterWindowID);
3605 : } else {
3606 0 : foundDoc = rootDoc;
3607 : }
3608 :
3609 0 : if (!foundDoc) {
3610 0 : aRecv->OnError(NS_ERROR_NO_CONTENT);
3611 : } else {
3612 : nsCOMPtr<nsIWebBrowserPersistDocument> pdoc =
3613 0 : new mozilla::WebBrowserPersistLocalDocument(foundDoc);
3614 0 : aRecv->OnDocumentReady(pdoc);
3615 : }
3616 0 : return NS_OK;
3617 : }
3618 :
3619 : void
3620 2 : nsFrameLoader::MaybeUpdatePrimaryTabParent(TabParentChange aChange)
3621 : {
3622 2 : if (mRemoteBrowser && mOwnerContent) {
3623 2 : nsCOMPtr<nsIDocShell> docShell = mOwnerContent->OwnerDoc()->GetDocShell();
3624 1 : if (!docShell) {
3625 0 : return;
3626 : }
3627 :
3628 1 : int32_t parentType = docShell->ItemType();
3629 1 : if (parentType != nsIDocShellTreeItem::typeChrome) {
3630 0 : return;
3631 : }
3632 :
3633 2 : nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
3634 1 : docShell->GetTreeOwner(getter_AddRefs(parentTreeOwner));
3635 1 : if (!parentTreeOwner) {
3636 0 : return;
3637 : }
3638 :
3639 1 : if (!mObservingOwnerContent) {
3640 1 : mOwnerContent->AddMutationObserver(this);
3641 1 : mObservingOwnerContent = true;
3642 : }
3643 :
3644 1 : parentTreeOwner->TabParentRemoved(mRemoteBrowser);
3645 1 : if (aChange == eTabParentChanged) {
3646 : bool isPrimary =
3647 1 : mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary,
3648 1 : nsGkAtoms::_true, eIgnoreCase);
3649 1 : parentTreeOwner->TabParentAdded(mRemoteBrowser, isPrimary);
3650 : }
3651 : }
3652 : }
3653 :
3654 : nsresult
3655 1 : nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext,
3656 : nsIURI* aURI)
3657 : {
3658 1 : if (IsForJSPlugin()) {
3659 0 : return aTabContext->SetTabContextForJSPluginFrame(mJSPluginID) ? NS_OK :
3660 0 : NS_ERROR_FAILURE;
3661 : }
3662 :
3663 2 : OriginAttributes attrs;
3664 1 : attrs.mInIsolatedMozBrowser = OwnerIsIsolatedMozBrowserFrame();
3665 : nsresult rv;
3666 :
3667 1 : attrs.mAppId = nsIScriptSecurityManager::NO_APP_ID;
3668 :
3669 : // set the userContextId on the attrs before we pass them into
3670 : // the tab context
3671 1 : rv = PopulateUserContextIdFromAttribute(attrs);
3672 1 : NS_ENSURE_SUCCESS(rv, rv);
3673 :
3674 2 : nsAutoString presentationURLStr;
3675 1 : mOwnerContent->GetAttr(kNameSpaceID_None,
3676 : nsGkAtoms::mozpresentation,
3677 2 : presentationURLStr);
3678 :
3679 2 : nsCOMPtr<nsIDocShell> docShell = mOwnerContent->OwnerDoc()->GetDocShell();
3680 2 : nsCOMPtr<nsILoadContext> parentContext = do_QueryInterface(docShell);
3681 1 : NS_ENSURE_STATE(parentContext);
3682 :
3683 1 : bool isPrivate = parentContext->UsePrivateBrowsing();
3684 1 : attrs.SyncAttributesWithPrivateBrowsing(isPrivate);
3685 :
3686 1 : UIStateChangeType showAccelerators = UIStateChangeType_NoChange;
3687 1 : UIStateChangeType showFocusRings = UIStateChangeType_NoChange;
3688 1 : nsIDocument* doc = mOwnerContent->OwnerDoc();
3689 1 : if (doc) {
3690 2 : nsCOMPtr<nsPIWindowRoot> root = nsContentUtils::GetWindowRoot(doc);
3691 1 : if (root) {
3692 1 : showAccelerators =
3693 1 : root->ShowAccelerators() ? UIStateChangeType_Set : UIStateChangeType_Clear;
3694 1 : showFocusRings =
3695 1 : root->ShowFocusRings() ? UIStateChangeType_Set : UIStateChangeType_Clear;
3696 : }
3697 : }
3698 :
3699 : bool tabContextUpdated =
3700 1 : aTabContext->SetTabContext(OwnerIsMozBrowserFrame(),
3701 1 : mIsPrerendered,
3702 : showAccelerators,
3703 : showFocusRings,
3704 : attrs,
3705 1 : presentationURLStr);
3706 1 : NS_ENSURE_STATE(tabContextUpdated);
3707 :
3708 1 : return NS_OK;
3709 : }
3710 :
3711 : nsresult
3712 3 : nsFrameLoader::PopulateUserContextIdFromAttribute(OriginAttributes& aAttr)
3713 : {
3714 3 : if (aAttr.mUserContextId ==
3715 : nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) {
3716 : // Grab the userContextId from owner if XUL
3717 6 : nsAutoString userContextIdStr;
3718 3 : int32_t namespaceID = mOwnerContent->GetNameSpaceID();
3719 6 : if ((namespaceID == kNameSpaceID_XUL) &&
3720 3 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::usercontextid,
3721 3 : userContextIdStr) &&
3722 0 : !userContextIdStr.IsEmpty()) {
3723 : nsresult rv;
3724 0 : aAttr.mUserContextId = userContextIdStr.ToInteger(&rv);
3725 0 : NS_ENSURE_SUCCESS(rv, rv);
3726 : }
3727 : }
3728 :
3729 3 : return NS_OK;
3730 : }
3731 :
3732 : NS_IMETHODIMP
3733 0 : nsFrameLoader::GetIsDead(bool* aIsDead)
3734 : {
3735 0 : *aIsDead = mDestroyCalled;
3736 0 : return NS_OK;
3737 : }
3738 :
3739 : nsIMessageSender*
3740 0 : nsFrameLoader::GetProcessMessageManager() const
3741 : {
3742 0 : return mRemoteBrowser ? mRemoteBrowser->Manager()->GetMessageManager()
3743 0 : : nullptr;
3744 : };
|