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 "nsAccessibilityService.h"
16 # include "mozilla/a11y/AccessibleWrap.h"
17 # include "mozilla/a11y/Compatibility.h"
18 # include "mozilla/a11y/nsWinUtils.h"
21 #include "mozilla/AppShutdown.h"
22 #include "mozilla/dom/CanonicalBrowsingContext.h"
23 #include "mozilla/dom/BindingIPCUtils.h"
24 #include "mozilla/dom/BrowserHost.h"
25 #include "mozilla/dom/BrowserChild.h"
26 #include "mozilla/dom/BrowserParent.h"
27 #include "mozilla/dom/BrowsingContextGroup.h"
28 #include "mozilla/dom/BrowsingContextBinding.h"
29 #include "mozilla/dom/ContentChild.h"
30 #include "mozilla/dom/ContentParent.h"
31 #include "mozilla/dom/Document.h"
32 #include "mozilla/dom/Element.h"
33 #include "mozilla/dom/HTMLEmbedElement.h"
34 #include "mozilla/dom/HTMLIFrameElement.h"
35 #include "mozilla/dom/Location.h"
36 #include "mozilla/dom/LocationBinding.h"
37 #include "mozilla/dom/MediaDevices.h"
38 #include "mozilla/dom/PopupBlocker.h"
39 #include "mozilla/dom/ScriptSettings.h"
40 #include "mozilla/dom/SessionStoreChild.h"
41 #include "mozilla/dom/SessionStorageManager.h"
42 #include "mozilla/dom/StructuredCloneTags.h"
43 #include "mozilla/dom/UserActivationIPCUtils.h"
44 #include "mozilla/dom/WindowBinding.h"
45 #include "mozilla/dom/WindowContext.h"
46 #include "mozilla/dom/WindowGlobalChild.h"
47 #include "mozilla/dom/WindowGlobalParent.h"
48 #include "mozilla/dom/WindowProxyHolder.h"
49 #include "mozilla/dom/SyncedContextInlines.h"
50 #include "mozilla/dom/XULFrameElement.h"
51 #include "mozilla/ipc/ProtocolUtils.h"
52 #include "mozilla/net/DocumentLoadListener.h"
53 #include "mozilla/net/RequestContextService.h"
54 #include "mozilla/Assertions.h"
55 #include "mozilla/AsyncEventDispatcher.h"
56 #include "mozilla/ClearOnShutdown.h"
57 #include "mozilla/Components.h"
58 #include "mozilla/HashTable.h"
59 #include "mozilla/Logging.h"
60 #include "mozilla/MediaFeatureChange.h"
61 #include "mozilla/ResultExtensions.h"
62 #include "mozilla/Services.h"
63 #include "mozilla/StaticPrefs_fission.h"
64 #include "mozilla/StaticPrefs_media.h"
65 #include "mozilla/StaticPrefs_page_load.h"
66 #include "mozilla/StaticPtr.h"
67 #include "mozilla/URLQueryStringStripper.h"
68 #include "mozilla/EventStateManager.h"
69 #include "nsIURIFixup.h"
70 #include "nsIXULRuntime.h"
72 #include "nsDocShell.h"
73 #include "nsDocShellLoadState.h"
74 #include "nsFocusManager.h"
75 #include "nsGlobalWindowInner.h"
76 #include "nsGlobalWindowOuter.h"
77 #include "PresShell.h"
78 #include "nsIObserverService.h"
79 #include "nsISHistory.h"
80 #include "nsContentUtils.h"
81 #include "nsQueryObject.h"
82 #include "nsSandboxFlags.h"
83 #include "nsScriptError.h"
84 #include "nsThreadUtils.h"
85 #include "xpcprivate.h"
87 #include "AutoplayPolicy.h"
88 #include "GVAutoplayRequestStatusIPC.h"
90 extern mozilla::LazyLogModule gAutoplayPermissionLog
;
91 extern mozilla::LazyLogModule gTimeoutDeferralLog
;
93 #define AUTOPLAY_LOG(msg, ...) \
94 MOZ_LOG(gAutoplayPermissionLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
97 // Allow serialization and deserialization of OrientationType over IPC
99 struct ParamTraits
<mozilla::dom::OrientationType
>
100 : public mozilla::dom::WebIDLEnumSerializer
<mozilla::dom::OrientationType
> {
104 struct ParamTraits
<mozilla::dom::DisplayMode
>
105 : public mozilla::dom::WebIDLEnumSerializer
<mozilla::dom::DisplayMode
> {};
108 struct ParamTraits
<mozilla::dom::PrefersColorSchemeOverride
>
109 : public mozilla::dom::WebIDLEnumSerializer
<
110 mozilla::dom::PrefersColorSchemeOverride
> {};
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 mozilla::dom::WebIDLEnumSerializer
<
123 mozilla::dom::TouchEventsOverride
> {};
126 struct ParamTraits
<mozilla::dom::EmbedderColorSchemes
> {
127 using paramType
= mozilla::dom::EmbedderColorSchemes
;
129 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
130 WriteParam(aWriter
, aParam
.mUsed
);
131 WriteParam(aWriter
, aParam
.mPreferred
);
134 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
135 return ReadParam(aReader
, &aResult
->mUsed
) &&
136 ReadParam(aReader
, &aResult
->mPreferred
);
145 // Explicit specialization of the `Transaction` type. Required by the `extern
146 // template class` declaration in the header.
147 template class syncedcontext::Transaction
<BrowsingContext
>;
149 extern mozilla::LazyLogModule gUserInteractionPRLog
;
151 #define USER_ACTIVATION_LOG(msg, ...) \
152 MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
154 static LazyLogModule
gBrowsingContextLog("BrowsingContext");
155 static LazyLogModule
gBrowsingContextSyncLog("BrowsingContextSync");
157 typedef nsTHashMap
<nsUint64HashKey
, BrowsingContext
*> BrowsingContextMap
;
159 // All BrowsingContexts indexed by Id
160 static StaticAutoPtr
<BrowsingContextMap
> sBrowsingContexts
;
161 // Top-level Content BrowsingContexts only, indexed by BrowserId instead of Id
162 static StaticAutoPtr
<BrowsingContextMap
> sCurrentTopByBrowserId
;
164 static bool gIPCEnabledAnnotation
= false;
165 static bool gFissionEnabledAnnotation
= false;
167 static void UnregisterBrowserId(BrowsingContext
* aBrowsingContext
) {
168 if (!aBrowsingContext
->IsTopContent() || !sCurrentTopByBrowserId
) {
172 // Avoids an extra lookup
173 auto browserIdEntry
=
174 sCurrentTopByBrowserId
->Lookup(aBrowsingContext
->BrowserId());
175 if (browserIdEntry
&& browserIdEntry
.Data() == aBrowsingContext
) {
176 browserIdEntry
.Remove();
180 static void Register(BrowsingContext
* aBrowsingContext
) {
181 sBrowsingContexts
->InsertOrUpdate(aBrowsingContext
->Id(), aBrowsingContext
);
182 if (aBrowsingContext
->IsTopContent()) {
183 sCurrentTopByBrowserId
->InsertOrUpdate(aBrowsingContext
->BrowserId(),
187 aBrowsingContext
->Group()->Register(aBrowsingContext
);
191 void BrowsingContext::UpdateCurrentTopByBrowserId(
192 BrowsingContext
* aNewBrowsingContext
) {
193 if (aNewBrowsingContext
->IsTopContent()) {
194 sCurrentTopByBrowserId
->InsertOrUpdate(aNewBrowsingContext
->BrowserId(),
195 aNewBrowsingContext
);
199 BrowsingContext
* BrowsingContext::GetParent() const {
200 return mParentWindow
? mParentWindow
->GetBrowsingContext() : nullptr;
203 bool BrowsingContext::IsInSubtreeOf(BrowsingContext
* aContext
) {
204 BrowsingContext
* bc
= this;
206 if (bc
== aContext
) {
209 } while ((bc
= bc
->GetParent()));
213 BrowsingContext
* BrowsingContext::Top() {
214 BrowsingContext
* bc
= this;
215 while (bc
->mParentWindow
) {
216 bc
= bc
->GetParent();
221 const BrowsingContext
* BrowsingContext::Top() const {
222 const BrowsingContext
* bc
= this;
223 while (bc
->mParentWindow
) {
224 bc
= bc
->GetParent();
229 int32_t BrowsingContext::IndexOf(BrowsingContext
* aChild
) {
231 for (BrowsingContext
* child
: Children()) {
233 if (child
== aChild
) {
240 WindowContext
* BrowsingContext::GetTopWindowContext() const {
242 return mParentWindow
->TopWindowContext();
244 return mCurrentWindowContext
;
248 void BrowsingContext::Init() {
249 if (!sBrowsingContexts
) {
250 sBrowsingContexts
= new BrowsingContextMap();
251 sCurrentTopByBrowserId
= new BrowsingContextMap();
252 ClearOnShutdown(&sBrowsingContexts
);
253 ClearOnShutdown(&sCurrentTopByBrowserId
);
254 CrashReporter::RegisterAnnotationBool(
255 CrashReporter::Annotation::DOMIPCEnabled
, &gIPCEnabledAnnotation
);
256 CrashReporter::RegisterAnnotationBool(
257 CrashReporter::Annotation::DOMFissionEnabled
,
258 &gFissionEnabledAnnotation
);
263 LogModule
* BrowsingContext::GetLog() { return gBrowsingContextLog
; }
266 LogModule
* BrowsingContext::GetSyncLog() { return gBrowsingContextSyncLog
; }
269 already_AddRefed
<BrowsingContext
> BrowsingContext::Get(uint64_t aId
) {
270 return do_AddRef(sBrowsingContexts
->Get(aId
));
274 already_AddRefed
<BrowsingContext
> BrowsingContext::GetCurrentTopByBrowserId(
275 uint64_t aBrowserId
) {
276 return do_AddRef(sCurrentTopByBrowserId
->Get(aBrowserId
));
280 already_AddRefed
<BrowsingContext
> BrowsingContext::GetFromWindow(
281 WindowProxyHolder
& aProxy
) {
282 return do_AddRef(aProxy
.get());
285 CanonicalBrowsingContext
* BrowsingContext::Canonical() {
286 return CanonicalBrowsingContext::Cast(this);
289 bool BrowsingContext::IsOwnedByProcess() const {
290 return mIsInProcess
&& mDocShell
&&
291 !nsDocShell::Cast(mDocShell
)->WillChangeProcess();
294 bool BrowsingContext::SameOriginWithTop() {
295 MOZ_ASSERT(IsInProcess());
296 // If the top BrowsingContext is not same-process to us, it is cross-origin
297 if (!Top()->IsInProcess()) {
301 nsIDocShell
* docShell
= GetDocShell();
305 Document
* doc
= docShell
->GetDocument();
309 nsIPrincipal
* principal
= doc
->NodePrincipal();
311 nsIDocShell
* topDocShell
= Top()->GetDocShell();
315 Document
* topDoc
= topDocShell
->GetDocument();
319 nsIPrincipal
* topPrincipal
= topDoc
->NodePrincipal();
321 return principal
->Equals(topPrincipal
);
325 already_AddRefed
<BrowsingContext
> BrowsingContext::CreateDetached(
326 nsGlobalWindowInner
* aParent
, BrowsingContext
* aOpener
,
327 BrowsingContextGroup
* aSpecificGroup
, const nsAString
& aName
, Type aType
,
328 bool aIsPopupRequested
, bool aCreatedDynamically
) {
330 MOZ_DIAGNOSTIC_ASSERT(aParent
->GetWindowContext());
331 MOZ_DIAGNOSTIC_ASSERT(aParent
->GetBrowsingContext()->mType
== aType
);
332 MOZ_DIAGNOSTIC_ASSERT(aParent
->GetBrowsingContext()->GetBrowserId() != 0);
335 MOZ_DIAGNOSTIC_ASSERT(aType
!= Type::Chrome
|| XRE_IsParentProcess());
337 uint64_t id
= nsContentUtils::GenerateBrowsingContextId();
339 MOZ_LOG(GetLog(), LogLevel::Debug
,
340 ("Creating 0x%08" PRIx64
" in %s", id
,
341 XRE_IsParentProcess() ? "Parent" : "Child"));
343 RefPtr
<BrowsingContext
> parentBC
=
344 aParent
? aParent
->GetBrowsingContext() : nullptr;
345 RefPtr
<WindowContext
> parentWC
=
346 aParent
? aParent
->GetWindowContext() : nullptr;
347 BrowsingContext
* inherit
= parentBC
? parentBC
.get() : aOpener
;
349 // Determine which BrowsingContextGroup this context should be created in.
350 RefPtr
<BrowsingContextGroup
> group
= aSpecificGroup
;
351 if (aType
== Type::Chrome
) {
352 MOZ_DIAGNOSTIC_ASSERT(!group
);
353 group
= BrowsingContextGroup::GetChromeGroup();
355 group
= BrowsingContextGroup::Select(parentWC
, aOpener
);
358 // Configure initial values for synced fields.
360 fields
.Get
<IDX_Name
>() = aName
;
363 MOZ_DIAGNOSTIC_ASSERT(!aParent
,
364 "new BC with both initial opener and parent");
365 MOZ_DIAGNOSTIC_ASSERT(aOpener
->Group() == group
);
366 MOZ_DIAGNOSTIC_ASSERT(aOpener
->mType
== aType
);
367 fields
.Get
<IDX_OpenerId
>() = aOpener
->Id();
368 fields
.Get
<IDX_HadOriginalOpener
>() = true;
370 if (aType
== Type::Chrome
&& !aParent
) {
371 // See SetOpener for why we do this inheritance.
372 fields
.Get
<IDX_PrefersColorSchemeOverride
>() =
373 aOpener
->Top()->GetPrefersColorSchemeOverride();
378 MOZ_DIAGNOSTIC_ASSERT(parentBC
->Group() == group
);
379 MOZ_DIAGNOSTIC_ASSERT(parentBC
->mType
== aType
);
380 fields
.Get
<IDX_EmbedderInnerWindowId
>() = aParent
->WindowID();
381 // Non-toplevel content documents are always embededed within content.
382 fields
.Get
<IDX_EmbeddedInContentDocument
>() =
383 parentBC
->mType
== Type::Content
;
385 // XXX(farre): Can/Should we check aParent->IsLoading() here? (Bug
386 // 1608448) Check if the parent was itself loading already
387 auto readystate
= aParent
->GetDocument()->GetReadyStateEnum();
388 fields
.Get
<IDX_AncestorLoading
>() =
389 parentBC
->GetAncestorLoading() ||
390 readystate
== Document::ReadyState::READYSTATE_LOADING
||
391 readystate
== Document::ReadyState::READYSTATE_INTERACTIVE
;
394 fields
.Get
<IDX_BrowserId
>() =
395 parentBC
? parentBC
->GetBrowserId() : nsContentUtils::GenerateBrowserId();
397 fields
.Get
<IDX_OpenerPolicy
>() = nsILoadInfo::OPENER_POLICY_UNSAFE_NONE
;
398 if (aOpener
&& aOpener
->SameOriginWithTop()) {
399 // We inherit the opener policy if there is a creator and if the creator's
400 // origin is same origin with the creator's top-level origin.
401 // If it is cross origin we should not inherit the CrossOriginOpenerPolicy
402 fields
.Get
<IDX_OpenerPolicy
>() = aOpener
->Top()->GetOpenerPolicy();
404 // If we inherit a policy which is potentially cross-origin isolated, we
405 // must be in a potentially cross-origin isolated BCG.
406 bool isPotentiallyCrossOriginIsolated
=
407 fields
.Get
<IDX_OpenerPolicy
>() ==
408 nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
;
409 MOZ_RELEASE_ASSERT(isPotentiallyCrossOriginIsolated
==
410 group
->IsPotentiallyCrossOriginIsolated());
411 } else if (aOpener
) {
412 // They are not same origin
413 auto topPolicy
= aOpener
->Top()->GetOpenerPolicy();
414 MOZ_RELEASE_ASSERT(topPolicy
== nsILoadInfo::OPENER_POLICY_UNSAFE_NONE
||
416 nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_ALLOW_POPUPS
);
417 } else if (!aParent
&& group
->IsPotentiallyCrossOriginIsolated()) {
418 // If we're creating a brand-new toplevel BC in a potentially cross-origin
419 // isolated group, it should start out with a strict opener policy.
420 fields
.Get
<IDX_OpenerPolicy
>() =
421 nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
;
424 fields
.Get
<IDX_HistoryID
>() = nsID::GenerateUUID();
425 fields
.Get
<IDX_ExplicitActive
>() = [&] {
426 if (parentBC
|| aType
== Type::Content
) {
427 // Non-root browsing-contexts inherit their status from its parent.
428 // Top-content either gets managed by the top chrome, or gets manually
429 // managed by the front-end (see ManuallyManagesActiveness). In any case
430 // we want to start off as inactive.
431 return ExplicitActiveStatus::None
;
433 // Chrome starts as active.
434 return ExplicitActiveStatus::Active
;
437 fields
.Get
<IDX_FullZoom
>() = parentBC
? parentBC
->FullZoom() : 1.0f
;
438 fields
.Get
<IDX_TextZoom
>() = parentBC
? parentBC
->TextZoom() : 1.0f
;
440 bool allowContentRetargeting
=
441 inherit
? inherit
->GetAllowContentRetargetingOnChildren() : true;
442 fields
.Get
<IDX_AllowContentRetargeting
>() = allowContentRetargeting
;
443 fields
.Get
<IDX_AllowContentRetargetingOnChildren
>() = allowContentRetargeting
;
445 // Assume top allows fullscreen for its children unless otherwise stated.
446 // Subframes start with it false unless otherwise noted in SetEmbedderElement.
447 fields
.Get
<IDX_FullscreenAllowedByOwner
>() = !aParent
;
449 fields
.Get
<IDX_DefaultLoadFlags
>() =
450 inherit
? inherit
->GetDefaultLoadFlags() : nsIRequest::LOAD_NORMAL
;
452 fields
.Get
<IDX_OrientationLock
>() = mozilla::hal::ScreenOrientation::None
;
454 fields
.Get
<IDX_UseGlobalHistory
>() =
455 inherit
? inherit
->GetUseGlobalHistory() : false;
457 fields
.Get
<IDX_UseErrorPages
>() = true;
459 fields
.Get
<IDX_TouchEventsOverrideInternal
>() = TouchEventsOverride::None
;
461 fields
.Get
<IDX_AllowJavascript
>() =
462 inherit
? inherit
->GetAllowJavascript() : true;
464 fields
.Get
<IDX_IsPopupRequested
>() = aIsPopupRequested
;
467 fields
.Get
<IDX_ShouldDelayMediaFromStart
>() =
468 StaticPrefs::media_block_autoplay_until_in_foreground();
471 RefPtr
<BrowsingContext
> context
;
472 if (XRE_IsParentProcess()) {
473 context
= new CanonicalBrowsingContext(parentWC
, group
, id
,
474 /* aOwnerProcessId */ 0,
475 /* aEmbedderProcessId */ 0, aType
,
479 new BrowsingContext(parentWC
, group
, id
, aType
, std::move(fields
));
482 context
->mEmbeddedByThisProcess
= XRE_IsParentProcess() || aParent
;
483 context
->mCreatedDynamically
= aCreatedDynamically
;
485 context
->mPrivateBrowsingId
= inherit
->mPrivateBrowsingId
;
486 context
->mUseRemoteTabs
= inherit
->mUseRemoteTabs
;
487 context
->mUseRemoteSubframes
= inherit
->mUseRemoteSubframes
;
488 context
->mOriginAttributes
= inherit
->mOriginAttributes
;
491 nsCOMPtr
<nsIRequestContextService
> rcsvc
=
492 net::RequestContextService::GetOrCreate();
494 nsCOMPtr
<nsIRequestContext
> requestContext
;
495 nsresult rv
= rcsvc
->NewRequestContext(getter_AddRefs(requestContext
));
496 if (NS_SUCCEEDED(rv
) && requestContext
) {
497 context
->mRequestContextId
= requestContext
->GetID();
501 return context
.forget();
504 already_AddRefed
<BrowsingContext
> BrowsingContext::CreateIndependent(
506 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess(),
507 "BCs created in the content process must be related to "
508 "some BrowserChild");
509 RefPtr
<BrowsingContext
> bc(
510 CreateDetached(nullptr, nullptr, nullptr, u
""_ns
, aType
, false));
511 bc
->mWindowless
= bc
->IsContent();
512 bc
->mEmbeddedByThisProcess
= true;
513 bc
->EnsureAttached();
517 void BrowsingContext::EnsureAttached() {
518 if (!mEverAttached
) {
521 // Attach the browsing context to the tree.
522 Attach(/* aFromIPC */ false, /* aOriginProcess */ nullptr);
527 mozilla::ipc::IPCResult
BrowsingContext::CreateFromIPC(
528 BrowsingContext::IPCInitializer
&& aInit
, BrowsingContextGroup
* aGroup
,
529 ContentParent
* aOriginProcess
) {
530 MOZ_DIAGNOSTIC_ASSERT(aOriginProcess
|| XRE_IsContentProcess());
531 MOZ_DIAGNOSTIC_ASSERT(aGroup
);
533 uint64_t originId
= 0;
534 if (aOriginProcess
) {
535 originId
= aOriginProcess
->ChildID();
536 aGroup
->EnsureHostProcess(aOriginProcess
);
539 MOZ_LOG(GetLog(), LogLevel::Debug
,
540 ("Creating 0x%08" PRIx64
" from IPC (origin=0x%08" PRIx64
")",
541 aInit
.mId
, originId
));
543 RefPtr
<WindowContext
> parent
= aInit
.GetParent();
545 RefPtr
<BrowsingContext
> context
;
546 if (XRE_IsParentProcess()) {
547 // If the new BrowsingContext has a parent, it is a sub-frame embedded in
548 // whatever process sent the message. If it doesn't, and is not windowless,
549 // it is a new window or tab, and will be embedded in the parent process.
550 uint64_t embedderProcessId
= (aInit
.mWindowless
|| parent
) ? originId
: 0;
551 context
= new CanonicalBrowsingContext(parent
, aGroup
, aInit
.mId
, originId
,
552 embedderProcessId
, Type::Content
,
553 std::move(aInit
.mFields
));
555 context
= new BrowsingContext(parent
, aGroup
, aInit
.mId
, Type::Content
,
556 std::move(aInit
.mFields
));
559 context
->mWindowless
= aInit
.mWindowless
;
560 context
->mCreatedDynamically
= aInit
.mCreatedDynamically
;
561 context
->mChildOffset
= aInit
.mChildOffset
;
562 if (context
->GetHasSessionHistory()) {
563 context
->CreateChildSHistory();
564 if (mozilla::SessionHistoryInParent()) {
565 context
->GetChildSessionHistory()->SetIndexAndLength(
566 aInit
.mSessionHistoryIndex
, aInit
.mSessionHistoryCount
, nsID());
570 // NOTE: Call through the `Set` methods for these values to ensure that any
571 // relevant process-local state is also updated.
572 context
->SetOriginAttributes(aInit
.mOriginAttributes
);
573 context
->SetRemoteTabs(aInit
.mUseRemoteTabs
);
574 context
->SetRemoteSubframes(aInit
.mUseRemoteSubframes
);
575 context
->mRequestContextId
= aInit
.mRequestContextId
;
576 // NOTE: Private browsing ID is set by `SetOriginAttributes`.
580 return context
->Attach(/* aFromIPC */ true, aOriginProcess
);
583 BrowsingContext::BrowsingContext(WindowContext
* aParentWindow
,
584 BrowsingContextGroup
* aGroup
,
585 uint64_t aBrowsingContextId
, Type aType
,
587 : mFields(std::move(aInit
)),
589 mBrowsingContextId(aBrowsingContextId
),
591 mParentWindow(aParentWindow
),
592 mPrivateBrowsingId(0),
593 mEverAttached(false),
597 mDanglingRemoteOuterProxies(false),
598 mEmbeddedByThisProcess(false),
599 mUseRemoteTabs(false),
600 mUseRemoteSubframes(false),
601 mCreatedDynamically(false),
603 mCanExecuteScripts(true),
605 MOZ_RELEASE_ASSERT(!mParentWindow
|| mParentWindow
->Group() == mGroup
);
606 MOZ_RELEASE_ASSERT(mBrowsingContextId
!= 0);
607 MOZ_RELEASE_ASSERT(mGroup
);
610 void BrowsingContext::SetDocShell(nsIDocShell
* aDocShell
) {
611 // XXX(nika): We should communicate that we are now an active BrowsingContext
612 // process to the parent & do other validation here.
613 MOZ_DIAGNOSTIC_ASSERT(mEverAttached
);
614 MOZ_RELEASE_ASSERT(aDocShell
->GetBrowsingContext() == this);
615 mDocShell
= aDocShell
;
616 mDanglingRemoteOuterProxies
= !mIsInProcess
;
618 if (mChildSessionHistory
) {
619 mChildSessionHistory
->SetIsInProcess(true);
622 RecomputeCanExecuteScripts();
623 ClearCachedValuesOfLocations();
626 // This class implements a callback that will return the remote window proxy for
627 // mBrowsingContext in that compartment, if it has one. It also removes the
628 // proxy from the map, because the object will be transplanted into another kind
630 class MOZ_STACK_CLASS CompartmentRemoteProxyTransplantCallback
631 : public js::CompartmentTransplantCallback
{
633 explicit CompartmentRemoteProxyTransplantCallback(
634 BrowsingContext
* aBrowsingContext
)
635 : mBrowsingContext(aBrowsingContext
) {}
637 virtual JSObject
* getObjectToTransplant(
638 JS::Compartment
* compartment
) override
{
639 auto* priv
= xpc::CompartmentPrivate::Get(compartment
);
644 auto& map
= priv
->GetRemoteProxyMap();
645 auto result
= map
.lookup(mBrowsingContext
);
649 JSObject
* resultObject
= result
->value();
656 BrowsingContext
* mBrowsingContext
;
659 void BrowsingContext::CleanUpDanglingRemoteOuterWindowProxies(
660 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aOuter
) {
661 if (!mDanglingRemoteOuterProxies
) {
664 mDanglingRemoteOuterProxies
= false;
666 CompartmentRemoteProxyTransplantCallback
cb(this);
667 js::RemapRemoteWindowProxies(aCx
, &cb
, aOuter
);
670 bool BrowsingContext::IsActive() const {
671 const BrowsingContext
* current
= this;
673 auto explicit_
= current
->GetExplicitActive();
674 if (explicit_
!= ExplicitActiveStatus::None
) {
675 return explicit_
== ExplicitActiveStatus::Active
;
677 if (mParentWindow
&& !mParentWindow
->IsCurrent()) {
680 } while ((current
= current
->GetParent()));
685 bool BrowsingContext::GetIsActiveBrowserWindow() {
686 if (!XRE_IsParentProcess()) {
687 return Top()->GetIsActiveBrowserWindowInternal();
690 // chrome:// urls loaded in the parent won't receive
691 // their own activation so we defer to the top chrome
692 // Browsing Context when in the parent process.
694 ->TopCrossChromeBoundary()
695 ->GetIsActiveBrowserWindowInternal();
698 void BrowsingContext::SetIsActiveBrowserWindow(bool aActive
) {
699 Unused
<< SetIsActiveBrowserWindowInternal(aActive
);
702 bool BrowsingContext::FullscreenAllowed() const {
703 for (auto* current
= this; current
; current
= current
->GetParent()) {
704 if (!current
->GetFullscreenAllowedByOwner()) {
711 static bool OwnerAllowsFullscreen(const Element
& aEmbedder
) {
712 if (aEmbedder
.IsXULElement()) {
713 return !aEmbedder
.HasAttr(nsGkAtoms::disablefullscreen
);
715 if (aEmbedder
.IsHTMLElement(nsGkAtoms::iframe
)) {
716 // This is controlled by feature policy.
719 if (const auto* embed
= HTMLEmbedElement::FromNode(aEmbedder
)) {
720 return embed
->AllowFullscreen();
725 void BrowsingContext::SetEmbedderElement(Element
* aEmbedder
) {
726 mEmbeddedByThisProcess
= true;
728 // Update embedder-element-specific fields in a shared transaction.
729 // Don't do this when clearing our embedder, as we're being destroyed either
733 txn
.SetEmbedderElementType(Some(aEmbedder
->LocalName()));
734 txn
.SetEmbeddedInContentDocument(
735 aEmbedder
->OwnerDoc()->IsContentDocument());
736 if (nsCOMPtr
<nsPIDOMWindowInner
> inner
=
737 do_QueryInterface(aEmbedder
->GetOwnerGlobal())) {
738 txn
.SetEmbedderInnerWindowId(inner
->WindowID());
740 txn
.SetFullscreenAllowedByOwner(OwnerAllowsFullscreen(*aEmbedder
));
741 if (XRE_IsParentProcess() && aEmbedder
->IsXULElement() && IsTopContent()) {
742 nsAutoString messageManagerGroup
;
743 aEmbedder
->GetAttr(nsGkAtoms::messagemanagergroup
, messageManagerGroup
);
744 txn
.SetMessageManagerGroup(messageManagerGroup
);
745 txn
.SetUseGlobalHistory(
746 !aEmbedder
->HasAttr(nsGkAtoms::disableglobalhistory
));
747 if (!aEmbedder
->HasAttr(nsGkAtoms::manualactiveness
)) {
748 // We're active iff the parent cross-chrome-boundary is active. Note we
749 // can't just use this->Canonical()->GetParentCrossChromeBoundary here,
750 // since mEmbedderElement is still null at this point.
751 RefPtr bc
= aEmbedder
->OwnerDoc()->GetBrowsingContext();
752 const bool isActive
= bc
&& bc
->IsActive();
753 txn
.SetExplicitActive(isActive
? ExplicitActiveStatus::Active
754 : ExplicitActiveStatus::Inactive
);
755 if (auto* bp
= Canonical()->GetBrowserParent()) {
756 bp
->SetRenderLayers(isActive
);
761 MOZ_ALWAYS_SUCCEEDS(txn
.Commit(this));
764 if (XRE_IsParentProcess() && IsTopContent()) {
765 Canonical()->MaybeSetPermanentKey(aEmbedder
);
768 mEmbedderElement
= aEmbedder
;
770 if (mEmbedderElement
) {
771 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
772 obs
->NotifyWhenScriptSafe(ToSupports(this),
773 "browsing-context-did-set-embedder", nullptr);
776 if (IsEmbedderTypeObjectOrEmbed()) {
777 Unused
<< SetSyntheticDocumentContainer(true);
782 bool BrowsingContext::IsEmbedderTypeObjectOrEmbed() {
783 if (const Maybe
<nsString
>& type
= GetEmbedderElementType()) {
784 return nsGkAtoms::object
->Equals(*type
) || nsGkAtoms::embed
->Equals(*type
);
789 void BrowsingContext::Embed() {
790 if (auto* frame
= HTMLIFrameElement::FromNode(mEmbedderElement
)) {
791 frame
->BindToBrowsingContext(this);
795 mozilla::ipc::IPCResult
BrowsingContext::Attach(bool aFromIPC
,
796 ContentParent
* aOriginProcess
) {
797 MOZ_DIAGNOSTIC_ASSERT(!mEverAttached
);
798 MOZ_DIAGNOSTIC_ASSERT_IF(aFromIPC
, aOriginProcess
|| XRE_IsContentProcess());
799 mEverAttached
= true;
801 if (MOZ_LOG_TEST(GetLog(), LogLevel::Debug
)) {
802 nsAutoCString suffix
;
803 mOriginAttributes
.CreateSuffix(suffix
);
804 MOZ_LOG(GetLog(), LogLevel::Debug
,
805 ("%s: Connecting 0x%08" PRIx64
" to 0x%08" PRIx64
806 " (private=%d, remote=%d, fission=%d, oa=%s)",
807 XRE_IsParentProcess() ? "Parent" : "Child", Id(),
808 GetParent() ? GetParent()->Id() : 0, (int)mPrivateBrowsingId
,
809 (int)mUseRemoteTabs
, (int)mUseRemoteSubframes
, suffix
.get()));
812 MOZ_DIAGNOSTIC_ASSERT(mGroup
);
813 MOZ_DIAGNOSTIC_ASSERT(!mIsDiscarded
);
815 if (mGroup
->IsPotentiallyCrossOriginIsolated() !=
816 (Top()->GetOpenerPolicy() ==
817 nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
)) {
818 MOZ_DIAGNOSTIC_ASSERT(aFromIPC
);
820 auto* actor
= aOriginProcess
821 ? static_cast<mozilla::ipc::IProtocol
*>(aOriginProcess
)
822 : static_cast<mozilla::ipc::IProtocol
*>(
823 ContentChild::GetSingleton());
826 "Invalid CrossOriginIsolated state in BrowsingContext::Attach call");
829 "Invalid CrossOriginIsolated state in BrowsingContext::Attach call");
833 AssertCoherentLoadContext();
835 // Add ourselves either to our parent or BrowsingContextGroup's child list.
836 // Important: We shouldn't return IPC_FAIL after this point, since the
837 // BrowsingContext will have already been added to the tree.
840 MOZ_DIAGNOSTIC_ASSERT(!mParentWindow
->IsDiscarded(),
841 "local attach in discarded window");
842 MOZ_DIAGNOSTIC_ASSERT(!GetParent()->IsDiscarded(),
843 "local attach call in discarded bc");
844 MOZ_DIAGNOSTIC_ASSERT(mParentWindow
->GetWindowGlobalChild(),
845 "local attach call with oop parent window");
846 MOZ_DIAGNOSTIC_ASSERT(mParentWindow
->GetWindowGlobalChild()->CanSend(),
847 "local attach call with dead parent window");
850 mCreatedDynamically
? -1 : mParentWindow
->Children().Length();
851 mParentWindow
->AppendChildBrowsingContext(this);
852 RecomputeCanExecuteScripts();
854 mGroup
->Toplevels().AppendElement(this);
857 if (GetIsPopupSpam()) {
858 PopupBlocker::RegisterOpenPopupSpam();
861 if (IsTop() && GetHasSessionHistory() && !mChildSessionHistory
) {
862 CreateChildSHistory();
865 // Why the context is being attached. This will always be "attach" in the
866 // content process, but may be "replace" if it's known the context being
867 // replaced in the parent process.
868 const char16_t
* why
= u
"attach";
870 if (XRE_IsContentProcess() && !aFromIPC
) {
871 // Send attach to our parent if we need to.
872 ContentChild::GetSingleton()->SendCreateBrowsingContext(
873 mGroup
->Id(), GetIPCInitializer());
874 } else if (XRE_IsParentProcess()) {
875 // If this window was created as a subframe by a content process, it must be
876 // being hosted within the same BrowserParent as its mParentWindow.
877 // Toplevel BrowsingContexts created by content have their BrowserParent
878 // configured during `RecvConstructPopupBrowser`.
879 if (mParentWindow
&& aOriginProcess
) {
880 MOZ_DIAGNOSTIC_ASSERT(
881 mParentWindow
->Canonical()->GetContentParent() == aOriginProcess
,
882 "Creator process isn't the same as our embedder?");
883 Canonical()->SetCurrentBrowserParent(
884 mParentWindow
->Canonical()->GetBrowserParent());
887 mGroup
->EachOtherParent(aOriginProcess
, [&](ContentParent
* aParent
) {
888 MOZ_DIAGNOSTIC_ASSERT(IsContent(),
889 "chrome BCG cannot be synced to content process");
890 if (!Canonical()->IsEmbeddedInProcess(aParent
->ChildID())) {
891 Unused
<< aParent
->SendCreateBrowsingContext(mGroup
->Id(),
892 GetIPCInitializer());
896 if (IsTop() && IsContent() && Canonical()->GetWebProgress()) {
900 // We want to create a BrowsingContextWebProgress for all content
902 if (IsContent() && !Canonical()->mWebProgress
) {
903 Canonical()->mWebProgress
= new BrowsingContextWebProgress(Canonical());
907 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
908 obs
->NotifyWhenScriptSafe(ToSupports(this), "browsing-context-attached",
912 if (XRE_IsParentProcess()) {
913 Canonical()->CanonicalAttach();
918 void BrowsingContext::Detach(bool aFromIPC
) {
919 MOZ_LOG(GetLog(), LogLevel::Debug
,
920 ("%s: Detaching 0x%08" PRIx64
" from 0x%08" PRIx64
,
921 XRE_IsParentProcess() ? "Parent" : "Child", Id(),
922 GetParent() ? GetParent()->Id() : 0));
924 MOZ_DIAGNOSTIC_ASSERT(mEverAttached
);
925 MOZ_DIAGNOSTIC_ASSERT(!mIsDiscarded
);
927 if (XRE_IsParentProcess()) {
928 Canonical()->AddPendingDiscard();
931 MakeScopeExit([&, listeners
= std::move(mDiscardListeners
), id
= Id()] {
932 for (const auto& listener
: listeners
) {
935 if (XRE_IsParentProcess()) {
936 Canonical()->RemovePendingDiscard();
940 nsCOMPtr
<nsIRequestContextService
> rcsvc
=
941 net::RequestContextService::GetOrCreate();
943 rcsvc
->RemoveRequestContext(GetRequestContextId());
946 // This will only ever be null if the cycle-collector has unlinked us. Don't
947 // try to detach ourselves in that case.
948 if (NS_WARN_IF(!mGroup
)) {
949 MOZ_ASSERT_UNREACHABLE();
954 mParentWindow
->RemoveChildBrowsingContext(this);
956 mGroup
->Toplevels().RemoveElement(this);
959 if (XRE_IsParentProcess()) {
960 RefPtr
<CanonicalBrowsingContext
> self
{Canonical()};
961 Group()->EachParent([&](ContentParent
* aParent
) {
962 // Only the embedder process is allowed to initiate a BrowsingContext
963 // detach, so if we've gotten here, the host process already knows we've
964 // been detached, and there's no need to tell it again.
966 // If the owner process is not the same as the embedder process, its
967 // BrowsingContext will be detached when its nsWebBrowser instance is
969 bool doDiscard
= !Canonical()->IsEmbeddedInProcess(aParent
->ChildID()) &&
970 !Canonical()->IsOwnedByProcess(aParent
->ChildID());
972 // Hold a strong reference to ourself, and keep our BrowsingContextGroup
973 // alive, until the responses comes back to ensure we don't die while
974 // messages relating to this context are in-flight.
976 // When the callback is called, the keepalive on our group will be
977 // destroyed, and the reference to the BrowsingContext will be dropped,
978 // which may cause it to be fully destroyed.
979 mGroup
->AddKeepAlive();
980 self
->AddPendingDiscard();
981 auto callback
= [self
](auto) {
982 self
->mGroup
->RemoveKeepAlive();
983 self
->RemovePendingDiscard();
986 aParent
->SendDiscardBrowsingContext(this, doDiscard
, callback
, callback
);
989 // Hold a strong reference to ourself until the responses come back to
990 // ensure the BrowsingContext isn't cleaned up before the parent process
991 // acknowledges the discard request.
992 auto callback
= [self
= RefPtr
{this}](auto) {};
993 ContentChild::GetSingleton()->SendDiscardBrowsingContext(
994 this, !aFromIPC
, callback
, callback
);
997 mGroup
->Unregister(this);
998 UnregisterBrowserId(this);
1001 if (XRE_IsParentProcess()) {
1002 nsFocusManager
* fm
= nsFocusManager::GetFocusManager();
1004 fm
->BrowsingContextDetached(this);
1008 if (nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService()) {
1009 // Why the context is being discarded. This will always be "discard" in the
1010 // content process, but may be "replace" if it's known the context being
1011 // replaced in the parent process.
1012 const char16_t
* why
= u
"discard";
1013 if (XRE_IsParentProcess() && IsTop() && !Canonical()->GetWebProgress()) {
1016 obs
->NotifyObservers(ToSupports(this), "browsing-context-discarded", why
);
1019 // NOTE: Doesn't use SetClosed, as it will be set in all processes
1020 // automatically by calls to Detach()
1021 mFields
.SetWithoutSyncing
<IDX_Closed
>(true);
1023 if (GetIsPopupSpam()) {
1024 PopupBlocker::UnregisterOpenPopupSpam();
1025 // NOTE: Doesn't use SetIsPopupSpam, as it will be set all processes
1027 mFields
.SetWithoutSyncing
<IDX_IsPopupSpam
>(false);
1030 AssertOriginAttributesMatchPrivateBrowsing();
1032 if (XRE_IsParentProcess()) {
1033 Canonical()->CanonicalDiscard();
1037 void BrowsingContext::AddDiscardListener(
1038 std::function
<void(uint64_t)>&& aListener
) {
1043 mDiscardListeners
.AppendElement(std::move(aListener
));
1046 void BrowsingContext::PrepareForProcessChange() {
1047 MOZ_LOG(GetLog(), LogLevel::Debug
,
1048 ("%s: Preparing 0x%08" PRIx64
" for a process change",
1049 XRE_IsParentProcess() ? "Parent" : "Child", Id()));
1051 MOZ_ASSERT(mIsInProcess
, "Must currently be an in-process frame");
1052 MOZ_ASSERT(!mIsDiscarded
, "We're already closed?");
1054 mIsInProcess
= false;
1055 mUserGestureStart
= TimeStamp();
1057 ClearCachedValuesOfLocations();
1059 // NOTE: For now, clear our nsDocShell reference, as we're primarily in a
1060 // different process now. This may need to change in the future with
1061 // Cross-Process BFCache.
1062 mDocShell
= nullptr;
1063 if (mChildSessionHistory
) {
1064 // This can be removed once session history is stored exclusively in the
1066 mChildSessionHistory
->SetIsInProcess(false);
1069 if (!mWindowProxy
) {
1073 // We have to go through mWindowProxy rather than calling GetDOMWindow() on
1074 // mDocShell because the mDocshell reference gets cleared immediately after
1075 // the window is closed.
1076 nsGlobalWindowOuter::PrepareForProcessChange(mWindowProxy
);
1077 MOZ_ASSERT(!mWindowProxy
);
1080 bool BrowsingContext::IsTargetable() const {
1081 return !GetClosed() && AncestorsAreCurrent();
1084 void BrowsingContext::SetOpener(BrowsingContext
* aOpener
) {
1085 MOZ_DIAGNOSTIC_ASSERT(!aOpener
|| aOpener
->Group() == Group());
1086 MOZ_DIAGNOSTIC_ASSERT(!aOpener
|| aOpener
->mType
== mType
);
1088 MOZ_ALWAYS_SUCCEEDS(SetOpenerId(aOpener
? aOpener
->Id() : 0));
1090 if (IsChrome() && IsTop() && aOpener
) {
1091 // Inherit color scheme overrides from parent window. This is to inherit the
1092 // color scheme of dark themed PBM windows in dialogs opened by such
1094 auto openerOverride
= aOpener
->Top()->PrefersColorSchemeOverride();
1095 if (openerOverride
!= PrefersColorSchemeOverride()) {
1096 MOZ_ALWAYS_SUCCEEDS(SetPrefersColorSchemeOverride(openerOverride
));
1101 bool BrowsingContext::HasOpener() const {
1102 return sBrowsingContexts
->Contains(GetOpenerId());
1105 bool BrowsingContext::AncestorsAreCurrent() const {
1106 const BrowsingContext
* bc
= this;
1108 if (bc
->IsDiscarded()) {
1112 if (WindowContext
* wc
= bc
->GetParentWindowContext()) {
1113 if (!wc
->IsCurrent() || wc
->IsDiscarded()) {
1117 bc
= wc
->GetBrowsingContext();
1124 bool BrowsingContext::IsInBFCache() const {
1125 if (mozilla::SessionHistoryInParent()) {
1126 return mIsInBFCache
;
1128 return mParentWindow
&&
1129 mParentWindow
->TopWindowContext()->GetWindowStateSaved();
1132 Span
<RefPtr
<BrowsingContext
>> BrowsingContext::Children() const {
1133 if (WindowContext
* current
= mCurrentWindowContext
) {
1134 return current
->Children();
1136 return Span
<RefPtr
<BrowsingContext
>>();
1139 void BrowsingContext::GetChildren(
1140 nsTArray
<RefPtr
<BrowsingContext
>>& aChildren
) {
1141 aChildren
.AppendElements(Children());
1144 Span
<RefPtr
<BrowsingContext
>> BrowsingContext::NonSyntheticChildren() const {
1145 if (WindowContext
* current
= mCurrentWindowContext
) {
1146 return current
->NonSyntheticChildren();
1148 return Span
<RefPtr
<BrowsingContext
>>();
1151 void BrowsingContext::GetWindowContexts(
1152 nsTArray
<RefPtr
<WindowContext
>>& aWindows
) {
1153 aWindows
.AppendElements(mWindowContexts
);
1156 void BrowsingContext::RegisterWindowContext(WindowContext
* aWindow
) {
1157 MOZ_ASSERT(!mWindowContexts
.Contains(aWindow
),
1158 "WindowContext already registered!");
1159 MOZ_ASSERT(aWindow
->GetBrowsingContext() == this);
1161 mWindowContexts
.AppendElement(aWindow
);
1163 // If the newly registered WindowContext is for our current inner window ID,
1164 // re-run the `DidSet` handler to re-establish the relationship.
1165 if (aWindow
->InnerWindowId() == GetCurrentInnerWindowId()) {
1166 DidSet(FieldIndex
<IDX_CurrentInnerWindowId
>());
1167 MOZ_DIAGNOSTIC_ASSERT(mCurrentWindowContext
== aWindow
);
1171 void BrowsingContext::UnregisterWindowContext(WindowContext
* aWindow
) {
1172 MOZ_ASSERT(mWindowContexts
.Contains(aWindow
),
1173 "WindowContext not registered!");
1174 mWindowContexts
.RemoveElement(aWindow
);
1176 // If our currently active window was unregistered, clear our reference to it.
1177 if (aWindow
== mCurrentWindowContext
) {
1178 // Re-read our `CurrentInnerWindowId` value and use it to set
1179 // `mCurrentWindowContext`. As `aWindow` is now unregistered and discarded,
1180 // we won't find it, and the value will be cleared back to `nullptr`.
1181 DidSet(FieldIndex
<IDX_CurrentInnerWindowId
>());
1182 MOZ_DIAGNOSTIC_ASSERT(mCurrentWindowContext
== nullptr);
1186 void BrowsingContext::PreOrderWalkVoid(
1187 const std::function
<void(BrowsingContext
*)>& aCallback
) {
1190 AutoTArray
<RefPtr
<BrowsingContext
>, 8> children
;
1191 children
.AppendElements(Children());
1193 for (auto& child
: children
) {
1194 child
->PreOrderWalkVoid(aCallback
);
1198 BrowsingContext::WalkFlag
BrowsingContext::PreOrderWalkFlag(
1199 const std::function
<WalkFlag(BrowsingContext
*)>& aCallback
) {
1200 switch (aCallback(this)) {
1201 case WalkFlag::Skip
:
1202 return WalkFlag::Next
;
1203 case WalkFlag::Stop
:
1204 return WalkFlag::Stop
;
1205 case WalkFlag::Next
:
1210 AutoTArray
<RefPtr
<BrowsingContext
>, 8> children
;
1211 children
.AppendElements(Children());
1213 for (auto& child
: children
) {
1214 switch (child
->PreOrderWalkFlag(aCallback
)) {
1215 case WalkFlag::Stop
:
1216 return WalkFlag::Stop
;
1222 return WalkFlag::Next
;
1225 void BrowsingContext::PostOrderWalk(
1226 const std::function
<void(BrowsingContext
*)>& aCallback
) {
1227 AutoTArray
<RefPtr
<BrowsingContext
>, 8> children
;
1228 children
.AppendElements(Children());
1230 for (auto& child
: children
) {
1231 child
->PostOrderWalk(aCallback
);
1237 void BrowsingContext::GetAllBrowsingContextsInSubtree(
1238 nsTArray
<RefPtr
<BrowsingContext
>>& aBrowsingContexts
) {
1239 PreOrderWalk([&](BrowsingContext
* aContext
) {
1240 aBrowsingContexts
.AppendElement(aContext
);
1244 BrowsingContext
* BrowsingContext::FindChildWithName(
1245 const nsAString
& aName
, WindowGlobalChild
& aRequestingWindow
) {
1246 if (aName
.IsEmpty()) {
1247 // You can't find a browsing context with the empty name.
1251 for (BrowsingContext
* child
: NonSyntheticChildren()) {
1252 if (child
->NameEquals(aName
) && aRequestingWindow
.CanNavigate(child
) &&
1253 child
->IsTargetable()) {
1261 BrowsingContext
* BrowsingContext::FindWithSpecialName(
1262 const nsAString
& aName
, WindowGlobalChild
& aRequestingWindow
) {
1263 // TODO(farre): Neither BrowsingContext nor nsDocShell checks if the
1264 // browsing context pointed to by a special name is active. Should
1265 // it be? See Bug 1527913.
1266 if (aName
.LowerCaseEqualsLiteral("_self")) {
1270 if (aName
.LowerCaseEqualsLiteral("_parent")) {
1271 if (BrowsingContext
* parent
= GetParent()) {
1272 return aRequestingWindow
.CanNavigate(parent
) ? parent
: nullptr;
1277 if (aName
.LowerCaseEqualsLiteral("_top")) {
1278 BrowsingContext
* top
= Top();
1280 return aRequestingWindow
.CanNavigate(top
) ? top
: nullptr;
1286 BrowsingContext
* BrowsingContext::FindWithNameInSubtree(
1287 const nsAString
& aName
, WindowGlobalChild
* aRequestingWindow
) {
1288 MOZ_DIAGNOSTIC_ASSERT(!aName
.IsEmpty());
1290 if (NameEquals(aName
) &&
1291 (!aRequestingWindow
|| aRequestingWindow
->CanNavigate(this)) &&
1296 for (BrowsingContext
* child
: NonSyntheticChildren()) {
1297 if (BrowsingContext
* found
=
1298 child
->FindWithNameInSubtree(aName
, aRequestingWindow
)) {
1306 bool BrowsingContext::IsSandboxedFrom(BrowsingContext
* aTarget
) {
1307 // If no target then not sandboxed.
1312 // We cannot be sandboxed from ourselves.
1313 if (aTarget
== this) {
1317 // Default the sandbox flags to our flags, so that if we can't retrieve the
1318 // active document, we will still enforce our own.
1319 uint32_t sandboxFlags
= GetSandboxFlags();
1321 if (RefPtr
<Document
> doc
= mDocShell
->GetExtantDocument()) {
1322 sandboxFlags
= doc
->GetSandboxFlags();
1326 // If no flags, we are not sandboxed at all.
1327 if (!sandboxFlags
) {
1331 // If aTarget has an ancestor, it is not top level.
1332 if (RefPtr
<BrowsingContext
> ancestorOfTarget
= aTarget
->GetParent()) {
1334 // We are not sandboxed if we are an ancestor of target.
1335 if (ancestorOfTarget
== this) {
1338 ancestorOfTarget
= ancestorOfTarget
->GetParent();
1339 } while (ancestorOfTarget
);
1341 // Otherwise, we are sandboxed from aTarget.
1345 // aTarget is top level, are we the "one permitted sandboxed
1346 // navigator", i.e. did we open aTarget?
1347 if (aTarget
->GetOnePermittedSandboxedNavigatorId() == Id()) {
1351 // If SANDBOXED_TOPLEVEL_NAVIGATION flag is not on, we are not sandboxed
1353 if (!(sandboxFlags
& SANDBOXED_TOPLEVEL_NAVIGATION
) && aTarget
== Top()) {
1357 // If SANDBOXED_TOPLEVEL_NAVIGATION_USER_ACTIVATION flag is not on, we are not
1358 // sandboxed from our top if we have user interaction. We assume there is a
1359 // valid transient user gesture interaction if this check happens in the
1360 // target process given that we have checked in the triggering process
1362 if (!(sandboxFlags
& SANDBOXED_TOPLEVEL_NAVIGATION_USER_ACTIVATION
) &&
1363 mCurrentWindowContext
&&
1364 (!mCurrentWindowContext
->IsInProcess() ||
1365 mCurrentWindowContext
->HasValidTransientUserGestureActivation()) &&
1370 // Otherwise, we are sandboxed from aTarget.
1374 RefPtr
<SessionStorageManager
> BrowsingContext::GetSessionStorageManager() {
1375 RefPtr
<SessionStorageManager
>& manager
= Top()->mSessionStorageManager
;
1377 manager
= new SessionStorageManager(this);
1382 bool BrowsingContext::CrossOriginIsolated() {
1383 MOZ_ASSERT(NS_IsMainThread());
1385 return StaticPrefs::
1386 dom_postMessage_sharedArrayBuffer_withCOOP_COEP_AtStartup() &&
1387 Top()->GetOpenerPolicy() ==
1389 OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
&&
1390 XRE_IsContentProcess() &&
1391 StringBeginsWith(ContentChild::GetSingleton()->GetRemoteType(),
1392 WITH_COOP_COEP_REMOTE_TYPE_PREFIX
);
1395 void BrowsingContext::SetTriggeringAndInheritPrincipals(
1396 nsIPrincipal
* aTriggeringPrincipal
, nsIPrincipal
* aPrincipalToInherit
,
1397 uint64_t aLoadIdentifier
) {
1398 mTriggeringPrincipal
= Some(
1399 PrincipalWithLoadIdentifierTuple(aTriggeringPrincipal
, aLoadIdentifier
));
1400 if (aPrincipalToInherit
) {
1401 mPrincipalToInherit
= Some(
1402 PrincipalWithLoadIdentifierTuple(aPrincipalToInherit
, aLoadIdentifier
));
1406 std::tuple
<nsCOMPtr
<nsIPrincipal
>, nsCOMPtr
<nsIPrincipal
>>
1407 BrowsingContext::GetTriggeringAndInheritPrincipalsForCurrentLoad() {
1408 nsCOMPtr
<nsIPrincipal
> triggeringPrincipal
=
1409 GetSavedPrincipal(mTriggeringPrincipal
);
1410 nsCOMPtr
<nsIPrincipal
> principalToInherit
=
1411 GetSavedPrincipal(mPrincipalToInherit
);
1412 return std::make_tuple(triggeringPrincipal
, principalToInherit
);
1415 nsIPrincipal
* BrowsingContext::GetSavedPrincipal(
1416 Maybe
<PrincipalWithLoadIdentifierTuple
> aPrincipalTuple
) {
1417 if (aPrincipalTuple
) {
1418 nsCOMPtr
<nsIPrincipal
> principal
;
1419 uint64_t loadIdentifier
;
1420 std::tie(principal
, loadIdentifier
) = *aPrincipalTuple
;
1421 // We want to return a principal only if the load identifier for it
1422 // matches the current one for this BC.
1423 if (auto current
= GetCurrentLoadIdentifier();
1424 current
&& *current
== loadIdentifier
) {
1431 BrowsingContext::~BrowsingContext() {
1432 MOZ_DIAGNOSTIC_ASSERT(!mParentWindow
||
1433 !mParentWindow
->mChildren
.Contains(this));
1434 MOZ_DIAGNOSTIC_ASSERT(!mGroup
|| !mGroup
->Toplevels().Contains(this));
1436 mDeprioritizedLoadRunner
.clear();
1438 if (sBrowsingContexts
) {
1439 sBrowsingContexts
->Remove(Id());
1441 UnregisterBrowserId(this);
1443 ClearCachedValuesOfLocations();
1448 void BrowsingContext::DiscardFromContentParent(ContentParent
* aCP
) {
1449 MOZ_ASSERT(XRE_IsParentProcess());
1451 if (sBrowsingContexts
) {
1452 AutoTArray
<RefPtr
<BrowsingContext
>, 8> toDiscard
;
1453 for (const auto& data
: sBrowsingContexts
->Values()) {
1454 auto* bc
= data
->Canonical();
1455 if (!bc
->IsDiscarded() && bc
->IsEmbeddedInProcess(aCP
->ChildID())) {
1456 toDiscard
.AppendElement(bc
);
1460 for (BrowsingContext
* bc
: toDiscard
) {
1461 bc
->Detach(/* aFromIPC */ true);
1466 nsISupports
* BrowsingContext::GetParentObject() const {
1467 return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
1470 JSObject
* BrowsingContext::WrapObject(JSContext
* aCx
,
1471 JS::Handle
<JSObject
*> aGivenProto
) {
1472 return BrowsingContext_Binding::Wrap(aCx
, this, aGivenProto
);
1475 bool BrowsingContext::WriteStructuredClone(JSContext
* aCx
,
1476 JSStructuredCloneWriter
* aWriter
,
1477 StructuredCloneHolder
* aHolder
) {
1478 MOZ_DIAGNOSTIC_ASSERT(mEverAttached
);
1479 return (JS_WriteUint32Pair(aWriter
, SCTAG_DOM_BROWSING_CONTEXT
, 0) &&
1480 JS_WriteUint32Pair(aWriter
, uint32_t(Id()), uint32_t(Id() >> 32)));
1484 JSObject
* BrowsingContext::ReadStructuredClone(JSContext
* aCx
,
1485 JSStructuredCloneReader
* aReader
,
1486 StructuredCloneHolder
* aHolder
) {
1488 uint32_t idHigh
= 0;
1489 if (!JS_ReadUint32Pair(aReader
, &idLow
, &idHigh
)) {
1492 uint64_t id
= uint64_t(idHigh
) << 32 | idLow
;
1494 // Note: Do this check after reading our ID data. Returning null will abort
1495 // the decode operation anyway, but we should at least be as safe as possible.
1496 if (NS_WARN_IF(!NS_IsMainThread())) {
1497 MOZ_DIAGNOSTIC_ASSERT(false,
1498 "We shouldn't be trying to decode a BrowsingContext "
1499 "on a background thread.");
1503 JS::Rooted
<JS::Value
> val(aCx
, JS::NullValue());
1504 // We'll get rooting hazard errors from the RefPtr destructor if it isn't
1505 // destroyed before we try to return a raw JSObject*, so create it in its own
1507 if (RefPtr
<BrowsingContext
> context
= Get(id
)) {
1508 if (!GetOrCreateDOMReflector(aCx
, context
, &val
) || !val
.isObject()) {
1512 return val
.toObjectOrNull();
1515 bool BrowsingContext::CanSetOriginAttributes() {
1516 // A discarded BrowsingContext has already been destroyed, and cannot modify
1517 // its OriginAttributes.
1518 if (NS_WARN_IF(IsDiscarded())) {
1522 // Before attaching is the safest time to set OriginAttributes, and the only
1523 // allowed time for content BrowsingContexts.
1524 if (!EverAttached()) {
1528 // Attached content BrowsingContexts may have been synced to other processes.
1529 if (NS_WARN_IF(IsContent())) {
1533 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
1535 // Cannot set OriginAttributes after we've created our child BrowsingContext.
1536 if (NS_WARN_IF(!Children().IsEmpty())) {
1540 // Only allow setting OriginAttributes if we have no associated document, or
1541 // the document is still `about:blank`.
1542 // TODO: Bug 1273058 - should have no document when setting origin attributes.
1543 if (WindowGlobalParent
* window
= Canonical()->GetCurrentWindowGlobal()) {
1544 if (nsIURI
* uri
= window
->GetDocumentURI()) {
1545 MOZ_ASSERT(NS_IsAboutBlank(uri
));
1546 return NS_IsAboutBlank(uri
);
1552 Nullable
<WindowProxyHolder
> BrowsingContext::GetAssociatedWindow() {
1553 // nsILoadContext usually only returns same-process windows,
1554 // so we intentionally return nullptr if this BC is out of
1556 if (IsInProcess()) {
1557 return WindowProxyHolder(this);
1562 Nullable
<WindowProxyHolder
> BrowsingContext::GetTopWindow() {
1563 return Top()->GetAssociatedWindow();
1566 Element
* BrowsingContext::GetTopFrameElement() {
1567 return Top()->GetEmbedderElement();
1570 void BrowsingContext::SetUsePrivateBrowsing(bool aUsePrivateBrowsing
,
1571 ErrorResult
& aError
) {
1572 nsresult rv
= SetUsePrivateBrowsing(aUsePrivateBrowsing
);
1573 if (NS_FAILED(rv
)) {
1578 void BrowsingContext::SetUseTrackingProtectionWebIDL(
1579 bool aUseTrackingProtection
, ErrorResult
& aRv
) {
1580 SetForceEnableTrackingProtection(aUseTrackingProtection
, aRv
);
1583 void BrowsingContext::GetOriginAttributes(JSContext
* aCx
,
1584 JS::MutableHandle
<JS::Value
> aVal
,
1585 ErrorResult
& aError
) {
1586 AssertOriginAttributesMatchPrivateBrowsing();
1588 if (!ToJSValue(aCx
, mOriginAttributes
, aVal
)) {
1589 aError
.NoteJSContextException(aCx
);
1593 NS_IMETHODIMP
BrowsingContext::GetAssociatedWindow(
1594 mozIDOMWindowProxy
** aAssociatedWindow
) {
1595 nsCOMPtr
<mozIDOMWindowProxy
> win
= GetDOMWindow();
1596 win
.forget(aAssociatedWindow
);
1600 NS_IMETHODIMP
BrowsingContext::GetTopWindow(mozIDOMWindowProxy
** aTopWindow
) {
1601 return Top()->GetAssociatedWindow(aTopWindow
);
1604 NS_IMETHODIMP
BrowsingContext::GetTopFrameElement(Element
** aTopFrameElement
) {
1605 RefPtr
<Element
> topFrameElement
= GetTopFrameElement();
1606 topFrameElement
.forget(aTopFrameElement
);
1610 NS_IMETHODIMP
BrowsingContext::GetIsContent(bool* aIsContent
) {
1611 *aIsContent
= IsContent();
1615 NS_IMETHODIMP
BrowsingContext::GetUsePrivateBrowsing(
1616 bool* aUsePrivateBrowsing
) {
1617 *aUsePrivateBrowsing
= mPrivateBrowsingId
> 0;
1621 NS_IMETHODIMP
BrowsingContext::SetUsePrivateBrowsing(bool aUsePrivateBrowsing
) {
1622 if (!CanSetOriginAttributes()) {
1623 bool changed
= aUsePrivateBrowsing
!= (mPrivateBrowsingId
> 0);
1625 NS_WARNING("SetUsePrivateBrowsing when !CanSetOriginAttributes()");
1627 return changed
? NS_ERROR_FAILURE
: NS_OK
;
1630 return SetPrivateBrowsing(aUsePrivateBrowsing
);
1633 NS_IMETHODIMP
BrowsingContext::SetPrivateBrowsing(bool aPrivateBrowsing
) {
1634 if (!CanSetOriginAttributes()) {
1635 NS_WARNING("Attempt to set PrivateBrowsing when !CanSetOriginAttributes");
1636 return NS_ERROR_FAILURE
;
1639 bool changed
= aPrivateBrowsing
!= (mPrivateBrowsingId
> 0);
1641 mPrivateBrowsingId
= aPrivateBrowsing
? 1 : 0;
1643 mOriginAttributes
.SyncAttributesWithPrivateBrowsing(aPrivateBrowsing
);
1646 if (XRE_IsParentProcess()) {
1647 Canonical()->AdjustPrivateBrowsingCount(aPrivateBrowsing
);
1650 AssertOriginAttributesMatchPrivateBrowsing();
1652 if (changed
&& mDocShell
) {
1653 nsDocShell::Cast(mDocShell
)->NotifyPrivateBrowsingChanged();
1658 NS_IMETHODIMP
BrowsingContext::GetUseRemoteTabs(bool* aUseRemoteTabs
) {
1659 *aUseRemoteTabs
= mUseRemoteTabs
;
1663 NS_IMETHODIMP
BrowsingContext::SetRemoteTabs(bool aUseRemoteTabs
) {
1664 if (!CanSetOriginAttributes()) {
1665 NS_WARNING("Attempt to set RemoteTabs when !CanSetOriginAttributes");
1666 return NS_ERROR_FAILURE
;
1669 if (aUseRemoteTabs
&& !gIPCEnabledAnnotation
) {
1670 gIPCEnabledAnnotation
= true;
1673 // Don't allow non-remote tabs with remote subframes.
1674 if (NS_WARN_IF(!aUseRemoteTabs
&& mUseRemoteSubframes
)) {
1675 return NS_ERROR_UNEXPECTED
;
1678 mUseRemoteTabs
= aUseRemoteTabs
;
1682 NS_IMETHODIMP
BrowsingContext::GetUseRemoteSubframes(
1683 bool* aUseRemoteSubframes
) {
1684 *aUseRemoteSubframes
= mUseRemoteSubframes
;
1688 NS_IMETHODIMP
BrowsingContext::SetRemoteSubframes(bool aUseRemoteSubframes
) {
1689 if (!CanSetOriginAttributes()) {
1690 NS_WARNING("Attempt to set RemoteSubframes when !CanSetOriginAttributes");
1691 return NS_ERROR_FAILURE
;
1694 if (aUseRemoteSubframes
&& !gFissionEnabledAnnotation
) {
1695 gFissionEnabledAnnotation
= true;
1698 // Don't allow non-remote tabs with remote subframes.
1699 if (NS_WARN_IF(aUseRemoteSubframes
&& !mUseRemoteTabs
)) {
1700 return NS_ERROR_UNEXPECTED
;
1703 mUseRemoteSubframes
= aUseRemoteSubframes
;
1707 NS_IMETHODIMP
BrowsingContext::GetUseTrackingProtection(
1708 bool* aUseTrackingProtection
) {
1709 *aUseTrackingProtection
= false;
1711 if (GetForceEnableTrackingProtection() ||
1712 StaticPrefs::privacy_trackingprotection_enabled() ||
1713 (UsePrivateBrowsing() &&
1714 StaticPrefs::privacy_trackingprotection_pbmode_enabled())) {
1715 *aUseTrackingProtection
= true;
1720 return GetParent()->GetUseTrackingProtection(aUseTrackingProtection
);
1726 NS_IMETHODIMP
BrowsingContext::SetUseTrackingProtection(
1727 bool aUseTrackingProtection
) {
1728 return SetForceEnableTrackingProtection(aUseTrackingProtection
);
1731 NS_IMETHODIMP
BrowsingContext::GetScriptableOriginAttributes(
1732 JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aVal
) {
1733 AssertOriginAttributesMatchPrivateBrowsing();
1735 bool ok
= ToJSValue(aCx
, mOriginAttributes
, aVal
);
1736 NS_ENSURE_TRUE(ok
, NS_ERROR_FAILURE
);
1740 NS_IMETHODIMP_(void)
1741 BrowsingContext::GetOriginAttributes(OriginAttributes
& aAttrs
) {
1742 aAttrs
= mOriginAttributes
;
1743 AssertOriginAttributesMatchPrivateBrowsing();
1746 nsresult
BrowsingContext::SetOriginAttributes(const OriginAttributes
& aAttrs
) {
1747 if (!CanSetOriginAttributes()) {
1748 NS_WARNING("Attempt to set OriginAttributes when !CanSetOriginAttributes");
1749 return NS_ERROR_FAILURE
;
1752 AssertOriginAttributesMatchPrivateBrowsing();
1753 mOriginAttributes
= aAttrs
;
1755 bool isPrivate
= mOriginAttributes
.mPrivateBrowsingId
!=
1756 nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID
;
1757 // Chrome Browsing Context can not contain OriginAttributes.mPrivateBrowsingId
1758 if (IsChrome() && isPrivate
) {
1759 mOriginAttributes
.mPrivateBrowsingId
=
1760 nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID
;
1762 SetPrivateBrowsing(isPrivate
);
1763 AssertOriginAttributesMatchPrivateBrowsing();
1768 void BrowsingContext::AssertCoherentLoadContext() {
1769 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
1770 // LoadContext should generally match our opener or parent.
1772 if (RefPtr
<BrowsingContext
> opener
= GetOpener()) {
1773 MOZ_DIAGNOSTIC_ASSERT(opener
->mType
== mType
);
1774 MOZ_DIAGNOSTIC_ASSERT(opener
->mGroup
== mGroup
);
1775 MOZ_DIAGNOSTIC_ASSERT(opener
->mUseRemoteTabs
== mUseRemoteTabs
);
1776 MOZ_DIAGNOSTIC_ASSERT(opener
->mUseRemoteSubframes
== mUseRemoteSubframes
);
1777 MOZ_DIAGNOSTIC_ASSERT(opener
->mPrivateBrowsingId
== mPrivateBrowsingId
);
1778 MOZ_DIAGNOSTIC_ASSERT(
1779 opener
->mOriginAttributes
.EqualsIgnoringFPD(mOriginAttributes
));
1782 if (RefPtr
<BrowsingContext
> parent
= GetParent()) {
1783 MOZ_DIAGNOSTIC_ASSERT(parent
->mType
== mType
);
1784 MOZ_DIAGNOSTIC_ASSERT(parent
->mGroup
== mGroup
);
1785 MOZ_DIAGNOSTIC_ASSERT(parent
->mUseRemoteTabs
== mUseRemoteTabs
);
1786 MOZ_DIAGNOSTIC_ASSERT(parent
->mUseRemoteSubframes
== mUseRemoteSubframes
);
1787 MOZ_DIAGNOSTIC_ASSERT(parent
->mPrivateBrowsingId
== mPrivateBrowsingId
);
1788 MOZ_DIAGNOSTIC_ASSERT(
1789 parent
->mOriginAttributes
.EqualsIgnoringFPD(mOriginAttributes
));
1792 // UseRemoteSubframes and UseRemoteTabs must match.
1793 MOZ_DIAGNOSTIC_ASSERT(
1794 !mUseRemoteSubframes
|| mUseRemoteTabs
,
1795 "Cannot set useRemoteSubframes without also setting useRemoteTabs");
1797 // Double-check OriginAttributes/Private Browsing
1798 AssertOriginAttributesMatchPrivateBrowsing();
1802 void BrowsingContext::AssertOriginAttributesMatchPrivateBrowsing() {
1803 // Chrome browsing contexts must not have a private browsing OriginAttribute
1804 // Content browsing contexts must maintain the equality:
1805 // mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId
1807 MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes
.mPrivateBrowsingId
== 0);
1809 MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes
.mPrivateBrowsingId
==
1810 mPrivateBrowsingId
);
1814 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowsingContext
)
1815 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1816 NS_INTERFACE_MAP_ENTRY(nsILoadContext
)
1817 NS_INTERFACE_MAP_ENTRY(nsISupports
)
1818 NS_INTERFACE_MAP_END
1820 NS_IMPL_CYCLE_COLLECTION_CLASS(BrowsingContext
)
1822 NS_IMPL_CYCLE_COLLECTING_ADDREF(BrowsingContext
)
1823 NS_IMPL_CYCLE_COLLECTING_RELEASE(BrowsingContext
)
1825 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(BrowsingContext
)
1826 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
1827 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1829 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowsingContext
)
1830 if (sBrowsingContexts
) {
1831 sBrowsingContexts
->Remove(tmp
->Id());
1833 UnregisterBrowserId(tmp
);
1835 if (tmp
->GetIsPopupSpam()) {
1836 PopupBlocker::UnregisterOpenPopupSpam();
1837 // NOTE: Doesn't use SetIsPopupSpam, as it will be set all processes
1839 tmp
->mFields
.SetWithoutSyncing
<IDX_IsPopupSpam
>(false);
1842 NS_IMPL_CYCLE_COLLECTION_UNLINK(
1843 mDocShell
, mParentWindow
, mGroup
, mEmbedderElement
, mWindowContexts
,
1844 mCurrentWindowContext
, mSessionStorageManager
, mChildSessionHistory
)
1845 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
1846 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1848 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowsingContext
)
1849 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
1850 mDocShell
, mParentWindow
, mGroup
, mEmbedderElement
, mWindowContexts
,
1851 mCurrentWindowContext
, mSessionStorageManager
, mChildSessionHistory
)
1852 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1854 static bool IsCertainlyAliveForCC(BrowsingContext
* aContext
) {
1855 return aContext
->HasKnownLiveWrapper() ||
1856 (AppShutdown::GetCurrentShutdownPhase() ==
1857 ShutdownPhase::NotInShutdown
&&
1858 aContext
->EverAttached() && !aContext
->IsDiscarded());
1861 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(BrowsingContext
)
1862 if (IsCertainlyAliveForCC(tmp
)) {
1863 if (tmp
->PreservingWrapper()) {
1864 tmp
->MarkWrapperLive();
1868 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
1870 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(BrowsingContext
)
1871 return IsCertainlyAliveForCC(tmp
) && tmp
->HasNothingToTrace(tmp
);
1872 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
1874 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(BrowsingContext
)
1875 return IsCertainlyAliveForCC(tmp
);
1876 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
1878 class RemoteLocationProxy
1879 : public RemoteObjectProxy
<BrowsingContext::LocationProxy
,
1880 Location_Binding::sCrossOriginProperties
> {
1882 typedef RemoteObjectProxy Base
;
1884 constexpr RemoteLocationProxy()
1885 : RemoteObjectProxy(prototypes::id::Location
) {}
1887 void NoteChildren(JSObject
* aProxy
,
1888 nsCycleCollectionTraversalCallback
& aCb
) const override
{
1890 static_cast<BrowsingContext::LocationProxy
*>(GetNative(aProxy
));
1891 CycleCollectionNoteChild(aCb
, location
->GetBrowsingContext(),
1892 "JS::GetPrivate(obj)->GetBrowsingContext()");
1896 static const RemoteLocationProxy sSingleton
;
1898 // Give RemoteLocationProxy 2 reserved slots, like the other wrappers,
1899 // so JSObject::swap can swap it with CrossCompartmentWrappers without requiring
1902 const JSClass
RemoteLocationProxy::Base::sClass
=
1903 PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));
1905 void BrowsingContext::Location(JSContext
* aCx
,
1906 JS::MutableHandle
<JSObject
*> aLocation
,
1907 ErrorResult
& aError
) {
1908 aError
.MightThrowJSException();
1909 sSingleton
.GetProxyObject(aCx
, &mLocation
, /* aTransplantTo = */ nullptr,
1912 aError
.StealExceptionFromJSContext(aCx
);
1916 bool BrowsingContext::RemoveRootFromBFCacheSync() {
1917 if (WindowContext
* wc
= GetParentWindowContext()) {
1918 if (RefPtr
<Document
> doc
= wc
->TopWindowContext()->GetDocument()) {
1919 return doc
->RemoveFromBFCacheSync();
1925 nsresult
BrowsingContext::CheckSandboxFlags(nsDocShellLoadState
* aLoadState
) {
1926 const auto& sourceBC
= aLoadState
->SourceBrowsingContext();
1927 if (sourceBC
.IsNull()) {
1931 // We might be called after the source BC has been discarded, but before we've
1932 // destroyed our in-process instance of the BrowsingContext object in some
1933 // situations (e.g. after creating a new pop-up with window.open while the
1934 // window is being closed). In these situations we want to still perform the
1935 // sandboxing check against our in-process copy. If we've forgotten about the
1936 // context already, assume it is sanboxed. (bug 1643450)
1937 BrowsingContext
* bc
= sourceBC
.GetMaybeDiscarded();
1938 if (!bc
|| bc
->IsSandboxedFrom(this)) {
1939 return NS_ERROR_DOM_SECURITY_ERR
;
1944 nsresult
BrowsingContext::LoadURI(nsDocShellLoadState
* aLoadState
,
1945 bool aSetNavigating
) {
1946 // Per spec, most load attempts are silently ignored when a BrowsingContext is
1947 // null (which in our code corresponds to discarded), so we simply fail
1948 // silently in those cases. Regardless, we cannot trigger loads in/from
1949 // discarded BrowsingContexts via IPC, so we need to abort in any case.
1950 if (IsDiscarded()) {
1954 MOZ_DIAGNOSTIC_ASSERT(aLoadState
->TargetBrowsingContext().IsNull(),
1955 "Targeting occurs in InternalLoad");
1956 aLoadState
->AssertProcessCouldTriggerLoadIfSystem();
1959 nsCOMPtr
<nsIDocShell
> docShell
= mDocShell
;
1960 return docShell
->LoadURI(aLoadState
, aSetNavigating
);
1963 // Note: We do this check both here and in `nsDocShell::InternalLoad`, since
1964 // document-specific sandbox flags are only available in the process
1965 // triggering the load, and we don't want the target process to have to trust
1966 // the triggering process to do the appropriate checks for the
1967 // BrowsingContext's sandbox flags.
1968 MOZ_TRY(CheckSandboxFlags(aLoadState
));
1969 SetTriggeringAndInheritPrincipals(aLoadState
->TriggeringPrincipal(),
1970 aLoadState
->PrincipalToInherit(),
1971 aLoadState
->GetLoadIdentifier());
1973 const auto& sourceBC
= aLoadState
->SourceBrowsingContext();
1975 if (net::SchemeIsJavascript(aLoadState
->URI())) {
1976 if (!XRE_IsParentProcess()) {
1977 // Web content should only be able to load javascript: URIs into documents
1978 // whose principals the caller principal subsumes, which by definition
1979 // excludes any document in a cross-process BrowsingContext.
1980 return NS_ERROR_DOM_BAD_CROSS_ORIGIN_URI
;
1982 MOZ_DIAGNOSTIC_ASSERT(!sourceBC
,
1983 "Should never see a cross-process javascript: load "
1984 "triggered from content");
1987 MOZ_DIAGNOSTIC_ASSERT(!sourceBC
|| sourceBC
->Group() == Group());
1988 if (sourceBC
&& sourceBC
->IsInProcess()) {
1989 nsCOMPtr
<nsPIDOMWindowOuter
> win(sourceBC
->GetDOMWindow());
1990 if (WindowGlobalChild
* wgc
=
1991 win
->GetCurrentInnerWindow()->GetWindowGlobalChild()) {
1992 if (!wgc
->CanNavigate(this)) {
1993 return NS_ERROR_DOM_PROP_ACCESS_DENIED
;
1995 wgc
->SendLoadURI(this, mozilla::WrapNotNull(aLoadState
), aSetNavigating
);
1997 } else if (XRE_IsParentProcess()) {
1998 if (Canonical()->LoadInParent(aLoadState
, aSetNavigating
)) {
2002 if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2003 // Attempt to initiate this load immediately in the parent, if it succeeds
2004 // it'll return a unique identifier so that we can find it later.
2005 uint64_t loadIdentifier
= 0;
2006 if (Canonical()->AttemptSpeculativeLoadInParent(aLoadState
)) {
2007 MOZ_DIAGNOSTIC_ASSERT(GetCurrentLoadIdentifier().isSome());
2008 loadIdentifier
= GetCurrentLoadIdentifier().value();
2009 aLoadState
->SetChannelInitialized(true);
2012 cp
->TransmitBlobDataIfBlobURL(aLoadState
->URI());
2014 // Setup a confirmation callback once the content process receives this
2015 // load. Normally we'd expect a PDocumentChannel actor to have been
2016 // created to claim the load identifier by that time. If not, then it
2017 // won't be coming, so make sure we clean up and deregister.
2018 cp
->SendLoadURI(this, mozilla::WrapNotNull(aLoadState
), aSetNavigating
)
2019 ->Then(GetMainThreadSerialEventTarget(), __func__
,
2021 const PContentParent::LoadURIPromise::ResolveOrRejectValue
&
2023 if (loadIdentifier
) {
2024 net::DocumentLoadListener::CleanupParentLoadAttempt(
2030 MOZ_DIAGNOSTIC_ASSERT(sourceBC
);
2032 return NS_ERROR_UNEXPECTED
;
2034 // If we're in a content process and the source BC is no longer in-process,
2035 // just fail silently.
2040 nsresult
BrowsingContext::InternalLoad(nsDocShellLoadState
* aLoadState
) {
2041 if (IsDiscarded()) {
2044 SetTriggeringAndInheritPrincipals(aLoadState
->TriggeringPrincipal(),
2045 aLoadState
->PrincipalToInherit(),
2046 aLoadState
->GetLoadIdentifier());
2048 MOZ_DIAGNOSTIC_ASSERT(aLoadState
->Target().IsEmpty(),
2049 "should already have retargeted");
2050 MOZ_DIAGNOSTIC_ASSERT(!aLoadState
->TargetBrowsingContext().IsNull(),
2051 "should have target bc set");
2052 MOZ_DIAGNOSTIC_ASSERT(aLoadState
->TargetBrowsingContext() == this,
2053 "must be targeting this BrowsingContext");
2054 aLoadState
->AssertProcessCouldTriggerLoadIfSystem();
2057 RefPtr
<nsDocShell
> docShell
= nsDocShell::Cast(mDocShell
);
2058 return docShell
->InternalLoad(aLoadState
);
2061 // Note: We do this check both here and in `nsDocShell::InternalLoad`, since
2062 // document-specific sandbox flags are only available in the process
2063 // triggering the load, and we don't want the target process to have to trust
2064 // the triggering process to do the appropriate checks for the
2065 // BrowsingContext's sandbox flags.
2066 MOZ_TRY(CheckSandboxFlags(aLoadState
));
2068 const auto& sourceBC
= aLoadState
->SourceBrowsingContext();
2070 if (net::SchemeIsJavascript(aLoadState
->URI())) {
2071 if (!XRE_IsParentProcess()) {
2072 // Web content should only be able to load javascript: URIs into documents
2073 // whose principals the caller principal subsumes, which by definition
2074 // excludes any document in a cross-process BrowsingContext.
2075 return NS_ERROR_DOM_BAD_CROSS_ORIGIN_URI
;
2077 MOZ_DIAGNOSTIC_ASSERT(!sourceBC
,
2078 "Should never see a cross-process javascript: load "
2079 "triggered from content");
2082 if (XRE_IsParentProcess()) {
2083 ContentParent
* cp
= Canonical()->GetContentParent();
2084 if (!cp
|| !cp
->CanSend()) {
2085 return NS_ERROR_FAILURE
;
2088 MOZ_ALWAYS_SUCCEEDS(
2089 SetCurrentLoadIdentifier(Some(aLoadState
->GetLoadIdentifier())));
2090 Unused
<< cp
->SendInternalLoad(mozilla::WrapNotNull(aLoadState
));
2092 MOZ_DIAGNOSTIC_ASSERT(sourceBC
);
2093 MOZ_DIAGNOSTIC_ASSERT(sourceBC
->Group() == Group());
2095 nsCOMPtr
<nsPIDOMWindowOuter
> win(sourceBC
->GetDOMWindow());
2096 WindowGlobalChild
* wgc
=
2097 win
->GetCurrentInnerWindow()->GetWindowGlobalChild();
2098 if (!wgc
|| !wgc
->CanSend()) {
2099 return NS_ERROR_FAILURE
;
2101 if (!wgc
->CanNavigate(this)) {
2102 return NS_ERROR_DOM_PROP_ACCESS_DENIED
;
2105 MOZ_ALWAYS_SUCCEEDS(
2106 SetCurrentLoadIdentifier(Some(aLoadState
->GetLoadIdentifier())));
2107 wgc
->SendInternalLoad(mozilla::WrapNotNull(aLoadState
));
2113 void BrowsingContext::DisplayLoadError(const nsAString
& aURI
) {
2114 MOZ_LOG(GetLog(), LogLevel::Debug
, ("DisplayLoadError"));
2115 MOZ_DIAGNOSTIC_ASSERT(!IsDiscarded());
2116 MOZ_DIAGNOSTIC_ASSERT(mDocShell
|| XRE_IsParentProcess());
2119 bool didDisplayLoadError
= false;
2120 nsCOMPtr
<nsIDocShell
> docShell
= mDocShell
;
2121 docShell
->DisplayLoadError(NS_ERROR_MALFORMED_URI
, nullptr,
2122 PromiseFlatString(aURI
).get(), nullptr,
2123 &didDisplayLoadError
);
2125 if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2126 Unused
<< cp
->SendDisplayLoadError(this, PromiseFlatString(aURI
));
2131 WindowProxyHolder
BrowsingContext::Window() {
2132 return WindowProxyHolder(Self());
2135 WindowProxyHolder
BrowsingContext::GetFrames(ErrorResult
& aError
) {
2139 void BrowsingContext::Close(CallerType aCallerType
, ErrorResult
& aError
) {
2145 // .close() on frames is a no-op.
2149 if (GetDOMWindow()) {
2150 nsGlobalWindowOuter::Cast(GetDOMWindow())
2151 ->CloseOuter(aCallerType
== CallerType::System
);
2155 // This is a bit of a hack for webcompat. Content needs to see an updated
2156 // |window.closed| value as early as possible, so we set this before we
2157 // actually send the DOMWindowClose event, which happens in the process where
2158 // the document for this browsing context is loaded.
2159 MOZ_ALWAYS_SUCCEEDS(SetClosed(true));
2161 if (ContentChild
* cc
= ContentChild::GetSingleton()) {
2162 cc
->SendWindowClose(this, aCallerType
== CallerType::System
);
2163 } else if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2164 Unused
<< cp
->SendWindowClose(this, aCallerType
== CallerType::System
);
2168 template <typename FuncT
>
2169 inline bool ApplyToDocumentsForPopup(Document
* doc
, FuncT func
) {
2170 // HACK: Some pages using bogus library + UA sniffing call window.open()
2171 // from a blank iframe, only on Firefox, see bug 1685056.
2173 // This is a hack-around to preserve behavior in that particular and
2174 // specific case, by consuming activation on the parent document, so we
2175 // don't care about the InProcessParent bits not being fission-safe or what
2180 if (!doc
->IsInitialDocument()) {
2183 Document
* parentDoc
= doc
->GetInProcessParentDocument();
2184 if (!parentDoc
|| !parentDoc
->NodePrincipal()->Equals(doc
->NodePrincipal())) {
2187 return func(parentDoc
);
2190 PopupBlocker::PopupControlState
BrowsingContext::RevisePopupAbuseLevel(
2191 PopupBlocker::PopupControlState aControl
) {
2193 return PopupBlocker::openAllowed
;
2196 RefPtr
<Document
> doc
= GetExtantDocument();
2197 PopupBlocker::PopupControlState abuse
= aControl
;
2199 case PopupBlocker::openControlled
:
2200 case PopupBlocker::openBlocked
:
2201 case PopupBlocker::openOverridden
:
2202 if (IsPopupAllowed()) {
2203 abuse
= PopupBlocker::PopupControlState(abuse
- 1);
2206 case PopupBlocker::openAbused
:
2207 if (IsPopupAllowed() ||
2208 (doc
&& doc
->HasValidTransientUserGestureActivation())) {
2209 // Skip PopupBlocker::openBlocked
2210 abuse
= PopupBlocker::openControlled
;
2213 case PopupBlocker::openAllowed
:
2216 NS_WARNING("Strange PopupControlState!");
2219 // limit the number of simultaneously open popups
2220 if (abuse
== PopupBlocker::openAbused
|| abuse
== PopupBlocker::openBlocked
||
2221 abuse
== PopupBlocker::openControlled
) {
2222 int32_t popupMax
= StaticPrefs::dom_popup_maximum();
2223 if (popupMax
>= 0 &&
2224 PopupBlocker::GetOpenPopupSpamCount() >= (uint32_t)popupMax
) {
2225 abuse
= PopupBlocker::openOverridden
;
2229 // If we're currently in-process, attempt to consume transient user gesture
2232 auto ConsumeTransientUserActivationForMultiplePopupBlocking
=
2234 return ApplyToDocumentsForPopup(doc
, [](Document
* doc
) {
2235 return doc
->ConsumeTransientUserGestureActivation();
2239 // If this popup is allowed, let's block any other for this event, forcing
2240 // PopupBlocker::openBlocked state.
2241 if ((abuse
== PopupBlocker::openAllowed
||
2242 abuse
== PopupBlocker::openControlled
) &&
2243 StaticPrefs::dom_block_multiple_popups() && !IsPopupAllowed() &&
2244 !ConsumeTransientUserActivationForMultiplePopupBlocking()) {
2245 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
, "DOM"_ns
,
2246 doc
, nsContentUtils::eDOM_PROPERTIES
,
2247 "MultiplePopupsBlockedNoUserActivation");
2248 abuse
= PopupBlocker::openBlocked
;
2255 void BrowsingContext::GetUserActivationModifiersForPopup(
2256 UserActivation::Modifiers
* aModifiers
) {
2257 RefPtr
<Document
> doc
= GetExtantDocument();
2259 // Unlike RevisePopupAbuseLevel, modifiers can always be used regardless
2260 // of PopupControlState.
2261 (void)ApplyToDocumentsForPopup(doc
, [&](Document
* doc
) {
2262 return doc
->GetTransientUserGestureActivationModifiers(aModifiers
);
2267 void BrowsingContext::IncrementHistoryEntryCountForBrowsingContext() {
2268 Unused
<< SetHistoryEntryCount(GetHistoryEntryCount() + 1);
2271 std::tuple
<bool, bool> BrowsingContext::CanFocusCheck(CallerType aCallerType
) {
2272 nsFocusManager
* fm
= nsFocusManager::GetFocusManager();
2274 return {false, false};
2277 nsCOMPtr
<nsPIDOMWindowInner
> caller
= do_QueryInterface(GetEntryGlobal());
2278 BrowsingContext
* callerBC
= caller
? caller
->GetBrowsingContext() : nullptr;
2279 RefPtr
<BrowsingContext
> openerBC
= GetOpener();
2280 MOZ_DIAGNOSTIC_ASSERT(!openerBC
|| openerBC
->Group() == Group());
2282 // Enforce dom.disable_window_flip (for non-chrome), but still allow the
2283 // window which opened us to raise us at times when popups are allowed
2284 // (bugs 355482 and 369306).
2285 bool canFocus
= aCallerType
== CallerType::System
||
2286 !Preferences::GetBool("dom.disable_window_flip", true);
2287 if (!canFocus
&& openerBC
== callerBC
) {
2289 (callerBC
? callerBC
: this)
2290 ->RevisePopupAbuseLevel(PopupBlocker::GetPopupControlState()) <
2291 PopupBlocker::openBlocked
;
2294 bool isActive
= false;
2295 if (XRE_IsParentProcess()) {
2296 CanonicalBrowsingContext
* chromeTop
= Canonical()->TopCrossChromeBoundary();
2297 nsCOMPtr
<nsPIDOMWindowOuter
> activeWindow
= fm
->GetActiveWindow();
2298 isActive
= activeWindow
== chromeTop
->GetDOMWindow();
2300 isActive
= fm
->GetActiveBrowsingContext() == Top();
2303 return {canFocus
, isActive
};
2306 void BrowsingContext::Focus(CallerType aCallerType
, ErrorResult
& aError
) {
2307 // These checks need to happen before the RequestFrameFocus call, which
2308 // is why they are done in an untrusted process. If we wanted to enforce
2309 // these in the parent, we'd need to do the checks there _also_.
2310 // These should be kept in sync with nsGlobalWindowOuter::FocusOuter.
2312 auto [canFocus
, isActive
] = CanFocusCheck(aCallerType
);
2314 if (!(canFocus
|| isActive
)) {
2318 // Permission check passed
2320 if (mEmbedderElement
) {
2321 // Make the activeElement in this process update synchronously.
2322 nsContentUtils::RequestFrameFocus(*mEmbedderElement
, true, aCallerType
);
2324 uint64_t actionId
= nsFocusManager::GenerateFocusActionId();
2325 if (ContentChild
* cc
= ContentChild::GetSingleton()) {
2326 cc
->SendWindowFocus(this, aCallerType
, actionId
);
2327 } else if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2328 Unused
<< cp
->SendWindowFocus(this, aCallerType
, actionId
);
2332 bool BrowsingContext::CanBlurCheck(CallerType aCallerType
) {
2333 // If dom.disable_window_flip == true, then content should not be allowed
2334 // to do blur (this would allow popunders, bug 369306)
2335 return aCallerType
== CallerType::System
||
2336 !Preferences::GetBool("dom.disable_window_flip", true);
2339 void BrowsingContext::Blur(CallerType aCallerType
, ErrorResult
& aError
) {
2340 if (!CanBlurCheck(aCallerType
)) {
2344 if (ContentChild
* cc
= ContentChild::GetSingleton()) {
2345 cc
->SendWindowBlur(this, aCallerType
);
2346 } else if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2347 Unused
<< cp
->SendWindowBlur(this, aCallerType
);
2351 Nullable
<WindowProxyHolder
> BrowsingContext::GetWindow() {
2352 if (XRE_IsParentProcess() && !IsInProcess()) {
2355 return WindowProxyHolder(this);
2358 Nullable
<WindowProxyHolder
> BrowsingContext::GetTop(ErrorResult
& aError
) {
2363 // We never return null or throw an error, but the implementation in
2364 // nsGlobalWindow does and we need to use the same signature.
2365 return WindowProxyHolder(Top());
2368 void BrowsingContext::GetOpener(JSContext
* aCx
,
2369 JS::MutableHandle
<JS::Value
> aOpener
,
2370 ErrorResult
& aError
) const {
2371 RefPtr
<BrowsingContext
> opener
= GetOpener();
2377 if (!ToJSValue(aCx
, WindowProxyHolder(opener
), aOpener
)) {
2378 aError
.NoteJSContextException(aCx
);
2382 // We never throw an error, but the implementation in nsGlobalWindow does and
2383 // we need to use the same signature.
2384 Nullable
<WindowProxyHolder
> BrowsingContext::GetParent(ErrorResult
& aError
) {
2390 return WindowProxyHolder(GetParent());
2392 return WindowProxyHolder(this);
2395 void BrowsingContext::PostMessageMoz(JSContext
* aCx
,
2396 JS::Handle
<JS::Value
> aMessage
,
2397 const nsAString
& aTargetOrigin
,
2398 const Sequence
<JSObject
*>& aTransfer
,
2399 nsIPrincipal
& aSubjectPrincipal
,
2400 ErrorResult
& aError
) {
2405 RefPtr
<BrowsingContext
> sourceBc
;
2406 PostMessageData data
;
2407 data
.targetOrigin() = aTargetOrigin
;
2408 data
.subjectPrincipal() = &aSubjectPrincipal
;
2409 RefPtr
<nsGlobalWindowInner
> callerInnerWindow
;
2410 nsAutoCString scriptLocation
;
2411 // We don't need to get the caller's agentClusterId since that is used for
2412 // checking whether it's okay to sharing memory (and it's not allowed to share
2413 // memory cross processes)
2414 if (!nsGlobalWindowOuter::GatherPostMessageData(
2415 aCx
, aTargetOrigin
, getter_AddRefs(sourceBc
), data
.origin(),
2416 getter_AddRefs(data
.targetOriginURI()),
2417 getter_AddRefs(data
.callerPrincipal()),
2418 getter_AddRefs(callerInnerWindow
), getter_AddRefs(data
.callerURI()),
2419 /* aCallerAgentClusterId */ nullptr, &scriptLocation
, aError
)) {
2422 if (sourceBc
&& sourceBc
->IsDiscarded()) {
2425 data
.source() = sourceBc
;
2426 data
.isFromPrivateWindow() =
2427 callerInnerWindow
&&
2428 nsScriptErrorBase::ComputeIsFromPrivateWindow(callerInnerWindow
);
2429 data
.innerWindowId() = callerInnerWindow
? callerInnerWindow
->WindowID() : 0;
2430 data
.scriptLocation() = scriptLocation
;
2431 JS::Rooted
<JS::Value
> transferArray(aCx
);
2432 aError
= nsContentUtils::CreateJSValueFromSequenceOfObject(aCx
, aTransfer
,
2434 if (NS_WARN_IF(aError
.Failed())) {
2438 JS::CloneDataPolicy clonePolicy
;
2439 if (callerInnerWindow
&& callerInnerWindow
->IsSharedMemoryAllowed()) {
2440 clonePolicy
.allowSharedMemoryObjects();
2443 // We will see if the message is required to be in the same process or it can
2444 // be in the different process after Write().
2445 ipc::StructuredCloneData message
= ipc::StructuredCloneData(
2446 StructuredCloneHolder::StructuredCloneScope::UnknownDestination
,
2447 StructuredCloneHolder::TransferringSupported
);
2448 message
.Write(aCx
, aMessage
, transferArray
, clonePolicy
, aError
);
2449 if (NS_WARN_IF(aError
.Failed())) {
2453 ClonedOrErrorMessageData messageData
;
2454 if (ContentChild
* cc
= ContentChild::GetSingleton()) {
2455 // The clone scope gets set when we write the message data based on the
2456 // requirements of that data that we're writing.
2457 // If the message data contains a shared memory object, then CloneScope
2458 // would return SameProcess. Otherwise, it returns DifferentProcess.
2459 if (message
.CloneScope() ==
2460 StructuredCloneHolder::StructuredCloneScope::DifferentProcess
) {
2461 ClonedMessageData clonedMessageData
;
2462 if (!message
.BuildClonedMessageData(clonedMessageData
)) {
2463 aError
.Throw(NS_ERROR_FAILURE
);
2467 messageData
= std::move(clonedMessageData
);
2469 MOZ_ASSERT(message
.CloneScope() ==
2470 StructuredCloneHolder::StructuredCloneScope::SameProcess
);
2472 messageData
= ErrorMessageData();
2474 nsContentUtils::ReportToConsole(
2475 nsIScriptError::warningFlag
, "DOM Window"_ns
,
2476 callerInnerWindow
? callerInnerWindow
->GetDocument() : nullptr,
2477 nsContentUtils::eDOM_PROPERTIES
,
2478 "PostMessageSharedMemoryObjectToCrossOriginWarning");
2481 cc
->SendWindowPostMessage(this, messageData
, data
);
2482 } else if (ContentParent
* cp
= Canonical()->GetContentParent()) {
2483 if (message
.CloneScope() ==
2484 StructuredCloneHolder::StructuredCloneScope::DifferentProcess
) {
2485 ClonedMessageData clonedMessageData
;
2486 if (!message
.BuildClonedMessageData(clonedMessageData
)) {
2487 aError
.Throw(NS_ERROR_FAILURE
);
2491 messageData
= std::move(clonedMessageData
);
2493 MOZ_ASSERT(message
.CloneScope() ==
2494 StructuredCloneHolder::StructuredCloneScope::SameProcess
);
2496 messageData
= ErrorMessageData();
2498 nsContentUtils::ReportToConsole(
2499 nsIScriptError::warningFlag
, "DOM Window"_ns
,
2500 callerInnerWindow
? callerInnerWindow
->GetDocument() : nullptr,
2501 nsContentUtils::eDOM_PROPERTIES
,
2502 "PostMessageSharedMemoryObjectToCrossOriginWarning");
2505 Unused
<< cp
->SendWindowPostMessage(this, messageData
, data
);
2509 void BrowsingContext::PostMessageMoz(JSContext
* aCx
,
2510 JS::Handle
<JS::Value
> aMessage
,
2511 const WindowPostMessageOptions
& aOptions
,
2512 nsIPrincipal
& aSubjectPrincipal
,
2513 ErrorResult
& aError
) {
2514 PostMessageMoz(aCx
, aMessage
, aOptions
.mTargetOrigin
, aOptions
.mTransfer
,
2515 aSubjectPrincipal
, aError
);
2518 void BrowsingContext::SendCommitTransaction(ContentParent
* aParent
,
2519 const BaseTransaction
& aTxn
,
2521 Unused
<< aParent
->SendCommitBrowsingContextTransaction(this, aTxn
, aEpoch
);
2524 void BrowsingContext::SendCommitTransaction(ContentChild
* aChild
,
2525 const BaseTransaction
& aTxn
,
2527 aChild
->SendCommitBrowsingContextTransaction(this, aTxn
, aEpoch
);
2530 BrowsingContext::IPCInitializer
BrowsingContext::GetIPCInitializer() {
2531 MOZ_DIAGNOSTIC_ASSERT(mEverAttached
);
2532 MOZ_DIAGNOSTIC_ASSERT(mType
== Type::Content
);
2534 IPCInitializer init
;
2536 init
.mParentId
= mParentWindow
? mParentWindow
->Id() : 0;
2537 init
.mWindowless
= mWindowless
;
2538 init
.mUseRemoteTabs
= mUseRemoteTabs
;
2539 init
.mUseRemoteSubframes
= mUseRemoteSubframes
;
2540 init
.mCreatedDynamically
= mCreatedDynamically
;
2541 init
.mChildOffset
= mChildOffset
;
2542 init
.mOriginAttributes
= mOriginAttributes
;
2543 if (mChildSessionHistory
&& mozilla::SessionHistoryInParent()) {
2544 init
.mSessionHistoryIndex
= mChildSessionHistory
->Index();
2545 init
.mSessionHistoryCount
= mChildSessionHistory
->Count();
2547 init
.mRequestContextId
= mRequestContextId
;
2548 init
.mFields
= mFields
.RawValues();
2552 already_AddRefed
<WindowContext
> BrowsingContext::IPCInitializer::GetParent() {
2553 RefPtr
<WindowContext
> parent
;
2554 if (mParentId
!= 0) {
2555 parent
= WindowContext::GetById(mParentId
);
2556 MOZ_RELEASE_ASSERT(parent
);
2558 return parent
.forget();
2561 already_AddRefed
<BrowsingContext
> BrowsingContext::IPCInitializer::GetOpener() {
2562 RefPtr
<BrowsingContext
> opener
;
2563 if (GetOpenerId() != 0) {
2564 opener
= BrowsingContext::Get(GetOpenerId());
2565 MOZ_RELEASE_ASSERT(opener
);
2567 return opener
.forget();
2570 void BrowsingContext::StartDelayedAutoplayMediaComponents() {
2574 AUTOPLAY_LOG("%s : StartDelayedAutoplayMediaComponents for bc 0x%08" PRIx64
,
2575 XRE_IsParentProcess() ? "Parent" : "Child", Id());
2576 mDocShell
->StartDelayedAutoplayMediaComponents();
2579 nsresult
BrowsingContext::ResetGVAutoplayRequestStatus() {
2581 "Should only set GVAudibleAutoplayRequestStatus in the top-level "
2582 "browsing context");
2585 txn
.SetGVAudibleAutoplayRequestStatus(GVAutoplayRequestStatus::eUNKNOWN
);
2586 txn
.SetGVInaudibleAutoplayRequestStatus(GVAutoplayRequestStatus::eUNKNOWN
);
2587 return txn
.Commit(this);
2590 template <typename Callback
>
2591 void BrowsingContext::WalkPresContexts(Callback
&& aCallback
) {
2592 PreOrderWalk([&](BrowsingContext
* aContext
) {
2593 if (nsIDocShell
* shell
= aContext
->GetDocShell()) {
2594 if (RefPtr pc
= shell
->GetPresContext()) {
2595 aCallback(pc
.get());
2601 void BrowsingContext::PresContextAffectingFieldChanged() {
2602 WalkPresContexts([&](nsPresContext
* aPc
) {
2603 aPc
->RecomputeBrowsingContextDependentData();
2607 void BrowsingContext::DidSet(FieldIndex
<IDX_SessionStoreEpoch
>,
2608 uint32_t aOldValue
) {
2609 if (!mCurrentWindowContext
) {
2612 SessionStoreChild
* sessionStoreChild
=
2613 SessionStoreChild::From(mCurrentWindowContext
->GetWindowGlobalChild());
2614 if (!sessionStoreChild
) {
2618 sessionStoreChild
->SetEpoch(GetSessionStoreEpoch());
2621 void BrowsingContext::DidSet(FieldIndex
<IDX_GVAudibleAutoplayRequestStatus
>) {
2623 "Should only set GVAudibleAutoplayRequestStatus in the top-level "
2624 "browsing context");
2627 void BrowsingContext::DidSet(FieldIndex
<IDX_GVInaudibleAutoplayRequestStatus
>) {
2629 "Should only set GVAudibleAutoplayRequestStatus in the top-level "
2630 "browsing context");
2633 bool BrowsingContext::CanSet(FieldIndex
<IDX_ExplicitActive
>,
2634 const ExplicitActiveStatus
&,
2635 ContentParent
* aSource
) {
2636 return XRE_IsParentProcess() && IsTop() && !aSource
;
2639 void BrowsingContext::DidSet(FieldIndex
<IDX_ExplicitActive
>,
2640 ExplicitActiveStatus aOldValue
) {
2641 MOZ_ASSERT(IsTop());
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
) {
2655 Group()->UpdateToplevelsSuspendedIfNeeded();
2656 if (XRE_IsParentProcess()) {
2657 if (BrowserParent
* bp
= Canonical()->GetBrowserParent()) {
2658 bp
->RecomputeProcessPriority();
2659 #if defined(XP_WIN) && defined(ACCESSIBILITY)
2660 if (a11y::Compatibility::IsDolphin()) {
2661 // update active accessible documents on windows
2662 if (a11y::DocAccessibleParent
* tabDoc
=
2663 bp
->GetTopLevelDocAccessible()) {
2664 HWND window
= tabDoc
->GetEmulatedWindowHandle();
2668 a11y::nsWinUtils::ShowNativeWindow(window
);
2670 a11y::nsWinUtils::HideNativeWindow(window
);
2678 // NOTE(emilio): Ideally we'd want to reuse the ExplicitActiveStatus::None
2679 // set-up, but that's non-trivial to do because in content processes we
2680 // can't access the top-cross-chrome-boundary bc.
2681 auto manageTopDescendant
= [&](auto* aChild
) {
2682 if (!aChild
->ManuallyManagesActiveness()) {
2683 aChild
->SetIsActiveInternal(isActive
, IgnoreErrors());
2684 if (BrowserParent
* bp
= aChild
->GetBrowserParent()) {
2685 bp
->SetRenderLayers(isActive
);
2688 return CallState::Continue
;
2690 Canonical()->CallOnAllTopDescendants(manageTopDescendant
,
2691 /* aIncludeNestedBrowsers = */ false);
2694 PreOrderWalk([&](BrowsingContext
* aContext
) {
2695 if (nsCOMPtr
<nsIDocShell
> ds
= aContext
->GetDocShell()) {
2696 nsDocShell::Cast(ds
)->ActivenessMaybeChanged();
2701 void BrowsingContext::DidSet(FieldIndex
<IDX_InRDMPane
>, bool aOldValue
) {
2703 "Should only set InRDMPane in the top-level browsing context");
2704 if (GetInRDMPane() == aOldValue
) {
2707 PresContextAffectingFieldChanged();
2710 bool BrowsingContext::CanSet(FieldIndex
<IDX_PageAwakeRequestCount
>,
2711 uint32_t aNewValue
, ContentParent
* aSource
) {
2712 return IsTop() && XRE_IsParentProcess() && !aSource
;
2715 void BrowsingContext::DidSet(FieldIndex
<IDX_PageAwakeRequestCount
>,
2716 uint32_t aOldValue
) {
2717 if (!IsTop() || aOldValue
== GetPageAwakeRequestCount()) {
2720 Group()->UpdateToplevelsSuspendedIfNeeded();
2723 auto BrowsingContext::CanSet(FieldIndex
<IDX_AllowJavascript
>, bool aValue
,
2724 ContentParent
* aSource
) -> CanSetResult
{
2725 if (mozilla::SessionHistoryInParent()) {
2726 return XRE_IsParentProcess() && !aSource
? CanSetResult::Allow
2727 : CanSetResult::Deny
;
2730 // Without Session History in Parent, session restore code still needs to set
2731 // this from content processes.
2732 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
2735 void BrowsingContext::DidSet(FieldIndex
<IDX_AllowJavascript
>, bool aOldValue
) {
2736 RecomputeCanExecuteScripts();
2739 void BrowsingContext::RecomputeCanExecuteScripts() {
2740 const bool old
= mCanExecuteScripts
;
2741 if (!AllowJavascript()) {
2742 // Scripting has been explicitly disabled on our BrowsingContext.
2743 mCanExecuteScripts
= false;
2744 } else if (GetParentWindowContext()) {
2745 // Otherwise, inherit parent.
2746 mCanExecuteScripts
= GetParentWindowContext()->CanExecuteScripts();
2748 // Otherwise, we're the root of the tree, and we haven't explicitly disabled
2750 mCanExecuteScripts
= true;
2753 if (old
!= mCanExecuteScripts
) {
2754 for (WindowContext
* wc
: GetWindowContexts()) {
2755 wc
->RecomputeCanExecuteScripts();
2760 bool BrowsingContext::InactiveForSuspend() const {
2761 if (!StaticPrefs::dom_suspend_inactive_enabled()) {
2764 // We should suspend a page only when it's inactive and doesn't have any awake
2765 // request that is used to prevent page from being suspended because web page
2766 // might still need to run their script. Eg. waiting for media keys to resume
2767 // media, playing web audio, waiting in a video call conference room.
2768 return !IsActive() && GetPageAwakeRequestCount() == 0;
2771 bool BrowsingContext::CanSet(FieldIndex
<IDX_TouchEventsOverrideInternal
>,
2772 dom::TouchEventsOverride
, ContentParent
* aSource
) {
2773 return XRE_IsParentProcess() && !aSource
;
2776 void BrowsingContext::DidSet(FieldIndex
<IDX_TouchEventsOverrideInternal
>,
2777 dom::TouchEventsOverride
&& aOldValue
) {
2778 if (GetTouchEventsOverrideInternal() == aOldValue
) {
2781 WalkPresContexts([&](nsPresContext
* aPc
) {
2782 aPc
->MediaFeatureValuesChanged(
2783 {MediaFeatureChangeReason::SystemMetricsChange
},
2784 // We're already iterating through sub documents, so we don't need to
2785 // propagate the change again.
2786 MediaFeatureChangePropagation::JustThisDocument
);
2790 void BrowsingContext::DidSet(FieldIndex
<IDX_EmbedderColorSchemes
>,
2791 EmbedderColorSchemes
&& aOldValue
) {
2792 if (GetEmbedderColorSchemes() == aOldValue
) {
2795 PresContextAffectingFieldChanged();
2798 void BrowsingContext::DidSet(FieldIndex
<IDX_PrefersColorSchemeOverride
>,
2799 dom::PrefersColorSchemeOverride aOldValue
) {
2800 MOZ_ASSERT(IsTop());
2801 if (PrefersColorSchemeOverride() == aOldValue
) {
2804 PresContextAffectingFieldChanged();
2807 void BrowsingContext::DidSet(FieldIndex
<IDX_MediumOverride
>,
2808 nsString
&& aOldValue
) {
2809 MOZ_ASSERT(IsTop());
2810 if (GetMediumOverride() == aOldValue
) {
2813 PresContextAffectingFieldChanged();
2816 void BrowsingContext::DidSet(FieldIndex
<IDX_DisplayMode
>,
2817 enum DisplayMode aOldValue
) {
2818 MOZ_ASSERT(IsTop());
2820 if (GetDisplayMode() == aOldValue
) {
2824 WalkPresContexts([&](nsPresContext
* aPc
) {
2825 aPc
->MediaFeatureValuesChanged(
2826 {MediaFeatureChangeReason::DisplayModeChange
},
2827 // We're already iterating through sub documents, so we don't need
2828 // to propagate the change again.
2830 // Images and other resources don't change their display-mode
2831 // evaluation, display-mode is a property of the browsing context.
2832 MediaFeatureChangePropagation::JustThisDocument
);
2836 void BrowsingContext::DidSet(FieldIndex
<IDX_Muted
>) {
2837 MOZ_ASSERT(IsTop(), "Set muted flag on non top-level context!");
2838 USER_ACTIVATION_LOG("Set audio muted %d for %s browsing context 0x%08" PRIx64
,
2839 GetMuted(), XRE_IsParentProcess() ? "Parent" : "Child",
2841 PreOrderWalk([&](BrowsingContext
* aContext
) {
2842 nsPIDOMWindowOuter
* win
= aContext
->GetDOMWindow();
2844 win
->RefreshMediaElementsVolume();
2849 bool BrowsingContext::CanSet(FieldIndex
<IDX_IsAppTab
>, const bool& aValue
,
2850 ContentParent
* aSource
) {
2851 return XRE_IsParentProcess() && !aSource
&& IsTop();
2854 bool BrowsingContext::CanSet(FieldIndex
<IDX_HasSiblings
>, const bool& aValue
,
2855 ContentParent
* aSource
) {
2856 return XRE_IsParentProcess() && !aSource
&& IsTop();
2859 bool BrowsingContext::CanSet(FieldIndex
<IDX_ShouldDelayMediaFromStart
>,
2860 const bool& aValue
, ContentParent
* aSource
) {
2864 void BrowsingContext::DidSet(FieldIndex
<IDX_ShouldDelayMediaFromStart
>,
2866 MOZ_ASSERT(IsTop(), "Set attribute on non top-level context!");
2867 if (aOldValue
== GetShouldDelayMediaFromStart()) {
2870 if (!GetShouldDelayMediaFromStart()) {
2871 PreOrderWalk([&](BrowsingContext
* aContext
) {
2872 if (nsPIDOMWindowOuter
* win
= aContext
->GetDOMWindow()) {
2873 win
->ActivateMediaComponents();
2879 bool BrowsingContext::CanSet(FieldIndex
<IDX_OverrideDPPX
>, const float& aValue
,
2880 ContentParent
* aSource
) {
2881 return XRE_IsParentProcess() && !aSource
&& IsTop();
2884 void BrowsingContext::DidSet(FieldIndex
<IDX_OverrideDPPX
>, float aOldValue
) {
2885 MOZ_ASSERT(IsTop());
2886 if (GetOverrideDPPX() == aOldValue
) {
2889 PresContextAffectingFieldChanged();
2892 void BrowsingContext::SetCustomUserAgent(const nsAString
& aUserAgent
,
2894 Top()->SetUserAgentOverride(aUserAgent
, aRv
);
2897 nsresult
BrowsingContext::SetCustomUserAgent(const nsAString
& aUserAgent
) {
2898 return Top()->SetUserAgentOverride(aUserAgent
);
2901 void BrowsingContext::DidSet(FieldIndex
<IDX_UserAgentOverride
>) {
2902 MOZ_ASSERT(IsTop());
2904 PreOrderWalk([&](BrowsingContext
* aContext
) {
2905 nsIDocShell
* shell
= aContext
->GetDocShell();
2907 shell
->ClearCachedUserAgent();
2912 bool BrowsingContext::CanSet(FieldIndex
<IDX_IsInBFCache
>, bool,
2913 ContentParent
* aSource
) {
2914 return IsTop() && !aSource
&& mozilla::BFCacheInParent();
2917 void BrowsingContext::DidSet(FieldIndex
<IDX_IsInBFCache
>) {
2918 MOZ_RELEASE_ASSERT(mozilla::BFCacheInParent());
2919 MOZ_DIAGNOSTIC_ASSERT(IsTop());
2921 const bool isInBFCache
= GetIsInBFCache();
2923 UpdateCurrentTopByBrowserId(this);
2924 PreOrderWalk([&](BrowsingContext
* aContext
) {
2925 aContext
->mIsInBFCache
= false;
2926 nsCOMPtr
<nsIDocShell
> shell
= aContext
->GetDocShell();
2928 nsDocShell::Cast(shell
)->ThawFreezeNonRecursive(true);
2933 if (isInBFCache
&& XRE_IsContentProcess() && mDocShell
) {
2934 nsDocShell::Cast(mDocShell
)->MaybeDisconnectChildListenersOnPageHide();
2938 PreOrderWalk([&](BrowsingContext
* aContext
) {
2939 nsCOMPtr
<nsIDocShell
> shell
= aContext
->GetDocShell();
2941 nsDocShell::Cast(shell
)->FirePageHideShowNonRecursive(false);
2945 PostOrderWalk([&](BrowsingContext
* aContext
) {
2946 nsCOMPtr
<nsIDocShell
> shell
= aContext
->GetDocShell();
2948 nsDocShell::Cast(shell
)->FirePageHideShowNonRecursive(true);
2954 PreOrderWalk([&](BrowsingContext
* aContext
) {
2955 nsCOMPtr
<nsIDocShell
> shell
= aContext
->GetDocShell();
2957 nsDocShell::Cast(shell
)->ThawFreezeNonRecursive(false);
2958 if (nsPresContext
* pc
= shell
->GetPresContext()) {
2959 pc
->EventStateManager()->ResetHoverState();
2962 aContext
->mIsInBFCache
= true;
2963 Document
* doc
= aContext
->GetDocument();
2965 // Notifying needs to happen after mIsInBFCache is set to true.
2966 doc
->NotifyActivityChanged();
2970 if (XRE_IsParentProcess()) {
2971 if (mCurrentWindowContext
&&
2972 mCurrentWindowContext
->Canonical()->Fullscreen()) {
2973 mCurrentWindowContext
->Canonical()->ExitTopChromeDocumentFullscreen();
2979 void BrowsingContext::DidSet(FieldIndex
<IDX_SyntheticDocumentContainer
>) {
2980 if (WindowContext
* parentWindowContext
= GetParentWindowContext()) {
2981 parentWindowContext
->UpdateChildSynthetic(this,
2982 GetSyntheticDocumentContainer());
2986 void BrowsingContext::SetCustomPlatform(const nsAString
& aPlatform
,
2988 Top()->SetPlatformOverride(aPlatform
, aRv
);
2991 void BrowsingContext::DidSet(FieldIndex
<IDX_PlatformOverride
>) {
2992 MOZ_ASSERT(IsTop());
2994 PreOrderWalk([&](BrowsingContext
* aContext
) {
2995 nsIDocShell
* shell
= aContext
->GetDocShell();
2997 shell
->ClearCachedPlatform();
3002 auto BrowsingContext::LegacyRevertIfNotOwningOrParentProcess(
3003 ContentParent
* aSource
) -> CanSetResult
{
3005 MOZ_ASSERT(XRE_IsParentProcess());
3007 if (!Canonical()->IsOwnedByProcess(aSource
->ChildID())) {
3008 return CanSetResult::Revert
;
3010 } else if (!IsInProcess() && !XRE_IsParentProcess()) {
3011 // Don't allow this to be set from content processes that
3012 // don't own the BrowsingContext.
3013 return CanSetResult::Deny
;
3016 return CanSetResult::Allow
;
3019 bool BrowsingContext::CanSet(FieldIndex
<IDX_IsActiveBrowserWindowInternal
>,
3020 const bool& aValue
, ContentParent
* aSource
) {
3021 // Should only be set in the parent process.
3022 return XRE_IsParentProcess() && !aSource
&& IsTop();
3025 void BrowsingContext::DidSet(FieldIndex
<IDX_IsActiveBrowserWindowInternal
>,
3027 bool isActivateEvent
= GetIsActiveBrowserWindowInternal();
3028 // The browser window containing this context has changed
3029 // activation state so update window inactive document states
3030 // for all in-process documents.
3031 PreOrderWalk([isActivateEvent
](BrowsingContext
* aContext
) {
3032 if (RefPtr
<Document
> doc
= aContext
->GetExtantDocument()) {
3033 doc
->UpdateDocumentStates(DocumentState::WINDOW_INACTIVE
, true);
3035 RefPtr
<nsPIDOMWindowInner
> win
= doc
->GetInnerWindow();
3037 RefPtr
<MediaDevices
> devices
;
3038 if (isActivateEvent
&& (devices
= win
->GetExtantMediaDevices())) {
3039 devices
->BrowserWindowBecameActive();
3042 if (XRE_IsContentProcess() &&
3043 (!aContext
->GetParent() || !aContext
->GetParent()->IsInProcess())) {
3044 // Send the inner window an activate/deactivate event if
3045 // the context is the top of a sub-tree of in-process
3047 nsContentUtils::DispatchEventOnlyToChrome(
3048 doc
, nsGlobalWindowInner::Cast(win
),
3049 isActivateEvent
? u
"activate"_ns
: u
"deactivate"_ns
,
3050 CanBubble::eYes
, Cancelable::eYes
, nullptr);
3057 bool BrowsingContext::CanSet(FieldIndex
<IDX_OpenerPolicy
>,
3058 nsILoadInfo::CrossOriginOpenerPolicy aPolicy
,
3059 ContentParent
* aSource
) {
3060 // A potentially cross-origin isolated BC can't change opener policy, nor can
3061 // a BC become potentially cross-origin isolated. An unchanged policy is
3063 return GetOpenerPolicy() == aPolicy
||
3064 (GetOpenerPolicy() !=
3066 OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
&&
3069 OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
);
3072 auto BrowsingContext::CanSet(FieldIndex
<IDX_AllowContentRetargeting
>,
3073 const bool& aAllowContentRetargeting
,
3074 ContentParent
* aSource
) -> CanSetResult
{
3075 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3078 auto BrowsingContext::CanSet(FieldIndex
<IDX_AllowContentRetargetingOnChildren
>,
3079 const bool& aAllowContentRetargetingOnChildren
,
3080 ContentParent
* aSource
) -> CanSetResult
{
3081 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3084 bool BrowsingContext::CanSet(FieldIndex
<IDX_FullscreenAllowedByOwner
>,
3085 const bool& aAllowed
, ContentParent
* aSource
) {
3086 return CheckOnlyEmbedderCanSet(aSource
);
3089 bool BrowsingContext::CanSet(FieldIndex
<IDX_UseErrorPages
>,
3090 const bool& aUseErrorPages
,
3091 ContentParent
* aSource
) {
3092 return CheckOnlyEmbedderCanSet(aSource
);
3095 TouchEventsOverride
BrowsingContext::TouchEventsOverride() const {
3096 for (const auto* bc
= this; bc
; bc
= bc
->GetParent()) {
3097 auto tev
= bc
->GetTouchEventsOverrideInternal();
3098 if (tev
!= dom::TouchEventsOverride::None
) {
3102 return dom::TouchEventsOverride::None
;
3105 bool BrowsingContext::TargetTopLevelLinkClicksToBlank() const {
3106 return Top()->GetTargetTopLevelLinkClicksToBlankInternal();
3109 // We map `watchedByDevTools` WebIDL attribute to `watchedByDevToolsInternal`
3110 // BC field. And we map it to the top level BrowsingContext.
3111 bool BrowsingContext::WatchedByDevTools() {
3112 return Top()->GetWatchedByDevToolsInternal();
3115 // Enforce that the watchedByDevTools BC field can only be set on the top level
3116 // Browsing Context.
3117 bool BrowsingContext::CanSet(FieldIndex
<IDX_WatchedByDevToolsInternal
>,
3118 const bool& aWatchedByDevTools
,
3119 ContentParent
* aSource
) {
3122 void BrowsingContext::SetWatchedByDevTools(bool aWatchedByDevTools
,
3125 aRv
.ThrowInvalidModificationError(
3126 "watchedByDevTools can only be set on top BrowsingContext");
3129 SetWatchedByDevToolsInternal(aWatchedByDevTools
, aRv
);
3132 auto BrowsingContext::CanSet(FieldIndex
<IDX_DefaultLoadFlags
>,
3133 const uint32_t& aDefaultLoadFlags
,
3134 ContentParent
* aSource
) -> CanSetResult
{
3135 // Bug 1623565 - Are these flags only used by the debugger, which makes it
3136 // possible that this field can only be settable by the parent process?
3137 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3140 void BrowsingContext::DidSet(FieldIndex
<IDX_DefaultLoadFlags
>) {
3141 auto loadFlags
= GetDefaultLoadFlags();
3142 if (GetDocShell()) {
3143 nsDocShell::Cast(GetDocShell())->SetLoadGroupDefaultLoadFlags(loadFlags
);
3146 if (XRE_IsParentProcess()) {
3147 PreOrderWalk([&](BrowsingContext
* aContext
) {
3148 if (aContext
!= this) {
3149 // Setting load flags on a discarded context has no effect.
3150 Unused
<< aContext
->SetDefaultLoadFlags(loadFlags
);
3156 bool BrowsingContext::CanSet(FieldIndex
<IDX_UseGlobalHistory
>,
3157 const bool& aUseGlobalHistory
,
3158 ContentParent
* aSource
) {
3159 // Should only be set in the parent process.
3160 // return XRE_IsParentProcess() && !aSource;
3164 auto BrowsingContext::CanSet(FieldIndex
<IDX_UserAgentOverride
>,
3165 const nsString
& aUserAgent
, ContentParent
* aSource
)
3168 return CanSetResult::Deny
;
3171 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3174 auto BrowsingContext::CanSet(FieldIndex
<IDX_PlatformOverride
>,
3175 const nsString
& aPlatform
, ContentParent
* aSource
)
3178 return CanSetResult::Deny
;
3181 return LegacyRevertIfNotOwningOrParentProcess(aSource
);
3184 bool BrowsingContext::CheckOnlyEmbedderCanSet(ContentParent
* aSource
) {
3185 if (XRE_IsParentProcess()) {
3186 uint64_t childId
= aSource
? aSource
->ChildID() : 0;
3187 return Canonical()->IsEmbeddedInProcess(childId
);
3189 return mEmbeddedByThisProcess
;
3192 bool BrowsingContext::CanSet(FieldIndex
<IDX_EmbedderInnerWindowId
>,
3193 const uint64_t& aValue
, ContentParent
* aSource
) {
3194 // If we have a parent window, our embedder inner window ID must match it.
3195 if (mParentWindow
) {
3196 return mParentWindow
->Id() == aValue
;
3199 // For toplevel BrowsingContext instances, this value may only be set by the
3200 // parent process, or initialized to `0`.
3201 return CheckOnlyEmbedderCanSet(aSource
);
3204 bool BrowsingContext::CanSet(FieldIndex
<IDX_EmbedderElementType
>,
3205 const Maybe
<nsString
>&, ContentParent
* aSource
) {
3206 return CheckOnlyEmbedderCanSet(aSource
);
3209 auto BrowsingContext::CanSet(FieldIndex
<IDX_CurrentInnerWindowId
>,
3210 const uint64_t& aValue
, ContentParent
* aSource
)
3212 // Generally allow clearing this. We may want to be more precise about this
3213 // check in the future.
3215 return CanSetResult::Allow
;
3218 // We must have access to the specified context.
3219 RefPtr
<WindowContext
> window
= WindowContext::GetById(aValue
);
3220 if (!window
|| window
->GetBrowsingContext() != this) {
3221 return CanSetResult::Deny
;
3225 // If the sending process is no longer the current owner, revert
3226 MOZ_ASSERT(XRE_IsParentProcess());
3227 if (!Canonical()->IsOwnedByProcess(aSource
->ChildID())) {
3228 return CanSetResult::Revert
;
3230 } else if (XRE_IsContentProcess() && !IsOwnedByProcess()) {
3231 return CanSetResult::Deny
;
3234 return CanSetResult::Allow
;
3237 bool BrowsingContext::CanSet(FieldIndex
<IDX_ParentInitiatedNavigationEpoch
>,
3238 const uint64_t& aValue
, ContentParent
* aSource
) {
3239 return XRE_IsParentProcess() && !aSource
;
3242 void BrowsingContext::DidSet(FieldIndex
<IDX_CurrentInnerWindowId
>) {
3243 RefPtr
<WindowContext
> prevWindowContext
= mCurrentWindowContext
.forget();
3244 mCurrentWindowContext
= WindowContext::GetById(GetCurrentInnerWindowId());
3246 !mCurrentWindowContext
|| mWindowContexts
.Contains(mCurrentWindowContext
),
3247 "WindowContext not registered?");
3249 // Clear our cached `children` value, to ensure that JS sees the up-to-date
3251 BrowsingContext_Binding::ClearCachedChildrenValue(this);
3253 if (XRE_IsParentProcess()) {
3254 if (prevWindowContext
!= mCurrentWindowContext
) {
3255 if (prevWindowContext
) {
3256 prevWindowContext
->Canonical()->DidBecomeCurrentWindowGlobal(false);
3258 if (mCurrentWindowContext
) {
3259 // We set a timer when we set the current inner window. This
3260 // will then flush the session storage to session store to
3261 // make sure that we don't miss to store session storage to
3262 // session store that is a result of navigation. This is due
3263 // to Bug 1700623. We wish to fix this in Bug 1711886, where
3264 // making sure to store everything would make this timer
3266 Canonical()->MaybeScheduleSessionStoreUpdate();
3267 mCurrentWindowContext
->Canonical()->DidBecomeCurrentWindowGlobal(true);
3270 BrowserParent::UpdateFocusFromBrowsingContext();
3274 bool BrowsingContext::CanSet(FieldIndex
<IDX_IsPopupSpam
>, const bool& aValue
,
3275 ContentParent
* aSource
) {
3276 // Ensure that we only mark a browsing context as popup spam once and never
3278 return aValue
&& !GetIsPopupSpam();
3281 void BrowsingContext::DidSet(FieldIndex
<IDX_IsPopupSpam
>) {
3282 if (GetIsPopupSpam()) {
3283 PopupBlocker::RegisterOpenPopupSpam();
3287 bool BrowsingContext::CanSet(FieldIndex
<IDX_MessageManagerGroup
>,
3288 const nsString
& aMessageManagerGroup
,
3289 ContentParent
* aSource
) {
3290 // Should only be set in the parent process on toplevel.
3291 return XRE_IsParentProcess() && !aSource
&& IsTopContent();
3294 bool BrowsingContext::CanSet(
3295 FieldIndex
<IDX_OrientationLock
>,
3296 const mozilla::hal::ScreenOrientation
& aOrientationLock
,
3297 ContentParent
* aSource
) {
3301 bool BrowsingContext::IsLoading() {
3306 // If we're in the same process as the page, we're possibly just
3307 // updating the flag.
3308 nsIDocShell
* shell
= GetDocShell();
3310 Document
* doc
= shell
->GetDocument();
3311 return doc
&& doc
->GetReadyStateEnum() < Document::READYSTATE_COMPLETE
;
3317 void BrowsingContext::DidSet(FieldIndex
<IDX_Loading
>) {
3318 if (mFields
.Get
<IDX_Loading
>()) {
3322 while (!mDeprioritizedLoadRunner
.isEmpty()) {
3323 nsCOMPtr
<nsIRunnable
> runner
= mDeprioritizedLoadRunner
.popFirst();
3324 NS_DispatchToCurrentThread(runner
.forget());
3328 Group()->FlushPostMessageEvents();
3332 // Inform the Document for this context of the (potential) change in
3334 void BrowsingContext::DidSet(FieldIndex
<IDX_AncestorLoading
>) {
3335 nsPIDOMWindowOuter
* outer
= GetDOMWindow();
3337 MOZ_LOG(gTimeoutDeferralLog
, mozilla::LogLevel::Debug
,
3338 ("DidSetAncestorLoading BC: %p -- No outer window", (void*)this));
3341 Document
* document
= nsGlobalWindowOuter::Cast(outer
)->GetExtantDoc();
3343 MOZ_LOG(gTimeoutDeferralLog
, mozilla::LogLevel::Debug
,
3344 ("DidSetAncestorLoading BC: %p -- NotifyLoading(%d, %d, %d)",
3345 (void*)this, GetAncestorLoading(), document
->GetReadyStateEnum(),
3346 document
->GetReadyStateEnum()));
3347 document
->NotifyLoading(GetAncestorLoading(), document
->GetReadyStateEnum(),
3348 document
->GetReadyStateEnum());
3352 void BrowsingContext::DidSet(FieldIndex
<IDX_AuthorStyleDisabledDefault
>) {
3354 "Should only set AuthorStyleDisabledDefault in the top "
3355 "browsing context");
3357 // We don't need to handle changes to this field, since PageStyleChild.sys.mjs
3358 // will respond to the PageStyle:Disable message in all content processes.
3360 // But we store the state here on the top BrowsingContext so that the
3361 // docshell has somewhere to look for the current author style disabling
3362 // state when new iframes are inserted.
3365 void BrowsingContext::DidSet(FieldIndex
<IDX_TextZoom
>, float aOldValue
) {
3366 if (GetTextZoom() == aOldValue
) {
3370 if (IsInProcess()) {
3371 if (nsIDocShell
* shell
= GetDocShell()) {
3372 if (nsPresContext
* pc
= shell
->GetPresContext()) {
3373 pc
->RecomputeBrowsingContextDependentData();
3377 for (BrowsingContext
* child
: Children()) {
3378 // Setting text zoom on a discarded context has no effect.
3379 Unused
<< child
->SetTextZoom(GetTextZoom());
3383 if (IsTop() && XRE_IsParentProcess()) {
3384 if (Element
* element
= GetEmbedderElement()) {
3385 AsyncEventDispatcher::RunDOMEventWhenSafe(*element
, u
"TextZoomChange"_ns
,
3387 ChromeOnlyDispatch::eYes
);
3392 // TODO(emilio): It'd be potentially nicer and cheaper to allow to set this only
3393 // on the Top() browsing context, but there are a lot of tests that rely on
3394 // zooming a subframe so...
3395 void BrowsingContext::DidSet(FieldIndex
<IDX_FullZoom
>, float aOldValue
) {
3396 if (GetFullZoom() == aOldValue
) {
3400 if (IsInProcess()) {
3401 if (nsIDocShell
* shell
= GetDocShell()) {
3402 if (nsPresContext
* pc
= shell
->GetPresContext()) {
3403 pc
->RecomputeBrowsingContextDependentData();
3407 for (BrowsingContext
* child
: Children()) {
3408 // Setting full zoom on a discarded context has no effect.
3409 Unused
<< child
->SetFullZoom(GetFullZoom());
3413 if (IsTop() && XRE_IsParentProcess()) {
3414 if (Element
* element
= GetEmbedderElement()) {
3415 AsyncEventDispatcher::RunDOMEventWhenSafe(*element
, u
"FullZoomChange"_ns
,
3417 ChromeOnlyDispatch::eYes
);
3422 void BrowsingContext::AddDeprioritizedLoadRunner(nsIRunnable
* aRunner
) {
3423 MOZ_ASSERT(IsLoading());
3424 MOZ_ASSERT(Top() == this);
3426 RefPtr
<DeprioritizedLoadRunner
> runner
= new DeprioritizedLoadRunner(aRunner
);
3427 mDeprioritizedLoadRunner
.insertBack(runner
);
3428 NS_DispatchToCurrentThreadQueue(
3429 runner
.forget(), StaticPrefs::page_load_deprioritization_period(),
3430 EventQueuePriority::Idle
);
3433 bool BrowsingContext::IsDynamic() const {
3434 const BrowsingContext
* current
= this;
3436 if (current
->CreatedDynamically()) {
3439 } while ((current
= current
->GetParent()));
3444 bool BrowsingContext::GetOffsetPath(nsTArray
<uint32_t>& aPath
) const {
3445 for (const BrowsingContext
* current
= this; current
&& current
->GetParent();
3446 current
= current
->GetParent()) {
3447 if (current
->CreatedDynamically()) {
3450 aPath
.AppendElement(current
->ChildOffset());
3455 void BrowsingContext::GetHistoryID(JSContext
* aCx
,
3456 JS::MutableHandle
<JS::Value
> aVal
,
3457 ErrorResult
& aError
) {
3458 if (!xpc::ID2JSValue(aCx
, GetHistoryID(), aVal
)) {
3459 aError
.Throw(NS_ERROR_OUT_OF_MEMORY
);
3463 void BrowsingContext::InitSessionHistory() {
3464 MOZ_ASSERT(!IsDiscarded());
3465 MOZ_ASSERT(IsTop());
3466 MOZ_ASSERT(EverAttached());
3468 if (!GetHasSessionHistory()) {
3469 MOZ_ALWAYS_SUCCEEDS(SetHasSessionHistory(true));
3473 ChildSHistory
* BrowsingContext::GetChildSessionHistory() {
3474 if (!mozilla::SessionHistoryInParent()) {
3475 // For now we're checking that the session history object for the child
3476 // process is available before returning the ChildSHistory object, because
3477 // it is the actual implementation that ChildSHistory forwards to. This can
3478 // be removed once session history is stored exclusively in the parent
3480 return mChildSessionHistory
&& mChildSessionHistory
->IsInProcess()
3481 ? mChildSessionHistory
.get()
3485 return mChildSessionHistory
;
3488 void BrowsingContext::CreateChildSHistory() {
3489 MOZ_ASSERT(IsTop());
3490 MOZ_ASSERT(GetHasSessionHistory());
3491 MOZ_ASSERT(!mChildSessionHistory
);
3493 // Because session history is global in a browsing context tree, every process
3494 // that has access to a browsing context tree needs access to its session
3495 // history. That is why we create the ChildSHistory object in every process
3496 // where we have access to this browsing context (which is the top one).
3497 mChildSessionHistory
= new ChildSHistory(this);
3499 // If the top browsing context (this one) is loaded in this process then we
3500 // also create the session history implementation for the child process.
3501 // This can be removed once session history is stored exclusively in the
3503 mChildSessionHistory
->SetIsInProcess(IsInProcess());
3506 void BrowsingContext::DidSet(FieldIndex
<IDX_HasSessionHistory
>,
3508 MOZ_ASSERT(GetHasSessionHistory() || !aOldValue
,
3509 "We don't support turning off session history.");
3511 if (GetHasSessionHistory() && !aOldValue
) {
3512 CreateChildSHistory();
3516 bool BrowsingContext::CanSet(
3517 FieldIndex
<IDX_TargetTopLevelLinkClicksToBlankInternal
>,
3518 const bool& aTargetTopLevelLinkClicksToBlankInternal
,
3519 ContentParent
* aSource
) {
3520 return XRE_IsParentProcess() && !aSource
&& IsTop();
3523 bool BrowsingContext::CanSet(FieldIndex
<IDX_BrowserId
>, const uint32_t& aValue
,
3524 ContentParent
* aSource
) {
3525 // We should only be able to set this for toplevel contexts which don't have
3527 return GetBrowserId() == 0 && IsTop() && Children().IsEmpty();
3530 bool BrowsingContext::CanSet(FieldIndex
<IDX_PendingInitialization
>,
3531 bool aNewValue
, ContentParent
* aSource
) {
3532 // Can only be cleared from `true` to `false`, and should only ever be set on
3533 // the toplevel BrowsingContext.
3534 return IsTop() && GetPendingInitialization() && !aNewValue
;
3537 bool BrowsingContext::CanSet(FieldIndex
<IDX_HasRestoreData
>, bool aNewValue
,
3538 ContentParent
* aSource
) {
3542 bool BrowsingContext::CanSet(FieldIndex
<IDX_IsUnderHiddenEmbedderElement
>,
3543 const bool& aIsUnderHiddenEmbedderElement
,
3544 ContentParent
* aSource
) {
3548 bool BrowsingContext::CanSet(FieldIndex
<IDX_ForceOffline
>, bool aNewValue
,
3549 ContentParent
* aSource
) {
3550 return XRE_IsParentProcess() && !aSource
;
3553 void BrowsingContext::DidSet(FieldIndex
<IDX_IsUnderHiddenEmbedderElement
>,
3555 nsIDocShell
* shell
= GetDocShell();
3559 const bool newValue
= IsUnderHiddenEmbedderElement();
3560 if (NS_WARN_IF(aOldValue
== newValue
)) {
3564 if (auto* bc
= BrowserChild::GetFrom(shell
)) {
3565 bc
->UpdateVisibility();
3568 if (PresShell
* presShell
= shell
->GetPresShell()) {
3569 presShell
->SetIsUnderHiddenEmbedderElement(newValue
);
3572 // Propagate to children.
3573 for (BrowsingContext
* child
: Children()) {
3574 Element
* embedderElement
= child
->GetEmbedderElement();
3575 if (!embedderElement
) {
3576 // TODO: We shouldn't need to null check here since `child` and the
3577 // element returned by `child->GetEmbedderElement()` are in our
3578 // process (the actual browsing context represented by `child` may not
3579 // be, but that doesn't matter). However, there are currently a very
3580 // small number of crashes due to `embedderElement` being null, somehow
3581 // - see bug 1551241. For now we wallpaper the crash.
3585 bool embedderFrameIsHidden
= true;
3586 if (auto* embedderFrame
= embedderElement
->GetPrimaryFrame()) {
3587 embedderFrameIsHidden
= !embedderFrame
->StyleVisibility()->IsVisible();
3590 bool hidden
= IsUnderHiddenEmbedderElement() || embedderFrameIsHidden
;
3591 if (child
->IsUnderHiddenEmbedderElement() != hidden
) {
3592 Unused
<< child
->SetIsUnderHiddenEmbedderElement(hidden
);
3597 bool BrowsingContext::IsPopupAllowed() {
3598 for (auto* context
= GetCurrentWindowContext(); context
;
3599 context
= context
->GetParentWindowContext()) {
3600 if (context
->CanShowPopup()) {
3609 bool BrowsingContext::ShouldAddEntryForRefresh(
3610 nsIURI
* aPreviousURI
, const SessionHistoryInfo
& aInfo
) {
3611 return ShouldAddEntryForRefresh(aPreviousURI
, aInfo
.GetURI(),
3612 aInfo
.HasPostData());
3616 bool BrowsingContext::ShouldAddEntryForRefresh(nsIURI
* aPreviousURI
,
3618 bool aHasPostData
) {
3623 bool equalsURI
= false;
3625 aPreviousURI
->Equals(aNewURI
, &equalsURI
);
3630 void BrowsingContext::SessionHistoryCommit(
3631 const LoadingSessionHistoryInfo
& aInfo
, uint32_t aLoadType
,
3632 nsIURI
* aPreviousURI
, SessionHistoryInfo
* aPreviousActiveEntry
,
3633 bool aPersist
, bool aCloneEntryChildren
, bool aChannelExpired
,
3634 uint32_t aCacheKey
) {
3636 if (XRE_IsContentProcess()) {
3637 RefPtr
<ChildSHistory
> rootSH
= Top()->GetChildSessionHistory();
3639 if (!aInfo
.mLoadIsFromSessionHistory
) {
3640 // We try to mimic as closely as possible what will happen in
3641 // CanonicalBrowsingContext::SessionHistoryCommit. We'll be
3642 // incrementing the session history length if we're not replacing,
3643 // this is a top-level load or it's not the initial load in an iframe,
3644 // ShouldUpdateSessionHistory(loadType) returns true and it's not a
3645 // refresh for which ShouldAddEntryForRefresh returns false.
3646 // It is possible that this leads to wrong length temporarily, but
3647 // so would not having the check for replace.
3648 // Note that nsSHistory::AddEntry does a replace load if the current
3649 // entry is not marked as a persisted entry. The child process does
3650 // not have access to the current entry, so we use the previous active
3651 // entry as the best approximation. When that's not the current entry
3652 // then the length might be wrong briefly, until the parent process
3653 // commits the actual length.
3654 if (!LOAD_TYPE_HAS_FLAGS(
3655 aLoadType
, nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY
) &&
3657 ? (!aPreviousActiveEntry
|| aPreviousActiveEntry
->GetPersist())
3658 : !!aPreviousActiveEntry
) &&
3659 ShouldUpdateSessionHistory(aLoadType
) &&
3660 (!LOAD_TYPE_HAS_FLAGS(aLoadType
,
3661 nsIWebNavigation::LOAD_FLAGS_IS_REFRESH
) ||
3662 ShouldAddEntryForRefresh(aPreviousURI
, aInfo
.mInfo
))) {
3663 changeID
= rootSH
->AddPendingHistoryChange();
3666 // History load doesn't change the length, only index.
3667 changeID
= rootSH
->AddPendingHistoryChange(aInfo
.mOffset
, 0);
3670 ContentChild
* cc
= ContentChild::GetSingleton();
3671 mozilla::Unused
<< cc
->SendHistoryCommit(
3672 this, aInfo
.mLoadId
, changeID
, aLoadType
, aPersist
, aCloneEntryChildren
,
3673 aChannelExpired
, aCacheKey
);
3675 Canonical()->SessionHistoryCommit(aInfo
.mLoadId
, changeID
, aLoadType
,
3676 aPersist
, aCloneEntryChildren
,
3677 aChannelExpired
, aCacheKey
);
3681 void BrowsingContext::SetActiveSessionHistoryEntry(
3682 const Maybe
<nsPoint
>& aPreviousScrollPos
, SessionHistoryInfo
* aInfo
,
3683 uint32_t aLoadType
, uint32_t aUpdatedCacheKey
, bool aUpdateLength
) {
3684 if (XRE_IsContentProcess()) {
3685 // XXX Why we update cache key only in content process case?
3686 if (aUpdatedCacheKey
!= 0) {
3687 aInfo
->SetCacheKey(aUpdatedCacheKey
);
3691 if (aUpdateLength
) {
3692 RefPtr
<ChildSHistory
> shistory
= Top()->GetChildSessionHistory();
3694 changeID
= shistory
->AddPendingHistoryChange();
3697 ContentChild::GetSingleton()->SendSetActiveSessionHistoryEntry(
3698 this, aPreviousScrollPos
, *aInfo
, aLoadType
, aUpdatedCacheKey
,
3701 Canonical()->SetActiveSessionHistoryEntry(
3702 aPreviousScrollPos
, aInfo
, aLoadType
, aUpdatedCacheKey
, nsID());
3706 void BrowsingContext::ReplaceActiveSessionHistoryEntry(
3707 SessionHistoryInfo
* aInfo
) {
3708 if (XRE_IsContentProcess()) {
3709 ContentChild::GetSingleton()->SendReplaceActiveSessionHistoryEntry(this,
3712 Canonical()->ReplaceActiveSessionHistoryEntry(aInfo
);
3716 void BrowsingContext::RemoveDynEntriesFromActiveSessionHistoryEntry() {
3717 if (XRE_IsContentProcess()) {
3718 ContentChild::GetSingleton()
3719 ->SendRemoveDynEntriesFromActiveSessionHistoryEntry(this);
3721 Canonical()->RemoveDynEntriesFromActiveSessionHistoryEntry();
3725 void BrowsingContext::RemoveFromSessionHistory(const nsID
& aChangeID
) {
3726 if (XRE_IsContentProcess()) {
3727 ContentChild::GetSingleton()->SendRemoveFromSessionHistory(this, aChangeID
);
3729 Canonical()->RemoveFromSessionHistory(aChangeID
);
3733 void BrowsingContext::HistoryGo(
3734 int32_t aOffset
, uint64_t aHistoryEpoch
, bool aRequireUserInteraction
,
3735 bool aUserActivation
, std::function
<void(Maybe
<int32_t>&&)>&& aResolver
) {
3736 if (XRE_IsContentProcess()) {
3737 ContentChild::GetSingleton()->SendHistoryGo(
3738 this, aOffset
, aHistoryEpoch
, aRequireUserInteraction
, aUserActivation
,
3739 std::move(aResolver
),
3741 ResponseRejectReason
) { /* FIXME Is ignoring this fine? */ });
3743 RefPtr
<CanonicalBrowsingContext
> self
= Canonical();
3744 aResolver(self
->HistoryGo(
3745 aOffset
, aHistoryEpoch
, aRequireUserInteraction
, aUserActivation
,
3746 Canonical()->GetContentParent()
3747 ? Some(Canonical()->GetContentParent()->ChildID())
3752 void BrowsingContext::SetChildSHistory(ChildSHistory
* aChildSHistory
) {
3753 mChildSessionHistory
= aChildSHistory
;
3754 mChildSessionHistory
->SetBrowsingContext(this);
3755 mFields
.SetWithoutSyncing
<IDX_HasSessionHistory
>(true);
3758 bool BrowsingContext::ShouldUpdateSessionHistory(uint32_t aLoadType
) {
3759 // We don't update session history on reload unless we're loading
3760 // an iframe in shift-reload case.
3761 return nsDocShell::ShouldUpdateGlobalHistory(aLoadType
) &&
3762 (!(aLoadType
& nsIDocShell::LOAD_CMD_RELOAD
) ||
3763 (IsForceReloadType(aLoadType
) && IsSubframe()));
3766 nsresult
BrowsingContext::CheckLocationChangeRateLimit(CallerType aCallerType
) {
3767 // We only rate limit non system callers
3768 if (aCallerType
== CallerType::System
) {
3772 // Fetch rate limiting preferences
3773 uint32_t limitCount
=
3774 StaticPrefs::dom_navigation_locationChangeRateLimit_count();
3775 uint32_t timeSpanSeconds
=
3776 StaticPrefs::dom_navigation_locationChangeRateLimit_timespan();
3778 // Disable throttling if either of the preferences is set to 0.
3779 if (limitCount
== 0 || timeSpanSeconds
== 0) {
3783 TimeDuration throttleSpan
= TimeDuration::FromSeconds(timeSpanSeconds
);
3785 if (mLocationChangeRateLimitSpanStart
.IsNull() ||
3786 ((TimeStamp::Now() - mLocationChangeRateLimitSpanStart
) > throttleSpan
)) {
3787 // Initial call or timespan exceeded, reset counter and timespan.
3788 mLocationChangeRateLimitSpanStart
= TimeStamp::Now();
3789 mLocationChangeRateLimitCount
= 1;
3793 if (mLocationChangeRateLimitCount
>= limitCount
) {
3794 // Rate limit reached
3796 Document
* doc
= GetDocument();
3798 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag
, "DOM"_ns
, doc
,
3799 nsContentUtils::eDOM_PROPERTIES
,
3800 "LocChangeFloodingPrevented");
3803 return NS_ERROR_DOM_SECURITY_ERR
;
3806 mLocationChangeRateLimitCount
++;
3810 void BrowsingContext::ResetLocationChangeRateLimit() {
3811 // Resetting the timestamp object will cause the check function to
3812 // init again and reset the rate limit.
3813 mLocationChangeRateLimitSpanStart
= TimeStamp();
3816 void BrowsingContext::LocationCreated(dom::Location
* aLocation
) {
3817 MOZ_ASSERT(!aLocation
->isInList());
3818 mLocations
.insertBack(aLocation
);
3821 void BrowsingContext::ClearCachedValuesOfLocations() {
3822 for (dom::Location
* loc
= mLocations
.getFirst(); loc
; loc
= loc
->getNext()) {
3823 loc
->ClearCachedValues();
3831 void IPDLParamTraits
<dom::MaybeDiscarded
<dom::BrowsingContext
>>::Write(
3832 IPC::MessageWriter
* aWriter
, IProtocol
* aActor
,
3833 const dom::MaybeDiscarded
<dom::BrowsingContext
>& aParam
) {
3834 MOZ_DIAGNOSTIC_ASSERT(!aParam
.GetMaybeDiscarded() ||
3835 aParam
.GetMaybeDiscarded()->EverAttached());
3836 uint64_t id
= aParam
.ContextId();
3837 WriteIPDLParam(aWriter
, aActor
, id
);
3840 bool IPDLParamTraits
<dom::MaybeDiscarded
<dom::BrowsingContext
>>::Read(
3841 IPC::MessageReader
* aReader
, IProtocol
* aActor
,
3842 dom::MaybeDiscarded
<dom::BrowsingContext
>* aResult
) {
3844 if (!ReadIPDLParam(aReader
, aActor
, &id
)) {
3850 } else if (RefPtr
<dom::BrowsingContext
> bc
= dom::BrowsingContext::Get(id
)) {
3851 *aResult
= std::move(bc
);
3853 aResult
->SetDiscarded(id
);
3858 void IPDLParamTraits
<dom::BrowsingContext::IPCInitializer
>::Write(
3859 IPC::MessageWriter
* aWriter
, IProtocol
* aActor
,
3860 const dom::BrowsingContext::IPCInitializer
& aInit
) {
3861 // Write actor ID parameters.
3862 WriteIPDLParam(aWriter
, aActor
, aInit
.mId
);
3863 WriteIPDLParam(aWriter
, aActor
, aInit
.mParentId
);
3864 WriteIPDLParam(aWriter
, aActor
, aInit
.mWindowless
);
3865 WriteIPDLParam(aWriter
, aActor
, aInit
.mUseRemoteTabs
);
3866 WriteIPDLParam(aWriter
, aActor
, aInit
.mUseRemoteSubframes
);
3867 WriteIPDLParam(aWriter
, aActor
, aInit
.mCreatedDynamically
);
3868 WriteIPDLParam(aWriter
, aActor
, aInit
.mChildOffset
);
3869 WriteIPDLParam(aWriter
, aActor
, aInit
.mOriginAttributes
);
3870 WriteIPDLParam(aWriter
, aActor
, aInit
.mRequestContextId
);
3871 WriteIPDLParam(aWriter
, aActor
, aInit
.mSessionHistoryIndex
);
3872 WriteIPDLParam(aWriter
, aActor
, aInit
.mSessionHistoryCount
);
3873 WriteIPDLParam(aWriter
, aActor
, aInit
.mFields
);
3876 bool IPDLParamTraits
<dom::BrowsingContext::IPCInitializer
>::Read(
3877 IPC::MessageReader
* aReader
, IProtocol
* aActor
,
3878 dom::BrowsingContext::IPCInitializer
* aInit
) {
3879 // Read actor ID parameters.
3880 if (!ReadIPDLParam(aReader
, aActor
, &aInit
->mId
) ||
3881 !ReadIPDLParam(aReader
, aActor
, &aInit
->mParentId
) ||
3882 !ReadIPDLParam(aReader
, aActor
, &aInit
->mWindowless
) ||
3883 !ReadIPDLParam(aReader
, aActor
, &aInit
->mUseRemoteTabs
) ||
3884 !ReadIPDLParam(aReader
, aActor
, &aInit
->mUseRemoteSubframes
) ||
3885 !ReadIPDLParam(aReader
, aActor
, &aInit
->mCreatedDynamically
) ||
3886 !ReadIPDLParam(aReader
, aActor
, &aInit
->mChildOffset
) ||
3887 !ReadIPDLParam(aReader
, aActor
, &aInit
->mOriginAttributes
) ||
3888 !ReadIPDLParam(aReader
, aActor
, &aInit
->mRequestContextId
) ||
3889 !ReadIPDLParam(aReader
, aActor
, &aInit
->mSessionHistoryIndex
) ||
3890 !ReadIPDLParam(aReader
, aActor
, &aInit
->mSessionHistoryCount
) ||
3891 !ReadIPDLParam(aReader
, aActor
, &aInit
->mFields
)) {
3897 template struct IPDLParamTraits
<dom::BrowsingContext::BaseTransaction
>;
3900 } // namespace mozilla