summaryrefslogtreecommitdiffstats
path: root/docshell/base/WindowContext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'docshell/base/WindowContext.cpp')
-rw-r--r--docshell/base/WindowContext.cpp656
1 files changed, 656 insertions, 0 deletions
diff --git a/docshell/base/WindowContext.cpp b/docshell/base/WindowContext.cpp
new file mode 100644
index 0000000000..10df96e1df
--- /dev/null
+++ b/docshell/base/WindowContext.cpp
@@ -0,0 +1,656 @@
+/* -*- 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/. */
+
+#include "mozilla/dom/WindowContext.h"
+#include "mozilla/dom/WindowGlobalActorsBinding.h"
+#include "mozilla/dom/WindowGlobalChild.h"
+#include "mozilla/dom/WindowGlobalParent.h"
+#include "mozilla/dom/SyncedContextInlines.h"
+#include "mozilla/dom/BrowsingContext.h"
+#include "mozilla/dom/Document.h"
+#include "mozilla/dom/UserActivationIPCUtils.h"
+#include "mozilla/PermissionDelegateIPCUtils.h"
+#include "mozilla/StaticPrefs_dom.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "nsGlobalWindowInner.h"
+#include "nsIScriptError.h"
+#include "nsIXULRuntime.h"
+#include "nsRefPtrHashtable.h"
+#include "nsContentUtils.h"
+
+namespace mozilla {
+namespace dom {
+
+// Explicit specialization of the `Transaction` type. Required by the `extern
+// template class` declaration in the header.
+template class syncedcontext::Transaction<WindowContext>;
+
+static LazyLogModule gWindowContextLog("WindowContext");
+static LazyLogModule gWindowContextSyncLog("WindowContextSync");
+
+extern mozilla::LazyLogModule gUserInteractionPRLog;
+
+#define USER_ACTIVATION_LOG(msg, ...) \
+ MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
+
+using WindowContextByIdMap = nsTHashMap<nsUint64HashKey, WindowContext*>;
+static StaticAutoPtr<WindowContextByIdMap> gWindowContexts;
+
+/* static */
+LogModule* WindowContext::GetLog() { return gWindowContextLog; }
+
+/* static */
+LogModule* WindowContext::GetSyncLog() { return gWindowContextSyncLog; }
+
+/* static */
+already_AddRefed<WindowContext> WindowContext::GetById(
+ uint64_t aInnerWindowId) {
+ if (!gWindowContexts) {
+ return nullptr;
+ }
+ return do_AddRef(gWindowContexts->Get(aInnerWindowId));
+}
+
+BrowsingContextGroup* WindowContext::Group() const {
+ return mBrowsingContext->Group();
+}
+
+WindowGlobalParent* WindowContext::Canonical() {
+ MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
+ return static_cast<WindowGlobalParent*>(this);
+}
+
+bool WindowContext::IsCurrent() const {
+ return mBrowsingContext->mCurrentWindowContext == this;
+}
+
+bool WindowContext::IsInBFCache() {
+ if (mozilla::SessionHistoryInParent()) {
+ return mBrowsingContext->IsInBFCache();
+ }
+ return TopWindowContext()->GetWindowStateSaved();
+}
+
+nsGlobalWindowInner* WindowContext::GetInnerWindow() const {
+ return mWindowGlobalChild ? mWindowGlobalChild->GetWindowGlobal() : nullptr;
+}
+
+Document* WindowContext::GetDocument() const {
+ nsGlobalWindowInner* innerWindow = GetInnerWindow();
+ return innerWindow ? innerWindow->GetDocument() : nullptr;
+}
+
+Document* WindowContext::GetExtantDoc() const {
+ nsGlobalWindowInner* innerWindow = GetInnerWindow();
+ return innerWindow ? innerWindow->GetExtantDoc() : nullptr;
+}
+
+WindowGlobalChild* WindowContext::GetWindowGlobalChild() const {
+ return mWindowGlobalChild;
+}
+
+WindowContext* WindowContext::GetParentWindowContext() {
+ return mBrowsingContext->GetParentWindowContext();
+}
+
+WindowContext* WindowContext::TopWindowContext() {
+ WindowContext* current = this;
+ while (current->GetParentWindowContext()) {
+ current = current->GetParentWindowContext();
+ }
+ return current;
+}
+
+bool WindowContext::IsTop() const { return mBrowsingContext->IsTop(); }
+
+bool WindowContext::SameOriginWithTop() const {
+ return mBrowsingContext->SameOriginWithTop();
+}
+
+nsIGlobalObject* WindowContext::GetParentObject() const {
+ return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
+}
+
+void WindowContext::AppendChildBrowsingContext(
+ BrowsingContext* aBrowsingContext) {
+ MOZ_DIAGNOSTIC_ASSERT(Group() == aBrowsingContext->Group(),
+ "Mismatched groups?");
+ MOZ_DIAGNOSTIC_ASSERT(!mChildren.Contains(aBrowsingContext));
+
+ mChildren.AppendElement(aBrowsingContext);
+ if (!nsContentUtils::ShouldHideObjectOrEmbedImageDocument() ||
+ !aBrowsingContext->IsEmbedderTypeObjectOrEmbed()) {
+ mNonSyntheticChildren.AppendElement(aBrowsingContext);
+ }
+
+ // If we're the current WindowContext in our BrowsingContext, make sure to
+ // clear any cached `children` value.
+ if (IsCurrent()) {
+ BrowsingContext_Binding::ClearCachedChildrenValue(mBrowsingContext);
+ }
+}
+
+void WindowContext::RemoveChildBrowsingContext(
+ BrowsingContext* aBrowsingContext) {
+ MOZ_DIAGNOSTIC_ASSERT(Group() == aBrowsingContext->Group(),
+ "Mismatched groups?");
+
+ mChildren.RemoveElement(aBrowsingContext);
+ mNonSyntheticChildren.RemoveElement(aBrowsingContext);
+
+ // If we're the current WindowContext in our BrowsingContext, make sure to
+ // clear any cached `children` value.
+ if (IsCurrent()) {
+ BrowsingContext_Binding::ClearCachedChildrenValue(mBrowsingContext);
+ }
+}
+
+void WindowContext::UpdateChildSynthetic(BrowsingContext* aBrowsingContext,
+ bool aIsSynthetic) {
+ MOZ_ASSERT(nsContentUtils::ShouldHideObjectOrEmbedImageDocument());
+ if (aIsSynthetic) {
+ mNonSyntheticChildren.RemoveElement(aBrowsingContext);
+ } else {
+ // The same BrowsingContext will be reused for error pages, so it can be in
+ // the list already.
+ if (!mNonSyntheticChildren.Contains(aBrowsingContext)) {
+ mNonSyntheticChildren.AppendElement(aBrowsingContext);
+ }
+ }
+}
+
+void WindowContext::SendCommitTransaction(ContentParent* aParent,
+ const BaseTransaction& aTxn,
+ uint64_t aEpoch) {
+ Unused << aParent->SendCommitWindowContextTransaction(this, aTxn, aEpoch);
+}
+
+void WindowContext::SendCommitTransaction(ContentChild* aChild,
+ const BaseTransaction& aTxn,
+ uint64_t aEpoch) {
+ aChild->SendCommitWindowContextTransaction(this, aTxn, aEpoch);
+}
+
+bool WindowContext::CheckOnlyOwningProcessCanSet(ContentParent* aSource) {
+ if (IsInProcess()) {
+ return true;
+ }
+
+ if (XRE_IsParentProcess() && aSource) {
+ return Canonical()->GetContentParent() == aSource;
+ }
+
+ return false;
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_IsSecure>, const bool& aIsSecure,
+ ContentParent* aSource) {
+ return CheckOnlyOwningProcessCanSet(aSource);
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_AllowMixedContent>,
+ const bool& aAllowMixedContent,
+ ContentParent* aSource) {
+ return CheckOnlyOwningProcessCanSet(aSource);
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_HasBeforeUnload>,
+ const bool& aHasBeforeUnload,
+ ContentParent* aSource) {
+ return CheckOnlyOwningProcessCanSet(aSource);
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_CookieBehavior>,
+ const Maybe<uint32_t>& aValue,
+ ContentParent* aSource) {
+ return CheckOnlyOwningProcessCanSet(aSource);
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_IsOnContentBlockingAllowList>,
+ const bool& aValue, ContentParent* aSource) {
+ return CheckOnlyOwningProcessCanSet(aSource);
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_IsThirdPartyWindow>,
+ const bool& IsThirdPartyWindow,
+ ContentParent* aSource) {
+ return CheckOnlyOwningProcessCanSet(aSource);
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_IsThirdPartyTrackingResourceWindow>,
+ const bool& aIsThirdPartyTrackingResourceWindow,
+ ContentParent* aSource) {
+ return CheckOnlyOwningProcessCanSet(aSource);
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_IsSecureContext>,
+ const bool& aIsSecureContext,
+ ContentParent* aSource) {
+ return CheckOnlyOwningProcessCanSet(aSource);
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_IsOriginalFrameSource>,
+ const bool& aIsOriginalFrameSource,
+ ContentParent* aSource) {
+ return CheckOnlyOwningProcessCanSet(aSource);
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_DocTreeHadMedia>, const bool& aValue,
+ ContentParent* aSource) {
+ return IsTop();
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_AutoplayPermission>,
+ const uint32_t& aValue, ContentParent* aSource) {
+ return CheckOnlyOwningProcessCanSet(aSource);
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_ShortcutsPermission>,
+ const uint32_t& aValue, ContentParent* aSource) {
+ return IsTop() && CheckOnlyOwningProcessCanSet(aSource);
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_ActiveMediaSessionContextId>,
+ const Maybe<uint64_t>& aValue,
+ ContentParent* aSource) {
+ return IsTop();
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_PopupPermission>, const uint32_t&,
+ ContentParent* aSource) {
+ return CheckOnlyOwningProcessCanSet(aSource);
+}
+
+bool WindowContext::CanSet(
+ FieldIndex<IDX_DelegatedPermissions>,
+ const PermissionDelegateHandler::DelegatedPermissionList& aValue,
+ ContentParent* aSource) {
+ return CheckOnlyOwningProcessCanSet(aSource);
+}
+
+bool WindowContext::CanSet(
+ FieldIndex<IDX_DelegatedExactHostMatchPermissions>,
+ const PermissionDelegateHandler::DelegatedPermissionList& aValue,
+ ContentParent* aSource) {
+ return CheckOnlyOwningProcessCanSet(aSource);
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_IsLocalIP>, const bool& aValue,
+ ContentParent* aSource) {
+ return CheckOnlyOwningProcessCanSet(aSource);
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_AllowJavascript>, bool aValue,
+ ContentParent* aSource) {
+ return (XRE_IsParentProcess() && !aSource) ||
+ CheckOnlyOwningProcessCanSet(aSource);
+}
+
+void WindowContext::DidSet(FieldIndex<IDX_AllowJavascript>, bool aOldValue) {
+ RecomputeCanExecuteScripts();
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_HasActivePeerConnections>, bool,
+ ContentParent*) {
+ return XRE_IsParentProcess() && IsTop();
+}
+
+void WindowContext::RecomputeCanExecuteScripts(bool aApplyChanges) {
+ const bool old = mCanExecuteScripts;
+ if (!AllowJavascript()) {
+ // Scripting has been explicitly disabled on our WindowContext.
+ mCanExecuteScripts = false;
+ } else {
+ // Otherwise, inherit.
+ mCanExecuteScripts = mBrowsingContext->CanExecuteScripts();
+ }
+
+ if (aApplyChanges && old != mCanExecuteScripts) {
+ // Inform our active DOM window.
+ if (nsGlobalWindowInner* window = GetInnerWindow()) {
+ // Only update scriptability if the window is current. Windows will have
+ // scriptability disabled when entering the bfcache and updated when
+ // coming out.
+ if (window->IsCurrentInnerWindow()) {
+ auto& scriptability =
+ xpc::Scriptability::Get(window->GetGlobalJSObject());
+ scriptability.SetWindowAllowsScript(mCanExecuteScripts);
+ }
+ }
+
+ for (const RefPtr<BrowsingContext>& child : Children()) {
+ child->RecomputeCanExecuteScripts();
+ }
+ }
+}
+
+void WindowContext::DidSet(FieldIndex<IDX_SHEntryHasUserInteraction>,
+ bool aOldValue) {
+ MOZ_ASSERT(
+ TopWindowContext() == this,
+ "SHEntryHasUserInteraction can only be set on the top window context");
+ // This field is set when the child notifies us of new user interaction, so we
+ // also set the currently active shentry in the parent as having interaction.
+ if (XRE_IsParentProcess() && mBrowsingContext) {
+ SessionHistoryEntry* activeEntry =
+ mBrowsingContext->Canonical()->GetActiveSessionHistoryEntry();
+ if (activeEntry && GetSHEntryHasUserInteraction()) {
+ activeEntry->SetHasUserInteraction(true);
+ }
+ }
+}
+
+void WindowContext::DidSet(FieldIndex<IDX_UserActivationState>) {
+ MOZ_ASSERT_IF(!IsInProcess(), mUserGestureStart.IsNull());
+ USER_ACTIVATION_LOG("Set user gesture activation %" PRIu8
+ " for %s browsing context 0x%08" PRIx64,
+ static_cast<uint8_t>(GetUserActivationState()),
+ XRE_IsParentProcess() ? "Parent" : "Child", Id());
+ if (IsInProcess()) {
+ USER_ACTIVATION_LOG(
+ "Set user gesture start time for %s browsing context 0x%08" PRIx64,
+ XRE_IsParentProcess() ? "Parent" : "Child", Id());
+ if (GetUserActivationState() == UserActivation::State::FullActivated) {
+ mUserGestureStart = TimeStamp::Now();
+ } else if (GetUserActivationState() == UserActivation::State::None) {
+ mUserGestureStart = TimeStamp();
+ }
+ }
+}
+
+void WindowContext::DidSet(FieldIndex<IDX_HasReportedShadowDOMUsage>,
+ bool aOldValue) {
+ if (!aOldValue && GetHasReportedShadowDOMUsage() && IsInProcess()) {
+ MOZ_ASSERT(TopWindowContext() == this);
+ if (mBrowsingContext) {
+ Document* topLevelDoc = mBrowsingContext->GetDocument();
+ if (topLevelDoc) {
+ nsAutoString uri;
+ Unused << topLevelDoc->GetDocumentURI(uri);
+ if (!uri.IsEmpty()) {
+ nsAutoString msg = u"Shadow DOM used in ["_ns + uri +
+ u"] or in some of its subdocuments."_ns;
+ nsContentUtils::ReportToConsoleNonLocalized(
+ msg, nsIScriptError::infoFlag, "DOM"_ns, topLevelDoc);
+ }
+ }
+ }
+ }
+}
+
+bool WindowContext::CanSet(FieldIndex<IDX_WindowStateSaved>, bool aValue,
+ ContentParent* aSource) {
+ return !mozilla::SessionHistoryInParent() && IsTop() &&
+ CheckOnlyOwningProcessCanSet(aSource);
+}
+
+void WindowContext::CreateFromIPC(IPCInitializer&& aInit) {
+ MOZ_RELEASE_ASSERT(XRE_IsContentProcess(),
+ "Should be a WindowGlobalParent in the parent");
+
+ RefPtr<BrowsingContext> bc = BrowsingContext::Get(aInit.mBrowsingContextId);
+ MOZ_RELEASE_ASSERT(bc);
+
+ if (bc->IsDiscarded()) {
+ // If we have already closed our browsing context, the
+ // WindowGlobalChild actor is bound to be destroyed soon and it's
+ // safe to ignore creating the WindowContext.
+ return;
+ }
+
+ RefPtr<WindowContext> context = new WindowContext(
+ bc, aInit.mInnerWindowId, aInit.mOuterWindowId, std::move(aInit.mFields));
+ context->Init();
+}
+
+void WindowContext::Init() {
+ MOZ_LOG(GetLog(), LogLevel::Debug,
+ ("Registering 0x%" PRIx64 " (bc=0x%" PRIx64 ")", mInnerWindowId,
+ mBrowsingContext->Id()));
+
+ // Register the WindowContext in the `WindowContextByIdMap`.
+ if (!gWindowContexts) {
+ gWindowContexts = new WindowContextByIdMap();
+ ClearOnShutdown(&gWindowContexts);
+ }
+ auto& entry = gWindowContexts->LookupOrInsert(mInnerWindowId);
+ MOZ_RELEASE_ASSERT(!entry, "Duplicate WindowContext for ID!");
+ entry = this;
+
+ // Register this to the browsing context.
+ mBrowsingContext->RegisterWindowContext(this);
+ Group()->Register(this);
+}
+
+void WindowContext::Discard() {
+ MOZ_LOG(GetLog(), LogLevel::Debug,
+ ("Discarding 0x%" PRIx64 " (bc=0x%" PRIx64 ")", mInnerWindowId,
+ mBrowsingContext->Id()));
+ if (mIsDiscarded) {
+ return;
+ }
+
+ mIsDiscarded = true;
+ if (gWindowContexts) {
+ gWindowContexts->Remove(InnerWindowId());
+ }
+ mBrowsingContext->UnregisterWindowContext(this);
+ Group()->Unregister(this);
+}
+
+void WindowContext::AddSecurityState(uint32_t aStateFlags) {
+ MOZ_ASSERT(TopWindowContext() == this);
+ MOZ_ASSERT((aStateFlags &
+ (nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT |
+ nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT |
+ nsIWebProgressListener::STATE_BLOCKED_MIXED_DISPLAY_CONTENT |
+ nsIWebProgressListener::STATE_BLOCKED_MIXED_ACTIVE_CONTENT |
+ nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADED |
+ nsIWebProgressListener::STATE_HTTPS_ONLY_MODE_UPGRADE_FAILED)) ==
+ aStateFlags,
+ "Invalid flags specified!");
+
+ if (XRE_IsParentProcess()) {
+ Canonical()->AddSecurityState(aStateFlags);
+ } else {
+ ContentChild* child = ContentChild::GetSingleton();
+ child->SendAddSecurityState(this, aStateFlags);
+ }
+}
+
+void WindowContext::NotifyUserGestureActivation() {
+ Unused << SetUserActivationState(UserActivation::State::FullActivated);
+}
+
+void WindowContext::NotifyResetUserGestureActivation() {
+ Unused << SetUserActivationState(UserActivation::State::None);
+}
+
+bool WindowContext::HasBeenUserGestureActivated() {
+ return GetUserActivationState() != UserActivation::State::None;
+}
+
+const TimeStamp& WindowContext::GetUserGestureStart() const {
+ MOZ_ASSERT(IsInProcess());
+ return mUserGestureStart;
+}
+
+bool WindowContext::HasValidTransientUserGestureActivation() {
+ MOZ_ASSERT(IsInProcess());
+
+ if (GetUserActivationState() != UserActivation::State::FullActivated) {
+ // mUserGestureStart should be null if the document hasn't ever been
+ // activated by user gesture
+ MOZ_ASSERT_IF(GetUserActivationState() == UserActivation::State::None,
+ mUserGestureStart.IsNull());
+ return false;
+ }
+
+ MOZ_ASSERT(!mUserGestureStart.IsNull(),
+ "mUserGestureStart shouldn't be null if the document has ever "
+ "been activated by user gesture");
+ TimeDuration timeout = TimeDuration::FromMilliseconds(
+ StaticPrefs::dom_user_activation_transient_timeout());
+
+ return timeout <= TimeDuration() ||
+ (TimeStamp::Now() - mUserGestureStart) <= timeout;
+}
+
+bool WindowContext::ConsumeTransientUserGestureActivation() {
+ MOZ_ASSERT(IsInProcess());
+ MOZ_ASSERT(IsCurrent());
+
+ if (!HasValidTransientUserGestureActivation()) {
+ return false;
+ }
+
+ BrowsingContext* top = mBrowsingContext->Top();
+ top->PreOrderWalk([&](BrowsingContext* aBrowsingContext) {
+ WindowContext* windowContext = aBrowsingContext->GetCurrentWindowContext();
+ if (windowContext && windowContext->GetUserActivationState() ==
+ UserActivation::State::FullActivated) {
+ Unused << windowContext->SetUserActivationState(
+ UserActivation::State::HasBeenActivated);
+ }
+ });
+
+ return true;
+}
+
+bool WindowContext::CanShowPopup() {
+ uint32_t permit = GetPopupPermission();
+ if (permit == nsIPermissionManager::ALLOW_ACTION) {
+ return true;
+ }
+ if (permit == nsIPermissionManager::DENY_ACTION) {
+ return false;
+ }
+
+ return !StaticPrefs::dom_disable_open_during_load();
+}
+
+void WindowContext::TransientSetHasActivePeerConnections() {
+ if (!IsTop()) {
+ return;
+ }
+
+ mFields.SetWithoutSyncing<IDX_HasActivePeerConnections>(true);
+}
+
+WindowContext::IPCInitializer WindowContext::GetIPCInitializer() {
+ IPCInitializer init;
+ init.mInnerWindowId = mInnerWindowId;
+ init.mOuterWindowId = mOuterWindowId;
+ init.mBrowsingContextId = mBrowsingContext->Id();
+ init.mFields = mFields.RawValues();
+ return init;
+}
+
+WindowContext::WindowContext(BrowsingContext* aBrowsingContext,
+ uint64_t aInnerWindowId, uint64_t aOuterWindowId,
+ FieldValues&& aInit)
+ : mFields(std::move(aInit)),
+ mInnerWindowId(aInnerWindowId),
+ mOuterWindowId(aOuterWindowId),
+ mBrowsingContext(aBrowsingContext) {
+ MOZ_ASSERT(mBrowsingContext);
+ MOZ_ASSERT(mInnerWindowId);
+ MOZ_ASSERT(mOuterWindowId);
+ RecomputeCanExecuteScripts(/* aApplyChanges */ false);
+}
+
+WindowContext::~WindowContext() {
+ if (gWindowContexts) {
+ gWindowContexts->Remove(InnerWindowId());
+ }
+}
+
+JSObject* WindowContext::WrapObject(JSContext* cx,
+ JS::Handle<JSObject*> aGivenProto) {
+ return WindowContext_Binding::Wrap(cx, this, aGivenProto);
+}
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WindowContext)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(WindowContext)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(WindowContext)
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(WindowContext)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WindowContext)
+ if (gWindowContexts) {
+ gWindowContexts->Remove(tmp->InnerWindowId());
+ }
+
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildren)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mNonSyntheticChildren)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WindowContext)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildren)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNonSyntheticChildren)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+} // namespace dom
+
+namespace ipc {
+
+void IPDLParamTraits<dom::MaybeDiscarded<dom::WindowContext>>::Write(
+ IPC::MessageWriter* aWriter, IProtocol* aActor,
+ const dom::MaybeDiscarded<dom::WindowContext>& aParam) {
+ uint64_t id = aParam.ContextId();
+ WriteIPDLParam(aWriter, aActor, id);
+}
+
+bool IPDLParamTraits<dom::MaybeDiscarded<dom::WindowContext>>::Read(
+ IPC::MessageReader* aReader, IProtocol* aActor,
+ dom::MaybeDiscarded<dom::WindowContext>* aResult) {
+ uint64_t id = 0;
+ if (!ReadIPDLParam(aReader, aActor, &id)) {
+ return false;
+ }
+
+ if (id == 0) {
+ *aResult = nullptr;
+ } else if (RefPtr<dom::WindowContext> wc = dom::WindowContext::GetById(id)) {
+ *aResult = std::move(wc);
+ } else {
+ aResult->SetDiscarded(id);
+ }
+ return true;
+}
+
+void IPDLParamTraits<dom::WindowContext::IPCInitializer>::Write(
+ IPC::MessageWriter* aWriter, IProtocol* aActor,
+ const dom::WindowContext::IPCInitializer& aInit) {
+ // Write actor ID parameters.
+ WriteIPDLParam(aWriter, aActor, aInit.mInnerWindowId);
+ WriteIPDLParam(aWriter, aActor, aInit.mOuterWindowId);
+ WriteIPDLParam(aWriter, aActor, aInit.mBrowsingContextId);
+ WriteIPDLParam(aWriter, aActor, aInit.mFields);
+}
+
+bool IPDLParamTraits<dom::WindowContext::IPCInitializer>::Read(
+ IPC::MessageReader* aReader, IProtocol* aActor,
+ dom::WindowContext::IPCInitializer* aInit) {
+ // Read actor ID parameters.
+ return ReadIPDLParam(aReader, aActor, &aInit->mInnerWindowId) &&
+ ReadIPDLParam(aReader, aActor, &aInit->mOuterWindowId) &&
+ ReadIPDLParam(aReader, aActor, &aInit->mBrowsingContextId) &&
+ ReadIPDLParam(aReader, aActor, &aInit->mFields);
+}
+
+template struct IPDLParamTraits<dom::WindowContext::BaseTransaction>;
+
+} // namespace ipc
+} // namespace mozilla