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/. */
7 #include "mozilla/dom/BrowsingContext.h"
9 #include "ipc/IPCMessageUtils.h"
12 # include "mozilla/a11y/DocAccessibleParent.h"
13 # include "mozilla/a11y/Platform.h"
14 # include "mozilla/a11y/RemoteAccessibleBase.h"
15 # include "nsAccessibilityService.h"
17 # include "mozilla/a11y/AccessibleWrap.h"
18 # include "mozilla/a11y/Compatibility.h"
19 # include "mozilla/a11y/nsWinUtils.h"
22 #include "mozilla/AppShutdown.h"
23 #include "mozilla/dom/CanonicalBrowsingContext.h"
24 #include "mozilla/dom/BrowserChild.h"
25 #include "mozilla/dom/BrowserParent.h"
26 #include "mozilla/dom/BrowsingContextGroup.h"
27 #include "mozilla/dom/BrowsingContextBinding.h"
28 #include "mozilla/dom/ContentChild.h"
29 #include "mozilla/dom/ContentParent.h"
30 #include "mozilla/dom/Document.h"
31 #include "mozilla/dom/Element.h"
32 #include "mozilla/dom/HTMLEmbedElement.h"
33 #include "mozilla/dom/HTMLIFrameElement.h"
34 #include "mozilla/dom/Location.h"
35 #include "mozilla/dom/LocationBinding.h"
36 #include "mozilla/dom/MediaDevices.h"
37 #include "mozilla/dom/PopupBlocker.h"
38 #include "mozilla/dom/ScriptSettings.h"
39 #include "mozilla/dom/SessionStorageManager.h"
40 #include "mozilla/dom/SessionStoreDataCollector.h"
41 #include "mozilla/dom/StructuredCloneTags.h"
42 #include "mozilla/dom/UserActivationIPCUtils.h"
43 #include "mozilla/dom/WindowBinding.h"
44 #include "mozilla/dom/WindowGlobalChild.h"
45 #include "mozilla/dom/WindowGlobalParent.h"
46 #include "mozilla/dom/WindowProxyHolder.h"
47 #include "mozilla/dom/SyncedContextInlines.h"
48 #include "mozilla/dom/XULFrameElement.h"
49 #include "mozilla/net/DocumentLoadListener.h"
50 #include "mozilla/net/RequestContextService.h"
51 #include "mozilla/Assertions.h"
52 #include "mozilla/AsyncEventDispatcher.h"
53 #include "mozilla/ClearOnShutdown.h"
54 #include "mozilla/Components.h"
55 #include "mozilla/HashTable.h"
56 #include "mozilla/Logging.h"
57 #include "mozilla/MediaFeatureChange.h"
58 #include "mozilla/ResultExtensions.h"
59 #include "mozilla/Services.h"
60 #include "mozilla/StaticPrefs_fission.h"
61 #include "mozilla/StaticPrefs_media.h"
62 #include "mozilla/StaticPrefs_page_load.h"
63 #include "mozilla/StaticPtr.h"
64 #include "mozilla/URLQueryStringStripper.h"
65 #include "nsIURIFixup.h"
66 #include "nsIXULRuntime.h"
68 #include "nsDocShell.h"
69 #include "nsDocShellLoadState.h"
70 #include "nsFocusManager.h"
71 #include "nsGlobalWindowOuter.h"
72 #include "nsIObserverService.h"
73 #include "nsISHistory.h"
74 #include "nsContentUtils.h"
75 #include "nsQueryObject.h"
76 #include "nsSandboxFlags.h"
77 #include "nsScriptError.h"
78 #include "nsThreadUtils.h"
79 #include "xpcprivate.h"
81 #include "AutoplayPolicy.h"
82 #include "GVAutoplayRequestStatusIPC.h"
84 extern mozilla::LazyLogModule gAutoplayPermissionLog
;
85 extern mozilla::LazyLogModule gTimeoutDeferralLog
;
87 #define AUTOPLAY_LOG(msg, ...) \
88 MOZ_LOG(gAutoplayPermissionLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
91 // Allow serialization and deserialization of OrientationType over IPC
93 struct ParamTraits
<mozilla::dom::OrientationType
>
94 : public ContiguousEnumSerializer
<
95 mozilla::dom::OrientationType
,
96 mozilla::dom::OrientationType::Portrait_primary
,
97 mozilla::dom::OrientationType::EndGuard_
> {};
100 struct ParamTraits
<mozilla::dom::DisplayMode
>
101 : public ContiguousEnumSerializer
<mozilla::dom::DisplayMode
,
102 mozilla::dom::DisplayMode::Browser
,
103 mozilla::dom::DisplayMode::EndGuard_
> {};
106 struct ParamTraits
<mozilla::dom::PrefersColorSchemeOverride
>
107 : public ContiguousEnumSerializer
<
108 mozilla::dom::PrefersColorSchemeOverride
,
109 mozilla::dom::PrefersColorSchemeOverride::None
,
110 mozilla::dom::PrefersColorSchemeOverride::EndGuard_
> {};
113 struct ParamTraits
<mozilla::dom::ExplicitActiveStatus
>
114 : public ContiguousEnumSerializer
<
115 mozilla::dom::ExplicitActiveStatus
,
116 mozilla::dom::ExplicitActiveStatus::None
,
117 mozilla::dom::ExplicitActiveStatus::EndGuard_
> {};
119 // Allow serialization and deserialization of TouchEventsOverride over IPC
121 struct ParamTraits
<mozilla::dom::TouchEventsOverride
>
122 : public ContiguousEnumSerializer
<
123 mozilla::dom::TouchEventsOverride
,
124 mozilla::dom::TouchEventsOverride::Disabled
,
125 mozilla::dom::TouchEventsOverride::EndGuard_
> {};
131 // Explicit specialization of the `Transaction` type. Required by the `extern
132 // template class` declaration in the header.
133 template class syncedcontext::Transaction
<BrowsingContext
>;
135 extern mozilla::LazyLogModule gUserInteractionPRLog
;
137 #define USER_ACTIVATION_LOG(msg, ...) \
138 MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
140 static LazyLogModule
gBrowsingContextLog("BrowsingContext");
141 static LazyLogModule
gBrowsingContextSyncLog("BrowsingContextSync");
143 typedef nsTHashMap
<nsUint64HashKey
, BrowsingContext
*> BrowsingContextMap
;
145 // All BrowsingContexts indexed by Id
146 static StaticAutoPtr
<BrowsingContextMap
> sBrowsingContexts
;
147 // Top-level Content BrowsingContexts only, indexed by BrowserId instead of Id
148 static StaticAutoPtr
<BrowsingContextMap
> sCurrentTopByBrowserId
;
150 static void UnregisterBrowserId(BrowsingContext
* aBrowsingContext
) {
151 if (!aBrowsingContext
->IsTopContent() || !sCurrentTopByBrowserId
) {
155 // Avoids an extra lookup
156 auto browserIdEntry
=
157 sCurrentTopByBrowserId
->Lookup(aBrowsingContext
->BrowserId());
158 if (browserIdEntry
&& browserIdEntry
.Data() == aBrowsingContext
) {
159 browserIdEntry
.Remove();
163 static void Register(BrowsingContext
* aBrowsingContext
) {
164 sBrowsingContexts
->InsertOrUpdate(aBrowsingContext
->Id(), aBrowsingContext
);
165 if (aBrowsingContext
->IsTopContent()) {
166 sCurrentTopByBrowserId
->InsertOrUpdate(aBrowsingContext
->BrowserId(),
170 aBrowsingContext
->Group()->Register(aBrowsingContext
);
173 BrowsingContext
* BrowsingContext::GetParent() const {
174 return mParentWindow
? mParentWindow
->GetBrowsingContext() : nullptr;
177 bool BrowsingContext::IsInSubtreeOf(BrowsingContext
* aContext
) {
178 BrowsingContext
* bc
= this;
180 if (bc
== aContext
) {
183 } while ((bc
= bc
->GetParent()));
187 BrowsingContext
* BrowsingContext::Top() {
188 BrowsingContext
* bc
= this;
189 while (bc
->mParentWindow
) {
190 bc
= bc
->GetParent();
195 const BrowsingContext
* BrowsingContext::Top() const {
196 const BrowsingContext
* bc
= this;
197 while (bc
->mParentWindow
) {
198 bc
= bc
->GetParent();
203 int32_t BrowsingContext::IndexOf(BrowsingContext
* aChild
) {
205 for (BrowsingContext
* child
: Children()) {
207 if (child
== aChild
) {
214 WindowContext
* BrowsingContext::GetTopWindowContext() const {
216 return mParentWindow
->TopWindowContext();
218 return mCurrentWindowContext
;
222 void BrowsingContext::Init() {
223 if (!sBrowsingContexts
) {
224 sBrowsingContexts
= new BrowsingContextMap();
225 sCurrentTopByBrowserId
= new BrowsingContextMap();
226 ClearOnShutdown(&sBrowsingContexts
);
227 ClearOnShutdown(&sCurrentTopByBrowserId
);
232 LogModule
* BrowsingContext::GetLog() { return gBrowsingContextLog
; }
235 LogModule
* BrowsingContext::GetSyncLog() { return gBrowsingContextSyncLog
; }
238 already_AddRefed
<BrowsingContext
> BrowsingContext::Get(uint64_t aId
) {
239 return do_AddRef(sBrowsingContexts
->Get(aId
));
243 already_AddRefed
<BrowsingContext
> BrowsingContext::GetCurrentTopByBrowserId(
244 uint64_t aBrowserId
) {
245 return do_AddRef(sCurrentTopByBrowserId
->Get(aBrowserId
));
249 already_AddRefed
<BrowsingContext
> BrowsingContext::GetFromWindow(
250 WindowProxyHolder
& aProxy
) {
251 return do_AddRef(aProxy
.get());
254 CanonicalBrowsingContext
* BrowsingContext::Canonical() {
255 return CanonicalBrowsingContext::Cast(this);
258 bool BrowsingContext::IsOwnedByProcess() const {
259 return mIsInProcess
&& mDocShell
&&
260 !nsDocShell::Cast(mDocShell
)->WillChangeProcess();
263 bool BrowsingContext::SameOriginWithTop() {
264 MOZ_ASSERT(IsInProcess());
265 // If the top BrowsingContext is not same-process to us, it is cross-origin
266 if (!Top()->IsInProcess()) {
270 nsIDocShell
* docShell
= GetDocShell();
274 Document
* doc
= docShell
->GetDocument();
278 nsIPrincipal
* principal
= doc
->NodePrincipal();
280 nsIDocShell
* topDocShell
= Top()->GetDocShell();
284 Document
* topDoc
= topDocShell
->GetDocument();
288 nsIPrincipal
* topPrincipal
= topDoc
->NodePrincipal();
290 return principal
->Equals(topPrincipal
);
294 already_AddRefed
<BrowsingContext
> BrowsingContext::CreateDetached(
295 nsGlobalWindowInner
* aParent
, BrowsingContext
* aOpener
,
296 BrowsingContextGroup
* aSpecificGroup
, const nsAString
& aName
, Type aType
,
297 bool aIsPopupRequested
, bool aCreatedDynamically
) {
299 MOZ_DIAGNOSTIC_ASSERT(aParent
->GetWindowContext());
300 MOZ_DIAGNOSTIC_ASSERT(aParent
->GetBrowsingContext()->mType
== aType
);
301 MOZ_DIAGNOSTIC_ASSERT(aParent
->GetBrowsingContext()->GetBrowserId() != 0);
304 MOZ_DIAGNOSTIC_ASSERT(aType
!= Type::Chrome
|| XRE_IsParentProcess());
306 uint64_t id
= nsContentUtils::GenerateBrowsingContextId();
308 MOZ_LOG(GetLog(), LogLevel::Debug
,
309 ("Creating 0x%08" PRIx64
" in %s", id
,
310 XRE_IsParentProcess() ? "Parent" : "Child"));
312 RefPtr
<BrowsingContext
> parentBC
=
313 aParent
? aParent
->GetBrowsingContext() : nullptr;
314 RefPtr
<WindowContext
> parentWC
=
315 aParent
? aParent
->GetWindowContext() : nullptr;
316 BrowsingContext
* inherit
= parentBC
? parentBC
.get() : aOpener
;
318 // Determine which BrowsingContextGroup this context should be created in.
319 RefPtr
<BrowsingContextGroup
> group
= aSpecificGroup
;
320 if (aType
== Type::Chrome
) {
321 MOZ_DIAGNOSTIC_ASSERT(!group
);
322 group
= BrowsingContextGroup::GetChromeGroup();
324 group
= BrowsingContextGroup::Select(parentWC
, aOpener
);
327 // Configure initial values for synced fields.
329 fields
.mName
= aName
;
332 MOZ_DIAGNOSTIC_ASSERT(!aParent
,
333 "new BC with both initial opener and parent");
334 MOZ_DIAGNOSTIC_ASSERT(aOpener
->Group() == group
);
335 MOZ_DIAGNOSTIC_ASSERT(aOpener
->mType
== aType
);
336 fields
.mOpenerId
= aOpener
->Id();
337 fields
.mHadOriginalOpener
= true;
341 MOZ_DIAGNOSTIC_ASSERT(parentBC
->Group() == group
);
342 MOZ_DIAGNOSTIC_ASSERT(parentBC
->mType
== aType
);
343 fields
.mEmbedderInnerWindowId
= aParent
->WindowID();
345 // XXX(farre): Can/Should we check aParent->IsLoading() here? (Bug
346 // 1608448) Check if the parent was itself loading already
347 auto readystate
= aParent
->GetDocument()->GetReadyStateEnum();
348 fields
.mAncestorLoading
=
349 parentBC
->GetAncestorLoading() ||
350 readystate
== Document::ReadyState::READYSTATE_LOADING
||
351 readystate
== Document::ReadyState::READYSTATE_INTERACTIVE
;
355 parentBC
? parentBC
->GetBrowserId() : nsContentUtils::GenerateBrowserId();
357 fields
.mOpenerPolicy
= nsILoadInfo::OPENER_POLICY_UNSAFE_NONE
;
358 if (aOpener
&& aOpener
->SameOriginWithTop()) {
359 // We inherit the opener policy if there is a creator and if the creator's
360 // origin is same origin with the creator's top-level origin.
361 // If it is cross origin we should not inherit the CrossOriginOpenerPolicy
362 fields
.mOpenerPolicy
= aOpener
->Top()->GetOpenerPolicy();
363 } else if (aOpener
) {
364 // They are not same origin
365 auto topPolicy
= aOpener
->Top()->GetOpenerPolicy();
366 MOZ_RELEASE_ASSERT(topPolicy
== nsILoadInfo::OPENER_POLICY_UNSAFE_NONE
||
368 nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_ALLOW_POPUPS
);
371 fields
.mHistoryID
= nsID::GenerateUUID();
372 fields
.mExplicitActive
= [&] {
374 // Non-root browsing-contexts inherit their status from its parent.
375 return ExplicitActiveStatus::None
;
377 if (aType
== Type::Content
) {
378 // Content gets managed by the chrome front-end / embedder element and
379 // starts as inactive.
380 return ExplicitActiveStatus::Inactive
;
382 // Chrome starts as active.
383 return ExplicitActiveStatus::Active
;
386 fields
.mFullZoom
= parentBC
? parentBC
->FullZoom() : 1.0f
;
387 fields
.mTextZoom
= parentBC
? parentBC
->TextZoom() : 1.0f
;
389 bool allowContentRetargeting
=
390 inherit
? inherit
->GetAllowContentRetargetingOnChildren() : true;
391 fields
.mAllowContentRetargeting
= allowContentRetargeting
;
392 fields
.mAllowContentRetargetingOnChildren
= allowContentRetargeting
;
394 // Assume top allows fullscreen for its children unless otherwise stated.
395 // Subframes start with it false unless otherwise noted in SetEmbedderElement.
396 fields
.mFullscreenAllowedByOwner
= !aParent
;
398 fields
.mAllowPlugins
= inherit
? inherit
->GetAllowPlugins() : true;
400 fields
.mDefaultLoadFlags
=
401 inherit
? inherit
->GetDefaultLoadFlags() : nsIRequest::LOAD_NORMAL
;
403 fields
.mOrientationLock
= mozilla::hal::eScreenOrientation_None
;
405 fields
.mUseGlobalHistory
= inherit
? inherit
->GetUseGlobalHistory() : false;
407 fields
.mUseErrorPages
= true;
409 fields
.mTouchEventsOverrideInternal
= TouchEventsOverride::None
;
411 fields
.mAllowJavascript
= inherit
? inherit
->GetAllowJavascript() : true;
413 fields
.mIsPopupRequested
= aIsPopupRequested
;
416 fields
.mShouldDelayMediaFromStart
=
417 StaticPrefs::media_block_autoplay_until_in_foreground();
420 RefPtr
<BrowsingContext
> context
;
421 if (XRE_IsParentProcess()) {
422 context
= new CanonicalBrowsingContext(parentWC
, group
, id
,
423 /* aOwnerProcessId */ 0,
424 /* aEmbedderProcessId */ 0, aType
,
428 new BrowsingContext(parentWC
, group
, id
, aType
, std::move(fields
));
431 context
->mEmbeddedByThisProcess
= XRE_IsParentProcess() || aParent
;
432 context
->mCreatedDynamically
= aCreatedDynamically
;
434 context
->mPrivateBrowsingId
= inherit
->mPrivateBrowsingId
;
435 context
->mUseRemoteTabs
= inherit
->mUseRemoteTabs
;
436 context
->mUseRemoteSubframes
= inherit
->mUseRemoteSubframes
;
437 context
->mOriginAttributes
= inherit
->mOriginAttributes
;
440 nsCOMPtr
<nsIRequestContextService
> rcsvc
=
441 net::RequestContextService::GetOrCreate();
443 nsCOMPtr
<nsIRequestContext
> requestContext
;
444 nsresult rv
= rcsvc
->NewRequestContext(getter_AddRefs(requestContext
));
445 if (NS_SUCCEEDED(rv
) && requestContext
) {
446 context
->mRequestContextId
= requestContext
->GetID();
450 return context
.forget();
453 already_AddRefed
<BrowsingContext
> BrowsingContext::CreateIndependent(
455 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess(),
456 "BCs created in the content process must be related to "
457 "some BrowserChild");
458 RefPtr
<BrowsingContext
> bc(
459 CreateDetached(nullptr, nullptr, nullptr, u
""_ns
, aType
, false));
460 bc
->mWindowless
= bc
->IsContent();
461 bc
->mEmbeddedByThisProcess
= true;
462 bc
->EnsureAttached();
466 void BrowsingContext::EnsureAttached() {
467 if (!mEverAttached
) {
470 // Attach the browsing context to the tree.
471 Attach(/* aFromIPC */ false, /* aOriginProcess */ nullptr);
476 void BrowsingContext::CreateFromIPC(BrowsingContext::IPCInitializer
&& aInit
,
477 BrowsingContextGroup
* aGroup
,
478 ContentParent
* aOriginProcess
) {
479 MOZ_DIAGNOSTIC_ASSERT(aOriginProcess
|| XRE_IsContentProcess());
480 MOZ_DIAGNOSTIC_ASSERT(aGroup
);
482 uint64_t originId
= 0;
483 if (aOriginProcess
) {
484 originId
= aOriginProcess
->ChildID();
485 aGroup
->EnsureHostProcess(aOriginProcess
);
488 MOZ_LOG(GetLog(), LogLevel::Debug
,
489 ("Creating 0x%08" PRIx64
" from IPC (origin=0x%08" PRIx64
")",
490 aInit
.mId
, originId
));
492 RefPtr
<WindowContext
> parent
= aInit
.GetParent();
494 RefPtr
<BrowsingContext
> context
;
495 if (XRE_IsParentProcess()) {
496 // If the new BrowsingContext has a parent, it is a sub-frame embedded in
497 // whatever process sent the message. If it doesn't, and is not windowless,
498 // it is a new window or tab, and will be embedded in the parent process.
499 uint64_t embedderProcessId
= (aInit
.mWindowless
|| parent
) ? originId
: 0;
500 context
= new CanonicalBrowsingContext(parent
, aGroup
, aInit
.mId
, originId
,
501 embedderProcessId
, Type::Content
,
502 std::move(aInit
.mFields
));
504 context
= new BrowsingContext(parent
, aGroup
, aInit
.mId
, Type::Content
,
505 std::move(aInit
.mFields
));
508 context
->mWindowless
= aInit
.mWindowless
;
509 context
->mCreatedDynamically
= aInit
.mCreatedDynamically
;
510 context
->mChildOffset
= aInit
.mChildOffset
;
511 if (context
->GetHasSessionHistory()) {
512 context
->CreateChildSHistory();
513 if (mozilla::SessionHistoryInParent()) {
514 context
->GetChildSessionHistory()->SetIndexAndLength(
515 aInit
.mSessionHistoryIndex
, aInit
.mSessionHistoryCount
, nsID());
519 // NOTE: Call through the `Set` methods for these values to ensure that any
520 // relevant process-local state is also updated.
521 context
->SetOriginAttributes(aInit
.mOriginAttributes
);
522 context
->SetRemoteTabs(aInit
.mUseRemoteTabs
);
523 context
->SetRemoteSubframes(aInit
.mUseRemoteSubframes
);
524 context
->mRequestContextId
= aInit
.mRequestContextId
;
525 // NOTE: Private browsing ID is set by `SetOriginAttributes`.
529 context
->Attach(/* aFromIPC */ true, aOriginProcess
);
532 BrowsingContext::BrowsingContext(WindowContext
* aParentWindow
,
533 BrowsingContextGroup
* aGroup
,
534 uint64_t aBrowsingContextId
, Type aType
,
536 : mFields(std::move(aInit
)),
538 mBrowsingContextId(aBrowsingContextId
),
540 mParentWindow(aParentWindow
),
541 mPrivateBrowsingId(0),
542 mEverAttached(false),
546 mDanglingRemoteOuterProxies(false),
547 mEmbeddedByThisProcess(false),
548 mUseRemoteTabs(false),
549 mUseRemoteSubframes(false),
550 mCreatedDynamically(false),
552 mCanExecuteScripts(true),
554 MOZ_RELEASE_ASSERT(!mParentWindow
|| mParentWindow
->Group() == mGroup
);
555 MOZ_RELEASE_ASSERT(mBrowsingContextId
!= 0);
556 MOZ_RELEASE_ASSERT(mGroup
);
559 void BrowsingContext::SetDocShell(nsIDocShell
* aDocShell
) {
560 // XXX(nika): We should communicate that we are now an active BrowsingContext
561 // process to the parent & do other validation here.
562 MOZ_DIAGNOSTIC_ASSERT(mEverAttached
);
563 MOZ_RELEASE_ASSERT(aDocShell
->GetBrowsingContext() == this);
564 mDocShell
= aDocShell
;
565 mDanglingRemoteOuterProxies
= !mIsInProcess
;
567 if (mChildSessionHistory
) {
568 mChildSessionHistory
->SetIsInProcess(true);
572 // This class implements a callback that will return the remote window proxy for
573 // mBrowsingContext in that compartment, if it has one. It also removes the
574 // proxy from the map, because the object will be transplanted into another kind
576 class MOZ_STACK_CLASS CompartmentRemoteProxyTransplantCallback
577 : public js::CompartmentTransplantCallback
{
579 explicit CompartmentRemoteProxyTransplantCallback(
580 BrowsingContext
* aBrowsingContext
)
581 : mBrowsingContext(aBrowsingContext
) {}
583 virtual JSObject
* getObjectToTransplant(
584 JS::Compartment
* compartment
) override
{
585 auto* priv
= xpc::CompartmentPrivate::Get(compartment
);
590 auto& map
= priv
->GetRemoteProxyMap();
591 auto result
= map
.lookup(mBrowsingContext
);
595 JSObject
* resultObject
= result
->value();
602 BrowsingContext
* mBrowsingContext
;
605 void BrowsingContext::CleanUpDanglingRemoteOuterWindowProxies(
606 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aOuter
) {
607 if (!mDanglingRemoteOuterProxies
) {
610 mDanglingRemoteOuterProxies
= false;
612 CompartmentRemoteProxyTransplantCallback
cb(this);
613 js::RemapRemoteWindowProxies(aCx
, &cb
, aOuter
);
616 bool BrowsingContext::IsActive() const {
617 const BrowsingContext
* current
= this;
619 auto explicit_
= current
->GetExplicitActive();
620 if (explicit_
!= ExplicitActiveStatus::None
) {
621 return explicit_
== ExplicitActiveStatus::Active
;
623 if (mParentWindow
&& !mParentWindow
->IsCurrent()) {
626 } while ((current
= current
->GetParent()));
631 bool BrowsingContext::GetIsActiveBrowserWindow() {
632 if (!XRE_IsParentProcess()) {
633 return Top()->GetIsActiveBrowserWindowInternal();
636 // chrome:// urls loaded in the parent won't receive
637 // their own activation so we defer to the top chrome
638 // Browsing Context when in the parent process.
639 RefPtr
<CanonicalBrowsingContext
> chromeTop
=
640 Canonical()->TopCrossChromeBoundary();
641 return chromeTop
->GetIsActiveBrowserWindowInternal();
644 void BrowsingContext::SetIsActiveBrowserWindow(bool aActive
) {
645 Unused
<< SetIsActiveBrowserWindowInternal(aActive
);
648 bool BrowsingContext::FullscreenAllowed() const {
649 for (auto* current
= this; current
; current
= current
->GetParent()) {
650 if (!current
->GetFullscreenAllowedByOwner()) {
657 static bool OwnerAllowsFullscreen(const Element
& aEmbedder
) {
658 if (aEmbedder
.IsXULElement()) {
659 return !aEmbedder
.HasAttr(nsGkAtoms::disablefullscreen
);
661 if (aEmbedder
.IsHTMLElement(nsGkAtoms::iframe
)) {
662 // This is controlled by feature policy.
665 if (const auto* embed
= HTMLEmbedElement::FromNode(aEmbedder
)) {
666 return embed
->AllowFullscreen();
671 void BrowsingContext::SetEmbedderElement(Element
* aEmbedder
) {
672 mEmbeddedByThisProcess
= true;
674 // Update embedder-element-specific fields in a shared transaction.
675 // Don't do this when clearing our embedder, as we're being destroyed either
679 txn
.SetEmbedderElementType(Some(aEmbedder
->LocalName()));
680 if (nsCOMPtr
<nsPIDOMWindowInner
> inner
=
681 do_QueryInterface(aEmbedder
->GetOwnerGlobal())) {
682 txn
.SetEmbedderInnerWindowId(inner
->WindowID());
684 txn
.SetFullscreenAllowedByOwner(OwnerAllowsFullscreen(*aEmbedder
));
685 if (XRE_IsParentProcess() && IsTopContent()) {
686 nsAutoString messageManagerGroup
;
687 if (aEmbedder
->IsXULElement()) {
688 aEmbedder
->GetAttr(nsGkAtoms::messagemanagergroup
, messageManagerGroup
);
689 if (!aEmbedder
->AttrValueIs(kNameSpaceID_None
,
690 nsGkAtoms::initiallyactive
,
691 nsGkAtoms::_false
, eIgnoreCase
)) {
692 txn
.SetExplicitActive(ExplicitActiveStatus::Active
);
695 txn
.SetMessageManagerGroup(messageManagerGroup
);
697 bool useGlobalHistory
= !aEmbedder
->HasAttr(
698 kNameSpaceID_None
, nsGkAtoms::disableglobalhistory
);
699 txn
.SetUseGlobalHistory(useGlobalHistory
);
702 MOZ_ALWAYS_SUCCEEDS(txn
.Commit(this));
705 if (XRE_IsParentProcess() && IsTopContent()) {
706 Canonical()->MaybeSetPermanentKey(aEmbedder
);
709 mEmbedderElement
= aEmbedder
;
711 if (mEmbedderElement
) {
712 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
713 obs
->NotifyWhenScriptSafe(ToSupports(this),
714 "browsing-context-did-set-embedder", nullptr);
719 void BrowsingContext::Embed() {
720 if (auto* frame
= HTMLIFrameElement::FromNode(mEmbedderElement
)) {
721 frame
->BindToBrowsingContext(this);
725 void BrowsingContext::Attach(bool aFromIPC
, ContentParent
* aOriginProcess
) {
726 MOZ_DIAGNOSTIC_ASSERT(!mEverAttached
);
727 MOZ_DIAGNOSTIC_ASSERT_IF(aFromIPC
, aOriginProcess
|| XRE_IsContentProcess());
728 mEverAttached
= true;
730 if (MOZ_LOG_TEST(GetLog(), LogLevel::Debug
)) {
731 nsAutoCString suffix
;
732 mOriginAttributes
.CreateSuffix(suffix
);
733 MOZ_LOG(GetLog(), LogLevel::Debug
,
734 ("%s: Connecting 0x%08" PRIx64
" to 0x%08" PRIx64
735 " (private=%d, remote=%d, fission=%d, oa=%s)",
736 XRE_IsParentProcess() ? "Parent" : "Child", Id(),
737 GetParent() ? GetParent()->Id() : 0, (int)mPrivateBrowsingId
,
738 (int)mUseRemoteTabs
, (int)mUseRemoteSubframes
, suffix
.get()));
741 MOZ_DIAGNOSTIC_ASSERT(mGroup
);
742 MOZ_DIAGNOSTIC_ASSERT(!mIsDiscarded
);
744 AssertCoherentLoadContext();
746 // Add ourselves either to our parent or BrowsingContextGroup's child list.
749 MOZ_DIAGNOSTIC_ASSERT(!mParentWindow
->IsDiscarded(),
750 "local attach in discarded window");
751 MOZ_DIAGNOSTIC_ASSERT(!GetParent()->IsDiscarded(),
752 "local attach call in discarded bc");
753 MOZ_DIAGNOSTIC_ASSERT(mParentWindow
->GetWindowGlobalChild(),
754 "local attach call with oop parent window");
755 MOZ_DIAGNOSTIC_ASSERT(mParentWindow
->GetWindowGlobalChild()->CanSend(),
756 "local attach call with dead parent window");
759 mCreatedDynamically
? -1 : mParentWindow
->Children().Length();
760 mParentWindow
->AppendChildBrowsingContext(this);
761 RecomputeCanExecuteScripts();
763 mGroup
->Toplevels().AppendElement(this);
766 if (GetIsPopupSpam()) {
767 PopupBlocker::RegisterOpenPopupSpam();
770 if (IsTop() && GetHasSessionHistory() && !mChildSessionHistory
) {
771 CreateChildSHistory();
774 // Why the context is being attached. This will always be "attach" in the
775 // content process, but may be "replace" if it's known the context being
776 // replaced in the parent process.
777 const char16_t
* why
= u
"attach";
779 if (XRE_IsContentProcess() && !aFromIPC
) {
780 // Send attach to our parent if we need to.
781 ContentChild::GetSingleton()->SendCreateBrowsingContext(
782 mGroup
->Id(), GetIPCInitializer());
783 } else if (XRE_IsParentProcess()) {
784 // If this window was created as a subframe by a content process, it must be
785 // being hosted within the same BrowserParent as its mParentWindow.
786 // Toplevel BrowsingContexts created by content have their BrowserParent
787 // configured during `RecvConstructPopupBrowser`.
788 if (mParentWindow
&& aOriginProcess
) {
789 MOZ_DIAGNOSTIC_ASSERT(
790 mParentWindow
->Canonical()->GetContentParent() == aOriginProcess
,
791 "Creator process isn't the same as our embedder?");
792 Canonical()->SetCurrentBrowserParent(
793 mParentWindow
->Canonical()->GetBrowserParent());
796 mGroup
->EachOtherParent(aOriginProcess
, [&](ContentParent
* aParent
) {
797 MOZ_DIAGNOSTIC_ASSERT(IsContent(),
798 "chrome BCG cannot be synced to content process");
799 if (!Canonical()->IsEmbeddedInProcess(aParent
->ChildID())) {
800 Unused
<< aParent
->SendCreateBrowsingContext(mGroup
->Id(),
801 GetIPCInitializer());
805 if (IsTop() && IsContent() && Canonical()->GetWebProgress()) {
809 // We want to create a BrowsingContextWebProgress for all content
811 if (IsContent() && !Canonical()->mWebProgress
) {
812 Canonical()->mWebProgress
= new BrowsingContextWebProgress(Canonical());
816 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
817 obs
->NotifyWhenScriptSafe(ToSupports(this), "browsing-context-attached",
821 if (XRE_IsParentProcess()) {
822 Canonical()->CanonicalAttach();
826 void BrowsingContext::Detach(bool aFromIPC
) {
827 MOZ_LOG(GetLog(), LogLevel::Debug
,
828 ("%s: Detaching 0x%08" PRIx64
" from 0x%08" PRIx64
,
829 XRE_IsParentProcess() ? "Parent" : "Child", Id(),
830 GetParent() ? GetParent()->Id() : 0));
832 MOZ_DIAGNOSTIC_ASSERT(mEverAttached
);
833 MOZ_DIAGNOSTIC_ASSERT(!mIsDiscarded
);
835 if (XRE_IsParentProcess()) {
836 Canonical()->AddPendingDiscard();
839 MakeScopeExit([&, listeners
= std::move(mDiscardListeners
), id
= Id()] {
840 for (const auto& listener
: listeners
) {
843 if (XRE_IsParentProcess()) {
844 Canonical()->RemovePendingDiscard();
848 nsCOMPtr
<nsIRequestContextService
> rcsvc
=
849 net::RequestContextService::GetOrCreate();
851 rcsvc
->RemoveRequestContext(GetRequestContextId());
854 // This will only ever be null if the cycle-collector has unlinked us. Don't
855 // try to detach ourselves in that case.
856 if (NS_WARN_IF(!mGroup
)) {
857 MOZ_ASSERT_UNREACHABLE();
862 mParentWindow
->RemoveChildBrowsingContext(this);
864 mGroup
->Toplevels().RemoveElement(this);
867 if (XRE_IsParentProcess()) {
868 RefPtr
<CanonicalBrowsingContext
> self
{Canonical()};
869 Group()->EachParent([&](ContentParent
* aParent
) {
870 // Only the embedder process is allowed to initiate a BrowsingContext
871 // detach, so if we've gotten here, the host process already knows we've
872 // been detached, and there's no need to tell it again.
874 // If the owner process is not the same as the embedder process, its
875 // BrowsingContext will be detached when its nsWebBrowser instance is
877 bool doDiscard
= !Canonical()->IsEmbeddedInProcess(aParent
->ChildID()) &&
878 !Canonical()->IsOwnedByProcess(aParent
->ChildID());
880 // Hold a strong reference to ourself, and keep our BrowsingContextGroup
881 // alive, until the responses comes back to ensure we don't die while
882 // messages relating to this context are in-flight.
884 // When the callback is called, the keepalive on our group will be
885 // destroyed, and the reference to the BrowsingContext will be dropped,
886 // which may cause it to be fully destroyed.
887 mGroup
->AddKeepAlive();
888 self
->AddPendingDiscard();
889 auto callback
= [self
](auto) {
890 self
->mGroup
->RemoveKeepAlive();
891 self
->RemovePendingDiscard();
894 aParent
->SendDiscardBrowsingContext(this, doDiscard
, callback
, callback
);
897 // Hold a strong reference to ourself until the responses come back to
898 // ensure the BrowsingContext isn't cleaned up before the parent process
899 // acknowledges the discard request.
900 auto callback
= [self
= RefPtr
{this}](auto) {};
901 ContentChild::GetSingleton()->SendDiscardBrowsingContext(
902 this, !aFromIPC
, callback
, callback
);
905 mGroup
->Unregister(this);
906 UnregisterBrowserId(this);
909 if (XRE_IsParentProcess()) {
910 nsFocusManager
* fm
= nsFocusManager::GetFocusManager();
912 fm
->BrowsingContextDetached(this);
916 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
917 // Why the context is being discarded. This will always be "discard" in the
918 // content process, but may be "replace" if it's known the context being
919 // replaced in the parent process.
920 const char16_t
* why
= u
"discard";
921 if (XRE_IsParentProcess() && IsTop() && !Canonical()->GetWebProgress()) {
924 obs
->NotifyObservers(ToSupports(this), "browsing-context-discarded", why
);
927 // NOTE: Doesn't use SetClosed, as it will be set in all processes
928 // automatically by calls to Detach()
929 mFields
.SetWithoutSyncing
<IDX_Closed
>(true);
931 if (GetIsPopupSpam()) {
932 PopupBlocker::UnregisterOpenPopupSpam();
933 // NOTE: Doesn't use SetIsPopupSpam, as it will be set all processes
935 mFields
.SetWithoutSyncing
<IDX_IsPopupSpam
>(false);
938 AssertOriginAttributesMatchPrivateBrowsing();
940 if (XRE_IsParentProcess()) {
941 Canonical()->CanonicalDiscard();
945 void BrowsingContext::AddDiscardListener(
946 std::function
<void(uint64_t)>&& aListener
) {
951 mDiscardListeners
.AppendElement(std::move(aListener
));
954 void BrowsingContext::PrepareForProcessChange() {
955 MOZ_LOG(GetLog(), LogLevel::Debug
,
956 ("%s: Preparing 0x%08" PRIx64
" for a process change",
957 XRE_IsParentProcess() ? "Parent" : "Child", Id()));
959 MOZ_ASSERT(mIsInProcess
, "Must currently be an in-process frame");
960 MOZ_ASSERT(!mIsDiscarded
, "We're already closed?");
962 mIsInProcess
= false;
963 mUserGestureStart
= TimeStamp();
965 // NOTE: For now, clear our nsDocShell reference, as we're primarily in a
966 // different process now. This may need to change in the future with
967 // Cross-Process BFCache.
969 if (mChildSessionHistory
) {
970 // This can be removed once session history is stored exclusively in the
972 mChildSessionHistory
->SetIsInProcess(false);
979 // We have to go through mWindowProxy rather than calling GetDOMWindow() on
980 // mDocShell because the mDocshell reference gets cleared immediately after
981 // the window is closed.
982 nsGlobalWindowOuter::PrepareForProcessChange(mWindowProxy
);
983 MOZ_ASSERT(!mWindowProxy
);
986 bool BrowsingContext::IsTargetable() const {
987 return !GetClosed() && AncestorsAreCurrent();
990 bool BrowsingContext::HasOpener() const {
991 return sBrowsingContexts
->Contains(GetOpenerId());
994 bool BrowsingContext::AncestorsAreCurrent() const {
995 const BrowsingContext
* bc
= this;
997 if (bc
->IsDiscarded()) {
1001 if (WindowContext
* wc
= bc
->GetParentWindowContext()) {
1002 if (!wc
->IsCurrent() || wc
->IsDiscarded()) {
1006 bc
= wc
->GetBrowsingContext();
1013 bool BrowsingContext::IsInBFCache() const {
1014 if (mozilla::SessionHistoryInParent()) {
1015 return mIsInBFCache
;
1017 return mParentWindow
&&
1018 mParentWindow
->TopWindowContext()->GetWindowStateSaved();
1021 Span
<RefPtr
<BrowsingContext
>> BrowsingContext::Children() const {
1022 if (WindowContext
* current
= mCurrentWindowContext
) {
1023 return current
->Children();
1025 return Span
<RefPtr
<BrowsingContext
>>();
1028 void BrowsingContext::GetChildren(
1029 nsTArray
<RefPtr
<BrowsingContext
>>& aChildren
) {
1030 aChildren
.AppendElements(Children());
1033 void BrowsingContext::GetWindowContexts(
1034 nsTArray
<RefPtr
<WindowContext
>>& aWindows
) {
1035 aWindows
.AppendElements(mWindowContexts
);
1038 void BrowsingContext::RegisterWindowContext(WindowContext
* aWindow
) {
1039 MOZ_ASSERT(!mWindowContexts
.Contains(aWindow
),
1040 "WindowContext already registered!");
1041 MOZ_ASSERT(aWindow
->GetBrowsingContext() == this);
1043 mWindowContexts
.AppendElement(aWindow
);
1045 // If the newly registered WindowContext is for our current inner window ID,
1046 // re-run the `DidSet` handler to re-establish the relationship.
1047 if (aWindow
->InnerWindowId() == GetCurrentInnerWindowId()) {
1048 DidSet(FieldIndex
<IDX_CurrentInnerWindowId
>());
1049 MOZ_DIAGNOSTIC_ASSERT(mCurrentWindowContext
== aWindow
);
1053 void BrowsingContext::UnregisterWindowContext(WindowContext
* aWindow
) {
1054 MOZ_ASSERT(mWindowContexts
.Contains(aWindow
),
1055 "WindowContext not registered!");
1056 mWindowContexts
.RemoveElement(aWindow
);
1058 // If our currently active window was unregistered, clear our reference to it.
1059 if (aWindow
== mCurrentWindowContext
) {
1060 // Re-read our `CurrentInnerWindowId` value and use it to set
1061 // `mCurrentWindowContext`. As `aWindow` is now unregistered and discarded,
1062 // we won't find it, and the value will be cleared back to `nullptr`.
1063 DidSet(FieldIndex
<IDX_CurrentInnerWindowId
>());
1064 MOZ_DIAGNOSTIC_ASSERT(mCurrentWindowContext
== nullptr);
1068 void BrowsingContext::PreOrderWalkVoid(
1069 const std::function
<void(BrowsingContext
*)>& aCallback
) {
1072 AutoTArray
<RefPtr
<BrowsingContext
>, 8> children
;
1073 children
.AppendElements(Children());
1075 for (auto& child
: children
) {
1076 child
->PreOrderWalkVoid(aCallback
);
1080 BrowsingContext::WalkFlag
BrowsingContext::PreOrderWalkFlag(
1081 const std::function
<WalkFlag(BrowsingContext
*)>& aCallback
) {
1082 switch (aCallback(this)) {
1083 case WalkFlag::Skip
:
1084 return WalkFlag::Next
;
1085 case WalkFlag::Stop
:
1086 return WalkFlag::Stop
;
1087 case WalkFlag::Next
:
1092 AutoTArray
<RefPtr
<BrowsingContext
>, 8> children
;
1093 children
.AppendElements(Children());
1095 for (auto& child
: children
) {
1096 switch (child
->PreOrderWalkFlag(aCallback
)) {
1097 case WalkFlag::Stop
:
1098 return WalkFlag::Stop
;
1104 return WalkFlag::Next
;
1107 void BrowsingContext::PostOrderWalk(
1108 const std::function
<void(BrowsingContext
*)>& aCallback
) {
1109 AutoTArray
<RefPtr
<BrowsingContext
>, 8> children
;
1110 children
.AppendElements(Children());
1112 for (auto& child
: children
) {
1113 child
->PostOrderWalk(aCallback
);
1119 void BrowsingContext::GetAllBrowsingContextsInSubtree(
1120 nsTArray
<RefPtr
<BrowsingContext
>>& aBrowsingContexts
) {
1121 PreOrderWalk([&](BrowsingContext
* aContext
) {
1122 aBrowsingContexts
.AppendElement(aContext
);
1126 // FindWithName follows the rules for choosing a browsing context,
1127 // with the exception of sandboxing for iframes. The implementation
1128 // for arbitrarily choosing between two browsing contexts with the
1129 // same name is as follows:
1131 // 1) The start browsing context, i.e. 'this'
1132 // 2) Descendants in insertion order
1134 // 4) Siblings and their children, both in insertion order
1135 // 5) After this we iteratively follow the parent chain, repeating 3
1137 // 6) If there is no parent, consider all other top level browsing
1138 // contexts and their children, both in insertion order
1141 // https://html.spec.whatwg.org/multipage/browsers.html#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name
1142 BrowsingContext
* BrowsingContext::FindWithName(
1143 const nsAString
& aName
, bool aUseEntryGlobalForAccessCheck
) {
1144 RefPtr
<BrowsingContext
> requestingContext
= this;
1145 if (aUseEntryGlobalForAccessCheck
) {
1146 if (nsCOMPtr
<nsIDocShell
> caller
= do_GetInterface(GetEntryGlobal())) {
1147 if (caller
->GetBrowsingContext()) {
1148 requestingContext
= caller
->GetBrowsingContext();
1153 BrowsingContext
* found
= nullptr;
1154 if (aName
.IsEmpty()) {
1155 // You can't find a browsing context with an empty name.
1157 } else if (aName
.LowerCaseEqualsLiteral("_blank")) {
1158 // Just return null. Caller must handle creating a new window with
1161 } else if (nsContentUtils::IsSpecialName(aName
)) {
1162 found
= FindWithSpecialName(aName
, *requestingContext
);
1163 } else if (BrowsingContext
* child
=
1164 FindWithNameInSubtree(aName
, *requestingContext
)) {
1167 BrowsingContext
* current
= this;
1170 Span
<RefPtr
<BrowsingContext
>> siblings
;
1171 BrowsingContext
* parent
= current
->GetParent();
1174 // We've reached the root of the tree, consider browsing
1175 // contexts in the same browsing context group.
1176 siblings
= mGroup
->Toplevels();
1177 } else if (parent
->NameEquals(aName
) &&
1178 requestingContext
->CanAccess(parent
) &&
1179 parent
->IsTargetable()) {
1183 siblings
= parent
->Children();
1186 for (BrowsingContext
* sibling
: siblings
) {
1187 if (sibling
== current
) {
1191 if (BrowsingContext
* relative
=
1192 sibling
->FindWithNameInSubtree(aName
, *requestingContext
)) {
1194 // Breaks the outer loop
1204 // Helpers should perform access control checks, which means that we
1205 // only need to assert that we can access found.
1206 MOZ_DIAGNOSTIC_ASSERT(!found
|| requestingContext
->CanAccess(found
));
1211 BrowsingContext
* BrowsingContext::FindChildWithName(
1212 const nsAString
& aName
, BrowsingContext
& aRequestingContext
) {
1213 if (aName
.IsEmpty()) {
1214 // You can't find a browsing context with the empty name.
1218 for (BrowsingContext
* child
: Children()) {
1219 if (child
->NameEquals(aName
) && aRequestingContext
.CanAccess(child
) &&
1220 child
->IsTargetable()) {
1228 BrowsingContext
* BrowsingContext::FindWithSpecialName(
1229 const nsAString
& aName
, BrowsingContext
& aRequestingContext
) {
1230 // TODO(farre): Neither BrowsingContext nor nsDocShell checks if the
1231 // browsing context pointed to by a special name is active. Should
1232 // it be? See Bug 1527913.
1233 if (aName
.LowerCaseEqualsLiteral("_self")) {
1237 if (aName
.LowerCaseEqualsLiteral("_parent")) {
1238 if (BrowsingContext
* parent
= GetParent()) {
1239 return aRequestingContext
.CanAccess(parent
) ? parent
: nullptr;
1244 if (aName
.LowerCaseEqualsLiteral("_top")) {
1245 BrowsingContext
* top
= Top();
1247 return aRequestingContext
.CanAccess(top
) ? top
: nullptr;
1253 BrowsingContext
* BrowsingContext::FindWithNameInSubtree(
1254 const nsAString
& aName
, BrowsingContext
& aRequestingContext
) {
1255 MOZ_DIAGNOSTIC_ASSERT(!aName
.IsEmpty());
1257 if (NameEquals(aName
) && aRequestingContext
.CanAccess(this) &&
1262 for (BrowsingContext
* child
: Children()) {
1263 if (BrowsingContext
* found
=
1264 child
->FindWithNameInSubtree(aName
, aRequestingContext
)) {
1272 // For historical context, see:
1274 // Bug 13871: Prevent frameset spoofing
1275 // Bug 103638: Targets with same name in different windows open in wrong
1276 // window with javascript
1277 // Bug 408052: Adopt "ancestor" frame navigation policy
1278 // Bug 1570207: Refactor logic to rely on BrowsingContextGroups to enforce
1279 // origin attribute isolation.
1280 bool BrowsingContext::CanAccess(BrowsingContext
* aTarget
,
1281 bool aConsiderOpener
) {
1284 "CanAccess() may only be called in the process of the accessing window");
1285 MOZ_ASSERT(aTarget
, "Must have a target");
1287 MOZ_DIAGNOSTIC_ASSERT(
1288 Group() == aTarget
->Group(),
1289 "A BrowsingContext should never see a context from a different group");
1291 // A frame can navigate itself and its own root.
1292 if (aTarget
== this || aTarget
== Top()) {
1296 // A frame can navigate any frame with a same-origin ancestor.
1297 for (BrowsingContext
* bc
= aTarget
; bc
; bc
= bc
->GetParent()) {
1298 if (bc
->mDocShell
&& nsDocShell::ValidateOrigin(this, bc
)) {
1303 // If the target is a top-level document, a frame can navigate it if it can
1304 // navigate its opener.
1305 if (aConsiderOpener
&& !aTarget
->GetParent()) {
1306 if (RefPtr
<BrowsingContext
> opener
= aTarget
->GetOpener()) {
1307 return CanAccess(opener
, false);
1314 bool BrowsingContext::IsSandboxedFrom(BrowsingContext
* aTarget
) {
1315 // If no target then not sandboxed.
1320 // We cannot be sandboxed from ourselves.
1321 if (aTarget
== this) {
1325 // Default the sandbox flags to our flags, so that if we can't retrieve the
1326 // active document, we will still enforce our own.
1327 uint32_t sandboxFlags
= GetSandboxFlags();
1329 if (RefPtr
<Document
> doc
= mDocShell
->GetExtantDocument()) {
1330 sandboxFlags
= doc
->GetSandboxFlags();
1334 // If no flags, we are not sandboxed at all.
1335 if (!sandboxFlags
) {
1339 // If aTarget has an ancestor, it is not top level.
1340 if (RefPtr
<BrowsingContext
> ancestorOfTarget
= aTarget
->GetParent()) {
1342 // We are not sandboxed if we are an ancestor of target.
1343 if (ancestorOfTarget
== this) {
1346 ancestorOfTarget
= ancestorOfTarget
->GetParent();
1347 } while (ancestorOfTarget
);
1349 // Otherwise, we are sandboxed from aTarget.
1353 // aTarget is top level, are we the "one permitted sandboxed
1354 // navigator", i.e. did we open aTarget?
1355 if (aTarget
->GetOnePermittedSandboxedNavigatorId() == Id()) {
1359 // If SANDBOXED_TOPLEVEL_NAVIGATION flag is not on, we are not sandboxed
1361 if (!(sandboxFlags
& SANDBOXED_TOPLEVEL_NAVIGATION
) && aTarget
== Top()) {
1365 // If SANDBOXED_TOPLEVEL_NAVIGATION_USER_ACTIVATION flag is not on, we are not
1366 // sandboxed from our top if we have user interaction. We assume there is a
1367 // valid transient user gesture interaction if this check happens in the
1368 // target process given that we have checked in the triggering process
1370 if (!(sandboxFlags
& SANDBOXED_TOPLEVEL_NAVIGATION_USER_ACTIVATION
) &&
1371 mCurrentWindowContext
&&
1372 (!mCurrentWindowContext
->IsInProcess() ||
1373 mCurrentWindowContext
->HasValidTransientUserGestureActivation()) &&
1378 // Otherwise, we are sandboxed from aTarget.
1382 RefPtr
<SessionStorageManager
> BrowsingContext::GetSessionStorageManager() {
1383 RefPtr
<SessionStorageManager
>& manager
= Top()->mSessionStorageManager
;
1385 manager
= new SessionStorageManager(this);
1390 bool BrowsingContext::CrossOriginIsolated() {
1391 MOZ_ASSERT(NS_IsMainThread());
1393 return StaticPrefs::
1394 dom_postMessage_sharedArrayBuffer_withCOOP_COEP_AtStartup() &&
1395 Top()->GetOpenerPolicy() ==
1397 OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
&&
1398 XRE_IsContentProcess() &&
1399 StringBeginsWith(ContentChild::GetSingleton()->GetRemoteType(),
1400 WITH_COOP_COEP_REMOTE_TYPE_PREFIX
);
1403 void BrowsingContext::SetTriggeringAndInheritPrincipals(
1404 nsIPrincipal
* aTriggeringPrincipal
, nsIPrincipal
* aPrincipalToInherit
,
1405 uint64_t aLoadIdentifier
) {
1406 mTriggeringPrincipal
= Some(
1407 PrincipalWithLoadIdentifierTuple(aTriggeringPrincipal
, aLoadIdentifier
));
1408 if (aPrincipalToInherit
) {
1409 mPrincipalToInherit
= Some(
1410 PrincipalWithLoadIdentifierTuple(aPrincipalToInherit
, aLoadIdentifier
));
1414 Tuple
<nsCOMPtr
<nsIPrincipal
>, nsCOMPtr
<nsIPrincipal
>>
1415 BrowsingContext::GetTriggeringAndInheritPrincipalsForCurrentLoad() {
1416 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
=
1417 GetSavedPrincipal(mTriggeringPrincipal
);
1418 nsCOMPtr
<nsIPrincipal
> principalToInherit
=
1419 GetSavedPrincipal(mPrincipalToInherit
);
1420 return MakeTuple(triggeringPrincipal
, principalToInherit
);
1423 nsIPrincipal
* BrowsingContext::GetSavedPrincipal(
1424 Maybe
<PrincipalWithLoadIdentifierTuple
> aPrincipalTuple
) {
1425 if (aPrincipalTuple
) {
1426 nsCOMPtr
<nsIPrincipal
> principal
;
1427 uint64_t loadIdentifier
;
1428 Tie(principal
, loadIdentifier
) = *aPrincipalTuple
;
1429 // We want to return a principal only if the load identifier for it
1430 // matches the current one for this BC.
1431 if (auto current
= GetCurrentLoadIdentifier();
1432 current
&& *current
== loadIdentifier
) {
1439 BrowsingContext::~BrowsingContext() {
1440 MOZ_DIAGNOSTIC_ASSERT(!mParentWindow
||
1441 !mParentWindow
->mChildren
.Contains(this));
1442 MOZ_DIAGNOSTIC_ASSERT(!mGroup
|| !mGroup
->Toplevels().Contains(this));
1444 mDeprioritizedLoadRunner
.clear();
1446 if (sBrowsingContexts
) {
1447 sBrowsingContexts
->Remove(Id());
1449 UnregisterBrowserId(this);
1453 void BrowsingContext::DiscardFromContentParent(ContentParent
* aCP
) {
1454 MOZ_ASSERT(XRE_IsParentProcess());
1456 if (sBrowsingContexts
) {
1457 AutoTArray
<RefPtr
<BrowsingContext
>, 8> toDiscard
;
1458 for (const auto& data
: sBrowsingContexts
->Values()) {
1459 auto* bc
= data
->Canonical();
1460 if (!bc
->IsDiscarded() && bc
->IsEmbeddedInProcess(aCP
->ChildID())) {
1461 toDiscard
.AppendElement(bc
);
1465 for (BrowsingContext
* bc
: toDiscard
) {
1466 bc
->Detach(/* aFromIPC */ true);
1471 nsISupports
* BrowsingContext::GetParentObject() const {
1472 return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
1475 JSObject
* BrowsingContext::WrapObject(JSContext
* aCx
,
1476 JS::Handle
<JSObject
*> aGivenProto
) {
1477 return BrowsingContext_Binding::Wrap(aCx
, this, aGivenProto
);
1480 bool BrowsingContext::WriteStructuredClone(JSContext
* aCx
,
1481 JSStructuredCloneWriter
* aWriter
,
1482 StructuredCloneHolder
* aHolder
) {
1483 MOZ_DIAGNOSTIC_ASSERT(mEverAttached
);
1484 return (JS_WriteUint32Pair(aWriter
, SCTAG_DOM_BROWSING_CONTEXT
, 0) &&
1485 JS_WriteUint32Pair(aWriter
, uint32_t(Id()), uint32_t(Id() >> 32)));
1489 JSObject
* BrowsingContext::ReadStructuredClone(JSContext
* aCx
,
1490 JSStructuredCloneReader
* aReader
,
1491 StructuredCloneHolder
* aHolder
) {
1493 uint32_t idHigh
= 0;
1494 if (!JS_ReadUint32Pair(aReader
, &idLow
, &idHigh
)) {
1497 uint64_t id
= uint64_t(idHigh
) << 32 | idLow
;
1499 // Note: Do this check after reading our ID data. Returning null will abort
1500 // the decode operation anyway, but we should at least be as safe as possible.
1501 if (NS_WARN_IF(!NS_IsMainThread())) {
1502 MOZ_DIAGNOSTIC_ASSERT(false,
1503 "We shouldn't be trying to decode a BrowsingContext "
1504 "on a background thread.");
1508 JS::RootedValue
val(aCx
, JS::NullValue());
1509 // We'll get rooting hazard errors from the RefPtr destructor if it isn't
1510 // destroyed before we try to return a raw JSObject*, so create it in its own
1512 if (RefPtr
<BrowsingContext
> context
= Get(id
)) {
1513 if (!GetOrCreateDOMReflector(aCx
, context
, &val
) || !val
.isObject()) {
1517 return val
.toObjectOrNull();
1520 bool BrowsingContext::CanSetOriginAttributes() {
1521 // A discarded BrowsingContext has already been destroyed, and cannot modify
1522 // its OriginAttributes.
1523 if (NS_WARN_IF(IsDiscarded())) {
1527 // Before attaching is the safest time to set OriginAttributes, and the only
1528 // allowed time for content BrowsingContexts.
1529 if (!EverAttached()) {
1533 // Attached content BrowsingContexts may have been synced to other processes.
1534 if (NS_WARN_IF(IsContent())) {
1538 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
1540 // Cannot set OriginAttributes after we've created our child BrowsingContext.
1541 if (NS_WARN_IF(!Children().IsEmpty())) {
1545 // Only allow setting OriginAttributes if we have no associated document, or
1546 // the document is still `about:blank`.
1547 // TODO: Bug 1273058 - should have no document when setting origin attributes.
1548 if (WindowGlobalParent
* window
= Canonical()->GetCurrentWindowGlobal()) {
1549 if (nsIURI
* uri
= window
->GetDocumentURI()) {
1550 MOZ_ASSERT(NS_IsAboutBlank(uri
));
1551 return NS_IsAboutBlank(uri
);
1557 Nullable
<WindowProxyHolder
> BrowsingContext::GetAssociatedWindow() {
1558 // nsILoadContext usually only returns same-process windows,
1559 // so we intentionally return nullptr if this BC is out of
1561 if (IsInProcess()) {
1562 return WindowProxyHolder(this);
1567 Nullable
<WindowProxyHolder
> BrowsingContext::GetTopWindow() {
1568 return Top()->GetAssociatedWindow();
1571 Element
* BrowsingContext::GetTopFrameElement() {
1572 return Top()->GetEmbedderElement();
1575 void BrowsingContext::SetUsePrivateBrowsing(bool aUsePrivateBrowsing
,
1576 ErrorResult
& aError
) {
1577 nsresult rv
= SetUsePrivateBrowsing(aUsePrivateBrowsing
);
1578 if (NS_FAILED(rv
)) {
1583 void BrowsingContext::SetUseTrackingProtectionWebIDL(
1584 bool aUseTrackingProtection
, ErrorResult
& aRv
) {
1585 SetForceEnableTrackingProtection(aUseTrackingProtection
, aRv
);
1588 void BrowsingContext::GetOriginAttributes(JSContext
* aCx
,
1589 JS::MutableHandle
<JS::Value
> aVal
,
1590 ErrorResult
& aError
) {
1591 AssertOriginAttributesMatchPrivateBrowsing();
1593 if (!ToJSValue(aCx
, mOriginAttributes
, aVal
)) {
1594 aError
.NoteJSContextException(aCx
);
1598 NS_IMETHODIMP
BrowsingContext::GetAssociatedWindow(
1599 mozIDOMWindowProxy
** aAssociatedWindow
) {
1600 nsCOMPtr
<mozIDOMWindowProxy
> win
= GetDOMWindow();
1601 win
.forget(aAssociatedWindow
);
1605 NS_IMETHODIMP
BrowsingContext::GetTopWindow(mozIDOMWindowProxy
** aTopWindow
) {
1606 return Top()->GetAssociatedWindow(aTopWindow
);
1609 NS_IMETHODIMP
BrowsingContext::GetTopFrameElement(Element
** aTopFrameElement
) {
1610 RefPtr
<Element
> topFrameElement
= GetTopFrameElement();
1611 topFrameElement
.forget(aTopFrameElement
);
1615 NS_IMETHODIMP
BrowsingContext::GetIsContent(bool* aIsContent
) {
1616 *aIsContent
= IsContent();
1620 NS_IMETHODIMP
BrowsingContext::GetUsePrivateBrowsing(
1621 bool* aUsePrivateBrowsing
) {
1622 *aUsePrivateBrowsing
= mPrivateBrowsingId
> 0;
1626 NS_IMETHODIMP
BrowsingContext::SetUsePrivateBrowsing(bool aUsePrivateBrowsing
) {
1627 if (!CanSetOriginAttributes()) {
1628 bool changed
= aUsePrivateBrowsing
!= (mPrivateBrowsingId
> 0);
1630 NS_WARNING("SetUsePrivateBrowsing when !CanSetOriginAttributes()");
1632 return changed
? NS_ERROR_FAILURE
: NS_OK
;
1635 return SetPrivateBrowsing(aUsePrivateBrowsing
);
1638 NS_IMETHODIMP
BrowsingContext::SetPrivateBrowsing(bool aPrivateBrowsing
) {
1639 if (!CanSetOriginAttributes()) {
1640 NS_WARNING("Attempt to set PrivateBrowsing when !CanSetOriginAttributes");
1641 return NS_ERROR_FAILURE
;
1644 bool changed
= aPrivateBrowsing
!= (mPrivateBrowsingId
> 0);
1646 mPrivateBrowsingId
= aPrivateBrowsing
? 1 : 0;
1648 mOriginAttributes
.SyncAttributesWithPrivateBrowsing(aPrivateBrowsing
);
1651 if (XRE_IsParentProcess()) {
1652 Canonical()->AdjustPrivateBrowsingCount(aPrivateBrowsing
);
1655 AssertOriginAttributesMatchPrivateBrowsing();
1657 if (changed
&& mDocShell
) {
1658 nsDocShell::Cast(mDocShell
)->NotifyPrivateBrowsingChanged();
1663 NS_IMETHODIMP
BrowsingContext::GetUseRemoteTabs(bool* aUseRemoteTabs
) {
1664 *aUseRemoteTabs
= mUseRemoteTabs
;
1668 NS_IMETHODIMP
BrowsingContext::SetRemoteTabs(bool aUseRemoteTabs
) {
1669 if (!CanSetOriginAttributes()) {
1670 NS_WARNING("Attempt to set RemoteTabs when !CanSetOriginAttributes");
1671 return NS_ERROR_FAILURE
;
1674 static bool annotated
= false;
1675 if (aUseRemoteTabs
&& !annotated
) {
1677 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::DOMIPCEnabled
,
1681 // Don't allow non-remote tabs with remote subframes.
1682 if (NS_WARN_IF(!aUseRemoteTabs
&& mUseRemoteSubframes
)) {
1683 return NS_ERROR_UNEXPECTED
;
1686 mUseRemoteTabs
= aUseRemoteTabs
;
1690 NS_IMETHODIMP
BrowsingContext::GetUseRemoteSubframes(
1691 bool* aUseRemoteSubframes
) {
1692 *aUseRemoteSubframes
= mUseRemoteSubframes
;
1696 NS_IMETHODIMP
BrowsingContext::SetRemoteSubframes(bool aUseRemoteSubframes
) {
1697 if (!CanSetOriginAttributes()) {
1698 NS_WARNING("Attempt to set RemoteSubframes when !CanSetOriginAttributes");
1699 return NS_ERROR_FAILURE
;
1702 static bool annotated
= false;
1703 if (aUseRemoteSubframes
&& !annotated
) {
1705 CrashReporter::AnnotateCrashReport(
1706 CrashReporter::Annotation::DOMFissionEnabled
, true);
1709 // Don't allow non-remote tabs with remote subframes.
1710 if (NS_WARN_IF(aUseRemoteSubframes
&& !mUseRemoteTabs
)) {
1711 return NS_ERROR_UNEXPECTED
;
1714 mUseRemoteSubframes
= aUseRemoteSubframes
;
1718 NS_IMETHODIMP
BrowsingContext::GetUseTrackingProtection(
1719 bool* aUseTrackingProtection
) {
1720 *aUseTrackingProtection
= false;
1722 if (GetForceEnableTrackingProtection() ||
1723 StaticPrefs::privacy_trackingprotection_enabled() ||
1724 (UsePrivateBrowsing() &&
1725 StaticPrefs::privacy_trackingprotection_pbmode_enabled())) {
1726 *aUseTrackingProtection
= true;
1731 return GetParent()->GetUseTrackingProtection(aUseTrackingProtection
);
1737 NS_IMETHODIMP
BrowsingContext::SetUseTrackingProtection(
1738 bool aUseTrackingProtection
) {
1739 return SetForceEnableTrackingProtection(aUseTrackingProtection
);
1742 NS_IMETHODIMP
BrowsingContext::GetScriptableOriginAttributes(
1743 JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aVal
) {
1744 AssertOriginAttributesMatchPrivateBrowsing();
1746 bool ok
= ToJSValue(aCx
, mOriginAttributes
, aVal
);
1747 NS_ENSURE_TRUE(ok
, NS_ERROR_FAILURE
);
1751 NS_IMETHODIMP_(void)
1752 BrowsingContext::GetOriginAttributes(OriginAttributes
& aAttrs
) {
1753 aAttrs
= mOriginAttributes
;
1754 AssertOriginAttributesMatchPrivateBrowsing();
1757 nsresult
BrowsingContext::SetOriginAttributes(const OriginAttributes
& aAttrs
) {
1758 if (!CanSetOriginAttributes()) {
1759 NS_WARNING("Attempt to set OriginAttributes when !CanSetOriginAttributes");
1760 return NS_ERROR_FAILURE
;
1763 AssertOriginAttributesMatchPrivateBrowsing();
1764 mOriginAttributes
= aAttrs
;
1766 bool isPrivate
= mOriginAttributes
.mPrivateBrowsingId
!=
1767 nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID
;
1768 // Chrome Browsing Context can not contain OriginAttributes.mPrivateBrowsingId
1769 if (IsChrome() && isPrivate
) {
1770 mOriginAttributes
.mPrivateBrowsingId
=
1771 nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID
;
1773 SetPrivateBrowsing(isPrivate
);
1774 AssertOriginAttributesMatchPrivateBrowsing();
1779 void BrowsingContext::AssertCoherentLoadContext() {
1780 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1781 // LoadContext should generally match our opener or parent.
1783 if (RefPtr
<BrowsingContext
> opener
= GetOpener()) {
1784 MOZ_DIAGNOSTIC_ASSERT(opener
->mType
== mType
);
1785 MOZ_DIAGNOSTIC_ASSERT(opener
->mGroup
== mGroup
);
1786 MOZ_DIAGNOSTIC_ASSERT(opener
->mUseRemoteTabs
== mUseRemoteTabs
);
1787 MOZ_DIAGNOSTIC_ASSERT(opener
->mUseRemoteSubframes
== mUseRemoteSubframes
);
1788 MOZ_DIAGNOSTIC_ASSERT(opener
->mPrivateBrowsingId
== mPrivateBrowsingId
);
1789 MOZ_DIAGNOSTIC_ASSERT(
1790 opener
->mOriginAttributes
.EqualsIgnoringFPD(mOriginAttributes
));
1793 if (RefPtr
<BrowsingContext
> parent
= GetParent()) {
1794 MOZ_DIAGNOSTIC_ASSERT(parent
->mType
== mType
);
1795 MOZ_DIAGNOSTIC_ASSERT(parent
->mGroup
== mGroup
);
1796 MOZ_DIAGNOSTIC_ASSERT(parent
->mUseRemoteTabs
== mUseRemoteTabs
);
1797 MOZ_DIAGNOSTIC_ASSERT(parent
->mUseRemoteSubframes
== mUseRemoteSubframes
);
1798 MOZ_DIAGNOSTIC_ASSERT(parent
->mPrivateBrowsingId
== mPrivateBrowsingId
);
1799 MOZ_DIAGNOSTIC_ASSERT(
1800 parent
->mOriginAttributes
.EqualsIgnoringFPD(mOriginAttributes
));
1803 // UseRemoteSubframes and UseRemoteTabs must match.
1804 MOZ_DIAGNOSTIC_ASSERT(
1805 !mUseRemoteSubframes
|| mUseRemoteTabs
,
1806 "Cannot set useRemoteSubframes without also setting useRemoteTabs");
1808 // Double-check OriginAttributes/Private Browsing
1809 AssertOriginAttributesMatchPrivateBrowsing();
1813 void BrowsingContext::AssertOriginAttributesMatchPrivateBrowsing() {
1814 // Chrome browsing contexts must not have a private browsing OriginAttribute
1815 // Content browsing contexts must maintain the equality:
1816 // mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId
1818 MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes
.mPrivateBrowsingId
== 0);
1820 MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes
.mPrivateBrowsingId
==
1821 mPrivateBrowsingId
);
1825 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowsingContext
)
1826 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1827 NS_INTERFACE_MAP_ENTRY(nsILoadContext
)
1828 NS_INTERFACE_MAP_ENTRY(nsISupports
)
1829 NS_INTERFACE_MAP_END
1831 NS_IMPL_CYCLE_COLLECTION_CLASS(BrowsingContext
)
1833 NS_IMPL_CYCLE_COLLECTING_ADDREF(BrowsingContext
)
1834 NS_IMPL_CYCLE_COLLECTING_RELEASE(BrowsingContext
)
1836 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(BrowsingContext
)
1837 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
1838 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1840 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowsingContext
)
1841 if (sBrowsingContexts
) {
1842 sBrowsingContexts
->Remove(tmp
->Id());
1844 UnregisterBrowserId(tmp
);
1846 if (tmp
->GetIsPopupSpam()) {
1847 PopupBlocker::UnregisterOpenPopupSpam();
1848 // NOTE: Doesn't use SetIsPopupSpam, as it will be set all processes
1850 tmp
->mFields
.SetWithoutSyncing
<IDX_IsPopupSpam
>(false);
1853 NS_IMPL_CYCLE_COLLECTION_UNLINK(
1854 mDocShell
, mParentWindow
, mGroup
, mEmbedderElement
, mWindowContexts
,
1855 mCurrentWindowContext
, mSessionStorageManager
, mChildSessionHistory
)
1856 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
1857 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1859 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowsingContext
)
1860 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
1861 mDocShell
, mParentWindow
, mGroup
, mEmbedderElement
, mWindowContexts
,
1862 mCurrentWindowContext
, mSessionStorageManager
, mChildSessionHistory
)
1863 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1865 static bool IsCertainlyAliveForCC(BrowsingContext
* aContext
) {
1866 return aContext
->HasKnownLiveWrapper() ||
1867 (AppShutdown::GetCurrentShutdownPhase() ==
1868 ShutdownPhase::NotInShutdown
&&
1869 aContext
->EverAttached() && !aContext
->IsDiscarded());
1872 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(BrowsingContext
)
1873 if (IsCertainlyAliveForCC(tmp
)) {
1874 if (tmp
->PreservingWrapper()) {
1875 tmp
->MarkWrapperLive();
1879 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
1881 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(BrowsingContext
)
1882 return IsCertainlyAliveForCC(tmp
) && tmp
->HasNothingToTrace(tmp
);
1883 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
1885 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(BrowsingContext
)
1886 return IsCertainlyAliveForCC(tmp
);
1887 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
1889 class RemoteLocationProxy
1890 : public RemoteObjectProxy
<BrowsingContext::LocationProxy
,
1891 Location_Binding::sCrossOriginProperties
> {
1893 typedef RemoteObjectProxy Base
;
1895 constexpr RemoteLocationProxy()
1896 : RemoteObjectProxy(prototypes::id::Location
) {}
1898 void NoteChildren(JSObject
* aProxy
,
1899 nsCycleCollectionTraversalCallback
& aCb
) const override
{
1901 static_cast<BrowsingContext::LocationProxy
*>(GetNative(aProxy
));
1902 CycleCollectionNoteChild(aCb
, location
->GetBrowsingContext(),
1903 "JS::GetPrivate(obj)->GetBrowsingContext()");
1907 static const RemoteLocationProxy sSingleton
;
1909 // Give RemoteLocationProxy 2 reserved slots, like the other wrappers,
1910 // so JSObject::swap can swap it with CrossCompartmentWrappers without requiring
1913 const JSClass
RemoteLocationProxy::Base::sClass
=
1914 PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
1916 void BrowsingContext::Location(JSContext
* aCx
,
1917 JS::MutableHandle
<JSObject
*> aLocation
,
1918 ErrorResult
& aError
) {
1919 aError
.MightThrowJSException();
1920 sSingleton
.GetProxyObject(aCx
, &mLocation
, /* aTransplantTo = */ nullptr,
1923 aError
.StealExceptionFromJSContext(aCx
);
1927 bool BrowsingContext::RemoveRootFromBFCacheSync() {
1928 if (WindowContext
* wc
= GetParentWindowContext()) {
1929 if (RefPtr
<Document
> doc
= wc
->TopWindowContext()->GetDocument()) {
1930 return doc
->RemoveFromBFCacheSync();
1936 nsresult
BrowsingContext::CheckSandboxFlags(nsDocShellLoadState
* aLoadState
) {
1937 const auto& sourceBC
= aLoadState
->SourceBrowsingContext();
1938 if (sourceBC
.IsNull()) {
1942 // We might be called after the source BC has been discarded, but before we've
1943 // destroyed our in-process instance of the BrowsingContext object in some
1944 // situations (e.g. after creating a new pop-up with window.open while the
1945 // window is being closed). In these situations we want to still perform the
1946 // sandboxing check against our in-process copy. If we've forgotten about the
1947 // context already, assume it is sanboxed. (bug 1643450)
1948 BrowsingContext
* bc
= sourceBC
.GetMaybeDiscarded();
1949 if (!bc
|| bc
->IsSandboxedFrom(this)) {
1950 return NS_ERROR_DOM_SECURITY_ERR
;
1955 nsresult
BrowsingContext::LoadURI(nsDocShellLoadState
* aLoadState
,
1956 bool aSetNavigating
) {
1957 // Per spec, most load attempts are silently ignored when a BrowsingContext is
1958 // null (which in our code corresponds to discarded), so we simply fail
1959 // silently in those cases. Regardless, we cannot trigger loads in/from
1960 // discarded BrowsingContexts via IPC, so we need to abort in any case.
1961 if (IsDiscarded()) {
1965 MOZ_DIAGNOSTIC_ASSERT(aLoadState
->TargetBrowsingContext().IsNull(),
1966 "Targeting occurs in InternalLoad");
1969 return mDocShell
->LoadURI(aLoadState
, aSetNavigating
);
1972 // Note: We do this check both here and in `nsDocShell::InternalLoad`, since
1973 // document-specific sandbox flags are only available in the process
1974 // triggering the load, and we don't want the target process to have to trust
1975 // the triggering process to do the appropriate checks for the
1976 // BrowsingContext's sandbox flags.
1977 MOZ_TRY(CheckSandboxFlags(aLoadState
));
1978 SetTriggeringAndInheritPrincipals(aLoadState
->TriggeringPrincipal(),
1979 aLoadState
->PrincipalToInherit(),
1980 aLoadState
->GetLoadIdentifier());
1982 const auto& sourceBC
= aLoadState
->SourceBrowsingContext();
1984 if (net::SchemeIsJavascript(aLoadState
->URI())) {
1985 if (!XRE_IsParentProcess()) {
1986 // Web content should only be able to load javascript: URIs into documents
1987 // whose principals the caller principal subsumes, which by definition
1988 // excludes any document in a cross-process BrowsingContext.
1989 return NS_ERROR_DOM_BAD_CROSS_ORIGIN_URI
;
1991 MOZ_DIAGNOSTIC_ASSERT(!sourceBC
,
1992 "Should never see a cross-process javascript: load "
1993 "triggered from content");
1996 MOZ_DIAGNOSTIC_ASSERT(!sourceBC
|| sourceBC
->Group() == Group());
1997 if (sourceBC
&& sourceBC
->IsInProcess()) {
1998 if (!sourceBC
->CanAccess(this)) {
1999 return NS_ERROR_DOM_PROP_ACCESS_DENIED
;
2002 nsCOMPtr
<nsPIDOMWindowOuter
> win(sourceBC
->GetDOMWindow());
2003 if (WindowGlobalChild
* wgc
=
2004 win
->GetCurrentInnerWindow()->GetWindowGlobalChild()) {
2005 wgc
->SendLoadURI(this, aLoadState
, aSetNavigating
);
2007 } else if (XRE_IsParentProcess()) {
2008 // Strip the target query parameters before loading the URI in the parent.
2009 // The loading in content will be handled in nsDocShell.
2010 aLoadState
->MaybeStripTrackerQueryStrings(this);
2012 if (Canonical()->LoadInParent(aLoadState
, aSetNavigating
)) {
2016 if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2017 // Attempt to initiate this load immediately in the parent, if it succeeds
2018 // it'll return a unique identifier so that we can find it later.
2019 uint64_t loadIdentifier
= 0;
2020 if (Canonical()->AttemptSpeculativeLoadInParent(aLoadState
)) {
2021 MOZ_DIAGNOSTIC_ASSERT(GetCurrentLoadIdentifier().isSome());
2022 loadIdentifier
= GetCurrentLoadIdentifier().value();
2023 aLoadState
->SetChannelInitialized(true);
2026 cp
->TransmitBlobDataIfBlobURL(aLoadState
->URI());
2028 // Setup a confirmation callback once the content process receives this
2029 // load. Normally we'd expect a PDocumentChannel actor to have been
2030 // created to claim the load identifier by that time. If not, then it
2031 // won't be coming, so make sure we clean up and deregister.
2032 cp
->SendLoadURI(this, aLoadState
, aSetNavigating
)
2033 ->Then(GetMainThreadSerialEventTarget(), __func__
,
2035 const PContentParent::LoadURIPromise::ResolveOrRejectValue
&
2037 if (loadIdentifier
) {
2038 net::DocumentLoadListener::CleanupParentLoadAttempt(
2044 MOZ_DIAGNOSTIC_ASSERT(sourceBC
);
2046 return NS_ERROR_UNEXPECTED
;
2048 // If we're in a content process and the source BC is no longer in-process,
2049 // just fail silently.
2054 nsresult
BrowsingContext::InternalLoad(nsDocShellLoadState
* aLoadState
) {
2055 if (IsDiscarded()) {
2058 SetTriggeringAndInheritPrincipals(aLoadState
->TriggeringPrincipal(),
2059 aLoadState
->PrincipalToInherit(),
2060 aLoadState
->GetLoadIdentifier());
2062 MOZ_DIAGNOSTIC_ASSERT(aLoadState
->Target().IsEmpty(),
2063 "should already have retargeted");
2064 MOZ_DIAGNOSTIC_ASSERT(!aLoadState
->TargetBrowsingContext().IsNull(),
2065 "should have target bc set");
2066 MOZ_DIAGNOSTIC_ASSERT(aLoadState
->TargetBrowsingContext() == this,
2067 "must be targeting this BrowsingContext");
2070 return nsDocShell::Cast(mDocShell
)->InternalLoad(aLoadState
);
2073 // Note: We do this check both here and in `nsDocShell::InternalLoad`, since
2074 // document-specific sandbox flags are only available in the process
2075 // triggering the load, and we don't want the target process to have to trust
2076 // the triggering process to do the appropriate checks for the
2077 // BrowsingContext's sandbox flags.
2078 MOZ_TRY(CheckSandboxFlags(aLoadState
));
2080 const auto& sourceBC
= aLoadState
->SourceBrowsingContext();
2082 if (net::SchemeIsJavascript(aLoadState
->URI())) {
2083 if (!XRE_IsParentProcess()) {
2084 // Web content should only be able to load javascript: URIs into documents
2085 // whose principals the caller principal subsumes, which by definition
2086 // excludes any document in a cross-process BrowsingContext.
2087 return NS_ERROR_DOM_BAD_CROSS_ORIGIN_URI
;
2089 MOZ_DIAGNOSTIC_ASSERT(!sourceBC
,
2090 "Should never see a cross-process javascript: load "
2091 "triggered from content");
2094 if (XRE_IsParentProcess()) {
2095 ContentParent
* cp
= Canonical()->GetContentParent();
2096 if (!cp
|| !cp
->CanSend()) {
2097 return NS_ERROR_FAILURE
;
2100 MOZ_ALWAYS_SUCCEEDS(
2101 SetCurrentLoadIdentifier(Some(aLoadState
->GetLoadIdentifier())));
2102 Unused
<< cp
->SendInternalLoad(aLoadState
);
2104 MOZ_DIAGNOSTIC_ASSERT(sourceBC
);
2105 MOZ_DIAGNOSTIC_ASSERT(sourceBC
->Group() == Group());
2107 if (!sourceBC
->CanAccess(this)) {
2108 return NS_ERROR_DOM_PROP_ACCESS_DENIED
;
2111 nsCOMPtr
<nsPIDOMWindowOuter
> win(sourceBC
->GetDOMWindow());
2112 WindowGlobalChild
* wgc
=
2113 win
->GetCurrentInnerWindow()->GetWindowGlobalChild();
2114 if (!wgc
|| !wgc
->CanSend()) {
2115 return NS_ERROR_FAILURE
;
2118 MOZ_ALWAYS_SUCCEEDS(
2119 SetCurrentLoadIdentifier(Some(aLoadState
->GetLoadIdentifier())));
2120 wgc
->SendInternalLoad(aLoadState
);
2126 void BrowsingContext::DisplayLoadError(const nsAString
& aURI
) {
2127 MOZ_LOG(GetLog(), LogLevel::Debug
, ("DisplayLoadError"));
2128 MOZ_DIAGNOSTIC_ASSERT(!IsDiscarded());
2129 MOZ_DIAGNOSTIC_ASSERT(mDocShell
|| XRE_IsParentProcess());
2132 bool didDisplayLoadError
= false;
2133 mDocShell
->DisplayLoadError(NS_ERROR_MALFORMED_URI
, nullptr,
2134 PromiseFlatString(aURI
).get(), nullptr,
2135 &didDisplayLoadError
);
2137 if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2138 Unused
<< cp
->SendDisplayLoadError(this, PromiseFlatString(aURI
));
2143 WindowProxyHolder
BrowsingContext::Window() {
2144 return WindowProxyHolder(Self());
2147 WindowProxyHolder
BrowsingContext::GetFrames(ErrorResult
& aError
) {
2151 void BrowsingContext::Close(CallerType aCallerType
, ErrorResult
& aError
) {
2157 // .close() on frames is a no-op.
2161 if (GetDOMWindow()) {
2162 nsGlobalWindowOuter::Cast(GetDOMWindow())
2163 ->CloseOuter(aCallerType
== CallerType::System
);
2167 // This is a bit of a hack for webcompat. Content needs to see an updated
2168 // |window.closed| value as early as possible, so we set this before we
2169 // actually send the DOMWindowClose event, which happens in the process where
2170 // the document for this browsing context is loaded.
2171 MOZ_ALWAYS_SUCCEEDS(SetClosed(true));
2173 if (ContentChild
* cc
= ContentChild::GetSingleton()) {
2174 cc
->SendWindowClose(this, aCallerType
== CallerType::System
);
2175 } else if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2176 Unused
<< cp
->SendWindowClose(this, aCallerType
== CallerType::System
);
2181 * Examine the current document state to see if we're in a way that is
2182 * typically abused by web designers. The window.open code uses this
2183 * routine to determine whether to allow the new window.
2184 * Returns a value from the PopupControlState enum.
2186 PopupBlocker::PopupControlState
BrowsingContext::RevisePopupAbuseLevel(
2187 PopupBlocker::PopupControlState aControl
) {
2189 return PopupBlocker::openAllowed
;
2192 RefPtr
<Document
> doc
= GetExtantDocument();
2193 PopupBlocker::PopupControlState abuse
= aControl
;
2195 case PopupBlocker::openControlled
:
2196 case PopupBlocker::openBlocked
:
2197 case PopupBlocker::openOverridden
:
2198 if (IsPopupAllowed()) {
2199 abuse
= PopupBlocker::PopupControlState(abuse
- 1);
2202 case PopupBlocker::openAbused
:
2203 if (IsPopupAllowed() ||
2204 (doc
&& doc
->HasValidTransientUserGestureActivation())) {
2205 // Skip PopupBlocker::openBlocked
2206 abuse
= PopupBlocker::openControlled
;
2209 case PopupBlocker::openAllowed
:
2212 NS_WARNING("Strange PopupControlState!");
2215 // limit the number of simultaneously open popups
2216 if (abuse
== PopupBlocker::openAbused
|| abuse
== PopupBlocker::openBlocked
||
2217 abuse
== PopupBlocker::openControlled
) {
2218 int32_t popupMax
= StaticPrefs::dom_popup_maximum();
2219 if (popupMax
>= 0 &&
2220 PopupBlocker::GetOpenPopupSpamCount() >= (uint32_t)popupMax
) {
2221 abuse
= PopupBlocker::openOverridden
;
2225 // If we're currently in-process, attempt to consume transient user gesture
2228 // HACK: Some pages using bogus library + UA sniffing call window.open()
2229 // from a blank iframe, only on Firefox, see bug 1685056.
2231 // This is a hack-around to preserve behavior in that particular and
2232 // specific case, by consuming activation on the parent document, so we
2233 // don't care about the InProcessParent bits not being fission-safe or what
2235 auto ConsumeTransientUserActivationForMultiplePopupBlocking
=
2237 if (doc
->ConsumeTransientUserGestureActivation()) {
2240 if (!doc
->IsInitialDocument()) {
2243 Document
* parentDoc
= doc
->GetInProcessParentDocument();
2245 !parentDoc
->NodePrincipal()->Equals(doc
->NodePrincipal())) {
2248 return parentDoc
->ConsumeTransientUserGestureActivation();
2251 // If this popup is allowed, let's block any other for this event, forcing
2252 // PopupBlocker::openBlocked state.
2253 if ((abuse
== PopupBlocker::openAllowed
||
2254 abuse
== PopupBlocker::openControlled
) &&
2255 StaticPrefs::dom_block_multiple_popups() && !IsPopupAllowed() &&
2256 !ConsumeTransientUserActivationForMultiplePopupBlocking()) {
2257 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
, "DOM"_ns
,
2258 doc
, nsContentUtils::eDOM_PROPERTIES
,
2259 "MultiplePopupsBlockedNoUserActivation");
2260 abuse
= PopupBlocker::openBlocked
;
2267 void BrowsingContext::IncrementHistoryEntryCountForBrowsingContext() {
2268 Unused
<< SetHistoryEntryCount(GetHistoryEntryCount() + 1);
2271 void BrowsingContext::FlushSessionStore() {
2272 nsTArray
<RefPtr
<BrowserChild
>> nestedBrowserChilds
;
2274 PreOrderWalk([&](BrowsingContext
* aContext
) {
2275 BrowserChild
* browserChild
= BrowserChild::GetFrom(aContext
->GetDocShell());
2276 if (browserChild
&& browserChild
->GetBrowsingContext() == aContext
) {
2277 nestedBrowserChilds
.AppendElement(browserChild
);
2280 if (aContext
->CreatedDynamically()) {
2281 return WalkFlag::Skip
;
2284 WindowContext
* windowContext
= aContext
->GetCurrentWindowContext();
2285 if (!windowContext
) {
2286 return WalkFlag::Skip
;
2289 WindowGlobalChild
* windowChild
= windowContext
->GetWindowGlobalChild();
2291 return WalkFlag::Next
;
2294 RefPtr
<SessionStoreDataCollector
> collector
=
2295 windowChild
->GetSessionStoreDataCollector();
2297 return WalkFlag::Next
;
2301 return WalkFlag::Next
;
2304 for (auto& child
: nestedBrowserChilds
) {
2305 child
->UpdateSessionStore();
2309 std::tuple
<bool, bool> BrowsingContext::CanFocusCheck(CallerType aCallerType
) {
2310 nsFocusManager
* fm
= nsFocusManager::GetFocusManager();
2312 return {false, false};
2315 nsCOMPtr
<nsPIDOMWindowInner
> caller
= do_QueryInterface(GetEntryGlobal());
2316 BrowsingContext
* callerBC
= caller
? caller
->GetBrowsingContext() : nullptr;
2317 RefPtr
<BrowsingContext
> openerBC
= GetOpener();
2318 MOZ_DIAGNOSTIC_ASSERT(!openerBC
|| openerBC
->Group() == Group());
2320 // Enforce dom.disable_window_flip (for non-chrome), but still allow the
2321 // window which opened us to raise us at times when popups are allowed
2322 // (bugs 355482 and 369306).
2323 bool canFocus
= aCallerType
== CallerType::System
||
2324 !Preferences::GetBool("dom.disable_window_flip", true);
2325 if (!canFocus
&& openerBC
== callerBC
) {
2327 (callerBC
? callerBC
: this)
2328 ->RevisePopupAbuseLevel(PopupBlocker::GetPopupControlState()) <
2329 PopupBlocker::openBlocked
;
2332 bool isActive
= false;
2333 if (XRE_IsParentProcess()) {
2334 RefPtr
<CanonicalBrowsingContext
> chromeTop
=
2335 Canonical()->TopCrossChromeBoundary();
2336 nsCOMPtr
<nsPIDOMWindowOuter
> activeWindow
= fm
->GetActiveWindow();
2337 isActive
= (activeWindow
== chromeTop
->GetDOMWindow());
2339 isActive
= (fm
->GetActiveBrowsingContext() == Top());
2342 return {canFocus
, isActive
};
2345 void BrowsingContext::Focus(CallerType aCallerType
, ErrorResult
& aError
) {
2346 // These checks need to happen before the RequestFrameFocus call, which
2347 // is why they are done in an untrusted process. If we wanted to enforce
2348 // these in the parent, we'd need to do the checks there _also_.
2349 // These should be kept in sync with nsGlobalWindowOuter::FocusOuter.
2351 auto [canFocus
, isActive
] = CanFocusCheck(aCallerType
);
2353 if (!(canFocus
|| isActive
)) {
2357 // Permission check passed
2359 if (mEmbedderElement
) {
2360 // Make the activeElement in this process update synchronously.
2361 nsContentUtils::RequestFrameFocus(*mEmbedderElement
, true, aCallerType
);
2363 uint64_t actionId
= nsFocusManager::GenerateFocusActionId();
2364 if (ContentChild
* cc
= ContentChild::GetSingleton()) {
2365 cc
->SendWindowFocus(this, aCallerType
, actionId
);
2366 } else if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2367 Unused
<< cp
->SendWindowFocus(this, aCallerType
, actionId
);
2371 bool BrowsingContext::CanBlurCheck(CallerType aCallerType
) {
2372 // If dom.disable_window_flip == true, then content should not be allowed
2373 // to do blur (this would allow popunders, bug 369306)
2374 return aCallerType
== CallerType::System
||
2375 !Preferences::GetBool("dom.disable_window_flip", true);
2378 void BrowsingContext::Blur(CallerType aCallerType
, ErrorResult
& aError
) {
2379 if (!CanBlurCheck(aCallerType
)) {
2383 if (ContentChild
* cc
= ContentChild::GetSingleton()) {
2384 cc
->SendWindowBlur(this, aCallerType
);
2385 } else if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2386 Unused
<< cp
->SendWindowBlur(this, aCallerType
);
2390 Nullable
<WindowProxyHolder
> BrowsingContext::GetWindow() {
2391 if (XRE_IsParentProcess() && !IsInProcess()) {
2394 return WindowProxyHolder(this);
2397 Nullable
<WindowProxyHolder
> BrowsingContext::GetTop(ErrorResult
& aError
) {
2402 // We never return null or throw an error, but the implementation in
2403 // nsGlobalWindow does and we need to use the same signature.
2404 return WindowProxyHolder(Top());
2407 void BrowsingContext::GetOpener(JSContext
* aCx
,
2408 JS::MutableHandle
<JS::Value
> aOpener
,
2409 ErrorResult
& aError
) const {
2410 RefPtr
<BrowsingContext
> opener
= GetOpener();
2416 if (!ToJSValue(aCx
, WindowProxyHolder(opener
), aOpener
)) {
2417 aError
.NoteJSContextException(aCx
);
2421 // We never throw an error, but the implementation in nsGlobalWindow does and
2422 // we need to use the same signature.
2423 Nullable
<WindowProxyHolder
> BrowsingContext::GetParent(ErrorResult
& aError
) {
2429 return WindowProxyHolder(GetParent());
2431 return WindowProxyHolder(this);
2434 void BrowsingContext::PostMessageMoz(JSContext
* aCx
,
2435 JS::Handle
<JS::Value
> aMessage
,
2436 const nsAString
& aTargetOrigin
,
2437 const Sequence
<JSObject
*>& aTransfer
,
2438 nsIPrincipal
& aSubjectPrincipal
,
2439 ErrorResult
& aError
) {
2444 RefPtr
<BrowsingContext
> sourceBc
;
2445 PostMessageData data
;
2446 data
.targetOrigin() = aTargetOrigin
;
2447 data
.subjectPrincipal() = &aSubjectPrincipal
;
2448 RefPtr
<nsGlobalWindowInner
> callerInnerWindow
;
2449 nsAutoCString scriptLocation
;
2450 // We don't need to get the caller's agentClusterId since that is used for
2451 // checking whether it's okay to sharing memory (and it's not allowed to share
2452 // memory cross processes)
2453 if (!nsGlobalWindowOuter::GatherPostMessageData(
2454 aCx
, aTargetOrigin
, getter_AddRefs(sourceBc
), data
.origin(),
2455 getter_AddRefs(data
.targetOriginURI()),
2456 getter_AddRefs(data
.callerPrincipal()),
2457 getter_AddRefs(callerInnerWindow
), getter_AddRefs(data
.callerURI()),
2458 /* aCallerAgentClusterId */ nullptr, &scriptLocation
, aError
)) {
2461 if (sourceBc
&& sourceBc
->IsDiscarded()) {
2464 data
.source() = sourceBc
;
2465 data
.isFromPrivateWindow() =
2466 callerInnerWindow
&&
2467 nsScriptErrorBase::ComputeIsFromPrivateWindow(callerInnerWindow
);
2468 data
.innerWindowId() = callerInnerWindow
? callerInnerWindow
->WindowID() : 0;
2469 data
.scriptLocation() = scriptLocation
;
2470 JS::Rooted
<JS::Value
> transferArray(aCx
);
2471 aError
= nsContentUtils::CreateJSValueFromSequenceOfObject(aCx
, aTransfer
,
2473 if (NS_WARN_IF(aError
.Failed())) {
2477 JS::CloneDataPolicy clonePolicy
;
2478 if (callerInnerWindow
&& callerInnerWindow
->IsSharedMemoryAllowed()) {
2479 clonePolicy
.allowSharedMemoryObjects();
2482 // We will see if the message is required to be in the same process or it can
2483 // be in the different process after Write().
2484 ipc::StructuredCloneData message
= ipc::StructuredCloneData(
2485 StructuredCloneHolder::StructuredCloneScope::UnknownDestination
,
2486 StructuredCloneHolder::TransferringSupported
);
2487 message
.Write(aCx
, aMessage
, transferArray
, clonePolicy
, aError
);
2488 if (NS_WARN_IF(aError
.Failed())) {
2492 ClonedOrErrorMessageData messageData
;
2493 if (ContentChild
* cc
= ContentChild::GetSingleton()) {
2494 // The clone scope gets set when we write the message data based on the
2495 // requirements of that data that we're writing.
2496 // If the message data contins a shared memory object, then CloneScope would
2497 // return SameProcess. Otherwise, it returns DifferentProcess.
2498 if (message
.CloneScope() ==
2499 StructuredCloneHolder::StructuredCloneScope::DifferentProcess
) {
2500 ClonedMessageData clonedMessageData
;
2501 if (!message
.BuildClonedMessageDataForChild(cc
, clonedMessageData
)) {
2502 aError
.Throw(NS_ERROR_FAILURE
);
2506 messageData
= std::move(clonedMessageData
);
2508 MOZ_ASSERT(message
.CloneScope() ==
2509 StructuredCloneHolder::StructuredCloneScope::SameProcess
);
2511 messageData
= ErrorMessageData();
2513 nsContentUtils::ReportToConsole(
2514 nsIScriptError::warningFlag
, "DOM Window"_ns
,
2515 callerInnerWindow
? callerInnerWindow
->GetDocument() : nullptr,
2516 nsContentUtils::eDOM_PROPERTIES
,
2517 "PostMessageSharedMemoryObjectToCrossOriginWarning");
2520 cc
->SendWindowPostMessage(this, messageData
, data
);
2521 } else if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2522 if (message
.CloneScope() ==
2523 StructuredCloneHolder::StructuredCloneScope::DifferentProcess
) {
2524 ClonedMessageData clonedMessageData
;
2525 if (!message
.BuildClonedMessageDataForParent(cp
, clonedMessageData
)) {
2526 aError
.Throw(NS_ERROR_FAILURE
);
2530 messageData
= std::move(clonedMessageData
);
2532 MOZ_ASSERT(message
.CloneScope() ==
2533 StructuredCloneHolder::StructuredCloneScope::SameProcess
);
2535 messageData
= ErrorMessageData();
2537 nsContentUtils::ReportToConsole(
2538 nsIScriptError::warningFlag
, "DOM Window"_ns
,
2539 callerInnerWindow
? callerInnerWindow
->GetDocument() : nullptr,
2540 nsContentUtils::eDOM_PROPERTIES
,
2541 "PostMessageSharedMemoryObjectToCrossOriginWarning");
2544 Unused
<< cp
->SendWindowPostMessage(this, messageData
, data
);
2548 void BrowsingContext::PostMessageMoz(JSContext
* aCx
,
2549 JS::Handle
<JS::Value
> aMessage
,
2550 const WindowPostMessageOptions
& aOptions
,
2551 nsIPrincipal
& aSubjectPrincipal
,
2552 ErrorResult
& aError
) {
2553 PostMessageMoz(aCx
, aMessage
, aOptions
.mTargetOrigin
, aOptions
.mTransfer
,
2554 aSubjectPrincipal
, aError
);
2557 void BrowsingContext::SendCommitTransaction(ContentParent
* aParent
,
2558 const BaseTransaction
& aTxn
,
2560 Unused
<< aParent
->SendCommitBrowsingContextTransaction(this, aTxn
, aEpoch
);
2563 void BrowsingContext::SendCommitTransaction(ContentChild
* aChild
,
2564 const BaseTransaction
& aTxn
,
2566 aChild
->SendCommitBrowsingContextTransaction(this, aTxn
, aEpoch
);
2569 BrowsingContext::IPCInitializer
BrowsingContext::GetIPCInitializer() {
2570 MOZ_DIAGNOSTIC_ASSERT(mEverAttached
);
2571 MOZ_DIAGNOSTIC_ASSERT(mType
== Type::Content
);
2573 IPCInitializer init
;
2575 init
.mParentId
= mParentWindow
? mParentWindow
->Id() : 0;
2576 init
.mWindowless
= mWindowless
;
2577 init
.mUseRemoteTabs
= mUseRemoteTabs
;
2578 init
.mUseRemoteSubframes
= mUseRemoteSubframes
;
2579 init
.mCreatedDynamically
= mCreatedDynamically
;
2580 init
.mChildOffset
= mChildOffset
;
2581 init
.mOriginAttributes
= mOriginAttributes
;
2582 if (mChildSessionHistory
&& mozilla::SessionHistoryInParent()) {
2583 init
.mSessionHistoryIndex
= mChildSessionHistory
->Index();
2584 init
.mSessionHistoryCount
= mChildSessionHistory
->Count();
2586 init
.mRequestContextId
= mRequestContextId
;
2587 init
.mFields
= mFields
.RawValues();
2591 already_AddRefed
<WindowContext
> BrowsingContext::IPCInitializer::GetParent() {
2592 RefPtr
<WindowContext
> parent
;
2593 if (mParentId
!= 0) {
2594 parent
= WindowContext::GetById(mParentId
);
2595 MOZ_RELEASE_ASSERT(parent
);
2597 return parent
.forget();
2600 already_AddRefed
<BrowsingContext
> BrowsingContext::IPCInitializer::GetOpener() {
2601 RefPtr
<BrowsingContext
> opener
;
2602 if (GetOpenerId() != 0) {
2603 opener
= BrowsingContext::Get(GetOpenerId());
2604 MOZ_RELEASE_ASSERT(opener
);
2606 return opener
.forget();
2609 void BrowsingContext::StartDelayedAutoplayMediaComponents() {
2613 AUTOPLAY_LOG("%s : StartDelayedAutoplayMediaComponents for bc 0x%08" PRIx64
,
2614 XRE_IsParentProcess() ? "Parent" : "Child", Id());
2615 mDocShell
->StartDelayedAutoplayMediaComponents();
2618 nsresult
BrowsingContext::ResetGVAutoplayRequestStatus() {
2620 "Should only set GVAudibleAutoplayRequestStatus in the top-level "
2621 "browsing context");
2624 txn
.SetGVAudibleAutoplayRequestStatus(GVAutoplayRequestStatus::eUNKNOWN
);
2625 txn
.SetGVInaudibleAutoplayRequestStatus(GVAutoplayRequestStatus::eUNKNOWN
);
2626 return txn
.Commit(this);
2629 void BrowsingContext::DidSet(FieldIndex
<IDX_GVAudibleAutoplayRequestStatus
>) {
2631 "Should only set GVAudibleAutoplayRequestStatus in the top-level "
2632 "browsing context");
2635 void BrowsingContext::DidSet(FieldIndex
<IDX_GVInaudibleAutoplayRequestStatus
>) {
2637 "Should only set GVAudibleAutoplayRequestStatus in the top-level "
2638 "browsing context");
2641 void BrowsingContext::DidSet(FieldIndex
<IDX_ExplicitActive
>,
2642 ExplicitActiveStatus aOldValue
) {
2643 const bool isActive
= IsActive();
2644 const bool wasActive
= [&] {
2645 if (aOldValue
!= ExplicitActiveStatus::None
) {
2646 return aOldValue
== ExplicitActiveStatus::Active
;
2648 return GetParent() && GetParent()->IsActive();
2651 if (isActive
== wasActive
) {
2656 Group()->UpdateToplevelsSuspendedIfNeeded();
2658 #if defined(XP_WIN) && defined(ACCESSIBILITY)
2659 if (XRE_IsParentProcess() && a11y::Compatibility::IsDolphin()) {
2660 // update active accessible documents on windows
2661 if (BrowserParent
* bp
= Canonical()->GetBrowserParent()) {
2662 if (a11y::DocAccessibleParent
* tabDoc
=
2663 bp
->GetTopLevelDocAccessible()) {
2664 HWND window
= tabDoc
->GetEmulatedWindowHandle();
2668 a11y::nsWinUtils::ShowNativeWindow(window
);
2670 a11y::nsWinUtils::HideNativeWindow(window
);
2679 PreOrderWalk([&](BrowsingContext
* aContext
) {
2680 if (nsCOMPtr
<nsIDocShell
> ds
= aContext
->GetDocShell()) {
2681 nsDocShell::Cast(ds
)->ActivenessMaybeChanged();
2686 void BrowsingContext::DidSet(FieldIndex
<IDX_InRDMPane
>, bool aOldValue
) {
2688 "Should only set InRDMPane in the top-level browsing context");
2689 if (GetInRDMPane() == aOldValue
) {
2693 PreOrderWalk([&](BrowsingContext
* aContext
) {
2694 if (nsIDocShell
* shell
= aContext
->GetDocShell()) {
2695 if (nsPresContext
* pc
= shell
->GetPresContext()) {
2696 pc
->RecomputeTheme();
2698 // This is a bit of a lie, but this affects the overlay-scrollbars
2699 // media query and it's the code-path that gets taken for regular system
2700 // metrics changes via ThemeChanged().
2701 pc
->MediaFeatureValuesChanged(
2702 {MediaFeatureChangeReason::SystemMetricsChange
},
2703 MediaFeatureChangePropagation::JustThisDocument
);
2709 bool BrowsingContext::CanSet(FieldIndex
<IDX_PageAwakeRequestCount
>,
2710 uint32_t aNewValue
, ContentParent
* aSource
) {
2711 return IsTop() && XRE_IsParentProcess() && !aSource
;
2714 void BrowsingContext::DidSet(FieldIndex
<IDX_PageAwakeRequestCount
>,
2715 uint32_t aOldValue
) {
2716 if (!IsTop() || aOldValue
== GetPageAwakeRequestCount()) {
2719 Group()->UpdateToplevelsSuspendedIfNeeded();
2722 auto BrowsingContext::CanSet(FieldIndex
<IDX_AllowJavascript
>, bool aValue
,
2723 ContentParent
* aSource
) -> CanSetResult
{
2724 if (mozilla::SessionHistoryInParent()) {
2725 return XRE_IsParentProcess() && !aSource
? CanSetResult::Allow
2726 : CanSetResult::Deny
;
2729 // Without Session History in Parent, session restore code still needs to set
2730 // this from content processes.
2731 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
2734 void BrowsingContext::DidSet(FieldIndex
<IDX_AllowJavascript
>, bool aOldValue
) {
2735 RecomputeCanExecuteScripts();
2738 void BrowsingContext::RecomputeCanExecuteScripts() {
2739 const bool old
= mCanExecuteScripts
;
2740 if (!AllowJavascript()) {
2741 // Scripting has been explicitly disabled on our BrowsingContext.
2742 mCanExecuteScripts
= false;
2743 } else if (GetParentWindowContext()) {
2744 // Otherwise, inherit parent.
2745 mCanExecuteScripts
= GetParentWindowContext()->CanExecuteScripts();
2747 // Otherwise, we're the root of the tree, and we haven't explicitly disabled
2749 mCanExecuteScripts
= true;
2752 if (old
!= mCanExecuteScripts
) {
2753 for (WindowContext
* wc
: GetWindowContexts()) {
2754 wc
->RecomputeCanExecuteScripts();
2759 bool BrowsingContext::InactiveForSuspend() const {
2760 if (!StaticPrefs::dom_suspend_inactive_enabled()) {
2763 // We should suspend a page only when it's inactive and doesn't have any awake
2764 // request that is used to prevent page from being suspended because web page
2765 // might still need to run their script. Eg. waiting for media keys to resume
2766 // media, playing web audio, waiting in a video call conference room.
2767 return !IsActive() && GetPageAwakeRequestCount() == 0;
2770 bool BrowsingContext::CanSet(FieldIndex
<IDX_TouchEventsOverrideInternal
>,
2771 dom::TouchEventsOverride
, ContentParent
* aSource
) {
2772 return XRE_IsParentProcess() && !aSource
;
2775 void BrowsingContext::DidSet(FieldIndex
<IDX_PrefersColorSchemeOverride
>,
2776 dom::PrefersColorSchemeOverride aOldValue
) {
2777 MOZ_ASSERT(IsTop());
2778 if (PrefersColorSchemeOverride() == aOldValue
) {
2781 PreOrderWalk([&](BrowsingContext
* aContext
) {
2782 if (nsIDocShell
* shell
= aContext
->GetDocShell()) {
2783 if (nsPresContext
* pc
= shell
->GetPresContext()) {
2784 pc
->RecomputeBrowsingContextDependentData();
2790 void BrowsingContext::DidSet(FieldIndex
<IDX_MediumOverride
>,
2791 nsString
&& aOldValue
) {
2792 MOZ_ASSERT(IsTop());
2793 if (GetMediumOverride() == aOldValue
) {
2796 PreOrderWalk([&](BrowsingContext
* aContext
) {
2797 if (nsIDocShell
* shell
= aContext
->GetDocShell()) {
2798 if (nsPresContext
* pc
= shell
->GetPresContext()) {
2799 pc
->RecomputeBrowsingContextDependentData();
2805 void BrowsingContext::DidSet(FieldIndex
<IDX_DisplayMode
>,
2806 enum DisplayMode aOldValue
) {
2807 MOZ_ASSERT(IsTop());
2809 if (GetDisplayMode() == aOldValue
) {
2813 PreOrderWalk([&](BrowsingContext
* aContext
) {
2814 if (nsIDocShell
* shell
= aContext
->GetDocShell()) {
2815 if (nsPresContext
* pc
= shell
->GetPresContext()) {
2816 pc
->MediaFeatureValuesChanged(
2817 {MediaFeatureChangeReason::DisplayModeChange
},
2818 // We're already iterating through sub documents, so we don't need
2819 // to propagate the change again.
2821 // Images and other resources don't change their display-mode
2822 // evaluation, display-mode is a property of the browsing context.
2823 MediaFeatureChangePropagation::JustThisDocument
);
2829 void BrowsingContext::DidSet(FieldIndex
<IDX_Muted
>) {
2830 MOZ_ASSERT(IsTop(), "Set muted flag on non top-level context!");
2831 USER_ACTIVATION_LOG("Set audio muted %d for %s browsing context 0x%08" PRIx64
,
2832 GetMuted(), XRE_IsParentProcess() ? "Parent" : "Child",
2834 PreOrderWalk([&](BrowsingContext
* aContext
) {
2835 nsPIDOMWindowOuter
* win
= aContext
->GetDOMWindow();
2837 win
->RefreshMediaElementsVolume();
2842 bool BrowsingContext::CanSet(FieldIndex
<IDX_ShouldDelayMediaFromStart
>,
2843 const bool& aValue
, ContentParent
* aSource
) {
2847 void BrowsingContext::DidSet(FieldIndex
<IDX_ShouldDelayMediaFromStart
>,
2849 MOZ_ASSERT(IsTop(), "Set attribute on non top-level context!");
2850 if (aOldValue
== GetShouldDelayMediaFromStart()) {
2853 if (!GetShouldDelayMediaFromStart()) {
2854 PreOrderWalk([&](BrowsingContext
* aContext
) {
2855 if (nsPIDOMWindowOuter
* win
= aContext
->GetDOMWindow()) {
2856 win
->ActivateMediaComponents();
2862 bool BrowsingContext::CanSet(FieldIndex
<IDX_OverrideDPPX
>, const float& aValue
,
2863 ContentParent
* aSource
) {
2864 return XRE_IsParentProcess() && !aSource
&& IsTop();
2867 void BrowsingContext::DidSet(FieldIndex
<IDX_OverrideDPPX
>, float aOldValue
) {
2868 MOZ_ASSERT(IsTop());
2869 if (GetOverrideDPPX() == aOldValue
) {
2873 PreOrderWalk([&](BrowsingContext
* aContext
) {
2874 if (nsIDocShell
* shell
= aContext
->GetDocShell()) {
2875 if (nsPresContext
* pc
= shell
->GetPresContext()) {
2876 pc
->RecomputeBrowsingContextDependentData();
2882 void BrowsingContext::SetCustomUserAgent(const nsAString
& aUserAgent
,
2884 Top()->SetUserAgentOverride(aUserAgent
, aRv
);
2887 nsresult
BrowsingContext::SetCustomUserAgent(const nsAString
& aUserAgent
) {
2888 return Top()->SetUserAgentOverride(aUserAgent
);
2891 void BrowsingContext::DidSet(FieldIndex
<IDX_UserAgentOverride
>) {
2892 MOZ_ASSERT(IsTop());
2894 PreOrderWalk([&](BrowsingContext
* aContext
) {
2895 nsIDocShell
* shell
= aContext
->GetDocShell();
2897 shell
->ClearCachedUserAgent();
2902 bool BrowsingContext::CanSet(FieldIndex
<IDX_IsInBFCache
>, bool,
2903 ContentParent
* aSource
) {
2904 return IsTop() && !aSource
&& mozilla::BFCacheInParent();
2907 void BrowsingContext::DidSet(FieldIndex
<IDX_IsInBFCache
>) {
2908 MOZ_RELEASE_ASSERT(mozilla::BFCacheInParent());
2909 MOZ_DIAGNOSTIC_ASSERT(IsTop());
2911 const bool isInBFCache
= GetIsInBFCache();
2913 PreOrderWalk([&](BrowsingContext
* aContext
) {
2914 aContext
->mIsInBFCache
= false;
2915 nsCOMPtr
<nsIDocShell
> shell
= aContext
->GetDocShell();
2917 nsDocShell::Cast(shell
)->ThawFreezeNonRecursive(true);
2922 if (isInBFCache
&& XRE_IsContentProcess() && mDocShell
) {
2923 nsDocShell::Cast(mDocShell
)->MaybeDisconnectChildListenersOnPageHide();
2927 PreOrderWalk([&](BrowsingContext
* aContext
) {
2928 nsCOMPtr
<nsIDocShell
> shell
= aContext
->GetDocShell();
2930 nsDocShell::Cast(shell
)->FirePageHideShowNonRecursive(false);
2934 PostOrderWalk([&](BrowsingContext
* aContext
) {
2935 nsCOMPtr
<nsIDocShell
> shell
= aContext
->GetDocShell();
2937 nsDocShell::Cast(shell
)->FirePageHideShowNonRecursive(true);
2943 PreOrderWalk([&](BrowsingContext
* aContext
) {
2944 nsCOMPtr
<nsIDocShell
> shell
= aContext
->GetDocShell();
2946 nsDocShell::Cast(shell
)->ThawFreezeNonRecursive(false);
2948 aContext
->mIsInBFCache
= true;
2949 Document
* doc
= aContext
->GetDocument();
2951 // Notifying needs to happen after mIsInBFCache is set to true.
2952 doc
->NotifyActivityChanged();
2958 void BrowsingContext::SetCustomPlatform(const nsAString
& aPlatform
,
2960 Top()->SetPlatformOverride(aPlatform
, aRv
);
2963 void BrowsingContext::DidSet(FieldIndex
<IDX_PlatformOverride
>) {
2964 MOZ_ASSERT(IsTop());
2966 PreOrderWalk([&](BrowsingContext
* aContext
) {
2967 nsIDocShell
* shell
= aContext
->GetDocShell();
2969 shell
->ClearCachedPlatform();
2974 auto BrowsingContext::LegacyRevertIfNotOwningOrParentProcess(
2975 ContentParent
* aSource
) -> CanSetResult
{
2977 MOZ_ASSERT(XRE_IsParentProcess());
2979 if (!Canonical()->IsOwnedByProcess(aSource
->ChildID())) {
2980 return CanSetResult::Revert
;
2982 } else if (!IsInProcess() && !XRE_IsParentProcess()) {
2983 // Don't allow this to be set from content processes that
2984 // don't own the BrowsingContext.
2985 return CanSetResult::Deny
;
2988 return CanSetResult::Allow
;
2991 bool BrowsingContext::CanSet(FieldIndex
<IDX_IsActiveBrowserWindowInternal
>,
2992 const bool& aValue
, ContentParent
* aSource
) {
2993 // Should only be set in the parent process.
2994 return XRE_IsParentProcess() && !aSource
&& IsTop();
2997 void BrowsingContext::DidSet(FieldIndex
<IDX_IsActiveBrowserWindowInternal
>,
2999 bool isActivateEvent
= GetIsActiveBrowserWindowInternal();
3000 // The browser window containing this context has changed
3001 // activation state so update window inactive document states
3002 // for all in-process documents.
3003 PreOrderWalk([isActivateEvent
](BrowsingContext
* aContext
) {
3004 if (RefPtr
<Document
> doc
= aContext
->GetExtantDocument()) {
3005 doc
->UpdateDocumentStates(NS_DOCUMENT_STATE_WINDOW_INACTIVE
, true);
3007 RefPtr
<nsPIDOMWindowInner
> win
= doc
->GetInnerWindow();
3008 RefPtr
<MediaDevices
> devices
;
3009 if (isActivateEvent
&& (devices
= win
->GetExtantMediaDevices())) {
3010 devices
->BrowserWindowBecameActive();
3013 if (XRE_IsContentProcess() &&
3014 (!aContext
->GetParent() || !aContext
->GetParent()->IsInProcess())) {
3015 // Send the inner window an activate/deactivate event if
3016 // the context is the top of a sub-tree of in-process
3018 nsContentUtils::DispatchEventOnlyToChrome(
3019 doc
, win
, isActivateEvent
? u
"activate"_ns
: u
"deactivate"_ns
,
3020 CanBubble::eYes
, Cancelable::eYes
, nullptr);
3026 auto BrowsingContext::CanSet(FieldIndex
<IDX_AllowContentRetargeting
>,
3027 const bool& aAllowContentRetargeting
,
3028 ContentParent
* aSource
) -> CanSetResult
{
3029 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3032 auto BrowsingContext::CanSet(FieldIndex
<IDX_AllowContentRetargetingOnChildren
>,
3033 const bool& aAllowContentRetargetingOnChildren
,
3034 ContentParent
* aSource
) -> CanSetResult
{
3035 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3038 auto BrowsingContext::CanSet(FieldIndex
<IDX_AllowPlugins
>,
3039 const bool& aAllowPlugins
, ContentParent
* aSource
)
3041 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3044 bool BrowsingContext::CanSet(FieldIndex
<IDX_FullscreenAllowedByOwner
>,
3045 const bool& aAllowed
, ContentParent
* aSource
) {
3046 return CheckOnlyEmbedderCanSet(aSource
);
3049 bool BrowsingContext::CanSet(FieldIndex
<IDX_UseErrorPages
>,
3050 const bool& aUseErrorPages
,
3051 ContentParent
* aSource
) {
3052 return CheckOnlyEmbedderCanSet(aSource
);
3055 mozilla::dom::TouchEventsOverride
BrowsingContext::TouchEventsOverride() const {
3056 const BrowsingContext
* bc
= this;
3058 mozilla::dom::TouchEventsOverride tev
=
3059 bc
->GetTouchEventsOverrideInternal();
3060 if (tev
!= mozilla::dom::TouchEventsOverride::None
) {
3064 bc
= bc
->GetParent();
3067 return mozilla::dom::TouchEventsOverride::None
;
3070 // We map `watchedByDevTools` WebIDL attribute to `watchedByDevToolsInternal`
3071 // BC field. And we map it to the top level BrowsingContext.
3072 bool BrowsingContext::WatchedByDevTools() {
3073 return Top()->GetWatchedByDevToolsInternal();
3076 // Enforce that the watchedByDevTools BC field can only be set on the top level
3077 // Browsing Context.
3078 bool BrowsingContext::CanSet(FieldIndex
<IDX_WatchedByDevToolsInternal
>,
3079 const bool& aWatchedByDevTools
,
3080 ContentParent
* aSource
) {
3083 void BrowsingContext::SetWatchedByDevTools(bool aWatchedByDevTools
,
3086 aRv
.ThrowInvalidModificationError(
3087 "watchedByDevTools can only be set on top BrowsingContext");
3090 SetWatchedByDevToolsInternal(aWatchedByDevTools
, aRv
);
3093 auto BrowsingContext::CanSet(FieldIndex
<IDX_DefaultLoadFlags
>,
3094 const uint32_t& aDefaultLoadFlags
,
3095 ContentParent
* aSource
) -> CanSetResult
{
3096 // Bug 1623565 - Are these flags only used by the debugger, which makes it
3097 // possible that this field can only be settable by the parent process?
3098 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3101 void BrowsingContext::DidSet(FieldIndex
<IDX_DefaultLoadFlags
>) {
3102 auto loadFlags
= GetDefaultLoadFlags();
3103 if (GetDocShell()) {
3104 nsDocShell::Cast(GetDocShell())->SetLoadGroupDefaultLoadFlags(loadFlags
);
3107 if (XRE_IsParentProcess()) {
3108 PreOrderWalk([&](BrowsingContext
* aContext
) {
3109 if (aContext
!= this) {
3110 // Setting load flags on a discarded context has no effect.
3111 Unused
<< aContext
->SetDefaultLoadFlags(loadFlags
);
3117 bool BrowsingContext::CanSet(FieldIndex
<IDX_UseGlobalHistory
>,
3118 const bool& aUseGlobalHistory
,
3119 ContentParent
* aSource
) {
3120 // Should only be set in the parent process.
3121 // return XRE_IsParentProcess() && !aSource;
3125 auto BrowsingContext::CanSet(FieldIndex
<IDX_UserAgentOverride
>,
3126 const nsString
& aUserAgent
, ContentParent
* aSource
)
3129 return CanSetResult::Deny
;
3132 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3135 auto BrowsingContext::CanSet(FieldIndex
<IDX_PlatformOverride
>,
3136 const nsString
& aPlatform
, ContentParent
* aSource
)
3139 return CanSetResult::Deny
;
3142 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3145 bool BrowsingContext::CheckOnlyEmbedderCanSet(ContentParent
* aSource
) {
3146 if (XRE_IsParentProcess()) {
3147 uint64_t childId
= aSource
? aSource
->ChildID() : 0;
3148 return Canonical()->IsEmbeddedInProcess(childId
);
3150 return mEmbeddedByThisProcess
;
3153 bool BrowsingContext::CanSet(FieldIndex
<IDX_EmbedderInnerWindowId
>,
3154 const uint64_t& aValue
, ContentParent
* aSource
) {
3155 // If we have a parent window, our embedder inner window ID must match it.
3156 if (mParentWindow
) {
3157 return mParentWindow
->Id() == aValue
;
3160 // For toplevel BrowsingContext instances, this value may only be set by the
3161 // parent process, or initialized to `0`.
3162 return CheckOnlyEmbedderCanSet(aSource
);
3165 bool BrowsingContext::CanSet(FieldIndex
<IDX_EmbedderElementType
>,
3166 const Maybe
<nsString
>&, ContentParent
* aSource
) {
3167 return CheckOnlyEmbedderCanSet(aSource
);
3170 auto BrowsingContext::CanSet(FieldIndex
<IDX_CurrentInnerWindowId
>,
3171 const uint64_t& aValue
, ContentParent
* aSource
)
3173 // Generally allow clearing this. We may want to be more precise about this
3174 // check in the future.
3176 return CanSetResult::Allow
;
3179 // We must have access to the specified context.
3180 RefPtr
<WindowContext
> window
= WindowContext::GetById(aValue
);
3181 if (!window
|| window
->GetBrowsingContext() != this) {
3182 return CanSetResult::Deny
;
3186 // If the sending process is no longer the current owner, revert
3187 MOZ_ASSERT(XRE_IsParentProcess());
3188 if (!Canonical()->IsOwnedByProcess(aSource
->ChildID())) {
3189 return CanSetResult::Revert
;
3191 } else if (XRE_IsContentProcess() && !IsOwnedByProcess()) {
3192 return CanSetResult::Deny
;
3195 return CanSetResult::Allow
;
3198 bool BrowsingContext::CanSet(FieldIndex
<IDX_ParentInitiatedNavigationEpoch
>,
3199 const uint64_t& aValue
, ContentParent
* aSource
) {
3200 return XRE_IsParentProcess() && !aSource
;
3203 void BrowsingContext::DidSet(FieldIndex
<IDX_CurrentInnerWindowId
>) {
3204 RefPtr
<WindowContext
> prevWindowContext
= mCurrentWindowContext
.forget();
3205 mCurrentWindowContext
= WindowContext::GetById(GetCurrentInnerWindowId());
3207 !mCurrentWindowContext
|| mWindowContexts
.Contains(mCurrentWindowContext
),
3208 "WindowContext not registered?");
3210 // Clear our cached `children` value, to ensure that JS sees the up-to-date
3212 BrowsingContext_Binding::ClearCachedChildrenValue(this);
3214 if (XRE_IsParentProcess()) {
3215 if (prevWindowContext
!= mCurrentWindowContext
) {
3216 if (prevWindowContext
) {
3217 prevWindowContext
->Canonical()->DidBecomeCurrentWindowGlobal(false);
3219 if (mCurrentWindowContext
) {
3220 // We set a timer when we set the current inner window. This
3221 // will then flush the session storage to session store to
3222 // make sure that we don't miss to store session storage to
3223 // session store that is a result of navigation. This is due
3224 // to Bug 1700623. We wish to fix this in Bug 1711886, where
3225 // making sure to store everything would make this timer
3227 Canonical()->MaybeScheduleSessionStoreUpdate();
3228 mCurrentWindowContext
->Canonical()->DidBecomeCurrentWindowGlobal(true);
3231 BrowserParent::UpdateFocusFromBrowsingContext();
3235 bool BrowsingContext::CanSet(FieldIndex
<IDX_IsPopupSpam
>, const bool& aValue
,
3236 ContentParent
* aSource
) {
3237 // Ensure that we only mark a browsing context as popup spam once and never
3239 return aValue
&& !GetIsPopupSpam();
3242 void BrowsingContext::DidSet(FieldIndex
<IDX_IsPopupSpam
>) {
3243 if (GetIsPopupSpam()) {
3244 PopupBlocker::RegisterOpenPopupSpam();
3248 bool BrowsingContext::CanSet(FieldIndex
<IDX_MessageManagerGroup
>,
3249 const nsString
& aMessageManagerGroup
,
3250 ContentParent
* aSource
) {
3251 // Should only be set in the parent process on toplevel.
3252 return XRE_IsParentProcess() && !aSource
&& IsTopContent();
3255 bool BrowsingContext::CanSet(
3256 FieldIndex
<IDX_OrientationLock
>,
3257 const mozilla::hal::ScreenOrientation
& aOrientationLock
,
3258 ContentParent
* aSource
) {
3262 bool BrowsingContext::IsLoading() {
3267 // If we're in the same process as the page, we're possibly just
3268 // updating the flag.
3269 nsIDocShell
* shell
= GetDocShell();
3271 Document
* doc
= shell
->GetDocument();
3272 return doc
&& doc
->GetReadyStateEnum() < Document::READYSTATE_COMPLETE
;
3278 void BrowsingContext::DidSet(FieldIndex
<IDX_Loading
>) {
3279 if (mFields
.Get
<IDX_Loading
>()) {
3283 while (!mDeprioritizedLoadRunner
.isEmpty()) {
3284 nsCOMPtr
<nsIRunnable
> runner
= mDeprioritizedLoadRunner
.popFirst();
3285 NS_DispatchToCurrentThread(runner
.forget());
3288 if (StaticPrefs::dom_separate_event_queue_for_post_message_enabled() &&
3290 Group()->FlushPostMessageEvents();
3294 // Inform the Document for this context of the (potential) change in
3296 void BrowsingContext::DidSet(FieldIndex
<IDX_AncestorLoading
>) {
3297 nsPIDOMWindowOuter
* outer
= GetDOMWindow();
3299 MOZ_LOG(gTimeoutDeferralLog
, mozilla::LogLevel::Debug
,
3300 ("DidSetAncestorLoading BC: %p -- No outer window", (void*)this));
3303 Document
* document
= nsGlobalWindowOuter::Cast(outer
)->GetExtantDoc();
3305 MOZ_LOG(gTimeoutDeferralLog
, mozilla::LogLevel::Debug
,
3306 ("DidSetAncestorLoading BC: %p -- NotifyLoading(%d, %d, %d)",
3307 (void*)this, GetAncestorLoading(), document
->GetReadyStateEnum(),
3308 document
->GetReadyStateEnum()));
3309 document
->NotifyLoading(GetAncestorLoading(), document
->GetReadyStateEnum(),
3310 document
->GetReadyStateEnum());
3314 void BrowsingContext::DidSet(FieldIndex
<IDX_AuthorStyleDisabledDefault
>) {
3316 "Should only set AuthorStyleDisabledDefault in the top "
3317 "browsing context");
3319 // We don't need to handle changes to this field, since PageStyleChild.jsm
3320 // will respond to the PageStyle:Disable message in all content processes.
3322 // But we store the state here on the top BrowsingContext so that the
3323 // docshell has somewhere to look for the current author style disabling
3324 // state when new iframes are inserted.
3327 void BrowsingContext::DidSet(FieldIndex
<IDX_TextZoom
>, float aOldValue
) {
3328 if (GetTextZoom() == aOldValue
) {
3332 if (IsInProcess()) {
3333 if (nsIDocShell
* shell
= GetDocShell()) {
3334 if (nsPresContext
* pc
= shell
->GetPresContext()) {
3335 pc
->RecomputeBrowsingContextDependentData();
3339 for (BrowsingContext
* child
: Children()) {
3340 // Setting text zoom on a discarded context has no effect.
3341 Unused
<< child
->SetTextZoom(GetTextZoom());
3345 if (IsTop() && XRE_IsParentProcess()) {
3346 if (Element
* element
= GetEmbedderElement()) {
3347 auto dispatcher
= MakeRefPtr
<AsyncEventDispatcher
>(
3348 element
, u
"TextZoomChange"_ns
, CanBubble::eYes
,
3349 ChromeOnlyDispatch::eYes
);
3350 dispatcher
->RunDOMEventWhenSafe();
3355 // TODO(emilio): It'd be potentially nicer and cheaper to allow to set this only
3356 // on the Top() browsing context, but there are a lot of tests that rely on
3357 // zooming a subframe so...
3358 void BrowsingContext::DidSet(FieldIndex
<IDX_FullZoom
>, float aOldValue
) {
3359 if (GetFullZoom() == aOldValue
) {
3363 if (IsInProcess()) {
3364 if (nsIDocShell
* shell
= GetDocShell()) {
3365 if (nsPresContext
* pc
= shell
->GetPresContext()) {
3366 pc
->RecomputeBrowsingContextDependentData();
3370 for (BrowsingContext
* child
: Children()) {
3371 // Setting full zoom on a discarded context has no effect.
3372 Unused
<< child
->SetFullZoom(GetFullZoom());
3376 if (IsTop() && XRE_IsParentProcess()) {
3377 if (Element
* element
= GetEmbedderElement()) {
3378 auto dispatcher
= MakeRefPtr
<AsyncEventDispatcher
>(
3379 element
, u
"FullZoomChange"_ns
, CanBubble::eYes
,
3380 ChromeOnlyDispatch::eYes
);
3381 dispatcher
->RunDOMEventWhenSafe();
3386 void BrowsingContext::AddDeprioritizedLoadRunner(nsIRunnable
* aRunner
) {
3387 MOZ_ASSERT(IsLoading());
3388 MOZ_ASSERT(Top() == this);
3390 RefPtr
<DeprioritizedLoadRunner
> runner
= new DeprioritizedLoadRunner(aRunner
);
3391 mDeprioritizedLoadRunner
.insertBack(runner
);
3392 NS_DispatchToCurrentThreadQueue(
3393 runner
.forget(), StaticPrefs::page_load_deprioritization_period(),
3394 EventQueuePriority::Idle
);
3397 bool BrowsingContext::GetOffsetPath(nsTArray
<uint32_t>& aPath
) const {
3398 for (const BrowsingContext
* current
= this; current
&& current
->GetParent();
3399 current
= current
->GetParent()) {
3400 if (current
->CreatedDynamically()) {
3403 aPath
.AppendElement(current
->ChildOffset());
3408 void BrowsingContext::GetHistoryID(JSContext
* aCx
,
3409 JS::MutableHandle
<JS::Value
> aVal
,
3410 ErrorResult
& aError
) {
3411 if (!xpc::ID2JSValue(aCx
, GetHistoryID(), aVal
)) {
3412 aError
.Throw(NS_ERROR_OUT_OF_MEMORY
);
3416 void BrowsingContext::InitSessionHistory() {
3417 MOZ_ASSERT(!IsDiscarded());
3418 MOZ_ASSERT(IsTop());
3419 MOZ_ASSERT(EverAttached());
3421 if (!GetHasSessionHistory()) {
3422 MOZ_ALWAYS_SUCCEEDS(SetHasSessionHistory(true));
3426 ChildSHistory
* BrowsingContext::GetChildSessionHistory() {
3427 if (!mozilla::SessionHistoryInParent()) {
3428 // For now we're checking that the session history object for the child
3429 // process is available before returning the ChildSHistory object, because
3430 // it is the actual implementation that ChildSHistory forwards to. This can
3431 // be removed once session history is stored exclusively in the parent
3433 return mChildSessionHistory
&& mChildSessionHistory
->IsInProcess()
3434 ? mChildSessionHistory
.get()
3438 return mChildSessionHistory
;
3441 void BrowsingContext::CreateChildSHistory() {
3442 MOZ_ASSERT(IsTop());
3443 MOZ_ASSERT(GetHasSessionHistory());
3444 MOZ_DIAGNOSTIC_ASSERT(!mChildSessionHistory
);
3446 // Because session history is global in a browsing context tree, every process
3447 // that has access to a browsing context tree needs access to its session
3448 // history. That is why we create the ChildSHistory object in every process
3449 // where we have access to this browsing context (which is the top one).
3450 mChildSessionHistory
= new ChildSHistory(this);
3452 // If the top browsing context (this one) is loaded in this process then we
3453 // also create the session history implementation for the child process.
3454 // This can be removed once session history is stored exclusively in the
3456 mChildSessionHistory
->SetIsInProcess(IsInProcess());
3459 void BrowsingContext::DidSet(FieldIndex
<IDX_HasSessionHistory
>,
3461 MOZ_ASSERT(GetHasSessionHistory() || !aOldValue
,
3462 "We don't support turning off session history.");
3464 if (GetHasSessionHistory() && !aOldValue
) {
3465 CreateChildSHistory();
3469 bool BrowsingContext::CanSet(FieldIndex
<IDX_BrowserId
>, const uint32_t& aValue
,
3470 ContentParent
* aSource
) {
3471 // We should only be able to set this for toplevel contexts which don't have
3473 return GetBrowserId() == 0 && IsTop() && Children().IsEmpty();
3476 bool BrowsingContext::CanSet(FieldIndex
<IDX_PendingInitialization
>,
3477 bool aNewValue
, ContentParent
* aSource
) {
3478 // Can only be cleared from `true` to `false`, and should only ever be set on
3479 // the toplevel BrowsingContext.
3480 return IsTop() && GetPendingInitialization() && !aNewValue
;
3483 bool BrowsingContext::CanSet(FieldIndex
<IDX_HasRestoreData
>, bool aNewValue
,
3484 ContentParent
* aSource
) {
3488 bool BrowsingContext::IsPopupAllowed() {
3489 for (auto* context
= GetCurrentWindowContext(); context
;
3490 context
= context
->GetParentWindowContext()) {
3491 if (context
->CanShowPopup()) {
3500 bool BrowsingContext::ShouldAddEntryForRefresh(
3501 nsIURI
* aCurrentURI
, const SessionHistoryInfo
& aInfo
) {
3502 return ShouldAddEntryForRefresh(aCurrentURI
, aInfo
.GetURI(),
3503 aInfo
.GetPostData());
3507 bool BrowsingContext::ShouldAddEntryForRefresh(nsIURI
* aCurrentURI
,
3509 bool aHasPostData
) {
3514 bool equalsURI
= false;
3516 aCurrentURI
->Equals(aNewURI
, &equalsURI
);
3521 void BrowsingContext::SessionHistoryCommit(
3522 const LoadingSessionHistoryInfo
& aInfo
, uint32_t aLoadType
,
3523 nsIURI
* aCurrentURI
, bool aHadActiveEntry
, bool aPersist
,
3524 bool aCloneEntryChildren
, bool aChannelExpired
, uint32_t aCacheKey
) {
3526 if (XRE_IsContentProcess()) {
3527 RefPtr
<ChildSHistory
> rootSH
= Top()->GetChildSessionHistory();
3529 if (!aInfo
.mLoadIsFromSessionHistory
) {
3530 // We try to mimic as closely as possible what will happen in
3531 // CanonicalBrowsingContext::SessionHistoryCommit. We'll be
3532 // incrementing the session history length if we're not replacing,
3533 // this is a top-level load or it's not the initial load in an iframe,
3534 // ShouldUpdateSessionHistory(loadType) returns true and it's not a
3535 // refresh for which ShouldAddEntryForRefresh returns false.
3536 // It is possible that this leads to wrong length temporarily, but
3537 // so would not having the check for replace.
3538 if (!LOAD_TYPE_HAS_FLAGS(
3539 aLoadType
, nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY
) &&
3540 (IsTop() || aHadActiveEntry
) &&
3541 ShouldUpdateSessionHistory(aLoadType
) &&
3542 (!LOAD_TYPE_HAS_FLAGS(aLoadType
,
3543 nsIWebNavigation::LOAD_FLAGS_IS_REFRESH
) ||
3544 ShouldAddEntryForRefresh(aCurrentURI
, aInfo
.mInfo
))) {
3545 changeID
= rootSH
->AddPendingHistoryChange();
3548 // History load doesn't change the length, only index.
3549 changeID
= rootSH
->AddPendingHistoryChange(aInfo
.mOffset
, 0);
3552 ContentChild
* cc
= ContentChild::GetSingleton();
3553 mozilla::Unused
<< cc
->SendHistoryCommit(
3554 this, aInfo
.mLoadId
, changeID
, aLoadType
, aPersist
, aCloneEntryChildren
,
3555 aChannelExpired
, aCacheKey
);
3557 Canonical()->SessionHistoryCommit(aInfo
.mLoadId
, changeID
, aLoadType
,
3558 aPersist
, aCloneEntryChildren
,
3559 aChannelExpired
, aCacheKey
);
3563 void BrowsingContext::SetActiveSessionHistoryEntry(
3564 const Maybe
<nsPoint
>& aPreviousScrollPos
, SessionHistoryInfo
* aInfo
,
3565 uint32_t aLoadType
, uint32_t aUpdatedCacheKey
) {
3566 if (XRE_IsContentProcess()) {
3567 // XXX Why we update cache key only in content process case?
3568 if (aUpdatedCacheKey
!= 0) {
3569 aInfo
->SetCacheKey(aUpdatedCacheKey
);
3573 RefPtr
<ChildSHistory
> shistory
= Top()->GetChildSessionHistory();
3575 changeID
= shistory
->AddPendingHistoryChange();
3577 ContentChild::GetSingleton()->SendSetActiveSessionHistoryEntry(
3578 this, aPreviousScrollPos
, *aInfo
, aLoadType
, aUpdatedCacheKey
,
3581 Canonical()->SetActiveSessionHistoryEntry(
3582 aPreviousScrollPos
, aInfo
, aLoadType
, aUpdatedCacheKey
, nsID());
3586 void BrowsingContext::ReplaceActiveSessionHistoryEntry(
3587 SessionHistoryInfo
* aInfo
) {
3588 if (XRE_IsContentProcess()) {
3589 ContentChild::GetSingleton()->SendReplaceActiveSessionHistoryEntry(this,
3592 Canonical()->ReplaceActiveSessionHistoryEntry(aInfo
);
3596 void BrowsingContext::RemoveDynEntriesFromActiveSessionHistoryEntry() {
3597 if (XRE_IsContentProcess()) {
3598 ContentChild::GetSingleton()
3599 ->SendRemoveDynEntriesFromActiveSessionHistoryEntry(this);
3601 Canonical()->RemoveDynEntriesFromActiveSessionHistoryEntry();
3605 void BrowsingContext::RemoveFromSessionHistory(const nsID
& aChangeID
) {
3606 if (XRE_IsContentProcess()) {
3607 ContentChild::GetSingleton()->SendRemoveFromSessionHistory(this, aChangeID
);
3609 Canonical()->RemoveFromSessionHistory(aChangeID
);
3613 void BrowsingContext::HistoryGo(int32_t aOffset
, uint64_t aHistoryEpoch
,
3614 bool aRequireUserInteraction
,
3615 bool aUserActivation
,
3616 std::function
<void(int32_t&&)>&& aResolver
) {
3617 if (XRE_IsContentProcess()) {
3618 ContentChild::GetSingleton()->SendHistoryGo(
3619 this, aOffset
, aHistoryEpoch
, aRequireUserInteraction
, aUserActivation
,
3620 std::move(aResolver
),
3622 ResponseRejectReason
) { /* FIXME Is ignoring this fine? */ });
3624 Canonical()->HistoryGo(
3625 aOffset
, aHistoryEpoch
, aRequireUserInteraction
, aUserActivation
,
3626 Canonical()->GetContentParent()
3627 ? Some(Canonical()->GetContentParent()->ChildID())
3629 std::move(aResolver
));
3633 void BrowsingContext::SetChildSHistory(ChildSHistory
* aChildSHistory
) {
3634 mChildSessionHistory
= aChildSHistory
;
3635 mChildSessionHistory
->SetBrowsingContext(this);
3636 mFields
.SetWithoutSyncing
<IDX_HasSessionHistory
>(true);
3639 bool BrowsingContext::ShouldUpdateSessionHistory(uint32_t aLoadType
) {
3640 // We don't update session history on reload unless we're loading
3641 // an iframe in shift-reload case.
3642 return nsDocShell::ShouldUpdateGlobalHistory(aLoadType
) &&
3643 (!(aLoadType
& nsIDocShell::LOAD_CMD_RELOAD
) ||
3644 (IsForceReloadType(aLoadType
) && IsSubframe()));
3647 nsresult
BrowsingContext::CheckLocationChangeRateLimit(CallerType aCallerType
) {
3648 // We only rate limit non system callers
3649 if (aCallerType
== CallerType::System
) {
3653 // Fetch rate limiting preferences
3654 uint32_t limitCount
=
3655 StaticPrefs::dom_navigation_locationChangeRateLimit_count();
3656 uint32_t timeSpanSeconds
=
3657 StaticPrefs::dom_navigation_locationChangeRateLimit_timespan();
3659 // Disable throttling if either of the preferences is set to 0.
3660 if (limitCount
== 0 || timeSpanSeconds
== 0) {
3664 TimeDuration throttleSpan
= TimeDuration::FromSeconds(timeSpanSeconds
);
3666 if (mLocationChangeRateLimitSpanStart
.IsNull() ||
3667 ((TimeStamp::Now() - mLocationChangeRateLimitSpanStart
) > throttleSpan
)) {
3668 // Initial call or timespan exceeded, reset counter and timespan.
3669 mLocationChangeRateLimitSpanStart
= TimeStamp::Now();
3670 mLocationChangeRateLimitCount
= 1;
3674 if (mLocationChangeRateLimitCount
>= limitCount
) {
3675 // Rate limit reached
3677 Document
* doc
= GetDocument();
3679 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag
, "DOM"_ns
, doc
,
3680 nsContentUtils::eDOM_PROPERTIES
,
3681 "LocChangeFloodingPrevented");
3684 return NS_ERROR_DOM_SECURITY_ERR
;
3687 mLocationChangeRateLimitCount
++;
3691 void BrowsingContext::ResetLocationChangeRateLimit() {
3692 // Resetting the timestamp object will cause the check function to
3693 // init again and reset the rate limit.
3694 mLocationChangeRateLimitSpanStart
= TimeStamp();
3701 void IPDLParamTraits
<dom::MaybeDiscarded
<dom::BrowsingContext
>>::Write(
3702 IPC::Message
* aMsg
, IProtocol
* aActor
,
3703 const dom::MaybeDiscarded
<dom::BrowsingContext
>& aParam
) {
3704 MOZ_DIAGNOSTIC_ASSERT(!aParam
.GetMaybeDiscarded() ||
3705 aParam
.GetMaybeDiscarded()->EverAttached());
3706 uint64_t id
= aParam
.ContextId();
3707 WriteIPDLParam(aMsg
, aActor
, id
);
3710 bool IPDLParamTraits
<dom::MaybeDiscarded
<dom::BrowsingContext
>>::Read(
3711 const IPC::Message
* aMsg
, PickleIterator
* aIter
, IProtocol
* aActor
,
3712 dom::MaybeDiscarded
<dom::BrowsingContext
>* aResult
) {
3714 if (!ReadIPDLParam(aMsg
, aIter
, aActor
, &id
)) {
3720 } else if (RefPtr
<dom::BrowsingContext
> bc
= dom::BrowsingContext::Get(id
)) {
3721 *aResult
= std::move(bc
);
3723 aResult
->SetDiscarded(id
);
3728 void IPDLParamTraits
<dom::BrowsingContext::IPCInitializer
>::Write(
3729 IPC::Message
* aMessage
, IProtocol
* aActor
,
3730 const dom::BrowsingContext::IPCInitializer
& aInit
) {
3731 // Write actor ID parameters.
3732 WriteIPDLParam(aMessage
, aActor
, aInit
.mId
);
3733 WriteIPDLParam(aMessage
, aActor
, aInit
.mParentId
);
3734 WriteIPDLParam(aMessage
, aActor
, aInit
.mWindowless
);
3735 WriteIPDLParam(aMessage
, aActor
, aInit
.mUseRemoteTabs
);
3736 WriteIPDLParam(aMessage
, aActor
, aInit
.mUseRemoteSubframes
);
3737 WriteIPDLParam(aMessage
, aActor
, aInit
.mCreatedDynamically
);
3738 WriteIPDLParam(aMessage
, aActor
, aInit
.mChildOffset
);
3739 WriteIPDLParam(aMessage
, aActor
, aInit
.mOriginAttributes
);
3740 WriteIPDLParam(aMessage
, aActor
, aInit
.mRequestContextId
);
3741 WriteIPDLParam(aMessage
, aActor
, aInit
.mSessionHistoryIndex
);
3742 WriteIPDLParam(aMessage
, aActor
, aInit
.mSessionHistoryCount
);
3743 WriteIPDLParam(aMessage
, aActor
, aInit
.mFields
);
3746 bool IPDLParamTraits
<dom::BrowsingContext::IPCInitializer
>::Read(
3747 const IPC::Message
* aMessage
, PickleIterator
* aIterator
, IProtocol
* aActor
,
3748 dom::BrowsingContext::IPCInitializer
* aInit
) {
3749 // Read actor ID parameters.
3750 if (!ReadIPDLParam(aMessage
, aIterator
, aActor
, &aInit
->mId
) ||
3751 !ReadIPDLParam(aMessage
, aIterator
, aActor
, &aInit
->mParentId
) ||
3752 !ReadIPDLParam(aMessage
, aIterator
, aActor
, &aInit
->mWindowless
) ||
3753 !ReadIPDLParam(aMessage
, aIterator
, aActor
, &aInit
->mUseRemoteTabs
) ||
3754 !ReadIPDLParam(aMessage
, aIterator
, aActor
,
3755 &aInit
->mUseRemoteSubframes
) ||
3756 !ReadIPDLParam(aMessage
, aIterator
, aActor
,
3757 &aInit
->mCreatedDynamically
) ||
3758 !ReadIPDLParam(aMessage
, aIterator
, aActor
, &aInit
->mChildOffset
) ||
3759 !ReadIPDLParam(aMessage
, aIterator
, aActor
, &aInit
->mOriginAttributes
) ||
3760 !ReadIPDLParam(aMessage
, aIterator
, aActor
, &aInit
->mRequestContextId
) ||
3761 !ReadIPDLParam(aMessage
, aIterator
, aActor
,
3762 &aInit
->mSessionHistoryIndex
) ||
3763 !ReadIPDLParam(aMessage
, aIterator
, aActor
,
3764 &aInit
->mSessionHistoryCount
) ||
3765 !ReadIPDLParam(aMessage
, aIterator
, aActor
, &aInit
->mFields
)) {
3771 template struct IPDLParamTraits
<dom::BrowsingContext::BaseTransaction
>;
3774 } // namespace mozilla