summaryrefslogtreecommitdiffstats
path: root/docshell/base/BrowsingContext.h
diff options
context:
space:
mode:
Diffstat (limited to 'docshell/base/BrowsingContext.h')
-rw-r--r--docshell/base/BrowsingContext.h1458
1 files changed, 1458 insertions, 0 deletions
diff --git a/docshell/base/BrowsingContext.h b/docshell/base/BrowsingContext.h
new file mode 100644
index 0000000000..4c245337b7
--- /dev/null
+++ b/docshell/base/BrowsingContext.h
@@ -0,0 +1,1458 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_BrowsingContext_h
+#define mozilla_dom_BrowsingContext_h
+
+#include <tuple>
+#include "GVAutoplayRequestUtils.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/HalScreenConfiguration.h"
+#include "mozilla/LinkedList.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/Span.h"
+
+#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/LocationBase.h"
+#include "mozilla/dom/MaybeDiscarded.h"
+#include "mozilla/dom/PopupBlocker.h"
+#include "mozilla/dom/UserActivation.h"
+#include "mozilla/dom/BrowsingContextBinding.h"
+#include "mozilla/dom/ScreenOrientationBinding.h"
+#include "mozilla/dom/SyncedContext.h"
+#include "nsCOMPtr.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsIDocShell.h"
+#include "nsTArray.h"
+#include "nsWrapperCache.h"
+#include "nsILoadInfo.h"
+#include "nsILoadContext.h"
+#include "nsThreadUtils.h"
+
+class nsDocShellLoadState;
+class nsGlobalWindowInner;
+class nsGlobalWindowOuter;
+class nsIPrincipal;
+class nsOuterWindowProxy;
+struct nsPoint;
+class PickleIterator;
+
+namespace IPC {
+class Message;
+class MessageReader;
+class MessageWriter;
+} // namespace IPC
+
+namespace mozilla {
+
+class ErrorResult;
+class LogModule;
+
+namespace ipc {
+class IProtocol;
+class IPCResult;
+
+template <typename T>
+struct IPDLParamTraits;
+} // namespace ipc
+
+namespace dom {
+class BrowsingContent;
+class BrowsingContextGroup;
+class CanonicalBrowsingContext;
+class ChildSHistory;
+class ContentParent;
+class Element;
+struct LoadingSessionHistoryInfo;
+template <typename>
+struct Nullable;
+template <typename T>
+class Sequence;
+class SessionHistoryInfo;
+class SessionStorageManager;
+class StructuredCloneHolder;
+class WindowContext;
+class WindowGlobalChild;
+struct WindowPostMessageOptions;
+class WindowProxyHolder;
+
+enum class ExplicitActiveStatus : uint8_t {
+ None,
+ Active,
+ Inactive,
+ EndGuard_,
+};
+
+struct EmbedderColorSchemes {
+ PrefersColorSchemeOverride mUsed{};
+ PrefersColorSchemeOverride mPreferred{};
+
+ bool operator==(const EmbedderColorSchemes& aOther) const {
+ return mUsed == aOther.mUsed && mPreferred == aOther.mPreferred;
+ }
+
+ bool operator!=(const EmbedderColorSchemes& aOther) const {
+ return !(*this == aOther);
+ }
+};
+
+// Fields are, by default, settable by any process and readable by any process.
+// Racy sets will be resolved as-if they occurred in the order the parent
+// process finds out about them.
+//
+// The `DidSet` and `CanSet` methods may be overloaded to provide different
+// behavior for a specific field.
+// * `DidSet` is called to run code in every process whenever the value is
+// updated (This currently occurs even if the value didn't change, though
+// this may change in the future).
+// * `CanSet` is called before attempting to set the value, in both the process
+// which calls `Set`, and the parent process, and will kill the misbehaving
+// process if it fails.
+#define MOZ_EACH_BC_FIELD(FIELD) \
+ FIELD(Name, nsString) \
+ FIELD(Closed, bool) \
+ FIELD(ExplicitActive, ExplicitActiveStatus) \
+ /* Top()-only. If true, new-playing media will be suspended when in an \
+ * inactive browsing context. */ \
+ FIELD(SuspendMediaWhenInactive, bool) \
+ /* If true, we're within the nested event loop in window.open, and this \
+ * context may not be used as the target of a load */ \
+ FIELD(PendingInitialization, bool) \
+ /* Indicates if the browser window is active for the purpose of the \
+ * :-moz-window-inactive pseudoclass. Only read from or set on the \
+ * top BrowsingContext. */ \
+ FIELD(IsActiveBrowserWindowInternal, bool) \
+ FIELD(OpenerPolicy, nsILoadInfo::CrossOriginOpenerPolicy) \
+ /* Current opener for the BrowsingContext. Weak reference */ \
+ FIELD(OpenerId, uint64_t) \
+ FIELD(OnePermittedSandboxedNavigatorId, uint64_t) \
+ /* WindowID of the inner window which embeds this BC */ \
+ FIELD(EmbedderInnerWindowId, uint64_t) \
+ FIELD(CurrentInnerWindowId, uint64_t) \
+ FIELD(HadOriginalOpener, bool) \
+ FIELD(IsPopupSpam, bool) \
+ /* Hold the audio muted state and should be used on top level browsing \
+ * contexts only */ \
+ FIELD(Muted, bool) \
+ /* Hold the pinned/app-tab state and should be used on top level browsing \
+ * contexts only */ \
+ FIELD(IsAppTab, bool) \
+ /* Whether there's more than 1 tab / toplevel browsing context in this \
+ * parent window. Used to determine if a given BC is allowed to resize \
+ * and/or move the window or not. */ \
+ FIELD(HasSiblings, bool) \
+ /* Indicate that whether we should delay media playback, which would only \
+ be done on an unvisited tab. And this should only be used on the top \
+ level browsing contexts */ \
+ FIELD(ShouldDelayMediaFromStart, bool) \
+ /* See nsSandboxFlags.h for the possible flags. */ \
+ FIELD(SandboxFlags, uint32_t) \
+ /* The value of SandboxFlags when the BrowsingContext is first created. \
+ * Used for sandboxing the initial about:blank document. */ \
+ FIELD(InitialSandboxFlags, uint32_t) \
+ /* A non-zero unique identifier for the browser element that is hosting \
+ * this \
+ * BrowsingContext tree. Every BrowsingContext in the element's tree will \
+ * return the same ID in all processes and it will remain stable \
+ * regardless of process changes. When a browser element's frameloader is \
+ * switched to another browser element this ID will remain the same but \
+ * hosted under the under the new browser element. */ \
+ FIELD(BrowserId, uint64_t) \
+ FIELD(HistoryID, nsID) \
+ FIELD(InRDMPane, bool) \
+ FIELD(Loading, bool) \
+ /* A field only set on top browsing contexts, which indicates that either: \
+ * \
+ * * This is a browsing context created explicitly for printing or print \
+ * preview (thus hosting static documents). \
+ * \
+ * * This is a browsing context where something in this tree is calling \
+ * window.print() (and thus showing a modal dialog). \
+ * \
+ * We use it exclusively to block navigation for both of these cases. */ \
+ FIELD(IsPrinting, bool) \
+ FIELD(AncestorLoading, bool) \
+ FIELD(AllowPlugins, bool) \
+ FIELD(AllowContentRetargeting, bool) \
+ FIELD(AllowContentRetargetingOnChildren, bool) \
+ FIELD(ForceEnableTrackingProtection, bool) \
+ FIELD(UseGlobalHistory, bool) \
+ FIELD(TargetTopLevelLinkClicksToBlankInternal, bool) \
+ FIELD(FullscreenAllowedByOwner, bool) \
+ FIELD(ForceDesktopViewport, bool) \
+ /* \
+ * "is popup" in the spec. \
+ * Set only on top browsing contexts. \
+ * This doesn't indicate whether this is actually a popup or not, \
+ * but whether this browsing context is created by requesting popup or not. \
+ * See also: nsWindowWatcher::ShouldOpenPopup. \
+ */ \
+ FIELD(IsPopupRequested, bool) \
+ /* These field are used to store the states of autoplay media request on \
+ * GeckoView only, and it would only be modified on the top level browsing \
+ * context. */ \
+ FIELD(GVAudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \
+ FIELD(GVInaudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \
+ /* ScreenOrientation-related APIs */ \
+ FIELD(CurrentOrientationAngle, float) \
+ FIELD(CurrentOrientationType, mozilla::dom::OrientationType) \
+ FIELD(OrientationLock, mozilla::hal::ScreenOrientation) \
+ FIELD(UserAgentOverride, nsString) \
+ FIELD(TouchEventsOverrideInternal, mozilla::dom::TouchEventsOverride) \
+ FIELD(EmbedderElementType, Maybe<nsString>) \
+ FIELD(MessageManagerGroup, nsString) \
+ FIELD(MaxTouchPointsOverride, uint8_t) \
+ FIELD(FullZoom, float) \
+ FIELD(WatchedByDevToolsInternal, bool) \
+ FIELD(TextZoom, float) \
+ FIELD(OverrideDPPX, float) \
+ /* The current in-progress load. */ \
+ FIELD(CurrentLoadIdentifier, Maybe<uint64_t>) \
+ /* See nsIRequest for possible flags. */ \
+ FIELD(DefaultLoadFlags, uint32_t) \
+ /* Signals that session history is enabled for this browsing context tree. \
+ * This is only ever set to true on the top BC, so consumers need to get \
+ * the value from the top BC! */ \
+ FIELD(HasSessionHistory, bool) \
+ /* Tracks if this context is the only top-level document in the session \
+ * history of the context. */ \
+ FIELD(IsSingleToplevelInHistory, bool) \
+ FIELD(UseErrorPages, bool) \
+ FIELD(PlatformOverride, nsString) \
+ /* Specifies if this BC has loaded documents besides the initial \
+ * about:blank document. about:privatebrowsing, about:home, about:newtab \
+ * and non-initial about:blank are not considered to be initial \
+ * documents. */ \
+ FIELD(HasLoadedNonInitialDocument, bool) \
+ /* Default value for nsIContentViewer::authorStyleDisabled in any new \
+ * browsing contexts created as a descendant of this one. Valid only for \
+ * top BCs. */ \
+ FIELD(AuthorStyleDisabledDefault, bool) \
+ FIELD(ServiceWorkersTestingEnabled, bool) \
+ FIELD(MediumOverride, nsString) \
+ /* DevTools override for prefers-color-scheme */ \
+ FIELD(PrefersColorSchemeOverride, dom::PrefersColorSchemeOverride) \
+ /* prefers-color-scheme override based on the color-scheme style of our \
+ * <browser> embedder element. */ \
+ FIELD(EmbedderColorSchemes, EmbedderColorSchemes) \
+ FIELD(DisplayMode, dom::DisplayMode) \
+ /* The number of entries added to the session history because of this \
+ * browsing context. */ \
+ FIELD(HistoryEntryCount, uint32_t) \
+ /* Don't use the getter of the field, but IsInBFCache() method */ \
+ FIELD(IsInBFCache, bool) \
+ FIELD(HasRestoreData, bool) \
+ FIELD(SessionStoreEpoch, uint32_t) \
+ /* Whether we can execute scripts in this BrowsingContext. Has no effect \
+ * unless scripts are also allowed in the parent WindowContext. */ \
+ FIELD(AllowJavascript, bool) \
+ /* The count of request that are used to prevent the browsing context tree \
+ * from being suspended, which would ONLY be modified on the top level \
+ * context in the chrome process because that's a non-atomic counter */ \
+ FIELD(PageAwakeRequestCount, uint32_t) \
+ /* This field only gets incrememented when we start navigations in the \
+ * parent process. This is used for keeping track of the racing navigations \
+ * between the parent and content processes. */ \
+ FIELD(ParentInitiatedNavigationEpoch, uint64_t) \
+ /* This browsing context is for a synthetic image document wrapping an \
+ * image embedded in <object> or <embed>. */ \
+ FIELD(SyntheticDocumentContainer, bool) \
+ /* If true, this document is embedded within a content document, either \
+ * loaded in the parent (e.g. about:addons or the devtools toolbox), or in \
+ * a content process. */ \
+ FIELD(EmbeddedInContentDocument, bool) \
+ /* If true, this browsing context is within a hidden embedded document. */ \
+ FIELD(IsUnderHiddenEmbedderElement, bool)
+
+// BrowsingContext, in this context, is the cross process replicated
+// environment in which information about documents is stored. In
+// particular the tree structure of nested browsing contexts is
+// represented by the tree of BrowsingContexts.
+//
+// The tree of BrowsingContexts is created in step with its
+// corresponding nsDocShell, and when nsDocShells are connected
+// through a parent/child relationship, so are BrowsingContexts. The
+// major difference is that BrowsingContexts are replicated (synced)
+// to the parent process, making it possible to traverse the
+// BrowsingContext tree for a tab, in both the parent and the child
+// process.
+//
+// Trees of BrowsingContexts should only ever contain nodes of the
+// same BrowsingContext::Type. This is enforced by asserts in the
+// BrowsingContext::Create* methods.
+class BrowsingContext : public nsILoadContext, public nsWrapperCache {
+ MOZ_DECL_SYNCED_CONTEXT(BrowsingContext, MOZ_EACH_BC_FIELD)
+
+ public:
+ enum class Type { Chrome, Content };
+
+ static void Init();
+ static LogModule* GetLog();
+ static LogModule* GetSyncLog();
+
+ // Look up a BrowsingContext in the current process by ID.
+ static already_AddRefed<BrowsingContext> Get(uint64_t aId);
+ static already_AddRefed<BrowsingContext> Get(GlobalObject&, uint64_t aId) {
+ return Get(aId);
+ }
+ // Look up the top-level BrowsingContext by BrowserID.
+ static already_AddRefed<BrowsingContext> GetCurrentTopByBrowserId(
+ uint64_t aBrowserId);
+ static already_AddRefed<BrowsingContext> GetCurrentTopByBrowserId(
+ GlobalObject&, uint64_t aId) {
+ return GetCurrentTopByBrowserId(aId);
+ }
+
+ static void UpdateCurrentTopByBrowserId(BrowsingContext* aNewBrowsingContext);
+
+ static already_AddRefed<BrowsingContext> GetFromWindow(
+ WindowProxyHolder& aProxy);
+ static already_AddRefed<BrowsingContext> GetFromWindow(
+ GlobalObject&, WindowProxyHolder& aProxy) {
+ return GetFromWindow(aProxy);
+ }
+
+ static void DiscardFromContentParent(ContentParent* aCP);
+
+ // Create a brand-new toplevel BrowsingContext with no relationships to other
+ // BrowsingContexts, and which is not embedded within any <browser> or frame
+ // element.
+ //
+ // This BrowsingContext is immediately attached, and cannot have LoadContext
+ // flags customized unless it is of `Type::Chrome`.
+ //
+ // The process which created this BrowsingContext is responsible for detaching
+ // it.
+ static already_AddRefed<BrowsingContext> CreateIndependent(Type aType);
+
+ // Create a brand-new BrowsingContext object, but does not immediately attach
+ // it. State such as OriginAttributes and PrivateBrowsingId may be customized
+ // to configure the BrowsingContext before it is attached.
+ //
+ // `EnsureAttached()` must be called before the BrowsingContext is used for a
+ // DocShell, BrowserParent, or BrowserBridgeChild.
+ static already_AddRefed<BrowsingContext> CreateDetached(
+ nsGlobalWindowInner* aParent, BrowsingContext* aOpener,
+ BrowsingContextGroup* aSpecificGroup, const nsAString& aName, Type aType,
+ bool aIsPopupRequested, bool aCreatedDynamically = false);
+
+ void EnsureAttached();
+
+ bool EverAttached() const { return mEverAttached; }
+
+ // Cast this object to a canonical browsing context, and return it.
+ CanonicalBrowsingContext* Canonical();
+
+ // Is the most recent Document in this BrowsingContext loaded within this
+ // process? This may be true with a null mDocShell after the Window has been
+ // closed.
+ bool IsInProcess() const { return mIsInProcess; }
+
+ bool IsOwnedByProcess() const;
+
+ bool CanHaveRemoteOuterProxies() const {
+ return !mIsInProcess || mDanglingRemoteOuterProxies;
+ }
+
+ // Has this BrowsingContext been discarded. A discarded browsing context has
+ // been destroyed, and may not be available on the other side of an IPC
+ // message.
+ bool IsDiscarded() const { return mIsDiscarded; }
+
+ // Returns true if none of the BrowsingContext's ancestor BrowsingContexts or
+ // WindowContexts are discarded or cached.
+ bool AncestorsAreCurrent() const;
+
+ bool Windowless() const { return mWindowless; }
+
+ // Get the DocShell for this BrowsingContext if it is in-process, or
+ // null if it's not.
+ nsIDocShell* GetDocShell() const { return mDocShell; }
+ void SetDocShell(nsIDocShell* aDocShell);
+ void ClearDocShell() { mDocShell = nullptr; }
+
+ // Get the Document for this BrowsingContext if it is in-process, or
+ // null if it's not.
+ Document* GetDocument() const {
+ return mDocShell ? mDocShell->GetDocument() : nullptr;
+ }
+ Document* GetExtantDocument() const {
+ return mDocShell ? mDocShell->GetExtantDocument() : nullptr;
+ }
+
+ // This cleans up remote outer window proxies that might have been left behind
+ // when the browsing context went from being remote to local. It does this by
+ // turning them into cross-compartment wrappers to aOuter. If there is already
+ // a remote proxy in the compartment of aOuter, then aOuter will get swapped
+ // to it and the value of aOuter will be set to the object that used to be the
+ // remote proxy and is now an OuterWindowProxy.
+ void CleanUpDanglingRemoteOuterWindowProxies(
+ JSContext* aCx, JS::MutableHandle<JSObject*> aOuter);
+
+ // Get the embedder element for this BrowsingContext if the embedder is
+ // in-process, or null if it's not.
+ Element* GetEmbedderElement() const { return mEmbedderElement; }
+ void SetEmbedderElement(Element* aEmbedder);
+
+ // Return true if the type of the embedder element is either object
+ // or embed, false otherwise.
+ bool IsEmbedderTypeObjectOrEmbed();
+
+ // Called after the BrowingContext has been embedded in a FrameLoader. This
+ // happens after `SetEmbedderElement` is called on the BrowsingContext and
+ // after the BrowsingContext has been set on the FrameLoader.
+ void Embed();
+
+ // Get the outer window object for this BrowsingContext if it is in-process
+ // and still has a docshell, or null otherwise.
+ nsPIDOMWindowOuter* GetDOMWindow() const {
+ return mDocShell ? mDocShell->GetWindow() : nullptr;
+ }
+
+ uint64_t GetRequestContextId() const { return mRequestContextId; }
+
+ // Detach the current BrowsingContext from its parent, in both the
+ // child and the parent process.
+ void Detach(bool aFromIPC = false);
+
+ // Prepare this BrowsingContext to leave the current process.
+ void PrepareForProcessChange();
+
+ // Triggers a load in the process which currently owns this BrowsingContext.
+ nsresult LoadURI(nsDocShellLoadState* aLoadState,
+ bool aSetNavigating = false);
+
+ nsresult InternalLoad(nsDocShellLoadState* aLoadState);
+
+ // Removes the root document for this BrowsingContext tree from the BFCache,
+ // if it is cached, and returns true if it was.
+ bool RemoveRootFromBFCacheSync();
+
+ // If the load state includes a source BrowsingContext has been passed, check
+ // to see if we are sandboxed from it as the result of an iframe or CSP
+ // sandbox.
+ nsresult CheckSandboxFlags(nsDocShellLoadState* aLoadState);
+
+ void DisplayLoadError(const nsAString& aURI);
+
+ // Check that this browsing context is targetable for navigations (i.e. that
+ // it is neither closed, cached, nor discarded).
+ bool IsTargetable() const;
+
+ // True if this browsing context is inactive and is able to be suspended.
+ bool InactiveForSuspend() const;
+
+ const nsString& Name() const { return GetName(); }
+ void GetName(nsAString& aName) { aName = GetName(); }
+ bool NameEquals(const nsAString& aName) { return GetName().Equals(aName); }
+
+ Type GetType() const { return mType; }
+ bool IsContent() const { return mType == Type::Content; }
+ bool IsChrome() const { return !IsContent(); }
+
+ bool IsTop() const { return !GetParent(); }
+ bool IsSubframe() const { return !IsTop(); }
+
+ bool IsTopContent() const { return IsContent() && IsTop(); }
+
+ bool IsInSubtreeOf(BrowsingContext* aContext);
+
+ bool IsContentSubframe() const { return IsContent() && IsSubframe(); }
+
+ // non-zero
+ uint64_t Id() const { return mBrowsingContextId; }
+
+ BrowsingContext* GetParent() const;
+ BrowsingContext* Top();
+ const BrowsingContext* Top() const;
+
+ int32_t IndexOf(BrowsingContext* aChild);
+
+ // NOTE: Unlike `GetEmbedderWindowGlobal`, `GetParentWindowContext` does not
+ // cross toplevel content browser boundaries.
+ WindowContext* GetParentWindowContext() const { return mParentWindow; }
+ WindowContext* GetTopWindowContext() const;
+
+ already_AddRefed<BrowsingContext> GetOpener() const {
+ RefPtr<BrowsingContext> opener(Get(GetOpenerId()));
+ if (!mIsDiscarded && opener && !opener->mIsDiscarded) {
+ MOZ_DIAGNOSTIC_ASSERT(opener->mType == mType);
+ return opener.forget();
+ }
+ return nullptr;
+ }
+ void SetOpener(BrowsingContext* aOpener) {
+ MOZ_DIAGNOSTIC_ASSERT(!aOpener || aOpener->Group() == Group());
+ MOZ_DIAGNOSTIC_ASSERT(!aOpener || aOpener->mType == mType);
+
+ MOZ_ALWAYS_SUCCEEDS(SetOpenerId(aOpener ? aOpener->Id() : 0));
+ }
+
+ bool HasOpener() const;
+
+ bool HadOriginalOpener() const { return GetHadOriginalOpener(); }
+
+ // Returns true if the browsing context and top context are same origin
+ bool SameOriginWithTop();
+
+ /**
+ * When a new browsing context is opened by a sandboxed document, it needs to
+ * keep track of the browsing context that opened it, so that it can be
+ * navigated by it. This is the "one permitted sandboxed navigator".
+ */
+ already_AddRefed<BrowsingContext> GetOnePermittedSandboxedNavigator() const {
+ return Get(GetOnePermittedSandboxedNavigatorId());
+ }
+ [[nodiscard]] nsresult SetOnePermittedSandboxedNavigator(
+ BrowsingContext* aNavigator) {
+ if (GetOnePermittedSandboxedNavigatorId()) {
+ MOZ_ASSERT(false,
+ "One Permitted Sandboxed Navigator should only be set once.");
+ return NS_ERROR_FAILURE;
+ } else {
+ return SetOnePermittedSandboxedNavigatorId(aNavigator ? aNavigator->Id()
+ : 0);
+ }
+ }
+
+ uint32_t SandboxFlags() const { return GetSandboxFlags(); }
+
+ Span<RefPtr<BrowsingContext>> Children() const;
+ void GetChildren(nsTArray<RefPtr<BrowsingContext>>& aChildren);
+
+ Span<RefPtr<BrowsingContext>> NonSyntheticChildren() const;
+
+ const nsTArray<RefPtr<WindowContext>>& GetWindowContexts() {
+ return mWindowContexts;
+ }
+ void GetWindowContexts(nsTArray<RefPtr<WindowContext>>& aWindows);
+
+ void RegisterWindowContext(WindowContext* aWindow);
+ void UnregisterWindowContext(WindowContext* aWindow);
+ WindowContext* GetCurrentWindowContext() const {
+ return mCurrentWindowContext;
+ }
+
+ // Helpers to traverse this BrowsingContext subtree. Note that these will only
+ // traverse active contexts, and will ignore ones in the BFCache.
+ enum class WalkFlag {
+ Next,
+ Skip,
+ Stop,
+ };
+
+ /**
+ * Walk the browsing context tree in pre-order and call `aCallback`
+ * for every node in the tree. PreOrderWalk accepts two types of
+ * callbacks, either of the type `void(BrowsingContext*)` or
+ * `WalkFlag(BrowsingContext*)`. The former traverses the entire
+ * tree, but the latter let's you control if a sub-tree should be
+ * skipped by returning `WalkFlag::Skip`, completely abort traversal
+ * by returning `WalkFlag::Stop` or continue as normal with
+ * `WalkFlag::Next`.
+ */
+ template <typename F>
+ void PreOrderWalk(F&& aCallback) {
+ if constexpr (std::is_void_v<
+ typename std::invoke_result_t<F, BrowsingContext*>>) {
+ PreOrderWalkVoid(std::forward<F>(aCallback));
+ } else {
+ PreOrderWalkFlag(std::forward<F>(aCallback));
+ }
+ }
+
+ void PreOrderWalkVoid(const std::function<void(BrowsingContext*)>& aCallback);
+ WalkFlag PreOrderWalkFlag(
+ const std::function<WalkFlag(BrowsingContext*)>& aCallback);
+
+ void PostOrderWalk(const std::function<void(BrowsingContext*)>& aCallback);
+
+ void GetAllBrowsingContextsInSubtree(
+ nsTArray<RefPtr<BrowsingContext>>& aBrowsingContexts);
+
+ BrowsingContextGroup* Group() { return mGroup; }
+
+ // WebIDL bindings for nsILoadContext
+ Nullable<WindowProxyHolder> GetAssociatedWindow();
+ Nullable<WindowProxyHolder> GetTopWindow();
+ Element* GetTopFrameElement();
+ bool GetIsContent() { return IsContent(); }
+ void SetUsePrivateBrowsing(bool aUsePrivateBrowsing, ErrorResult& aError);
+ // Needs a different name to disambiguate from the xpidl method with
+ // the same signature but different return value.
+ void SetUseTrackingProtectionWebIDL(bool aUseTrackingProtection,
+ ErrorResult& aRv);
+ bool UseTrackingProtectionWebIDL() { return UseTrackingProtection(); }
+ void GetOriginAttributes(JSContext* aCx, JS::MutableHandle<JS::Value> aVal,
+ ErrorResult& aError);
+
+ bool InRDMPane() const { return GetInRDMPane(); }
+
+ bool WatchedByDevTools();
+ void SetWatchedByDevTools(bool aWatchedByDevTools, ErrorResult& aRv);
+
+ dom::TouchEventsOverride TouchEventsOverride() const;
+ bool TargetTopLevelLinkClicksToBlank() const;
+
+ bool FullscreenAllowed() const;
+
+ float FullZoom() const { return GetFullZoom(); }
+ float TextZoom() const { return GetTextZoom(); }
+
+ float OverrideDPPX() const { return Top()->GetOverrideDPPX(); }
+
+ bool SuspendMediaWhenInactive() const {
+ return GetSuspendMediaWhenInactive();
+ }
+
+ bool IsActive() const;
+ void SetIsActive(bool aIsActive, mozilla::ErrorResult& aRv) {
+ SetExplicitActive(aIsActive ? ExplicitActiveStatus::Active
+ : ExplicitActiveStatus::Inactive,
+ aRv);
+ }
+
+ bool ForceDesktopViewport() const { return GetForceDesktopViewport(); }
+
+ bool AuthorStyleDisabledDefault() const {
+ return GetAuthorStyleDisabledDefault();
+ }
+
+ bool UseGlobalHistory() const { return GetUseGlobalHistory(); }
+
+ bool GetIsActiveBrowserWindow();
+
+ void SetIsActiveBrowserWindow(bool aActive);
+
+ uint64_t BrowserId() const { return GetBrowserId(); }
+
+ bool IsLoading();
+
+ void GetEmbedderElementType(nsString& aElementType) {
+ if (GetEmbedderElementType().isSome()) {
+ aElementType = GetEmbedderElementType().value();
+ }
+ }
+
+ bool IsLoadingIdentifier(uint64_t aLoadIdentifer) {
+ if (GetCurrentLoadIdentifier() &&
+ *GetCurrentLoadIdentifier() == aLoadIdentifer) {
+ return true;
+ }
+ return false;
+ }
+
+ // ScreenOrientation related APIs
+ [[nodiscard]] nsresult SetCurrentOrientation(OrientationType aType,
+ float aAngle) {
+ Transaction txn;
+ txn.SetCurrentOrientationType(aType);
+ txn.SetCurrentOrientationAngle(aAngle);
+ return txn.Commit(this);
+ }
+
+ void SetRDMPaneOrientation(OrientationType aType, float aAngle,
+ ErrorResult& aRv) {
+ if (InRDMPane()) {
+ if (NS_FAILED(SetCurrentOrientation(aType, aAngle))) {
+ aRv.ThrowInvalidStateError("Browsing context is discarded");
+ }
+ }
+ }
+
+ void SetRDMPaneMaxTouchPoints(uint8_t aMaxTouchPoints, ErrorResult& aRv) {
+ if (InRDMPane()) {
+ SetMaxTouchPointsOverride(aMaxTouchPoints, aRv);
+ }
+ }
+
+ // Find a browsing context in this context's list of
+ // children. Doesn't consider the special names, '_self', '_parent',
+ // '_top', or '_blank'. Performs access control checks with regard to
+ // 'this'.
+ BrowsingContext* FindChildWithName(const nsAString& aName,
+ WindowGlobalChild& aRequestingWindow);
+
+ // Find a browsing context in the subtree rooted at 'this' Doesn't
+ // consider the special names, '_self', '_parent', '_top', or
+ // '_blank'.
+ //
+ // If passed, performs access control checks with regard to
+ // 'aRequestingContext', otherwise performs no access checks.
+ BrowsingContext* FindWithNameInSubtree(const nsAString& aName,
+ WindowGlobalChild* aRequestingWindow);
+
+ // Find the special browsing context if aName is '_self', '_parent',
+ // '_top', but not '_blank'. The latter is handled in FindWithName
+ BrowsingContext* FindWithSpecialName(const nsAString& aName,
+ WindowGlobalChild& aRequestingWindow);
+
+ nsISupports* GetParentObject() const;
+ JSObject* WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) override;
+
+ // Return the window proxy object that corresponds to this browsing context.
+ inline JSObject* GetWindowProxy() const { return mWindowProxy; }
+ inline JSObject* GetUnbarrieredWindowProxy() const {
+ return mWindowProxy.unbarrieredGet();
+ }
+
+ // Set the window proxy object that corresponds to this browsing context.
+ void SetWindowProxy(JS::Handle<JSObject*> aWindowProxy) {
+ mWindowProxy = aWindowProxy;
+ }
+
+ Nullable<WindowProxyHolder> GetWindow();
+
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(BrowsingContext)
+ NS_DECL_NSILOADCONTEXT
+
+ // Window APIs that are cross-origin-accessible (from the HTML spec).
+ WindowProxyHolder Window();
+ BrowsingContext* GetBrowsingContext() { return this; };
+ BrowsingContext* Self() { return this; }
+ void Location(JSContext* aCx, JS::MutableHandle<JSObject*> aLocation,
+ ErrorResult& aError);
+ void Close(CallerType aCallerType, ErrorResult& aError);
+ bool GetClosed(ErrorResult&) { return GetClosed(); }
+ void Focus(CallerType aCallerType, ErrorResult& aError);
+ void Blur(CallerType aCallerType, ErrorResult& aError);
+ WindowProxyHolder GetFrames(ErrorResult& aError);
+ int32_t Length() const { return Children().Length(); }
+ Nullable<WindowProxyHolder> GetTop(ErrorResult& aError);
+ void GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aOpener,
+ ErrorResult& aError) const;
+ Nullable<WindowProxyHolder> GetParent(ErrorResult& aError);
+ void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
+ const nsAString& aTargetOrigin,
+ const Sequence<JSObject*>& aTransfer,
+ nsIPrincipal& aSubjectPrincipal, ErrorResult& aError);
+ void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
+ const WindowPostMessageOptions& aOptions,
+ nsIPrincipal& aSubjectPrincipal, ErrorResult& aError);
+
+ void GetCustomUserAgent(nsAString& aUserAgent) {
+ aUserAgent = Top()->GetUserAgentOverride();
+ }
+ nsresult SetCustomUserAgent(const nsAString& aUserAgent);
+ void SetCustomUserAgent(const nsAString& aUserAgent, ErrorResult& aRv);
+
+ void GetCustomPlatform(nsAString& aPlatform) {
+ aPlatform = Top()->GetPlatformOverride();
+ }
+ void SetCustomPlatform(const nsAString& aPlatform, ErrorResult& aRv);
+
+ JSObject* WrapObject(JSContext* aCx);
+
+ static JSObject* ReadStructuredClone(JSContext* aCx,
+ JSStructuredCloneReader* aReader,
+ StructuredCloneHolder* aHolder);
+ bool WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter,
+ StructuredCloneHolder* aHolder);
+
+ void StartDelayedAutoplayMediaComponents();
+
+ [[nodiscard]] nsresult ResetGVAutoplayRequestStatus();
+
+ /**
+ * Information required to initialize a BrowsingContext in another process.
+ * This object may be serialized over IPC.
+ */
+ struct IPCInitializer {
+ uint64_t mId = 0;
+
+ // IDs are used for Parent and Opener to allow for this object to be
+ // deserialized before other BrowsingContext in the BrowsingContextGroup
+ // have been initialized.
+ uint64_t mParentId = 0;
+ already_AddRefed<WindowContext> GetParent();
+ already_AddRefed<BrowsingContext> GetOpener();
+
+ uint64_t GetOpenerId() const { return mFields.Get<IDX_OpenerId>(); }
+
+ bool mWindowless = false;
+ bool mUseRemoteTabs = false;
+ bool mUseRemoteSubframes = false;
+ bool mCreatedDynamically = false;
+ int32_t mChildOffset = 0;
+ int32_t mSessionHistoryIndex = -1;
+ int32_t mSessionHistoryCount = 0;
+ OriginAttributes mOriginAttributes;
+ uint64_t mRequestContextId = 0;
+
+ FieldValues mFields;
+ };
+
+ // Create an IPCInitializer object for this BrowsingContext.
+ IPCInitializer GetIPCInitializer();
+
+ // Create a BrowsingContext object from over IPC.
+ static mozilla::ipc::IPCResult CreateFromIPC(IPCInitializer&& aInitializer,
+ BrowsingContextGroup* aGroup,
+ ContentParent* aOriginProcess);
+
+ bool IsSandboxedFrom(BrowsingContext* aTarget);
+
+ // The runnable will be called once there is idle time, or the top level
+ // page has been loaded or if a timeout has fired.
+ // Must be called only on the top level BrowsingContext.
+ void AddDeprioritizedLoadRunner(nsIRunnable* aRunner);
+
+ RefPtr<SessionStorageManager> GetSessionStorageManager();
+
+ // Set PendingInitialization on this BrowsingContext before the context has
+ // been attached.
+ void InitPendingInitialization(bool aPendingInitialization) {
+ MOZ_ASSERT(!EverAttached());
+ mFields.SetWithoutSyncing<IDX_PendingInitialization>(
+ aPendingInitialization);
+ }
+
+ bool CreatedDynamically() const { return mCreatedDynamically; }
+
+ // Returns true if this browsing context, or any ancestor to this browsing
+ // context was created dynamically. See also `CreatedDynamically`.
+ bool IsDynamic() const;
+
+ int32_t ChildOffset() const { return mChildOffset; }
+
+ bool GetOffsetPath(nsTArray<uint32_t>& aPath) const;
+
+ const OriginAttributes& OriginAttributesRef() { return mOriginAttributes; }
+ nsresult SetOriginAttributes(const OriginAttributes& aAttrs);
+
+ void GetHistoryID(JSContext* aCx, JS::MutableHandle<JS::Value> aVal,
+ ErrorResult& aError);
+
+ // This should only be called on the top browsing context.
+ void InitSessionHistory();
+
+ // This will only ever return a non-null value if called on the top browsing
+ // context.
+ ChildSHistory* GetChildSessionHistory();
+
+ bool CrossOriginIsolated();
+
+ // Check if it is allowed to open a popup from the current browsing
+ // context or any of its ancestors.
+ bool IsPopupAllowed();
+
+ // aCurrentURI is only required to be non-null if the load type contains the
+ // nsIWebNavigation::LOAD_FLAGS_IS_REFRESH flag and aInfo is for a refresh to
+ // the current URI.
+ void SessionHistoryCommit(const LoadingSessionHistoryInfo& aInfo,
+ uint32_t aLoadType, nsIURI* aCurrentURI,
+ SessionHistoryInfo* aPreviousActiveEntry,
+ bool aPersist, bool aCloneEntryChildren,
+ bool aChannelExpired, uint32_t aCacheKey);
+
+ // Set a new active entry on this browsing context. This is used for
+ // implementing history.pushState/replaceState and same document navigations.
+ // The new active entry will be linked to the current active entry through
+ // its shared state.
+ // aPreviousScrollPos is the scroll position that needs to be saved on the
+ // previous active entry.
+ // aUpdatedCacheKey is the cache key to set on the new active entry. If
+ // aUpdatedCacheKey is 0 then it will be ignored.
+ void SetActiveSessionHistoryEntry(const Maybe<nsPoint>& aPreviousScrollPos,
+ SessionHistoryInfo* aInfo,
+ uint32_t aLoadType,
+ uint32_t aUpdatedCacheKey,
+ bool aUpdateLength = true);
+
+ // Replace the active entry for this browsing context. This is used for
+ // implementing history.replaceState and same document navigations.
+ void ReplaceActiveSessionHistoryEntry(SessionHistoryInfo* aInfo);
+
+ // Removes dynamic child entries of the active entry.
+ void RemoveDynEntriesFromActiveSessionHistoryEntry();
+
+ // Removes entries corresponding to this BrowsingContext from session history.
+ void RemoveFromSessionHistory(const nsID& aChangeID);
+
+ void SetTriggeringAndInheritPrincipals(nsIPrincipal* aTriggeringPrincipal,
+ nsIPrincipal* aPrincipalToInherit,
+ uint64_t aLoadIdentifier);
+
+ // Return mTriggeringPrincipal and mPrincipalToInherit if the load id
+ // saved with the principal matches the current load identifier of this BC.
+ std::tuple<nsCOMPtr<nsIPrincipal>, nsCOMPtr<nsIPrincipal>>
+ GetTriggeringAndInheritPrincipalsForCurrentLoad();
+
+ void HistoryGo(int32_t aOffset, uint64_t aHistoryEpoch,
+ bool aRequireUserInteraction, bool aUserActivation,
+ std::function<void(Maybe<int32_t>&&)>&& aResolver);
+
+ bool ShouldUpdateSessionHistory(uint32_t aLoadType);
+
+ // Checks if we reached the rate limit for calls to Location and History API.
+ // The rate limit is controlled by the
+ // "dom.navigation.locationChangeRateLimit" prefs.
+ // Rate limit applies per BrowsingContext.
+ // Returns NS_OK if we are below the rate limit and increments the counter.
+ // Returns NS_ERROR_DOM_SECURITY_ERR if limit is reached.
+ nsresult CheckLocationChangeRateLimit(CallerType aCallerType);
+
+ void ResetLocationChangeRateLimit();
+
+ mozilla::dom::DisplayMode DisplayMode() { return Top()->GetDisplayMode(); }
+
+ // Returns canFocus, isActive
+ std::tuple<bool, bool> CanFocusCheck(CallerType aCallerType);
+
+ bool CanBlurCheck(CallerType aCallerType);
+
+ PopupBlocker::PopupControlState RevisePopupAbuseLevel(
+ PopupBlocker::PopupControlState aControl);
+
+ void IncrementHistoryEntryCountForBrowsingContext();
+
+ bool ServiceWorkersTestingEnabled() const {
+ return GetServiceWorkersTestingEnabled();
+ }
+
+ void GetMediumOverride(nsAString& aOverride) const {
+ aOverride = GetMediumOverride();
+ }
+
+ dom::PrefersColorSchemeOverride PrefersColorSchemeOverride() const {
+ return GetPrefersColorSchemeOverride();
+ }
+
+ bool IsInBFCache() const;
+
+ bool AllowJavascript() const { return GetAllowJavascript(); }
+ bool CanExecuteScripts() const { return mCanExecuteScripts; }
+
+ uint32_t DefaultLoadFlags() const { return GetDefaultLoadFlags(); }
+
+ // When request for page awake, it would increase a count that is used to
+ // prevent whole browsing context tree from being suspended. The request can
+ // be called multiple times. When calling the revoke, it would decrease the
+ // count and once the count reaches to zero, the browsing context tree could
+ // be suspended when the tree is inactive.
+ void RequestForPageAwake();
+ void RevokeForPageAwake();
+
+ void AddDiscardListener(std::function<void(uint64_t)>&& aListener);
+
+ bool IsAppTab() { return GetIsAppTab(); }
+ bool HasSiblings() { return GetHasSiblings(); }
+
+ bool IsUnderHiddenEmbedderElement() const {
+ return GetIsUnderHiddenEmbedderElement();
+ }
+
+ protected:
+ virtual ~BrowsingContext();
+ BrowsingContext(WindowContext* aParentWindow, BrowsingContextGroup* aGroup,
+ uint64_t aBrowsingContextId, Type aType, FieldValues&& aInit);
+
+ void SetChildSHistory(ChildSHistory* aChildSHistory);
+ already_AddRefed<ChildSHistory> ForgetChildSHistory() {
+ // FIXME Do we need to unset mHasSessionHistory?
+ return mChildSessionHistory.forget();
+ }
+
+ static bool ShouldAddEntryForRefresh(nsIURI* aCurrentURI,
+ const SessionHistoryInfo& aInfo);
+ static bool ShouldAddEntryForRefresh(nsIURI* aCurrentURI, nsIURI* aNewURI,
+ bool aHasPostData);
+
+ private:
+ mozilla::ipc::IPCResult Attach(bool aFromIPC, ContentParent* aOriginProcess);
+
+ // Recomputes whether we can execute scripts in this BrowsingContext based on
+ // the value of AllowJavascript() and whether scripts are allowed in the
+ // parent WindowContext. Called whenever the AllowJavascript() flag or the
+ // parent WC changes.
+ void RecomputeCanExecuteScripts();
+
+ // Is it early enough in the BrowsingContext's lifecycle that it is still
+ // OK to set OriginAttributes?
+ bool CanSetOriginAttributes();
+
+ void AssertOriginAttributesMatchPrivateBrowsing();
+
+ // Assert that the BrowsingContext's LoadContext flags appear coherent
+ // relative to related BrowsingContexts.
+ void AssertCoherentLoadContext();
+
+ friend class ::nsOuterWindowProxy;
+ friend class ::nsGlobalWindowOuter;
+ friend class WindowContext;
+
+ // Update the window proxy object that corresponds to this browsing context.
+ // This should be called from the window proxy object's objectMoved hook, if
+ // the object mWindowProxy points to was moved by the JS GC.
+ void UpdateWindowProxy(JSObject* obj, JSObject* old) {
+ if (mWindowProxy) {
+ MOZ_ASSERT(mWindowProxy == old);
+ mWindowProxy = obj;
+ }
+ }
+ // Clear the window proxy object that corresponds to this browsing context.
+ // This should be called if the window proxy object is finalized, or it can't
+ // reach its browsing context anymore.
+ void ClearWindowProxy() { mWindowProxy = nullptr; }
+
+ friend class Location;
+ friend class RemoteLocationProxy;
+ /**
+ * LocationProxy is the class for the native object stored as a private in a
+ * RemoteLocationProxy proxy representing a Location object in a different
+ * process. It forwards all operations to its BrowsingContext and aggregates
+ * its refcount to that BrowsingContext.
+ */
+ class LocationProxy final : public LocationBase {
+ public:
+ MozExternalRefCountType AddRef() { return GetBrowsingContext()->AddRef(); }
+ MozExternalRefCountType Release() {
+ return GetBrowsingContext()->Release();
+ }
+
+ protected:
+ friend class RemoteLocationProxy;
+ BrowsingContext* GetBrowsingContext() override {
+ return reinterpret_cast<BrowsingContext*>(
+ uintptr_t(this) - offsetof(BrowsingContext, mLocation));
+ }
+
+ already_AddRefed<nsIDocShell> GetDocShell() override { return nullptr; }
+ };
+
+ // Send a given `BaseTransaction` object to the correct remote.
+ void SendCommitTransaction(ContentParent* aParent,
+ const BaseTransaction& aTxn, uint64_t aEpoch);
+ void SendCommitTransaction(ContentChild* aChild, const BaseTransaction& aTxn,
+ uint64_t aEpoch);
+
+ bool CanSet(FieldIndex<IDX_SessionStoreEpoch>, uint32_t aEpoch,
+ ContentParent* aSource) {
+ return IsTop() && !aSource;
+ }
+
+ void DidSet(FieldIndex<IDX_SessionStoreEpoch>, uint32_t aOldValue);
+
+ using CanSetResult = syncedcontext::CanSetResult;
+
+ // Ensure that opener is in the same BrowsingContextGroup.
+ bool CanSet(FieldIndex<IDX_OpenerId>, const uint64_t& aValue,
+ ContentParent* aSource) {
+ if (aValue != 0) {
+ RefPtr<BrowsingContext> opener = Get(aValue);
+ return opener && opener->Group() == Group();
+ }
+ return true;
+ }
+
+ bool CanSet(FieldIndex<IDX_OpenerPolicy>,
+ nsILoadInfo::CrossOriginOpenerPolicy, ContentParent*);
+
+ bool CanSet(FieldIndex<IDX_ServiceWorkersTestingEnabled>, bool,
+ ContentParent*) {
+ return IsTop();
+ }
+
+ bool CanSet(FieldIndex<IDX_MediumOverride>, const nsString&, ContentParent*) {
+ return IsTop();
+ }
+
+ bool CanSet(FieldIndex<IDX_EmbedderColorSchemes>, const EmbedderColorSchemes&,
+ ContentParent* aSource) {
+ return CheckOnlyEmbedderCanSet(aSource);
+ }
+
+ bool CanSet(FieldIndex<IDX_PrefersColorSchemeOverride>,
+ dom::PrefersColorSchemeOverride, ContentParent*) {
+ return IsTop();
+ }
+
+ void DidSet(FieldIndex<IDX_InRDMPane>, bool aOldValue);
+
+ void DidSet(FieldIndex<IDX_EmbedderColorSchemes>,
+ EmbedderColorSchemes&& aOldValue);
+
+ void DidSet(FieldIndex<IDX_PrefersColorSchemeOverride>,
+ dom::PrefersColorSchemeOverride aOldValue);
+
+ template <typename Callback>
+ void WalkPresContexts(Callback&&);
+ void PresContextAffectingFieldChanged();
+
+ void DidSet(FieldIndex<IDX_MediumOverride>, nsString&& aOldValue);
+
+ bool CanSet(FieldIndex<IDX_SuspendMediaWhenInactive>, bool, ContentParent*) {
+ return IsTop();
+ }
+
+ bool CanSet(FieldIndex<IDX_TouchEventsOverrideInternal>,
+ dom::TouchEventsOverride aTouchEventsOverride,
+ ContentParent* aSource);
+ void DidSet(FieldIndex<IDX_TouchEventsOverrideInternal>,
+ dom::TouchEventsOverride&& aOldValue);
+
+ bool CanSet(FieldIndex<IDX_DisplayMode>, const enum DisplayMode& aDisplayMode,
+ ContentParent* aSource) {
+ return IsTop();
+ }
+
+ void DidSet(FieldIndex<IDX_DisplayMode>, enum DisplayMode aOldValue);
+
+ void DidSet(FieldIndex<IDX_ExplicitActive>, ExplicitActiveStatus aOldValue);
+
+ bool CanSet(FieldIndex<IDX_IsActiveBrowserWindowInternal>, const bool& aValue,
+ ContentParent* aSource);
+ void DidSet(FieldIndex<IDX_IsActiveBrowserWindowInternal>, bool aOldValue);
+
+ // Ensure that we only set the flag on the top level browsingContext.
+ // And then, we do a pre-order walk in the tree to refresh the
+ // volume of all media elements.
+ void DidSet(FieldIndex<IDX_Muted>);
+
+ bool CanSet(FieldIndex<IDX_IsAppTab>, const bool& aValue,
+ ContentParent* aSource);
+
+ bool CanSet(FieldIndex<IDX_HasSiblings>, const bool& aValue,
+ ContentParent* aSource);
+
+ bool CanSet(FieldIndex<IDX_ShouldDelayMediaFromStart>, const bool& aValue,
+ ContentParent* aSource);
+ void DidSet(FieldIndex<IDX_ShouldDelayMediaFromStart>, bool aOldValue);
+
+ bool CanSet(FieldIndex<IDX_OverrideDPPX>, const float& aValue,
+ ContentParent* aSource);
+ void DidSet(FieldIndex<IDX_OverrideDPPX>, float aOldValue);
+
+ bool CanSet(FieldIndex<IDX_EmbedderInnerWindowId>, const uint64_t& aValue,
+ ContentParent* aSource);
+
+ CanSetResult CanSet(FieldIndex<IDX_CurrentInnerWindowId>,
+ const uint64_t& aValue, ContentParent* aSource);
+
+ void DidSet(FieldIndex<IDX_CurrentInnerWindowId>);
+
+ bool CanSet(FieldIndex<IDX_ParentInitiatedNavigationEpoch>,
+ const uint64_t& aValue, ContentParent* aSource);
+
+ bool CanSet(FieldIndex<IDX_IsPopupSpam>, const bool& aValue,
+ ContentParent* aSource);
+
+ void DidSet(FieldIndex<IDX_IsPopupSpam>);
+
+ void DidSet(FieldIndex<IDX_GVAudibleAutoplayRequestStatus>);
+ void DidSet(FieldIndex<IDX_GVInaudibleAutoplayRequestStatus>);
+
+ void DidSet(FieldIndex<IDX_Loading>);
+
+ void DidSet(FieldIndex<IDX_AncestorLoading>);
+
+ void DidSet(FieldIndex<IDX_PlatformOverride>);
+ CanSetResult CanSet(FieldIndex<IDX_PlatformOverride>,
+ const nsString& aPlatformOverride,
+ ContentParent* aSource);
+
+ void DidSet(FieldIndex<IDX_UserAgentOverride>);
+ CanSetResult CanSet(FieldIndex<IDX_UserAgentOverride>,
+ const nsString& aUserAgent, ContentParent* aSource);
+ bool CanSet(FieldIndex<IDX_OrientationLock>,
+ const mozilla::hal::ScreenOrientation& aOrientationLock,
+ ContentParent* aSource);
+
+ bool CanSet(FieldIndex<IDX_EmbedderElementType>,
+ const Maybe<nsString>& aInitiatorType, ContentParent* aSource);
+
+ bool CanSet(FieldIndex<IDX_MessageManagerGroup>,
+ const nsString& aMessageManagerGroup, ContentParent* aSource);
+
+ CanSetResult CanSet(FieldIndex<IDX_AllowContentRetargeting>,
+ const bool& aAllowContentRetargeting,
+ ContentParent* aSource);
+ CanSetResult CanSet(FieldIndex<IDX_AllowContentRetargetingOnChildren>,
+ const bool& aAllowContentRetargetingOnChildren,
+ ContentParent* aSource);
+ CanSetResult CanSet(FieldIndex<IDX_AllowPlugins>, const bool& aAllowPlugins,
+ ContentParent* aSource);
+ bool CanSet(FieldIndex<IDX_FullscreenAllowedByOwner>, const bool&,
+ ContentParent*);
+ bool CanSet(FieldIndex<IDX_WatchedByDevToolsInternal>,
+ const bool& aWatchedByDevToolsInternal, ContentParent* aSource);
+
+ CanSetResult CanSet(FieldIndex<IDX_DefaultLoadFlags>,
+ const uint32_t& aDefaultLoadFlags,
+ ContentParent* aSource);
+ void DidSet(FieldIndex<IDX_DefaultLoadFlags>);
+
+ bool CanSet(FieldIndex<IDX_UseGlobalHistory>, const bool& aUseGlobalHistory,
+ ContentParent* aSource);
+
+ bool CanSet(FieldIndex<IDX_TargetTopLevelLinkClicksToBlankInternal>,
+ const bool& aTargetTopLevelLinkClicksToBlankInternal,
+ ContentParent* aSource);
+
+ void DidSet(FieldIndex<IDX_HasSessionHistory>, bool aOldValue);
+
+ bool CanSet(FieldIndex<IDX_BrowserId>, const uint32_t& aValue,
+ ContentParent* aSource);
+
+ bool CanSet(FieldIndex<IDX_UseErrorPages>, const bool& aUseErrorPages,
+ ContentParent* aSource);
+
+ bool CanSet(FieldIndex<IDX_PendingInitialization>, bool aNewValue,
+ ContentParent* aSource);
+
+ bool CanSet(FieldIndex<IDX_PageAwakeRequestCount>, uint32_t aNewValue,
+ ContentParent* aSource);
+ void DidSet(FieldIndex<IDX_PageAwakeRequestCount>, uint32_t aOldValue);
+
+ CanSetResult CanSet(FieldIndex<IDX_AllowJavascript>, bool aValue,
+ ContentParent* aSource);
+ void DidSet(FieldIndex<IDX_AllowJavascript>, bool aOldValue);
+
+ bool CanSet(FieldIndex<IDX_ForceDesktopViewport>, bool aValue,
+ ContentParent* aSource) {
+ return IsTop() && XRE_IsParentProcess();
+ }
+
+ // TODO(emilio): Maybe handle the flag being set dynamically without
+ // navigating? The previous code didn't do it tho, and a reload is probably
+ // worth it regardless.
+ // void DidSet(FieldIndex<IDX_ForceDesktopViewport>, bool aOldValue);
+
+ bool CanSet(FieldIndex<IDX_HasRestoreData>, bool aNewValue,
+ ContentParent* aSource);
+
+ bool CanSet(FieldIndex<IDX_IsUnderHiddenEmbedderElement>,
+ const bool& aIsUnderHiddenEmbedderElement,
+ ContentParent* aSource);
+
+ bool CanSet(FieldIndex<IDX_EmbeddedInContentDocument>, bool,
+ ContentParent* aSource) {
+ return CheckOnlyEmbedderCanSet(aSource);
+ }
+
+ template <size_t I, typename T>
+ bool CanSet(FieldIndex<I>, const T&, ContentParent*) {
+ return true;
+ }
+
+ // Overload `DidSet` to get notifications for a particular field being set.
+ //
+ // You can also overload the variant that gets the old value if you need it.
+ template <size_t I>
+ void DidSet(FieldIndex<I>) {}
+ template <size_t I, typename T>
+ void DidSet(FieldIndex<I>, T&& aOldValue) {}
+
+ void DidSet(FieldIndex<IDX_FullZoom>, float aOldValue);
+ void DidSet(FieldIndex<IDX_TextZoom>, float aOldValue);
+ void DidSet(FieldIndex<IDX_AuthorStyleDisabledDefault>);
+
+ bool CanSet(FieldIndex<IDX_IsInBFCache>, bool, ContentParent* aSource);
+ void DidSet(FieldIndex<IDX_IsInBFCache>);
+
+ void DidSet(FieldIndex<IDX_SyntheticDocumentContainer>);
+
+ void DidSet(FieldIndex<IDX_IsUnderHiddenEmbedderElement>, bool aOldValue);
+
+ // Allow if the process attemping to set field is the same as the owning
+ // process. Deprecated. New code that might use this should generally be moved
+ // to WindowContext or be settable only by the parent process.
+ CanSetResult LegacyRevertIfNotOwningOrParentProcess(ContentParent* aSource);
+
+ // True if the process attempting to set field is the same as the embedder's
+ // process.
+ bool CheckOnlyEmbedderCanSet(ContentParent* aSource);
+
+ void CreateChildSHistory();
+
+ using PrincipalWithLoadIdentifierTuple =
+ std::tuple<nsCOMPtr<nsIPrincipal>, uint64_t>;
+
+ nsIPrincipal* GetSavedPrincipal(
+ Maybe<PrincipalWithLoadIdentifierTuple> aPrincipalTuple);
+
+ // Type of BrowsingContent
+ const Type mType;
+
+ // Unique id identifying BrowsingContext
+ const uint64_t mBrowsingContextId;
+
+ RefPtr<BrowsingContextGroup> mGroup;
+ RefPtr<WindowContext> mParentWindow;
+ nsCOMPtr<nsIDocShell> mDocShell;
+
+ RefPtr<Element> mEmbedderElement;
+
+ nsTArray<RefPtr<WindowContext>> mWindowContexts;
+ RefPtr<WindowContext> mCurrentWindowContext;
+
+ // This is not a strong reference, but using a JS::Heap for that should be
+ // fine. The JSObject stored in here should be a proxy with a
+ // nsOuterWindowProxy handler, which will update the pointer from its
+ // objectMoved hook and clear it from its finalize hook.
+ JS::Heap<JSObject*> mWindowProxy;
+ LocationProxy mLocation;
+
+ // OriginAttributes for this BrowsingContext. May not be changed after this
+ // BrowsingContext is attached.
+ OriginAttributes mOriginAttributes;
+
+ // The network request context id, representing the nsIRequestContext
+ // associated with this BrowsingContext, and LoadGroups created for it.
+ uint64_t mRequestContextId = 0;
+
+ // Determines if private browsing should be used. May not be changed after
+ // this BrowsingContext is attached. This field matches mOriginAttributes in
+ // content Browsing Contexts. Currently treated as a binary value: 1 - in
+ // private mode, 0 - not private mode.
+ uint32_t mPrivateBrowsingId;
+
+ // True if Attach() has been called on this BrowsingContext already.
+ bool mEverAttached : 1;
+
+ // Is the most recent Document in this BrowsingContext loaded within this
+ // process? This may be true with a null mDocShell after the Window has been
+ // closed.
+ bool mIsInProcess : 1;
+
+ // Has this browsing context been discarded? BrowsingContexts should
+ // only be discarded once.
+ bool mIsDiscarded : 1;
+
+ // True if this BrowsingContext has no associated visible window, and is owned
+ // by whichever process created it, even if top-level.
+ bool mWindowless : 1;
+
+ // This is true if the BrowsingContext was out of process, but is now in
+ // process, and might have remote window proxies that need to be cleaned up.
+ bool mDanglingRemoteOuterProxies : 1;
+
+ // True if this BrowsingContext has been embedded in a element in this
+ // process.
+ bool mEmbeddedByThisProcess : 1;
+
+ // Determines if remote (out-of-process) tabs should be used. May not be
+ // changed after this BrowsingContext is attached.
+ bool mUseRemoteTabs : 1;
+
+ // Determines if out-of-process iframes should be used. May not be changed
+ // after this BrowsingContext is attached.
+ bool mUseRemoteSubframes : 1;
+
+ // True if this BrowsingContext is for a frame that was added dynamically.
+ bool mCreatedDynamically : 1;
+
+ // Set to true if the browsing context is in the bfcache and pagehide has been
+ // dispatched. When coming out from the bfcache, the value is set to false
+ // before dispatching pageshow.
+ bool mIsInBFCache : 1;
+
+ // Determines if we can execute scripts in this BrowsingContext. True if
+ // AllowJavascript() is true and script execution is allowed in the parent
+ // WindowContext.
+ bool mCanExecuteScripts : 1;
+
+ // The original offset of this context in its container. This property is -1
+ // if this BrowsingContext is for a frame that was added dynamically.
+ int32_t mChildOffset;
+
+ // The start time of user gesture, this is only available if the browsing
+ // context is in process.
+ TimeStamp mUserGestureStart;
+
+ // Triggering principal and principal to inherit need to point to original
+ // principal instances if the document is loaded in the same process as the
+ // process that initiated the load. When the load starts we save the
+ // principals along with the current load id.
+ // These principals correspond to the most recent load that took place within
+ // the process of this browsing context.
+ Maybe<PrincipalWithLoadIdentifierTuple> mTriggeringPrincipal;
+ Maybe<PrincipalWithLoadIdentifierTuple> mPrincipalToInherit;
+
+ class DeprioritizedLoadRunner
+ : public mozilla::Runnable,
+ public mozilla::LinkedListElement<DeprioritizedLoadRunner> {
+ public:
+ explicit DeprioritizedLoadRunner(nsIRunnable* aInner)
+ : Runnable("DeprioritizedLoadRunner"), mInner(aInner) {}
+
+ NS_IMETHOD Run() override {
+ if (mInner) {
+ RefPtr<nsIRunnable> inner = std::move(mInner);
+ inner->Run();
+ }
+
+ return NS_OK;
+ }
+
+ private:
+ RefPtr<nsIRunnable> mInner;
+ };
+
+ mozilla::LinkedList<DeprioritizedLoadRunner> mDeprioritizedLoadRunner;
+
+ RefPtr<SessionStorageManager> mSessionStorageManager;
+ RefPtr<ChildSHistory> mChildSessionHistory;
+
+ nsTArray<std::function<void(uint64_t)>> mDiscardListeners;
+
+ // Counter and time span for rate limiting Location and History API calls.
+ // Used by CheckLocationChangeRateLimit. Do not apply cross-process.
+ uint32_t mLocationChangeRateLimitCount;
+ mozilla::TimeStamp mLocationChangeRateLimitSpanStart;
+};
+
+/**
+ * Gets a WindowProxy object for a BrowsingContext that lives in a different
+ * process (creating the object if it doesn't already exist). The WindowProxy
+ * object will be in the compartment that aCx is currently in. This should only
+ * be called if aContext doesn't hold a docshell, otherwise the BrowsingContext
+ * lives in this process, and a same-process WindowProxy should be used (see
+ * nsGlobalWindowOuter). This should only be called by bindings code, ToJSValue
+ * is the right API to get a WindowProxy for a BrowsingContext.
+ *
+ * If aTransplantTo is non-null, then the WindowProxy object will eventually be
+ * transplanted onto it. Therefore it should be used as the value in the remote
+ * proxy map.
+ */
+extern bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
+ JS::Handle<JSObject*> aTransplantTo,
+ JS::MutableHandle<JSObject*> aRetVal);
+
+using BrowsingContextTransaction = BrowsingContext::BaseTransaction;
+using BrowsingContextInitializer = BrowsingContext::IPCInitializer;
+using MaybeDiscardedBrowsingContext = MaybeDiscarded<BrowsingContext>;
+
+// Specialize the transaction object for every translation unit it's used in.
+extern template class syncedcontext::Transaction<BrowsingContext>;
+
+} // namespace dom
+
+// Allow sending BrowsingContext objects over IPC.
+namespace ipc {
+template <>
+struct IPDLParamTraits<dom::MaybeDiscarded<dom::BrowsingContext>> {
+ static void Write(IPC::MessageWriter* aWriter, IProtocol* aActor,
+ const dom::MaybeDiscarded<dom::BrowsingContext>& aParam);
+ static bool Read(IPC::MessageReader* aReader, IProtocol* aActor,
+ dom::MaybeDiscarded<dom::BrowsingContext>* aResult);
+};
+
+template <>
+struct IPDLParamTraits<dom::BrowsingContext::IPCInitializer> {
+ static void Write(IPC::MessageWriter* aWriter, IProtocol* aActor,
+ const dom::BrowsingContext::IPCInitializer& aInitializer);
+
+ static bool Read(IPC::MessageReader* aReader, IProtocol* aActor,
+ dom::BrowsingContext::IPCInitializer* aInitializer);
+};
+} // namespace ipc
+} // namespace mozilla
+
+#endif // !defined(mozilla_dom_BrowsingContext_h)