Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/docshell/base/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 135 kB image not shown  

Quelle  BrowsingContext.cpp   Sprache: 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/BrowsingContext.h"

#include "ipc/IPCMessageUtils.h"

#ifdef ACCESSIBILITY
#  include "mozilla/a11y/DocAccessibleParent.h"
#  include "mozilla/a11y/Platform.h"
#  include "nsAccessibilityService.h"
#  if defined(XP_WIN)
#    include "mozilla/a11y/AccessibleWrap.h"
#    include "mozilla/a11y/Compatibility.h"
#    include "mozilla/a11y/nsWinUtils.h"
#  endif
#endif
#include "mozilla/AppShutdown.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/dom/BindingIPCUtils.h"
#include "mozilla/dom/BrowserHost.h"
#include "mozilla/dom/BrowserChild.h"
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/BrowsingContextGroup.h"
#include "mozilla/dom/BrowsingContextBinding.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLEmbedElement.h"
#include "mozilla/dom/HTMLIFrameElement.h"
#include "mozilla/dom/Location.h"
#include "mozilla/dom/LocationBinding.h"
#include "mozilla/dom/MediaDevices.h"
#include "mozilla/dom/PopupBlocker.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/SessionStoreChild.h"
#include "mozilla/dom/SessionStorageManager.h"
#include "mozilla/dom/StructuredCloneTags.h"
#include "mozilla/dom/UserActivationIPCUtils.h"
#include "mozilla/dom/WindowBinding.h"
#include "mozilla/dom/WindowContext.h"
#include "mozilla/dom/WindowGlobalChild.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "mozilla/dom/WindowProxyHolder.h"
#include "mozilla/dom/SyncedContextInlines.h"
#include "mozilla/dom/XULFrameElement.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/net/DocumentLoadListener.h"
#include "mozilla/net/RequestContextService.h"
#include "mozilla/Assertions.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Components.h"
#include "mozilla/HashTable.h"
#include "mozilla/Logging.h"
#include "mozilla/MediaFeatureChange.h"
#include "mozilla/ResultExtensions.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPrefs_fission.h"
#include "mozilla/StaticPrefs_media.h"
#include "mozilla/StaticPrefs_page_load.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/URLQueryStringStripper.h"
#include "mozilla/EventStateManager.h"
#include "nsIURIFixup.h"
#include "nsIXULRuntime.h"

#include "nsDocShell.h"
#include "nsDocShellLoadState.h"
#include "nsFocusManager.h"
#include "nsGlobalWindowInner.h"
#include "nsGlobalWindowOuter.h"
#include "PresShell.h"
#include "nsIObserverService.h"
#include "nsISHistory.h"
#include "nsContentUtils.h"
#include "nsQueryObject.h"
#include "nsSandboxFlags.h"
#include "nsScriptError.h"
#include "nsThreadUtils.h"
#include "xpcprivate.h"

#include "AutoplayPolicy.h"
#include "GVAutoplayRequestStatusIPC.h"

extern mozilla::LazyLogModule gAutoplayPermissionLog;
extern mozilla::LazyLogModule gTimeoutDeferralLog;

#define AUTOPLAY_LOG(msg, ...) \
  MOZ_LOG(gAutoplayPermissionLog, LogLevel::Debug, (msg, ##__VA_ARGS__))

namespace IPC {
// Allow serialization and deserialization of OrientationType over IPC
template <>
struct ParamTraits<mozilla::dom::OrientationType>
    : public mozilla::dom::WebIDLEnumSerializer<mozilla::dom::OrientationType> {
};

template <>
struct ParamTraits<mozilla::dom::DisplayMode>
    : public mozilla::dom::WebIDLEnumSerializer<mozilla::dom::DisplayMode> {};

template <>
struct ParamTraits<mozilla::dom::PrefersColorSchemeOverride>
    : public mozilla::dom::WebIDLEnumSerializer<
          mozilla::dom::PrefersColorSchemeOverride> {};

template <>
struct ParamTraits<mozilla::dom::ForcedColorsOverride>
    : public mozilla::dom::WebIDLEnumSerializer<
          mozilla::dom::ForcedColorsOverride> {};

template <>
struct ParamTraits<mozilla::dom::ExplicitActiveStatus>
    : public ContiguousEnumSerializer<
          mozilla::dom::ExplicitActiveStatus,
          mozilla::dom::ExplicitActiveStatus::None,
          mozilla::dom::ExplicitActiveStatus::EndGuard_> {};

// Allow serialization and deserialization of TouchEventsOverride over IPC
template <>
struct ParamTraits<mozilla::dom::TouchEventsOverride>
    : public mozilla::dom::WebIDLEnumSerializer<
          mozilla::dom::TouchEventsOverride> {};

template <>
struct ParamTraits<mozilla::dom::EmbedderColorSchemes> {
  using paramType = mozilla::dom::EmbedderColorSchemes;

  static void Write(MessageWriter* aWriter, const paramType& aParam) {
    WriteParam(aWriter, aParam.mUsed);
    WriteParam(aWriter, aParam.mPreferred);
  }

  static bool Read(MessageReader* aReader, paramType* aResult) {
    return ReadParam(aReader, &aResult->mUsed) &&
           ReadParam(aReader, &aResult->mPreferred);
  }
};

}  // namespace IPC

namespace mozilla {
namespace dom {

// Explicit specialization of the `Transaction` type. Required by the `extern
// template class` declaration in the header.
template class syncedcontext::Transaction<BrowsingContext>;

extern mozilla::LazyLogModule gUserInteractionPRLog;

#define USER_ACTIVATION_LOG(msg, ...) \
  MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug, (msg, ##__VA_ARGS__))

static LazyLogModule gBrowsingContextLog("BrowsingContext");
static LazyLogModule gBrowsingContextSyncLog("BrowsingContextSync");

typedef nsTHashMap<nsUint64HashKey, BrowsingContext*> BrowsingContextMap;

// All BrowsingContexts indexed by Id
static StaticAutoPtr<BrowsingContextMap> sBrowsingContexts;
// Top-level Content BrowsingContexts only, indexed by BrowserId instead of Id
static StaticAutoPtr<BrowsingContextMap> sCurrentTopByBrowserId;

static bool gIPCEnabledAnnotation = false;
static bool gFissionEnabledAnnotation = false;

static void UnregisterBrowserId(BrowsingContext* aBrowsingContext) {
  if (!aBrowsingContext->IsTopContent() || !sCurrentTopByBrowserId) {
    return;
  }

  // Avoids an extra lookup
  auto browserIdEntry =
      sCurrentTopByBrowserId->Lookup(aBrowsingContext->BrowserId());
  if (browserIdEntry && browserIdEntry.Data() == aBrowsingContext) {
    browserIdEntry.Remove();
  }
}

static void Register(BrowsingContext* aBrowsingContext) {
  sBrowsingContexts->InsertOrUpdate(aBrowsingContext->Id(), aBrowsingContext);
  if (aBrowsingContext->IsTopContent()) {
    sCurrentTopByBrowserId->InsertOrUpdate(aBrowsingContext->BrowserId(),
                                           aBrowsingContext);
  }

  aBrowsingContext->Group()->Register(aBrowsingContext);
}

// static
void BrowsingContext::UpdateCurrentTopByBrowserId(
    BrowsingContext* aNewBrowsingContext) {
  if (aNewBrowsingContext->IsTopContent()) {
    sCurrentTopByBrowserId->InsertOrUpdate(aNewBrowsingContext->BrowserId(),
                                           aNewBrowsingContext);
  }
}

BrowsingContext* BrowsingContext::GetParent() const {
  return mParentWindow ? mParentWindow->GetBrowsingContext() : nullptr;
}

bool BrowsingContext::IsInSubtreeOf(BrowsingContext* aContext) {
  BrowsingContext* bc = this;
  do {
    if (bc == aContext) {
      return true;
    }
  } while ((bc = bc->GetParent()));
  return false;
}

BrowsingContext* BrowsingContext::Top() {
  BrowsingContext* bc = this;
  while (bc->mParentWindow) {
    bc = bc->GetParent();
  }
  return bc;
}

const BrowsingContext* BrowsingContext::Top() const {
  const BrowsingContext* bc = this;
  while (bc->mParentWindow) {
    bc = bc->GetParent();
  }
  return bc;
}

int32_t BrowsingContext::IndexOf(BrowsingContext* aChild) {
  int32_t index = -1;
  for (BrowsingContext* child : Children()) {
    ++index;
    if (child == aChild) {
      break;
    }
  }
  return index;
}

WindowContext* BrowsingContext::GetTopWindowContext() const {
  if (mParentWindow) {
    return mParentWindow->TopWindowContext();
  }
  return mCurrentWindowContext;
}

/* static */
void BrowsingContext::Init() {
  if (!sBrowsingContexts) {
    sBrowsingContexts = new BrowsingContextMap();
    sCurrentTopByBrowserId = new BrowsingContextMap();
    ClearOnShutdown(&sBrowsingContexts);
    ClearOnShutdown(&sCurrentTopByBrowserId);
    CrashReporter::RegisterAnnotationBool(
        CrashReporter::Annotation::DOMIPCEnabled, &gIPCEnabledAnnotation);
    CrashReporter::RegisterAnnotationBool(
        CrashReporter::Annotation::DOMFissionEnabled,
        &gFissionEnabledAnnotation);
  }
}

/* static */
LogModule* BrowsingContext::GetLog() { return gBrowsingContextLog; }

/* static */
LogModule* BrowsingContext::GetSyncLog() { return gBrowsingContextSyncLog; }

/* static */
already_AddRefed<BrowsingContext> BrowsingContext::Get(uint64_t aId) {
  return do_AddRef(sBrowsingContexts->Get(aId));
}

/* static */
already_AddRefed<BrowsingContext> BrowsingContext::GetCurrentTopByBrowserId(
    uint64_t aBrowserId) {
  return do_AddRef(sCurrentTopByBrowserId->Get(aBrowserId));
}

/* static */
already_AddRefed<BrowsingContext> BrowsingContext::GetFromWindow(
    WindowProxyHolder& aProxy) {
  return do_AddRef(aProxy.get());
}

CanonicalBrowsingContext* BrowsingContext::Canonical() {
  return CanonicalBrowsingContext::Cast(this);
}

bool BrowsingContext::IsOwnedByProcess() const {
  return mIsInProcess && mDocShell &&
         !nsDocShell::Cast(mDocShell)->WillChangeProcess();
}

bool BrowsingContext::SameOriginWithTop() {
  MOZ_ASSERT(IsInProcess());
  // If the top BrowsingContext is not same-process to us, it is cross-origin
  if (!Top()->IsInProcess()) {
    return false;
  }

  nsIDocShell* docShell = GetDocShell();
  if (!docShell) {
    return false;
  }
  Document* doc = docShell->GetDocument();
  if (!doc) {
    return false;
  }
  nsIPrincipal* principal = doc->NodePrincipal();

  nsIDocShell* topDocShell = Top()->GetDocShell();
  if (!topDocShell) {
    return false;
  }
  Document* topDoc = topDocShell->GetDocument();
  if (!topDoc) {
    return false;
  }
  nsIPrincipal* topPrincipal = topDoc->NodePrincipal();

  return principal->Equals(topPrincipal);
}

/* static */
already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
    nsGlobalWindowInner* aParent, BrowsingContext* aOpener,
    BrowsingContextGroup* aSpecificGroup, const nsAString& aName, Type aType,
    CreateDetachedOptions aOptions) {
  if (aParent) {
    MOZ_DIAGNOSTIC_ASSERT(aParent->GetWindowContext());
    MOZ_DIAGNOSTIC_ASSERT(aParent->GetBrowsingContext()->mType == aType);
    MOZ_DIAGNOSTIC_ASSERT(aParent->GetBrowsingContext()->GetBrowserId() != 0);
  }

  MOZ_DIAGNOSTIC_ASSERT(aType != Type::Chrome || XRE_IsParentProcess());

  uint64_t id = nsContentUtils::GenerateBrowsingContextId();

  MOZ_LOG(GetLog(), LogLevel::Debug,
          ("Creating 0x%08" PRIx64 " in %s", id,
           XRE_IsParentProcess() ? "Parent" : "Child"));

  RefPtr<BrowsingContext> parentBC =
      aParent ? aParent->GetBrowsingContext() : nullptr;
  RefPtr<WindowContext> parentWC =
      aParent ? aParent->GetWindowContext() : nullptr;
  BrowsingContext* inherit = parentBC ? parentBC.get() : aOpener;

  // Determine which BrowsingContextGroup this context should be created in.
  RefPtr<BrowsingContextGroup> group = aSpecificGroup;
  if (aType == Type::Chrome) {
    MOZ_DIAGNOSTIC_ASSERT(!group);
    group = BrowsingContextGroup::GetChromeGroup();
  } else if (!group) {
    group = BrowsingContextGroup::Select(parentWC, aOpener);
  }

  // Configure initial values for synced fields.
  FieldValues fields;
  fields.Get<IDX_Name>() = aName;

  if (aOpener) {
    MOZ_DIAGNOSTIC_ASSERT(!aParent,
                          "new BC with both initial opener and parent");
    MOZ_DIAGNOSTIC_ASSERT(aOpener->Group() == group);
    MOZ_DIAGNOSTIC_ASSERT(aOpener->mType == aType);
    fields.Get<IDX_OpenerId>() = aOpener->Id();
    fields.Get<IDX_HadOriginalOpener>() = true;

    if (aType == Type::Chrome && !aParent) {
      // See SetOpener for why we do this inheritance.
      fields.Get<IDX_PrefersColorSchemeOverride>() =
          aOpener->Top()->GetPrefersColorSchemeOverride();
    }
  }

  if (aParent) {
    MOZ_DIAGNOSTIC_ASSERT(parentBC->Group() == group);
    MOZ_DIAGNOSTIC_ASSERT(parentBC->mType == aType);
    fields.Get<IDX_EmbedderInnerWindowId>() = aParent->WindowID();
    // Non-toplevel content documents are always embededed within content.
    fields.Get<IDX_EmbeddedInContentDocument>() =
        parentBC->mType == Type::Content;

    // XXX(farre): Can/Should we check aParent->IsLoading() here? (Bug
    // 1608448) Check if the parent was itself loading already
    auto readystate = aParent->GetDocument()->GetReadyStateEnum();
    fields.Get<IDX_AncestorLoading>() =
        parentBC->GetAncestorLoading() ||
        readystate == Document::ReadyState::READYSTATE_LOADING ||
        readystate == Document::ReadyState::READYSTATE_INTERACTIVE;
  }

  fields.Get<IDX_BrowserId>() =
      parentBC ? parentBC->GetBrowserId() : nsContentUtils::GenerateBrowserId();

  fields.Get<IDX_OpenerPolicy>() = nsILoadInfo::OPENER_POLICY_UNSAFE_NONE;
  if (aOpener && aOpener->SameOriginWithTop()) {
    // We inherit the opener policy if there is a creator and if the creator's
    // origin is same origin with the creator's top-level origin.
    // If it is cross origin we should not inherit the CrossOriginOpenerPolicy
    fields.Get<IDX_OpenerPolicy>() = aOpener->Top()->GetOpenerPolicy();

    // If we inherit a policy which is potentially cross-origin isolated, we
    // must be in a potentially cross-origin isolated BCG.
    bool isPotentiallyCrossOriginIsolated =
        fields.Get<IDX_OpenerPolicy>() ==
        nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP;
    MOZ_RELEASE_ASSERT(isPotentiallyCrossOriginIsolated ==
                       group->IsPotentiallyCrossOriginIsolated());
  } else if (aOpener) {
    // They are not same origin
    auto topPolicy = aOpener->Top()->GetOpenerPolicy();
    MOZ_RELEASE_ASSERT(
        topPolicy == nsILoadInfo::OPENER_POLICY_UNSAFE_NONE ||
        topPolicy == nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_ALLOW_POPUPS ||
        aOptions.isForPrinting);
    if (aOptions.isForPrinting) {
      // Ensure our opener policy is consistent for printing for our top.
      fields.Get<IDX_OpenerPolicy>() = topPolicy;
    }
  } else if (!aParent && group->IsPotentiallyCrossOriginIsolated()) {
    // If we're creating a brand-new toplevel BC in a potentially cross-origin
    // isolated group, it should start out with a strict opener policy.
    fields.Get<IDX_OpenerPolicy>() =
        nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP;
  }

  fields.Get<IDX_HistoryID>() = nsID::GenerateUUID();
  fields.Get<IDX_ExplicitActive>() = [&] {
    if (parentBC || aType == Type::Content) {
      // Non-root browsing-contexts inherit their status from its parent.
      // Top-content either gets managed by the top chrome, or gets manually
      // managed by the front-end (see ManuallyManagesActiveness). In any case
      // we want to start off as inactive.
      return ExplicitActiveStatus::None;
    }
    // Chrome starts as active.
    return ExplicitActiveStatus::Active;
  }();

  fields.Get<IDX_FullZoom>() = parentBC ? parentBC->FullZoom() : 1.0f;
  fields.Get<IDX_TextZoom>() = parentBC ? parentBC->TextZoom() : 1.0f;

  bool allowContentRetargeting =
      inherit ? inherit->GetAllowContentRetargetingOnChildren() : true;
  fields.Get<IDX_AllowContentRetargeting>() = allowContentRetargeting;
  fields.Get<IDX_AllowContentRetargetingOnChildren>() = allowContentRetargeting;

  // Assume top allows fullscreen for its children unless otherwise stated.
  // Subframes start with it false unless otherwise noted in SetEmbedderElement.
  fields.Get<IDX_FullscreenAllowedByOwner>() = !aParent;

  fields.Get<IDX_DefaultLoadFlags>() =
      inherit ? inherit->GetDefaultLoadFlags() : nsIRequest::LOAD_NORMAL;

  fields.Get<IDX_OrientationLock>() = mozilla::hal::ScreenOrientation::None;

  fields.Get<IDX_UseGlobalHistory>() =
      inherit ? inherit->GetUseGlobalHistory() : false;

  fields.Get<IDX_UseErrorPages>() = true;

  fields.Get<IDX_TouchEventsOverrideInternal>() = TouchEventsOverride::None;

  fields.Get<IDX_AllowJavascript>() =
      inherit ? inherit->GetAllowJavascript() : true;

  fields.Get<IDX_IsPopupRequested>() = aOptions.isPopupRequested;

  fields.Get<IDX_TopLevelCreatedByWebContent>() =
      aOptions.topLevelCreatedByWebContent;

  if (!parentBC) {
    fields.Get<IDX_ShouldDelayMediaFromStart>() =
        StaticPrefs::media_block_autoplay_until_in_foreground();
  }

  RefPtr<BrowsingContext> context;
  if (XRE_IsParentProcess()) {
    context = new CanonicalBrowsingContext(parentWC, group, id,
                                           /* aOwnerProcessId */ 0,
                                           /* aEmbedderProcessId */ 0, aType,
                                           std::move(fields));
  } else {
    context =
        new BrowsingContext(parentWC, group, id, aType, std::move(fields));
  }

  context->mWindowless = aOptions.windowless;
  context->mEmbeddedByThisProcess = XRE_IsParentProcess() || aParent;
  context->mCreatedDynamically = aOptions.createdDynamically;
  if (inherit) {
    context->mPrivateBrowsingId = inherit->mPrivateBrowsingId;
    context->mUseRemoteTabs = inherit->mUseRemoteTabs;
    context->mUseRemoteSubframes = inherit->mUseRemoteSubframes;
    context->mOriginAttributes = inherit->mOriginAttributes;
  }

  nsCOMPtr<nsIRequestContextService> rcsvc =
      net::RequestContextService::GetOrCreate();
  if (rcsvc) {
    nsCOMPtr<nsIRequestContext> requestContext;
    nsresult rv = rcsvc->NewRequestContext(getter_AddRefs(requestContext));
    if (NS_SUCCEEDED(rv) && requestContext) {
      context->mRequestContextId = requestContext->GetID();
    }
  }

  return context.forget();
}

already_AddRefed<BrowsingContext> BrowsingContext::CreateIndependent(
    Type aType, bool aWindowless) {
  MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess(),
                        "BCs created in the content process must be related to "
                        "some BrowserChild");
  RefPtr<BrowsingContext> bc(
      CreateDetached(nullptr, nullptr, nullptr, u""_ns, aType, {}));
  bc->mWindowless = aWindowless;
  bc->mEmbeddedByThisProcess = true;
  bc->EnsureAttached();
  return bc.forget();
}

void BrowsingContext::EnsureAttached() {
  if (!mEverAttached) {
    Register(this);

    // Attach the browsing context to the tree.
    Attach(/* aFromIPC */ false, /* aOriginProcess */ nullptr);
  }
}

/* static */
mozilla::ipc::IPCResult BrowsingContext::CreateFromIPC(
    BrowsingContext::IPCInitializer&& aInit, BrowsingContextGroup* aGroup,
    ContentParent* aOriginProcess) {
  MOZ_DIAGNOSTIC_ASSERT(aOriginProcess || XRE_IsContentProcess());
  MOZ_DIAGNOSTIC_ASSERT(aGroup);

  uint64_t originId = 0;
  if (aOriginProcess) {
    originId = aOriginProcess->ChildID();
    aGroup->EnsureHostProcess(aOriginProcess);
  }

  MOZ_LOG(GetLog(), LogLevel::Debug,
          ("Creating 0x%08" PRIx64 " from IPC (origin=0x%08" PRIx64 ")",
           aInit.mId, originId));

  RefPtr<WindowContext> parent = aInit.GetParent();

  RefPtr<BrowsingContext> context;
  if (XRE_IsParentProcess()) {
    // If the new BrowsingContext has a parent, it is a sub-frame embedded in
    // whatever process sent the message. If it doesn't, and is not windowless,
    // it is a new window or tab, and will be embedded in the parent process.
    uint64_t embedderProcessId = (aInit.mWindowless || parent) ? originId : 0;
    context = new CanonicalBrowsingContext(parent, aGroup, aInit.mId, originId,
                                           embedderProcessId, Type::Content,
                                           std::move(aInit.mFields));
  } else {
    context = new BrowsingContext(parent, aGroup, aInit.mId, Type::Content,
                                  std::move(aInit.mFields));
  }

  context->mWindowless = aInit.mWindowless;
  context->mCreatedDynamically = aInit.mCreatedDynamically;
  context->mChildOffset = aInit.mChildOffset;
  if (context->GetHasSessionHistory()) {
    context->CreateChildSHistory();
    if (mozilla::SessionHistoryInParent()) {
      context->GetChildSessionHistory()->SetIndexAndLength(
          aInit.mSessionHistoryIndex, aInit.mSessionHistoryCount, nsID());
    }
  }

  // NOTE: Call through the `Set` methods for these values to ensure that any
  // relevant process-local state is also updated.
  context->SetOriginAttributes(aInit.mOriginAttributes);
  context->SetRemoteTabs(aInit.mUseRemoteTabs);
  context->SetRemoteSubframes(aInit.mUseRemoteSubframes);
  context->mRequestContextId = aInit.mRequestContextId;
  // NOTE: Private browsing ID is set by `SetOriginAttributes`.

  if (const char* failure =
          context->BrowsingContextCoherencyChecks(aOriginProcess)) {
    mozilla::ipc::IProtocol* actor = aOriginProcess;
    if (!actor) {
      actor = ContentChild::GetSingleton();
    }
    return IPC_FAIL_UNSAFE_PRINTF(actor, "Incoherent BrowsingContext: %s",
                                  failure);
  }

  Register(context);

  context->Attach(/* aFromIPC */ true, aOriginProcess);
  return IPC_OK();
}

BrowsingContext::BrowsingContext(WindowContext* aParentWindow,
                                 BrowsingContextGroup* aGroup,
                                 uint64_t aBrowsingContextId, Type aType,
                                 FieldValues&& aInit)
    : mFields(std::move(aInit)),
      mType(aType),
      mBrowsingContextId(aBrowsingContextId),
      mGroup(aGroup),
      mParentWindow(aParentWindow),
      mPrivateBrowsingId(0),
      mEverAttached(false),
      mIsInProcess(false),
      mIsDiscarded(false),
      mWindowless(false),
      mDanglingRemoteOuterProxies(false),
      mEmbeddedByThisProcess(false),
      mUseRemoteTabs(false),
      mUseRemoteSubframes(false),
      mCreatedDynamically(false),
      mIsInBFCache(false),
      mCanExecuteScripts(true),
      mChildOffset(0) {
  MOZ_RELEASE_ASSERT(!mParentWindow || mParentWindow->Group() == mGroup);
  MOZ_RELEASE_ASSERT(mBrowsingContextId != 0);
  MOZ_RELEASE_ASSERT(mGroup);
}

void BrowsingContext::SetDocShell(nsIDocShell* aDocShell) {
  // XXX(nika): We should communicate that we are now an active BrowsingContext
  // process to the parent & do other validation here.
  MOZ_DIAGNOSTIC_ASSERT(mEverAttached);
  MOZ_RELEASE_ASSERT(aDocShell->GetBrowsingContext() == this);
  mDocShell = aDocShell;
  mDanglingRemoteOuterProxies = !mIsInProcess;
  mIsInProcess = true;
  if (mChildSessionHistory) {
    mChildSessionHistory->SetIsInProcess(true);
  }

  RecomputeCanExecuteScripts();
  ClearCachedValuesOfLocations();
}

// This class implements a callback that will return the remote window proxy for
// mBrowsingContext in that compartment, if it has one. It also removes the
// proxy from the map, because the object will be transplanted into another kind
// of object.
class MOZ_STACK_CLASS CompartmentRemoteProxyTransplantCallback
    : public js::CompartmentTransplantCallback {
 public:
  explicit CompartmentRemoteProxyTransplantCallback(
      BrowsingContext* aBrowsingContext)
      : mBrowsingContext(aBrowsingContext) {}

  virtual JSObject* getObjectToTransplant(
      JS::Compartment* compartment) override {
    auto* priv = xpc::CompartmentPrivate::Get(compartment);
    if (!priv) {
      return nullptr;
    }

    auto& map = priv->GetRemoteProxyMap();
    auto result = map.lookup(mBrowsingContext);
    if (!result) {
      return nullptr;
    }
    JSObject* resultObject = result->value();
    map.remove(result);

    return resultObject;
  }

 private:
  BrowsingContext* mBrowsingContext;
};

void BrowsingContext::CleanUpDanglingRemoteOuterWindowProxies(
    JSContext* aCx, JS::MutableHandle<JSObject*> aOuter) {
  if (!mDanglingRemoteOuterProxies) {
    return;
  }
  mDanglingRemoteOuterProxies = false;

  CompartmentRemoteProxyTransplantCallback cb(this);
  js::RemapRemoteWindowProxies(aCx, &cb, aOuter);
}

bool BrowsingContext::IsActive() const {
  const BrowsingContext* current = this;
  do {
    auto explicit_ = current->GetExplicitActive();
    if (explicit_ != ExplicitActiveStatus::None) {
      return explicit_ == ExplicitActiveStatus::Active;
    }
    if (mParentWindow && !mParentWindow->IsCurrent()) {
      return false;
    }
  } while ((current = current->GetParent()));

  return false;
}

bool BrowsingContext::GetIsActiveBrowserWindow() {
  if (!XRE_IsParentProcess()) {
    return Top()->GetIsActiveBrowserWindowInternal();
  }

  // chrome:// urls loaded in the parent won't receive
  // their own activation so we defer to the top chrome
  // Browsing Context when in the parent process.
  return Canonical()
      ->TopCrossChromeBoundary()
      ->GetIsActiveBrowserWindowInternal();
}

void BrowsingContext::SetIsActiveBrowserWindow(bool aActive) {
  Unused << SetIsActiveBrowserWindowInternal(aActive);
}

bool BrowsingContext::FullscreenAllowed() const {
  for (auto* current = this; current; current = current->GetParent()) {
    if (!current->GetFullscreenAllowedByOwner()) {
      return false;
    }
  }
  return true;
}

static bool OwnerAllowsFullscreen(const Element& aEmbedder) {
  if (aEmbedder.IsXULElement()) {
    return !aEmbedder.HasAttr(nsGkAtoms::disablefullscreen);
  }
  if (aEmbedder.IsHTMLElement(nsGkAtoms::iframe)) {
    // This is controlled by feature policy.
    return true;
  }
  if (const auto* embed = HTMLEmbedElement::FromNode(aEmbedder)) {
    return embed->AllowFullscreen();
  }
  return false;
}

void BrowsingContext::SetEmbedderElement(Element* aEmbedder) {
  mEmbeddedByThisProcess = true;

  // Update embedder-element-specific fields in a shared transaction.
  // Don't do this when clearing our embedder, as we're being destroyed either
  // way.
  if (aEmbedder) {
    Transaction txn;
    txn.SetEmbedderElementType(Some(aEmbedder->LocalName()));
    txn.SetEmbeddedInContentDocument(
        aEmbedder->OwnerDoc()->IsContentDocument());
    if (nsCOMPtr<nsPIDOMWindowInner> inner =
            do_QueryInterface(aEmbedder->GetOwnerGlobal())) {
      txn.SetEmbedderInnerWindowId(inner->WindowID());
    }
    txn.SetFullscreenAllowedByOwner(OwnerAllowsFullscreen(*aEmbedder));
    if (XRE_IsParentProcess() && aEmbedder->IsXULElement() && IsTopContent()) {
      nsAutoString messageManagerGroup;
      aEmbedder->GetAttr(nsGkAtoms::messagemanagergroup, messageManagerGroup);
      txn.SetMessageManagerGroup(messageManagerGroup);
      txn.SetUseGlobalHistory(
          !aEmbedder->HasAttr(nsGkAtoms::disableglobalhistory));
      if (!aEmbedder->HasAttr(nsGkAtoms::manualactiveness)) {
        // We're active iff the parent cross-chrome-boundary is active. Note we
        // can't just use this->Canonical()->GetParentCrossChromeBoundary here,
        // since mEmbedderElement is still null at this point.
        RefPtr bc = aEmbedder->OwnerDoc()->GetBrowsingContext();
        const bool isActive = bc && bc->IsActive();
        txn.SetExplicitActive(isActive ? ExplicitActiveStatus::Active
                                       : ExplicitActiveStatus::Inactive);
        if (auto* bp = Canonical()->GetBrowserParent()) {
          bp->SetRenderLayers(isActive);
        }
      }
    }

    MOZ_ALWAYS_SUCCEEDS(txn.Commit(this));
  }

  if (XRE_IsParentProcess() && IsTopContent()) {
    Canonical()->MaybeSetPermanentKey(aEmbedder);
  }

  mEmbedderElement = aEmbedder;

  if (mEmbedderElement) {
    if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
      obs->NotifyWhenScriptSafe(ToSupports(this),
                                "browsing-context-did-set-embedder", nullptr);
    }

    if (IsEmbedderTypeObjectOrEmbed()) {
      Unused << SetIsSyntheticDocumentContainer(true);
    }
  }
}

bool BrowsingContext::IsEmbedderTypeObjectOrEmbed() {
  if (const Maybe<nsString>& type = GetEmbedderElementType()) {
    return nsGkAtoms::object->Equals(*type) || nsGkAtoms::embed->Equals(*type);
  }
  return false;
}

void BrowsingContext::Embed() {
  if (auto* frame = HTMLIFrameElement::FromNode(mEmbedderElement)) {
    frame->BindToBrowsingContext(this);
  }
}

const char* BrowsingContext::BrowsingContextCoherencyChecks(
    ContentParent* aOriginProcess) {
#define COHERENCY_ASSERT(condition) \
  if (!(condition)) return "Assertion " #condition " failed";

  if (mGroup->IsPotentiallyCrossOriginIsolated() !=
      (Top()->GetOpenerPolicy() ==
       nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP)) {
    return "Invalid CrossOriginIsolated state";
  }

  if (aOriginProcess && !IsContent()) {
    return "Content cannot create chrome BCs";
  }

  // LoadContext should generally match our opener or parent.
  if (IsContent()) {
    if (RefPtr<BrowsingContext> opener = GetOpener()) {
      COHERENCY_ASSERT(opener->mType == mType);
      COHERENCY_ASSERT(opener->mGroup == mGroup);
      COHERENCY_ASSERT(opener->mUseRemoteTabs == mUseRemoteTabs);
      COHERENCY_ASSERT(opener->mUseRemoteSubframes == mUseRemoteSubframes);
      COHERENCY_ASSERT(opener->mPrivateBrowsingId == mPrivateBrowsingId);
      COHERENCY_ASSERT(
          opener->mOriginAttributes.EqualsIgnoringFPD(mOriginAttributes));
    }
  }
  if (RefPtr<BrowsingContext> parent = GetParent()) {
    COHERENCY_ASSERT(parent->mType == mType);
    COHERENCY_ASSERT(parent->mGroup == mGroup);
    COHERENCY_ASSERT(parent->mUseRemoteTabs == mUseRemoteTabs);
    COHERENCY_ASSERT(parent->mUseRemoteSubframes == mUseRemoteSubframes);
    COHERENCY_ASSERT(parent->mPrivateBrowsingId == mPrivateBrowsingId);
    COHERENCY_ASSERT(
        parent->mOriginAttributes.EqualsIgnoringFPD(mOriginAttributes));
  }

  // UseRemoteSubframes and UseRemoteTabs must match.
  if (mUseRemoteSubframes && !mUseRemoteTabs) {
    return "Cannot set useRemoteSubframes without also setting useRemoteTabs";
  }

  // Double-check OriginAttributes/Private Browsing
  // Chrome browsing contexts must not have a private browsing OriginAttribute
  // Content browsing contexts must maintain the equality:
  // mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId
  if (IsChrome()) {
    COHERENCY_ASSERT(mOriginAttributes.mPrivateBrowsingId == 0);
  } else {
    COHERENCY_ASSERT(mOriginAttributes.mPrivateBrowsingId ==
                     mPrivateBrowsingId);
  }
#undef COHERENCY_ASSERT

  return nullptr;
}

void BrowsingContext::Attach(bool aFromIPC, ContentParent* aOriginProcess) {
  MOZ_DIAGNOSTIC_ASSERT(!mEverAttached);
  MOZ_DIAGNOSTIC_ASSERT_IF(aFromIPC, aOriginProcess || XRE_IsContentProcess());
  mEverAttached = true;

  if (MOZ_LOG_TEST(GetLog(), LogLevel::Debug)) {
    nsAutoCString suffix;
    mOriginAttributes.CreateSuffix(suffix);
    MOZ_LOG(GetLog(), LogLevel::Debug,
            ("%s: Connecting 0x%08" PRIx64 " to 0x%08" PRIx64
             " (private=%d, remote=%d, fission=%d, oa=%s)",
             XRE_IsParentProcess() ? "Parent" : "Child", Id(),
             GetParent() ? GetParent()->Id() : 0, (int)mPrivateBrowsingId,
             (int)mUseRemoteTabs, (int)mUseRemoteSubframes, suffix.get()));
  }

  MOZ_DIAGNOSTIC_ASSERT(mGroup);
  MOZ_DIAGNOSTIC_ASSERT(!mIsDiscarded);

#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
  // We'll already have checked this if `aFromIPC` is set before calling this
  // function.
  if (!aFromIPC) {
    if (const char* failure = BrowsingContextCoherencyChecks(aOriginProcess)) {
      MOZ_CRASH_UNSAFE_PRINTF("Incoherent BrowsingContext: %s", failure);
    }
  }
#endif

  // Add ourselves either to our parent or BrowsingContextGroup's child list.
  // Important: We shouldn't return IPC_FAIL after this point, since the
  // BrowsingContext will have already been added to the tree.
  if (mParentWindow) {
    if (!aFromIPC) {
      MOZ_DIAGNOSTIC_ASSERT(!mParentWindow->IsDiscarded(),
                            "local attach in discarded window");
      MOZ_DIAGNOSTIC_ASSERT(!GetParent()->IsDiscarded(),
                            "local attach call in discarded bc");
      MOZ_DIAGNOSTIC_ASSERT(mParentWindow->GetWindowGlobalChild(),
                            "local attach call with oop parent window");
      MOZ_DIAGNOSTIC_ASSERT(mParentWindow->GetWindowGlobalChild()->CanSend(),
                            "local attach call with dead parent window");
    }
    mChildOffset =
        mCreatedDynamically ? -1 : mParentWindow->Children().Length();
    mParentWindow->AppendChildBrowsingContext(this);
    RecomputeCanExecuteScripts();
  } else {
    mGroup->Toplevels().AppendElement(this);
  }

  if (GetIsPopupSpam()) {
    PopupBlocker::RegisterOpenPopupSpam();
  }

  if (IsTop() && GetHasSessionHistory() && !mChildSessionHistory) {
    CreateChildSHistory();
  }

  // Why the context is being attached. This will always be "attach" in the
  // content process, but may be "replace" if it's known the context being
  // replaced in the parent process.
  const char16_t* why = u"attach";

  if (XRE_IsContentProcess() && !aFromIPC) {
    // Send attach to our parent if we need to.
    ContentChild::GetSingleton()->SendCreateBrowsingContext(
        mGroup->Id(), GetIPCInitializer());
  } else if (XRE_IsParentProcess()) {
    // If this window was created as a subframe by a content process, it must be
    // being hosted within the same BrowserParent as its mParentWindow.
    // Toplevel BrowsingContexts created by content have their BrowserParent
    // configured during `RecvConstructPopupBrowser`.
    if (mParentWindow && aOriginProcess) {
      MOZ_DIAGNOSTIC_ASSERT(
          mParentWindow->Canonical()->GetContentParent() == aOriginProcess,
          "Creator process isn't the same as our embedder?");
      Canonical()->SetCurrentBrowserParent(
          mParentWindow->Canonical()->GetBrowserParent());
    }

    mGroup->EachOtherParent(aOriginProcess, [&](ContentParent* aParent) {
      MOZ_DIAGNOSTIC_ASSERT(IsContent(),
                            "chrome BCG cannot be synced to content process");
      if (!Canonical()->IsEmbeddedInProcess(aParent->ChildID())) {
        Unused << aParent->SendCreateBrowsingContext(mGroup->Id(),
                                                     GetIPCInitializer());
      }
    });

    if (IsTop() && IsContent() && Canonical()->GetWebProgress()) {
      why = u"replace";
    }

    // We want to create a BrowsingContextWebProgress for all content
    // BrowsingContexts.
    if (IsContent() && !Canonical()->mWebProgress) {
      Canonical()->mWebProgress = new BrowsingContextWebProgress(Canonical());
    }
  }

  if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
    obs->NotifyWhenScriptSafe(ToSupports(this), "browsing-context-attached",
                              why);
  }

  if (XRE_IsParentProcess()) {
    Canonical()->CanonicalAttach();
  }
}

void BrowsingContext::Detach(bool aFromIPC) {
  MOZ_LOG(GetLog(), LogLevel::Debug,
          ("%s: Detaching 0x%08" PRIx64 " from 0x%08" PRIx64,
           XRE_IsParentProcess() ? "Parent" : "Child", Id(),
           GetParent() ? GetParent()->Id() : 0));

  MOZ_DIAGNOSTIC_ASSERT(mEverAttached);
  MOZ_DIAGNOSTIC_ASSERT(!mIsDiscarded);

  if (XRE_IsParentProcess()) {
    Canonical()->AddPendingDiscard();
  }
  auto callListeners =
      MakeScopeExit([&, listeners = std::move(mDiscardListeners), id = Id()] {
        for (const auto& listener : listeners) {
          listener(id);
        }
        if (XRE_IsParentProcess()) {
          Canonical()->RemovePendingDiscard();
        }
      });

  nsCOMPtr<nsIRequestContextService> rcsvc =
      net::RequestContextService::GetOrCreate();
  if (rcsvc) {
    rcsvc->RemoveRequestContext(GetRequestContextId());
  }

  // This will only ever be null if the cycle-collector has unlinked us. Don't
  // try to detach ourselves in that case.
  if (NS_WARN_IF(!mGroup)) {
    MOZ_ASSERT_UNREACHABLE();
    return;
  }

  if (mParentWindow) {
    mParentWindow->RemoveChildBrowsingContext(this);
  } else {
    mGroup->Toplevels().RemoveElement(this);
  }

  if (XRE_IsParentProcess()) {
    RefPtr<CanonicalBrowsingContext> self{Canonical()};
    Group()->EachParent([&](ContentParent* aParent) {
      // Only the embedder process is allowed to initiate a BrowsingContext
      // detach, so if we've gotten here, the host process already knows we've
      // been detached, and there's no need to tell it again.
      //
      // If the owner process is not the same as the embedder process, its
      // BrowsingContext will be detached when its nsWebBrowser instance is
      // destroyed.
      bool doDiscard = !Canonical()->IsEmbeddedInProcess(aParent->ChildID()) &&
                       !Canonical()->IsOwnedByProcess(aParent->ChildID());

      // Hold a strong reference to ourself, and keep our BrowsingContextGroup
      // alive, until the responses comes back to ensure we don't die while
      // messages relating to this context are in-flight.
      //
      // When the callback is called, the keepalive on our group will be
      // destroyed, and the reference to the BrowsingContext will be dropped,
      // which may cause it to be fully destroyed.
      mGroup->AddKeepAlive();
      self->AddPendingDiscard();
      auto callback = [self](auto) {
        self->mGroup->RemoveKeepAlive();
        self->RemovePendingDiscard();
      };

      aParent->SendDiscardBrowsingContext(this, doDiscard, callback, callback);
    });
  } else {
    // Hold a strong reference to ourself until the responses come back to
    // ensure the BrowsingContext isn't cleaned up before the parent process
    // acknowledges the discard request.
    auto callback = [self = RefPtr{this}](auto) {};
    ContentChild::GetSingleton()->SendDiscardBrowsingContext(
        this, !aFromIPC, callback, callback);
  }

  mGroup->Unregister(this);
  UnregisterBrowserId(this);
  mIsDiscarded = true;

  if (XRE_IsParentProcess()) {
    nsFocusManager* fm = nsFocusManager::GetFocusManager();
    if (fm) {
      fm->BrowsingContextDetached(this);
    }
  }

  if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
    // Why the context is being discarded. This will always be "discard" in the
    // content process, but may be "replace" if it's known the context being
    // replaced in the parent process.
    const char16_t* why = u"discard";
    if (XRE_IsParentProcess() && IsTop() && !Canonical()->GetWebProgress()) {
      why = u"replace";
    }
    obs->NotifyObservers(ToSupports(this), "browsing-context-discarded", why);
  }

  // NOTE: Doesn't use SetClosed, as it will be set in all processes
  // automatically by calls to Detach()
  mFields.SetWithoutSyncing<IDX_Closed>(true);

  if (GetIsPopupSpam()) {
    PopupBlocker::UnregisterOpenPopupSpam();
    // NOTE: Doesn't use SetIsPopupSpam, as it will be set all processes
    // automatically.
    mFields.SetWithoutSyncing<IDX_IsPopupSpam>(false);
  }

  AssertOriginAttributesMatchPrivateBrowsing();

  if (XRE_IsParentProcess()) {
    Canonical()->CanonicalDiscard();
  }
}

void BrowsingContext::AddDiscardListener(
    std::function<void(uint64_t)>&& aListener) {
  if (mIsDiscarded) {
    aListener(Id());
    return;
  }
  mDiscardListeners.AppendElement(std::move(aListener));
}

void BrowsingContext::PrepareForProcessChange() {
  MOZ_LOG(GetLog(), LogLevel::Debug,
          ("%s: Preparing 0x%08" PRIx64 " for a process change",
           XRE_IsParentProcess() ? "Parent" : "Child", Id()));

  MOZ_ASSERT(mIsInProcess, "Must currently be an in-process frame");
  MOZ_ASSERT(!mIsDiscarded, "We're already closed?");

  mIsInProcess = false;
  mUserGestureStart = TimeStamp();

  ClearCachedValuesOfLocations();

  // NOTE: For now, clear our nsDocShell reference, as we're primarily in a
  // different process now. This may need to change in the future with
  // Cross-Process BFCache.
  mDocShell = nullptr;
  if (mChildSessionHistory) {
    // This can be removed once session history is stored exclusively in the
    // parent process.
    mChildSessionHistory->SetIsInProcess(false);
  }

  if (!mWindowProxy) {
    return;
  }

  // We have to go through mWindowProxy rather than calling GetDOMWindow() on
  // mDocShell because the mDocshell reference gets cleared immediately after
  // the window is closed.
  nsGlobalWindowOuter::PrepareForProcessChange(mWindowProxy);
  MOZ_ASSERT(!mWindowProxy);
}

bool BrowsingContext::IsTargetable() const {
  return !GetClosed() && AncestorsAreCurrent();
}

void BrowsingContext::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));

  if (IsChrome() && IsTop() && aOpener) {
    // Inherit color scheme overrides from parent window. This is to inherit the
    // color scheme of dark themed PBM windows in dialogs opened by such
    // windows.
    auto openerOverride = aOpener->Top()->PrefersColorSchemeOverride();
    if (openerOverride != PrefersColorSchemeOverride()) {
      MOZ_ALWAYS_SUCCEEDS(SetPrefersColorSchemeOverride(openerOverride));
    }
  }
}

bool BrowsingContext::HasOpener() const {
  return sBrowsingContexts->Contains(GetOpenerId());
}

bool BrowsingContext::AncestorsAreCurrent() const {
  const BrowsingContext* bc = this;
  while (true) {
    if (bc->IsDiscarded()) {
      return false;
    }

    if (WindowContext* wc = bc->GetParentWindowContext()) {
      if (!wc->IsCurrent() || wc->IsDiscarded()) {
        return false;
      }

      bc = wc->GetBrowsingContext();
    } else {
      return true;
    }
  }
}

bool BrowsingContext::IsInBFCache() const {
  if (mozilla::SessionHistoryInParent()) {
    return mIsInBFCache;
  }
  return mParentWindow &&
         mParentWindow->TopWindowContext()->GetWindowStateSaved();
}

Span<RefPtr<BrowsingContext>> BrowsingContext::Children() const {
  if (WindowContext* current = mCurrentWindowContext) {
    return current->Children();
  }
  return Span<RefPtr<BrowsingContext>>();
}

void BrowsingContext::GetChildren(
    nsTArray<RefPtr<BrowsingContext>>& aChildren) {
  aChildren.AppendElements(Children());
}

Span<RefPtr<BrowsingContext>> BrowsingContext::NonSyntheticChildren() const {
  if (WindowContext* current = mCurrentWindowContext) {
    return current->NonSyntheticChildren();
  }
  return Span<RefPtr<BrowsingContext>>();
}

void BrowsingContext::GetWindowContexts(
    nsTArray<RefPtr<WindowContext>>& aWindows) {
  aWindows.AppendElements(mWindowContexts);
}

void BrowsingContext::RegisterWindowContext(WindowContext* aWindow) {
  MOZ_ASSERT(!mWindowContexts.Contains(aWindow),
             "WindowContext already registered!");
  MOZ_ASSERT(aWindow->GetBrowsingContext() == this);

  mWindowContexts.AppendElement(aWindow);

  // If the newly registered WindowContext is for our current inner window ID,
  // re-run the `DidSet` handler to re-establish the relationship.
  if (aWindow->InnerWindowId() == GetCurrentInnerWindowId()) {
    DidSet(FieldIndex<IDX_CurrentInnerWindowId>());
    MOZ_DIAGNOSTIC_ASSERT(mCurrentWindowContext == aWindow);
  }
}

void BrowsingContext::UnregisterWindowContext(WindowContext* aWindow) {
  MOZ_ASSERT(mWindowContexts.Contains(aWindow),
             "WindowContext not registered!");
  mWindowContexts.RemoveElement(aWindow);

  // If our currently active window was unregistered, clear our reference to it.
  if (aWindow == mCurrentWindowContext) {
    // Re-read our `CurrentInnerWindowId` value and use it to set
    // `mCurrentWindowContext`. As `aWindow` is now unregistered and discarded,
    // we won't find it, and the value will be cleared back to `nullptr`.
    DidSet(FieldIndex<IDX_CurrentInnerWindowId>());
    MOZ_DIAGNOSTIC_ASSERT(mCurrentWindowContext == nullptr);
  }
}

void BrowsingContext::PreOrderWalkVoid(
    const std::function<void(BrowsingContext*)>& aCallback) {
  aCallback(this);

  AutoTArray<RefPtr<BrowsingContext>, 8> children;
  children.AppendElements(Children());

  for (auto& child : children) {
    child->PreOrderWalkVoid(aCallback);
  }
}

BrowsingContext::WalkFlag BrowsingContext::PreOrderWalkFlag(
    const std::function<WalkFlag(BrowsingContext*)>& aCallback) {
  switch (aCallback(this)) {
    case WalkFlag::Skip:
      return WalkFlag::Next;
    case WalkFlag::Stop:
      return WalkFlag::Stop;
    case WalkFlag::Next:
    default:
      break;
  }

  AutoTArray<RefPtr<BrowsingContext>, 8> children;
  children.AppendElements(Children());

  for (auto& child : children) {
    switch (child->PreOrderWalkFlag(aCallback)) {
      case WalkFlag::Stop:
        return WalkFlag::Stop;
      default:
        break;
    }
  }

  return WalkFlag::Next;
}

void BrowsingContext::PostOrderWalk(
    const std::function<void(BrowsingContext*)>& aCallback) {
  AutoTArray<RefPtr<BrowsingContext>, 8> children;
  children.AppendElements(Children());

  for (auto& child : children) {
    child->PostOrderWalk(aCallback);
  }

  aCallback(this);
}

void BrowsingContext::GetAllBrowsingContextsInSubtree(
    nsTArray<RefPtr<BrowsingContext>>& aBrowsingContexts) {
  PreOrderWalk([&](BrowsingContext* aContext) {
    aBrowsingContexts.AppendElement(aContext);
  });
}

BrowsingContext* BrowsingContext::FindChildWithName(
    const nsAString& aName, WindowGlobalChild& aRequestingWindow) {
  if (aName.IsEmpty()) {
    // You can't find a browsing context with the empty name.
    return nullptr;
  }

  for (BrowsingContext* child : NonSyntheticChildren()) {
    if (child->NameEquals(aName) && aRequestingWindow.CanNavigate(child) &&
        child->IsTargetable()) {
      return child;
    }
  }

  return nullptr;
}

BrowsingContext* BrowsingContext::FindWithSpecialName(
    const nsAString& aName, WindowGlobalChild& aRequestingWindow) {
  // TODO(farre): Neither BrowsingContext nor nsDocShell checks if the
  // browsing context pointed to by a special name is active. Should
  // it be? See Bug 1527913.
  if (aName.LowerCaseEqualsLiteral("_self")) {
    return this;
  }

  if (aName.LowerCaseEqualsLiteral("_parent")) {
    if (BrowsingContext* parent = GetParent()) {
      return aRequestingWindow.CanNavigate(parent) ? parent : nullptr;
    }
    return this;
  }

  if (aName.LowerCaseEqualsLiteral("_top")) {
    BrowsingContext* top = Top();

    return aRequestingWindow.CanNavigate(top) ? top : nullptr;
  }

  return nullptr;
}

BrowsingContext* BrowsingContext::FindWithNameInSubtree(
    const nsAString& aName, WindowGlobalChild* aRequestingWindow) {
  MOZ_DIAGNOSTIC_ASSERT(!aName.IsEmpty());

  if (NameEquals(aName) &&
      (!aRequestingWindow || aRequestingWindow->CanNavigate(this)) &&
      IsTargetable()) {
    return this;
  }

  for (BrowsingContext* child : NonSyntheticChildren()) {
    if (BrowsingContext* found =
            child->FindWithNameInSubtree(aName, aRequestingWindow)) {
      return found;
    }
  }

  return nullptr;
}

bool BrowsingContext::IsSandboxedFrom(BrowsingContext* aTarget) {
  // If no target then not sandboxed.
  if (!aTarget) {
    return false;
  }

  // We cannot be sandboxed from ourselves.
  if (aTarget == this) {
    return false;
  }

  // Default the sandbox flags to our flags, so that if we can't retrieve the
  // active document, we will still enforce our own.
  uint32_t sandboxFlags = GetSandboxFlags();
  if (mDocShell) {
    if (RefPtr<Document> doc = mDocShell->GetExtantDocument()) {
      sandboxFlags = doc->GetSandboxFlags();
    }
  }

  // If no flags, we are not sandboxed at all.
  if (!sandboxFlags) {
    return false;
  }

  // If aTarget has an ancestor, it is not top level.
  if (RefPtr<BrowsingContext> ancestorOfTarget = aTarget->GetParent()) {
    do {
      // We are not sandboxed if we are an ancestor of target.
      if (ancestorOfTarget == this) {
        return false;
      }
      ancestorOfTarget = ancestorOfTarget->GetParent();
    } while (ancestorOfTarget);

    // Otherwise, we are sandboxed from aTarget.
    return true;
  }

  // aTarget is top level, are we the "one permitted sandboxed
  // navigator", i.e. did we open aTarget?
  if (aTarget->GetOnePermittedSandboxedNavigatorId() == Id()) {
    return false;
  }

  // If SANDBOXED_TOPLEVEL_NAVIGATION flag is not on, we are not sandboxed
  // from our top.
  if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION) && aTarget == Top()) {
    return false;
  }

  // If SANDBOXED_TOPLEVEL_NAVIGATION_USER_ACTIVATION flag is not on, we are not
  // sandboxed from our top if we have user interaction. We assume there is a
  // valid transient user gesture interaction if this check happens in the
  // target process given that we have checked in the triggering process
  // already.
  if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION_USER_ACTIVATION) &&
      mCurrentWindowContext &&
      (!mCurrentWindowContext->IsInProcess() ||
       mCurrentWindowContext->HasValidTransientUserGestureActivation()) &&
      aTarget == Top()) {
    return false;
  }

  // Otherwise, we are sandboxed from aTarget.
  return true;
}

RefPtr<SessionStorageManager> BrowsingContext::GetSessionStorageManager() {
  RefPtr<SessionStorageManager>& manager = Top()->mSessionStorageManager;
  if (!manager) {
    manager = new SessionStorageManager(this);
  }
  return manager;
}

bool BrowsingContext::CrossOriginIsolated() {
  MOZ_ASSERT(NS_IsMainThread());

  return StaticPrefs::
             dom_postMessage_sharedArrayBuffer_withCOOP_COEP_AtStartup() &&
         Top()->GetOpenerPolicy() ==
             nsILoadInfo::
                 OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP &&
         XRE_IsContentProcess() &&
         StringBeginsWith(ContentChild::GetSingleton()->GetRemoteType(),
                          WITH_COOP_COEP_REMOTE_TYPE_PREFIX);
}

void BrowsingContext::SetTriggeringAndInheritPrincipals(
    nsIPrincipal* aTriggeringPrincipal, nsIPrincipal* aPrincipalToInherit,
    uint64_t aLoadIdentifier) {
  mTriggeringPrincipal = Some(
      PrincipalWithLoadIdentifierTuple(aTriggeringPrincipal, aLoadIdentifier));
  if (aPrincipalToInherit) {
    mPrincipalToInherit = Some(
        PrincipalWithLoadIdentifierTuple(aPrincipalToInherit, aLoadIdentifier));
  }
}

std::tuple<nsCOMPtr<nsIPrincipal>, nsCOMPtr<nsIPrincipal>>
BrowsingContext::GetTriggeringAndInheritPrincipalsForCurrentLoad() {
  nsCOMPtr<nsIPrincipal> triggeringPrincipal =
      GetSavedPrincipal(mTriggeringPrincipal);
  nsCOMPtr<nsIPrincipal> principalToInherit =
      GetSavedPrincipal(mPrincipalToInherit);
  return std::make_tuple(triggeringPrincipal, principalToInherit);
}

nsIPrincipal* BrowsingContext::GetSavedPrincipal(
    Maybe<PrincipalWithLoadIdentifierTuple> aPrincipalTuple) {
  if (aPrincipalTuple) {
    nsCOMPtr<nsIPrincipal> principal;
    uint64_t loadIdentifier;
    std::tie(principal, loadIdentifier) = *aPrincipalTuple;
    // We want to return a principal only if the load identifier for it
    // matches the current one for this BC.
    if (auto current = GetCurrentLoadIdentifier();
        current && *current == loadIdentifier) {
      return principal;
    }
  }
  return nullptr;
}

BrowsingContext::~BrowsingContext() {
  MOZ_DIAGNOSTIC_ASSERT(!mParentWindow ||
                        !mParentWindow->mChildren.Contains(this));
  MOZ_DIAGNOSTIC_ASSERT(!mGroup || !mGroup->Toplevels().Contains(this));

  mDeprioritizedLoadRunner.clear();

  if (sBrowsingContexts) {
    sBrowsingContexts->Remove(Id());
  }
  UnregisterBrowserId(this);

  ClearCachedValuesOfLocations();
  mLocations.clear();
}

/* static */
void BrowsingContext::DiscardFromContentParent(ContentParent* aCP) {
  MOZ_ASSERT(XRE_IsParentProcess());

  if (sBrowsingContexts) {
    AutoTArray<RefPtr<BrowsingContext>, 8> toDiscard;
    for (const auto& data : sBrowsingContexts->Values()) {
      auto* bc = data->Canonical();
      if (!bc->IsDiscarded() && bc->IsEmbeddedInProcess(aCP->ChildID())) {
        toDiscard.AppendElement(bc);
      }
    }

    for (BrowsingContext* bc : toDiscard) {
      bc->Detach(/* aFromIPC */ true);
    }
  }
}

nsISupports* BrowsingContext::GetParentObject() const {
  return xpc::NativeGlobal(xpc::PrivilegedJunkScope());
}

JSObject* BrowsingContext::WrapObject(JSContext* aCx,
                                      JS::Handle<JSObject*> aGivenProto) {
  return BrowsingContext_Binding::Wrap(aCx, this, aGivenProto);
}

bool BrowsingContext::WriteStructuredClone(JSContext* aCx,
                                           JSStructuredCloneWriter* aWriter,
                                           StructuredCloneHolder* aHolder) {
  MOZ_DIAGNOSTIC_ASSERT(mEverAttached);
  return (JS_WriteUint32Pair(aWriter, SCTAG_DOM_BROWSING_CONTEXT, 0) &&
          JS_WriteUint32Pair(aWriter, uint32_t(Id()), uint32_t(Id() >> 32)));
}

/* static */
JSObject* BrowsingContext::ReadStructuredClone(JSContext* aCx,
                                               JSStructuredCloneReader* aReader,
                                               StructuredCloneHolder* aHolder) {
  uint32_t idLow = 0;
  uint32_t idHigh = 0;
  if (!JS_ReadUint32Pair(aReader, &idLow, &idHigh)) {
    return nullptr;
  }
  uint64_t id = uint64_t(idHigh) << 32 | idLow;

  // Note: Do this check after reading our ID data. Returning null will abort
  // the decode operation anyway, but we should at least be as safe as possible.
  if (NS_WARN_IF(!NS_IsMainThread())) {
    MOZ_DIAGNOSTIC_CRASH(
        "We shouldn't be trying to decode a BrowsingContext "
        "on a background thread.");
    return nullptr;
  }

  JS::Rooted<JS::Value> val(aCx, JS::NullValue());
  // We'll get rooting hazard errors from the RefPtr destructor if it isn't
  // destroyed before we try to return a raw JSObject*, so create it in its own
  // scope.
  if (RefPtr<BrowsingContext> context = Get(id)) {
    if (!GetOrCreateDOMReflector(aCx, context, &val) || !val.isObject()) {
      return nullptr;
    }
  }
  return val.toObjectOrNull();
}

bool BrowsingContext::CanSetOriginAttributes() {
  // A discarded BrowsingContext has already been destroyed, and cannot modify
  // its OriginAttributes.
  if (NS_WARN_IF(IsDiscarded())) {
    return false;
  }

  // Before attaching is the safest time to set OriginAttributes, and the only
  // allowed time for content BrowsingContexts.
  if (!EverAttached()) {
    return true;
  }

  // Attached content BrowsingContexts may have been synced to other processes.
  if (NS_WARN_IF(IsContent())) {
    MOZ_CRASH();
    return false;
  }
  MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());

  // Cannot set OriginAttributes after we've created our child BrowsingContext.
  if (NS_WARN_IF(!Children().IsEmpty())) {
    return false;
  }

  // Only allow setting OriginAttributes if we have no associated document, or
  // the document is still `about:blank`.
  // TODO: Bug 1273058 - should have no document when setting origin attributes.
  if (WindowGlobalParent* window = Canonical()->GetCurrentWindowGlobal()) {
    if (nsIURI* uri = window->GetDocumentURI()) {
      MOZ_ASSERT(NS_IsAboutBlank(uri));
      return NS_IsAboutBlank(uri);
    }
  }
  return true;
}

Nullable<WindowProxyHolder> BrowsingContext::GetAssociatedWindow() {
  // nsILoadContext usually only returns same-process windows,
  // so we intentionally return nullptr if this BC is out of
  // process.
  if (IsInProcess()) {
    return WindowProxyHolder(this);
  }
  return nullptr;
}

Nullable<WindowProxyHolder> BrowsingContext::GetTopWindow() {
  return Top()->GetAssociatedWindow();
}

Element* BrowsingContext::GetTopFrameElement() {
  return Top()->GetEmbedderElement();
}

void BrowsingContext::SetUsePrivateBrowsing(bool aUsePrivateBrowsing,
                                            ErrorResult& aError) {
  nsresult rv = SetUsePrivateBrowsing(aUsePrivateBrowsing);
  if (NS_FAILED(rv)) {
    aError.Throw(rv);
  }
}

void BrowsingContext::SetUseTrackingProtectionWebIDL(
    bool aUseTrackingProtection, ErrorResult& aRv) {
  SetForceEnableTrackingProtection(aUseTrackingProtection, aRv);
}

void BrowsingContext::GetOriginAttributes(JSContext* aCx,
                                          JS::MutableHandle<JS::Value> aVal,
                                          ErrorResult& aError) {
  AssertOriginAttributesMatchPrivateBrowsing();

  if (!ToJSValue(aCx, mOriginAttributes, aVal)) {
    aError.NoteJSContextException(aCx);
  }
}

NS_IMETHODIMP BrowsingContext::GetAssociatedWindow(
    mozIDOMWindowProxy** aAssociatedWindow) {
  nsCOMPtr<mozIDOMWindowProxy> win = GetDOMWindow();
  win.forget(aAssociatedWindow);
  return NS_OK;
}

NS_IMETHODIMP BrowsingContext::GetTopWindow(mozIDOMWindowProxy** aTopWindow) {
  return Top()->GetAssociatedWindow(aTopWindow);
}

NS_IMETHODIMP BrowsingContext::GetTopFrameElement(Element** aTopFrameElement) {
  RefPtr<Element> topFrameElement = GetTopFrameElement();
  topFrameElement.forget(aTopFrameElement);
  return NS_OK;
}

NS_IMETHODIMP BrowsingContext::GetIsContent(bool* aIsContent) {
  *aIsContent = IsContent();
  return NS_OK;
}

NS_IMETHODIMP BrowsingContext::GetUsePrivateBrowsing(
    bool* aUsePrivateBrowsing) {
  *aUsePrivateBrowsing = mPrivateBrowsingId > 0;
  return NS_OK;
}

NS_IMETHODIMP BrowsingContext::SetUsePrivateBrowsing(bool aUsePrivateBrowsing) {
  if (!CanSetOriginAttributes()) {
    bool changed = aUsePrivateBrowsing != (mPrivateBrowsingId > 0);
    if (changed) {
      NS_WARNING("SetUsePrivateBrowsing when !CanSetOriginAttributes()");
    }
    return changed ? NS_ERROR_FAILURE : NS_OK;
  }

  return SetPrivateBrowsing(aUsePrivateBrowsing);
}

NS_IMETHODIMP BrowsingContext::SetPrivateBrowsing(bool aPrivateBrowsing) {
  if (!CanSetOriginAttributes()) {
    NS_WARNING("Attempt to set PrivateBrowsing when !CanSetOriginAttributes");
    return NS_ERROR_FAILURE;
  }

  bool changed = aPrivateBrowsing != (mPrivateBrowsingId > 0);
  if (changed) {
    mPrivateBrowsingId = aPrivateBrowsing ? 1 : 0;
    if (IsContent()) {
      mOriginAttributes.SyncAttributesWithPrivateBrowsing(aPrivateBrowsing);
    }

    if (XRE_IsParentProcess()) {
      Canonical()->AdjustPrivateBrowsingCount(aPrivateBrowsing);
    }
  }
  AssertOriginAttributesMatchPrivateBrowsing();

  if (changed && mDocShell) {
    nsDocShell::Cast(mDocShell)->NotifyPrivateBrowsingChanged();
  }
  return NS_OK;
}

NS_IMETHODIMP BrowsingContext::GetUseRemoteTabs(bool* aUseRemoteTabs) {
  *aUseRemoteTabs = mUseRemoteTabs;
  return NS_OK;
}

NS_IMETHODIMP BrowsingContext::SetRemoteTabs(bool aUseRemoteTabs) {
  if (!CanSetOriginAttributes()) {
    NS_WARNING("Attempt to set RemoteTabs when !CanSetOriginAttributes");
    return NS_ERROR_FAILURE;
  }

  if (aUseRemoteTabs && !gIPCEnabledAnnotation) {
    gIPCEnabledAnnotation = true;
  }

  // Don't allow non-remote tabs with remote subframes.
  if (NS_WARN_IF(!aUseRemoteTabs && mUseRemoteSubframes)) {
    return NS_ERROR_UNEXPECTED;
  }

  mUseRemoteTabs = aUseRemoteTabs;
  return NS_OK;
}

NS_IMETHODIMP BrowsingContext::GetUseRemoteSubframes(
    bool* aUseRemoteSubframes) {
  *aUseRemoteSubframes = mUseRemoteSubframes;
  return NS_OK;
}

NS_IMETHODIMP BrowsingContext::SetRemoteSubframes(bool aUseRemoteSubframes) {
  if (!CanSetOriginAttributes()) {
    NS_WARNING("Attempt to set RemoteSubframes when !CanSetOriginAttributes");
    return NS_ERROR_FAILURE;
  }

  if (aUseRemoteSubframes && !gFissionEnabledAnnotation) {
    gFissionEnabledAnnotation = true;
  }

  // Don't allow non-remote tabs with remote subframes.
  if (NS_WARN_IF(aUseRemoteSubframes && !mUseRemoteTabs)) {
    return NS_ERROR_UNEXPECTED;
  }

  mUseRemoteSubframes = aUseRemoteSubframes;
  return NS_OK;
}

NS_IMETHODIMP BrowsingContext::GetUseTrackingProtection(
    bool* aUseTrackingProtection) {
  *aUseTrackingProtection = false;

  if (GetForceEnableTrackingProtection() ||
      StaticPrefs::privacy_trackingprotection_enabled() ||
      (UsePrivateBrowsing() &&
       StaticPrefs::privacy_trackingprotection_pbmode_enabled())) {
    *aUseTrackingProtection = true;
    return NS_OK;
  }

  if (GetParent()) {
    return GetParent()->GetUseTrackingProtection(aUseTrackingProtection);
  }

  return NS_OK;
}

NS_IMETHODIMP BrowsingContext::SetUseTrackingProtection(
    bool aUseTrackingProtection) {
  return SetForceEnableTrackingProtection(aUseTrackingProtection);
}

NS_IMETHODIMP BrowsingContext::GetScriptableOriginAttributes(
    JSContext* aCx, JS::MutableHandle<JS::Value> aVal) {
  AssertOriginAttributesMatchPrivateBrowsing();

  bool ok = ToJSValue(aCx, mOriginAttributes, aVal);
  NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
  return NS_OK;
}

NS_IMETHODIMP_(void)
BrowsingContext::GetOriginAttributes(OriginAttributes& aAttrs) {
  aAttrs = mOriginAttributes;
  AssertOriginAttributesMatchPrivateBrowsing();
}

nsresult BrowsingContext::SetOriginAttributes(const OriginAttributes& aAttrs) {
  if (!CanSetOriginAttributes()) {
    NS_WARNING("Attempt to set OriginAttributes when !CanSetOriginAttributes");
    return NS_ERROR_FAILURE;
  }

  AssertOriginAttributesMatchPrivateBrowsing();
  mOriginAttributes = aAttrs;

  bool isPrivate = mOriginAttributes.mPrivateBrowsingId !=
                   nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID;
  // Chrome Browsing Context can not contain OriginAttributes.mPrivateBrowsingId
  if (IsChrome() && isPrivate) {
    mOriginAttributes.mPrivateBrowsingId =
        nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID;
  }
  SetPrivateBrowsing(isPrivate);
  AssertOriginAttributesMatchPrivateBrowsing();

  return NS_OK;
}

void BrowsingContext::AssertOriginAttributesMatchPrivateBrowsing() {
  // Chrome browsing contexts must not have a private browsing OriginAttribute
  // Content browsing contexts must maintain the equality:
  // mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId
  if (IsChrome()) {
    MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes.mPrivateBrowsingId == 0);
  } else {
    MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes.mPrivateBrowsingId ==
                          mPrivateBrowsingId);
  }
}

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BrowsingContext)
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  NS_INTERFACE_MAP_ENTRY(nsILoadContext)
  NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

NS_IMPL_CYCLE_COLLECTION_CLASS(BrowsingContext)

NS_IMPL_CYCLE_COLLECTING_ADDREF(BrowsingContext)
NS_IMPL_CYCLE_COLLECTING_RELEASE(BrowsingContext)

NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(BrowsingContext)
  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_END

NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowsingContext)
  if (sBrowsingContexts) {
    sBrowsingContexts->Remove(tmp->Id());
  }
  UnregisterBrowserId(tmp);

  if (tmp->GetIsPopupSpam()) {
    PopupBlocker::UnregisterOpenPopupSpam();
    // NOTE: Doesn't use SetIsPopupSpam, as it will be set all processes
    // automatically.
    tmp->mFields.SetWithoutSyncing<IDX_IsPopupSpam>(false);
  }

  NS_IMPL_CYCLE_COLLECTION_UNLINK(
      mDocShell, mParentWindow, mGroup, mEmbedderElement, mWindowContexts,
      mCurrentWindowContext, mSessionStorageManager, mChildSessionHistory)
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowsingContext)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
      mDocShell, mParentWindow, mGroup, mEmbedderElement, mWindowContexts,
      mCurrentWindowContext, mSessionStorageManager, mChildSessionHistory)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

static bool IsCertainlyAliveForCC(BrowsingContext* aContext) {
  return aContext->HasKnownLiveWrapper() ||
         (AppShutdown::GetCurrentShutdownPhase() ==
              ShutdownPhase::NotInShutdown &&
          aContext->EverAttached() && !aContext->IsDiscarded());
}

NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(BrowsingContext)
  if (IsCertainlyAliveForCC(tmp)) {
    if (tmp->PreservingWrapper()) {
      tmp->MarkWrapperLive();
    }
    return true;
  }
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END

NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(BrowsingContext)
  return IsCertainlyAliveForCC(tmp) && tmp->HasNothingToTrace(tmp);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END

NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(BrowsingContext)
  return IsCertainlyAliveForCC(tmp);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END

class RemoteLocationProxy
    : public RemoteObjectProxy<BrowsingContext::LocationProxy,
                               Location_Binding::sCrossOriginProperties> {
 public:
  typedef RemoteObjectProxy Base;

  constexpr RemoteLocationProxy()
      : RemoteObjectProxy(prototypes::id::Location) {}

  void NoteChildren(JSObject* aProxy,
                    nsCycleCollectionTraversalCallback& aCb) const override {
    auto location =
        static_cast<BrowsingContext::LocationProxy*>(GetNative(aProxy));
    CycleCollectionNoteChild(aCb, location->GetBrowsingContext(),
                             "JS::GetPrivate(obj)->GetBrowsingContext()");
  }
};

static const RemoteLocationProxy sSingleton;

// Give RemoteLocationProxy 2 reserved slots, like the other wrappers,
// so JSObject::swap can swap it with CrossCompartmentWrappers without requiring
// malloc.
template <>
const JSClass RemoteLocationProxy::Base::sClass =
    PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_RESERVED_SLOTS(2));

void BrowsingContext::Location(JSContext* aCx,
--> --------------------

--> maximum size reached

--> --------------------

95%


¤ Dauer der Verarbeitung: 0.34 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.