gecko-dev/docshell/base/WindowContext.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

656 строки
22 KiB
C++
Исходник Обычный вид История

/* -*- 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");
Bug 1691410 - Add support for reverting racy changes in CanSet, r=kmag In some cases, a content process may think they should be able to make a change to a synced field, but in the meantime something in the parent process has changed and the change can no longer be applied. This was the cause of a number of issues around the in-flight process ID, and can cause issues such as crashes if the CanSet method was made too strict. This patch introduces a new possible return type from `CanSet` which allows requesting a `Revert`. A reverted field change will either be cancelled at the source (if the CanSet fails in the setting process), or will be cancelled by sending a new transaction back to the source process reverting the change to ensure consistency. In addition, some additional logging is added which made it easier to locate the underlying bug and verify the correctness of the change. The current primary use-case for this new feature is the CurrentInnerWindowId field which can be updated by the previous process' docshell after the parent process has already performed a switch to a new process. This can lead to the current WindowContext being inaccurate for a BrowsingContext in some edge cases as we allow the flawed set due the in-flight process ID matching. This patch changes the logic to no longer check the in-flight process ID, and instead revert any changes to the CurrentInnerWindowId field coming from a process which is not currently active in the BrowsingContext. No tests were added as it is very timing-sensitive, and difficult to create the specific scenario, however without these changes my patch for bug 1663757 consistently causes geckoview-junit crashes due to currentWindowGlobal being incorrect. Differential Revision: https://phabricator.services.mozilla.com/D105553
2021-02-20 06:55:06 +03:00
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; }
Bug 1691410 - Add support for reverting racy changes in CanSet, r=kmag In some cases, a content process may think they should be able to make a change to a synced field, but in the meantime something in the parent process has changed and the change can no longer be applied. This was the cause of a number of issues around the in-flight process ID, and can cause issues such as crashes if the CanSet method was made too strict. This patch introduces a new possible return type from `CanSet` which allows requesting a `Revert`. A reverted field change will either be cancelled at the source (if the CanSet fails in the setting process), or will be cancelled by sending a new transaction back to the source process reverting the change to ensure consistency. In addition, some additional logging is added which made it easier to locate the underlying bug and verify the correctness of the change. The current primary use-case for this new feature is the CurrentInnerWindowId field which can be updated by the previous process' docshell after the parent process has already performed a switch to a new process. This can lead to the current WindowContext being inaccurate for a BrowsingContext in some edge cases as we allow the flawed set due the in-flight process ID matching. This patch changes the logic to no longer check the in-flight process ID, and instead revert any changes to the CurrentInnerWindowId field coming from a process which is not currently active in the BrowsingContext. No tests were added as it is very timing-sensitive, and difficult to create the specific scenario, however without these changes my patch for bug 1663757 consistently causes geckoview-junit crashes due to currentWindowGlobal being incorrect. Differential Revision: https://phabricator.services.mozilla.com/D105553
2021-02-20 06:55:06 +03:00
/* 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;
}
Bug 1668156 - Fix some IntersectionObserver edge cases, and enable the assertion for good. r=hiro This patch fixes two issues, described below: First, the GetTopLevelDocument function was looking at the browsing context tree. It should look at the window context tree, as looking at the browsing context tree means that if you're in a discarded or about-to-get-discarded document, you can end up with a document from a different tree. Computing intersections between those of course makes no sense and triggers the assertion we're enabling. Second, this patch fixes an issue when you have fission enabled, and a setup such as: A1 -> B1 -> A2 If you try to use IntersectionObserver from A2 with the implicit root, we'd end up with: * rootRect: A1's root scrollport rect (this is fine, because it's only used to compute the root margin and bounds and so on, not to compute geometry). * rootFrame: A1's root scroll frame (this is _not_ fine, see below). Then, we'd try to map rects from A2's target to A1's viewport, and we can't really do that sensibly with the existing nsLayoutUtils functions, because we're not accounting for all the OOP iframe transforms that may be going on. This also triggers the assertion that this patch enables in same-origin-grand-child-iframe.sub.html. To fix it, for the A2 case, use the same code that we have for other OOP iframes. The test tweaks fails with fission enabled without the patch (because we don't account for the OOP iframe clip). Differential Revision: https://phabricator.services.mozilla.com/D92089
2020-10-02 01:41:55 +03:00
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_HadLazyLoadImage>, const bool& aValue,
ContentParent* aSource) {
return IsTop();
}
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();
}
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_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
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(WindowContext)
} // 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