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

SSL nsGlobalWindowInner.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 "nsGlobalWindowInner.h"

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdint>
#include <new>
#include <type_traits>
#include <utility>
#include "AudioChannelService.h"
#include "AutoplayPolicy.h"
#include "Crypto.h"
#include "MainThreadUtils.h"
#include "Navigator.h"
#include "PaintWorkletImpl.h"
#include "SessionStorageCache.h"
#include "Units.h"
#include "VRManagerChild.h"
#include "WindowDestroyedEvent.h"
#include "WindowNamedPropertiesHandler.h"
#include "js/ComparisonOperators.h"
#include "js/CompilationAndEvaluation.h"
#include "js/CompileOptions.h"
#include "js/friend/PerformanceHint.h"
#include "js/Id.h"
#include "js/loader/LoadedScript.h"
#include "js/PropertyAndElement.h"  // JS_DefineProperty, JS_GetProperty
#include "js/PropertyDescriptor.h"
#include "js/RealmOptions.h"
#include "js/RootingAPI.h"
#include "js/TypeDecls.h"
#include "js/Value.h"
#include "js/Warnings.h"
#include "js/shadow/String.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "mozIDOMWindow.h"
#include "moz_external_vr.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/ArrayIterator.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/BaseProfilerMarkersPrerequisites.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/BounceTrackingStorageObserver.h"
#include "mozilla/CallState.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/EventQueue.h"
#include "mozilla/ExtensionPolicyService.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/FlushType.h"
#include "mozilla/Likely.h"
#include "mozilla/LinkedList.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/Logging.h"
#include "mozilla/MacroForEach.h"
#include "mozilla/Maybe.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/PermissionDelegateHandler.h"
#include "mozilla/Preferences.h"
#include "mozilla/PresShell.h"
#include "mozilla/ProcessHangMonitor.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Result.h"
#include "mozilla/ScrollContainerFrame.h"
#include "mozilla/ScrollTypes.h"
#include "mozilla/Components.h"
#include "mozilla/SizeOfState.h"
#include "mozilla/Span.h"
#include "mozilla/SpinEventLoopUntil.h"
#include "mozilla/Sprintf.h"
#include "mozilla/StaticPrefs_browser.h"
#include "mozilla/StaticPrefs_docshell.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_extensions.h"
#include "mozilla/StaticPrefs_privacy.h"
#include "mozilla/StorageAccess.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TelemetryHistogramEnums.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/AudioContext.h"
#include "mozilla/dom/AutoEntryScript.h"
#include "mozilla/dom/BarProps.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/BrowserChild.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/Credential.h"
#include "mozilla/dom/CSPEvalChecker.h"
#include "mozilla/dom/CallbackDebuggerNotification.h"
#include "mozilla/dom/ChromeMessageBroadcaster.h"
#include "mozilla/dom/ClientInfo.h"
#include "mozilla/dom/ClientManager.h"
#include "mozilla/dom/ClientSource.h"
#include "mozilla/dom/ClientState.h"
#include "mozilla/dom/ClientsBinding.h"
#include "mozilla/dom/CloseWatcher.h"
#include "mozilla/dom/CloseWatcherManager.h"
#include "mozilla/dom/Console.h"
#include "mozilla/dom/CookieStore.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentFrameMessageManager.h"
#include "mozilla/dom/ContentMediaController.h"
#include "mozilla/dom/CustomElementRegistry.h"
#include "mozilla/dom/DebuggerNotification.h"
#include "mozilla/dom/DebuggerNotificationBinding.h"
#include "mozilla/dom/DebuggerNotificationManager.h"
#include "mozilla/dom/DocGroup.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/EventTarget.h"
#include "mozilla/dom/External.h"
#include "mozilla/dom/Fetch.h"
#include "mozilla/dom/Gamepad.h"
#include "mozilla/dom/GamepadHandle.h"
#include "mozilla/dom/GamepadManager.h"
#include "mozilla/dom/HashChangeEvent.h"
#include "mozilla/dom/HashChangeEventBinding.h"
#include "mozilla/dom/IDBFactory.h"
#include "mozilla/dom/IdleRequest.h"
#include "mozilla/dom/ImageBitmap.h"
#include "mozilla/dom/ImageBitmapSource.h"
#include "mozilla/dom/InstallTriggerBinding.h"
#include "mozilla/dom/IntlUtils.h"
#include "mozilla/dom/JSExecutionUtils.h"  // mozilla::dom::Compile, mozilla::dom::EvaluationExceptionToNSResult
#include "mozilla/dom/LSObject.h"
#include "mozilla/dom/LocalStorage.h"
#include "mozilla/dom/LocalStorageCommon.h"
#include "mozilla/dom/Location.h"
#include "mozilla/dom/MediaDevices.h"
#include "mozilla/dom/MediaKeys.h"
#include "mozilla/dom/Navigation.h"
#include "mozilla/dom/NavigatorBinding.h"
#include "mozilla/dom/Nullable.h"
#include "mozilla/dom/PartitionedLocalStorage.h"
#include "mozilla/dom/Performance.h"
#include "mozilla/dom/PerformanceMainThread.h"
#include "mozilla/dom/PopStateEvent.h"
#include "mozilla/dom/PopStateEventBinding.h"
#include "mozilla/dom/PopupBlocker.h"
#include "mozilla/dom/PrimitiveConversions.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/RootedDictionary.h"
#include "mozilla/dom/WebTaskSchedulerMainThread.h"
#include "mozilla/dom/ScriptLoader.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/ServiceWorker.h"
#include "mozilla/dom/ServiceWorkerDescriptor.h"
#include "mozilla/dom/ServiceWorkerRegistration.h"
#include "mozilla/dom/SessionStorageManager.h"
#include "mozilla/dom/SharedWorker.h"
#include "mozilla/dom/Storage.h"
#include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h"
#include "mozilla/dom/StorageNotifierService.h"
#include "mozilla/dom/StorageUtils.h"
#include "mozilla/dom/TabMessageTypes.h"
#include "mozilla/dom/Timeout.h"
#include "mozilla/dom/TimeoutHandler.h"
#include "mozilla/dom/TimeoutManager.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/dom/TrustedTypePolicyFactory.h"
#include "mozilla/dom/TrustedTypeUtils.h"
#include "mozilla/dom/TrustedTypesConstants.h"
#include "mozilla/dom/VRDisplay.h"
#include "mozilla/dom/VRDisplayEvent.h"
#include "mozilla/dom/VRDisplayEventBinding.h"
#include "mozilla/dom/VREventObserver.h"
#include "mozilla/dom/VisualViewport.h"
#include "mozilla/dom/WebIDLGlobalNameHash.h"
#include "mozilla/dom/WindowBinding.h"
#include "mozilla/dom/WindowContext.h"
#include "mozilla/dom/WindowGlobalChild.h"
#include "mozilla/dom/WindowOrWorkerGlobalScopeBinding.h"
#include "mozilla/dom/WindowProxyHolder.h"
#include "mozilla/dom/WorkerCommon.h"
#include "mozilla/dom/Worklet.h"
#include "mozilla/dom/XRPermissionRequest.h"
#include "mozilla/dom/cache/CacheStorage.h"
#include "mozilla/dom/cache/Types.h"
#include "mozilla/glean/bindings/Glean.h"
#include "mozilla/glean/bindings/GleanPings.h"
#include "mozilla/extensions/WebExtensionPolicy.h"
#include "mozilla/fallible.h"
#include "mozilla/gfx/BasePoint.h"
#include "mozilla/gfx/BaseRect.h"
#include "mozilla/gfx/BaseSize.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/intl/LocaleService.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "mozilla/net/CookieJarSettings.h"
#include "nsAtom.h"
#include "nsBaseHashtable.h"
#include "nsCCUncollectableMarker.h"
#include "nsCOMPtr.h"
#include "nsCRT.h"
#include "nsCRTGlue.h"
#include "nsCanvasFrame.h"
#include "nsCharTraits.h"
#include "nsCheapSets.h"
#include "nsContentUtils.h"
#include "nsCoord.h"
#include "nsCycleCollectionNoteChild.h"
#include "nsCycleCollectionTraversalCallback.h"
#include "nsDOMNavigationTiming.h"
#include "nsDebug.h"
#include "nsDeviceContext.h"
#include "nsDocShell.h"
#include "nsFocusManager.h"
#include "nsFrameMessageManager.h"
#include "nsGkAtoms.h"
#include "nsGlobalWindowOuter.h"
#include "nsHashKeys.h"
#include "nsHistory.h"
#include "nsIAddonPolicyService.h"
#include "nsIArray.h"
#include "nsIBaseWindow.h"
#include "nsIBrowserChild.h"
#include "nsICancelableRunnable.h"
#include "nsIChannel.h"
#include "nsIClipboard.h"
#include "nsIContentSecurityPolicy.h"
#include "nsIControllers.h"
#include "nsICookieJarSettings.h"
#include "nsICookieService.h"
#include "nsID.h"
#include "nsIDOMStorageManager.h"
#include "nsIDeviceSensors.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIDocumentLoader.h"
#include "nsIDragService.h"
#include "nsIFocusManager.h"
#include "nsIFrame.h"
#include "nsIGlobalObject.h"
#include "nsIIOService.h"
#include "nsIIdleRunnable.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsILoadContext.h"
#include "nsILoadGroup.h"
#include "nsILoadInfo.h"
#include "nsINamed.h"
#include "nsINode.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsIPermission.h"
#include "nsIPermissionManager.h"
#include "nsIPrefBranch.h"
#include "nsIPrincipal.h"
#include "nsIPrompt.h"
#include "nsIRunnable.h"
#include "nsIScreen.h"
#include "nsIScreenManager.h"
#include "nsIScriptContext.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsISerialEventTarget.h"
#include "nsISimpleEnumerator.h"
#include "nsISizeOfEventTarget.h"
#include "nsISlowScriptDebug.h"
#include "nsISupportsUtils.h"
#include "nsIThread.h"
#include "nsITimedChannel.h"
#include "nsIURI.h"
#include "nsIWeakReference.h"
#include "nsIWebBrowserChrome.h"
#include "nsIWebNavigation.h"
#include "nsIWebProgressListener.h"
#include "nsIWidget.h"
#include "nsIWidgetListener.h"
#include "nsIXULRuntime.h"
#include "nsJSPrincipals.h"
#include "nsJSUtils.h"
#include "nsLayoutStatics.h"
#include "nsLiteralString.h"
#include "nsNetUtil.h"
#include "nsPIDOMWindow.h"
#include "nsPIDOMWindowInlines.h"
#include "nsPIWindowRoot.h"
#include "nsPoint.h"
#include "nsPresContext.h"
#include "nsQueryObject.h"
#include "nsSandboxFlags.h"
#include "nsScreen.h"
#include "nsServiceManagerUtils.h"
#include "nsString.h"
#include "nsStringFlags.h"
#include "nsStringFwd.h"
#include "nsTArray.h"
#include "nsTLiteralString.h"
#include "nsTObserverArray.h"
#include "nsTStringRepr.h"
#include "nsThreadUtils.h"
#include "nsWeakReference.h"
#include "nsWindowMemoryReporter.h"
#include "nsWindowSizes.h"
#include "nsWrapperCache.h"
#include "nsWrapperCacheInlines.h"
#include "nsXULAppAPI.h"
#include "nsrootidl.h"
#include "prclist.h"
#include "prtypes.h"
#include "xpcprivate.h"
#include "xpcpublic.h"
#include "mozilla/ThrottledEventQueue.h"

#include "nsIDOMXULControlElement.h"

#ifdef NS_PRINTING
#  include "nsIPrintSettings.h"
#endif

#ifdef MOZ_WEBSPEECH
#  include "mozilla/dom/SpeechSynthesis.h"
#endif

#ifdef ANDROID
#  include <android/log.h>
#endif

#ifdef XP_WIN
#  include "mozilla/Debug.h"
#  include <process.h>
#  define getpid _getpid
#else
#  include <unistd.h>  // for getpid()
#endif

using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::ipc;
using mozilla::TimeDuration;
using mozilla::TimeStamp;
using mozilla::dom::GamepadHandle;
using mozilla::dom::cache::CacheStorage;

#define FORWARD_TO_OUTER(method, args, err_rval)                     \
  PR_BEGIN_MACRO                                                     \
  RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowInternal();      \
  if (!HasActiveDocument()) {                                        \
    NS_WARNING(outer ? "Inner window does not have active document." \
                     : "No outer window available!");                \
    return err_rval;                                                 \
  }                                                                  \
  return outer->method args;                                         \
  PR_END_MACRO

static nsGlobalWindowOuter* GetOuterWindowForForwarding(
    nsGlobalWindowInner* aInner, ErrorResult& aError) {
  nsGlobalWindowOuter* outer = aInner->GetOuterWindowInternal();
  if (MOZ_LIKELY(aInner->HasActiveDocument())) {
    return outer;
  }
  if (!outer) {
    NS_WARNING("No outer window available!");
    aError.Throw(NS_ERROR_NOT_INITIALIZED);
  } else {
    aError.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO);
  }
  return nullptr;
}

#define FORWARD_TO_OUTER_OR_THROW(method, args, rv, err_rval)                \
  PR_BEGIN_MACRO                                                             \
  RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowForForwarding(this, rv); \
  if (MOZ_LIKELY(outer)) {                                                   \
    return outer->method args;                                               \
  }                                                                          \
  return err_rval;                                                           \
  PR_END_MACRO

#define FORWARD_TO_OUTER_VOID(method, args)                          \
  PR_BEGIN_MACRO                                                     \
  RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowInternal();      \
  if (!HasActiveDocument()) {                                        \
    NS_WARNING(outer ? "Inner window does not have active document." \
                     : "No outer window available!");                \
    return;                                                          \
  }                                                                  \
  outer->method args;                                                \
  return;                                                            \
  PR_END_MACRO

#define ENSURE_ACTIVE_DOCUMENT(errorresult, err_rval) \
  PR_BEGIN_MACRO                                      \
  if (MOZ_UNLIKELY(!HasActiveDocument())) {           \
    aError.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO); \
    return err_rval;                                  \
  }                                                   \
  PR_END_MACRO

#define DOM_TOUCH_LISTENER_ADDED "dom-touch-listener-added"
#define MEMORY_PRESSURE_OBSERVER_TOPIC "memory-pressure"
#define PERMISSION_CHANGED_TOPIC "perm-changed"

static LazyLogModule gDOMLeakPRLogInner("DOMLeakInner");
extern mozilla::LazyLogModule gTimeoutLog;

#ifdef DEBUG
static LazyLogModule gDocShellAndDOMWindowLeakLogging(
    "DocShellAndDOMWindowLeak");
#endif

static FILE* gDumpFile = nullptr;

nsGlobalWindowInner::InnerWindowByIdTable*
    nsGlobalWindowInner::sInnerWindowsById = nullptr;

bool nsGlobalWindowInner::sDragServiceDisabled = false;
bool nsGlobalWindowInner::sMouseDown = false;

/**
 * An indirect observer object that means we don't have to implement nsIObserver
 * on nsGlobalWindow, where any script could see it.
 */

class nsGlobalWindowObserver final : public nsIObserver,
                                     public nsIInterfaceRequestor,
                                     public StorageNotificationObserver {
 public:
  explicit nsGlobalWindowObserver(nsGlobalWindowInner* aWindow)
      : mWindow(aWindow) {}
  NS_DECL_ISUPPORTS
  NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
                     const char16_t* aData) override {
    if (!mWindow) return NS_OK;
    return mWindow->Observe(aSubject, aTopic, aData);
  }
  void Forget() { mWindow = nullptr; }
  NS_IMETHOD GetInterface(const nsIID& aIID, void** aResult) override {
    if (mWindow && aIID.Equals(NS_GET_IID(nsIDOMWindow)) && mWindow) {
      return mWindow->QueryInterface(aIID, aResult);
    }
    return NS_NOINTERFACE;
  }

  void ObserveStorageNotification(StorageEvent* aEvent,
                                  const char16_t* aStorageType,
                                  bool aPrivateBrowsing) override {
    if (mWindow) {
      mWindow->ObserveStorageNotification(aEvent, aStorageType,
                                          aPrivateBrowsing);
    }
  }

  nsIPrincipal* GetEffectiveCookiePrincipal() const override {
    return mWindow ? mWindow->GetEffectiveCookiePrincipal() : nullptr;
  }

  nsIPrincipal* GetEffectiveStoragePrincipal() const override {
    return mWindow ? mWindow->GetEffectiveStoragePrincipal() : nullptr;
  }

  bool IsPrivateBrowsing() const override {
    return mWindow ? mWindow->IsPrivateBrowsing() : false;
  }

  nsIEventTarget* GetEventTarget() const override {
    return mWindow ? mWindow->SerialEventTarget() : nullptr;
  }

 private:
  ~nsGlobalWindowObserver() = default;

  // This reference is non-owning and safe because it's cleared by
  // nsGlobalWindowInner::FreeInnerObjects().
  nsGlobalWindowInner* MOZ_NON_OWNING_REF mWindow;
};

NS_IMPL_ISUPPORTS(nsGlobalWindowObserver, nsIObserver, nsIInterfaceRequestor)

class IdleRequestExecutor;

class IdleRequestExecutorTimeoutHandler final : public TimeoutHandler {
 public:
  explicit IdleRequestExecutorTimeoutHandler(IdleRequestExecutor* aExecutor)
      : mExecutor(aExecutor) {}

  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  NS_DECL_CYCLE_COLLECTION_CLASS(IdleRequestExecutorTimeoutHandler)

  bool Call(const char/* unused */) override;

 private:
  ~IdleRequestExecutorTimeoutHandler() override = default;
  RefPtr<IdleRequestExecutor> mExecutor;
};

NS_IMPL_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler, mExecutor)

NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutorTimeoutHandler)
NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutorTimeoutHandler)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler)
  NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

class IdleRequestExecutor final : public nsIRunnable,
                                  public nsICancelableRunnable,
                                  public nsINamed,
                                  public nsIIdleRunnable {
 public:
  explicit IdleRequestExecutor(nsGlobalWindowInner* aWindow)
      : mDispatched(false), mDeadline(TimeStamp::Now()), mWindow(aWindow) {
    MOZ_DIAGNOSTIC_ASSERT(mWindow);

    mIdlePeriodLimit = {mDeadline, mWindow->LastIdleRequestHandle()};
    mDelayedExecutorDispatcher = new IdleRequestExecutorTimeoutHandler(this);
  }

  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IdleRequestExecutor, nsIRunnable)

  NS_DECL_NSIRUNNABLE
  NS_DECL_NSINAMED
  nsresult Cancel() override;
  void SetDeadline(TimeStamp aDeadline) override;

  bool IsCancelled() const { return !mWindow || mWindow->IsDying(); }
  // Checks if aRequest shouldn't execute in the current idle period
  // since it has been queued from a chained call to
  // requestIdleCallback from within a running idle callback.
  bool IneligibleForCurrentIdlePeriod(IdleRequest* aRequest) const {
    return aRequest->Handle() >= mIdlePeriodLimit.mLastRequestIdInIdlePeriod &&
           TimeStamp::Now() <= mIdlePeriodLimit.mEndOfIdlePeriod;
  }

  void MaybeUpdateIdlePeriodLimit();

  // Maybe dispatch the IdleRequestExecutor. MabyeDispatch will
  // schedule a delayed dispatch if the associated window is in the
  // background or if given a time to wait until dispatching.
  void MaybeDispatch(TimeStamp aDelayUntil = TimeStamp());
  void ScheduleDispatch();

 private:
  struct IdlePeriodLimit {
    TimeStamp mEndOfIdlePeriod;
    uint32_t mLastRequestIdInIdlePeriod;
  };

  void DelayedDispatch(uint32_t aDelay);

  ~IdleRequestExecutor() override = default;

  bool mDispatched;
  TimeStamp mDeadline;
  IdlePeriodLimit mIdlePeriodLimit;
  RefPtr<nsGlobalWindowInner> mWindow;
  // The timeout handler responsible for dispatching this executor in
  // the case of immediate dispatch to the idle queue isn't
  // desirable. This is used if we've dispatched all idle callbacks
  // that are allowed to run in the current idle period, or if the
  // associated window is currently in the background.
  RefPtr<TimeoutHandler> mDelayedExecutorDispatcher;
  // If not Nothing() then this value is the handle to the currently
  // scheduled delayed executor dispatcher. This is needed to be able
  // to cancel the timeout handler in case of the executor being
  // cancelled.
  Maybe<int32_t> mDelayedExecutorHandle;
};

NS_IMPL_CYCLE_COLLECTION(IdleRequestExecutor, mWindow,
                         mDelayedExecutorDispatcher)

NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutor)
NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutor)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutor)
  NS_INTERFACE_MAP_ENTRY(nsIRunnable)
  NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable)
  NS_INTERFACE_MAP_ENTRY(nsINamed)
  NS_INTERFACE_MAP_ENTRY(nsIIdleRunnable)
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRunnable)
NS_INTERFACE_MAP_END

NS_IMETHODIMP
IdleRequestExecutor::GetName(nsACString& aName) {
  aName.AssignLiteral("IdleRequestExecutor");
  return NS_OK;
}

// MOZ_CAN_RUN_SCRIPT_BOUNDARY until nsIRunnable::Run is MOZ_CAN_RUN_SCRIPT.
// See bug 1535398.
MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP IdleRequestExecutor::Run() {
  MOZ_ASSERT(NS_IsMainThread());

  mDispatched = false;
  if (mWindow) {
    RefPtr<nsGlobalWindowInner> window(mWindow);
    window->ExecuteIdleRequest(mDeadline);
  }

  return NS_OK;
}

nsresult IdleRequestExecutor::Cancel() {
  MOZ_ASSERT(NS_IsMainThread());

  if (mDelayedExecutorHandle && mWindow) {
    mWindow->GetTimeoutManager()->ClearTimeout(
        mDelayedExecutorHandle.value(), Timeout::Reason::eIdleCallbackTimeout);
  }

  mWindow = nullptr;
  return NS_OK;
}

void IdleRequestExecutor::SetDeadline(TimeStamp aDeadline) {
  MOZ_ASSERT(NS_IsMainThread());

  if (!mWindow) {
    return;
  }

  mDeadline = aDeadline;
}

void IdleRequestExecutor::MaybeUpdateIdlePeriodLimit() {
  if (TimeStamp::Now() > mIdlePeriodLimit.mEndOfIdlePeriod) {
    mIdlePeriodLimit = {mDeadline, mWindow->LastIdleRequestHandle()};
  }
}

void IdleRequestExecutor::MaybeDispatch(TimeStamp aDelayUntil) {
  // If we've already dispatched the executor we don't want to do it
  // again. Also, if we've called IdleRequestExecutor::Cancel mWindow
  // will be null, which indicates that we shouldn't dispatch this
  // executor either.
  if (mDispatched || IsCancelled()) {
    return;
  }

  mDispatched = true;

  nsPIDOMWindowOuter* outer = mWindow->GetOuterWindow();
  if (outer && outer->IsBackground()) {
    // Set a timeout handler with a timeout of 0 ms to throttle idle
    // callback requests coming from a backround window using
    // background timeout throttling.
    DelayedDispatch(0);
    return;
  }

  TimeStamp now = TimeStamp::Now();
  if (!aDelayUntil || aDelayUntil < now) {
    ScheduleDispatch();
    return;
  }

  TimeDuration delay = aDelayUntil - now;
  DelayedDispatch(static_cast<uint32_t>(delay.ToMilliseconds()));
}

void IdleRequestExecutor::ScheduleDispatch() {
  MOZ_ASSERT(mWindow);
  mDelayedExecutorHandle = Nothing();
  RefPtr<IdleRequestExecutor> request = this;
  NS_DispatchToCurrentThreadQueue(request.forget(), EventQueuePriority::Idle);
}

void IdleRequestExecutor::DelayedDispatch(uint32_t aDelay) {
  MOZ_ASSERT(mWindow);
  MOZ_ASSERT(mDelayedExecutorHandle.isNothing());
  int32_t handle;
  mWindow->GetTimeoutManager()->SetTimeout(
      mDelayedExecutorDispatcher, aDelay, false,
      Timeout::Reason::eIdleCallbackTimeout, &handle);
  mDelayedExecutorHandle = Some(handle);
}

bool IdleRequestExecutorTimeoutHandler::Call(const char/* unused */) {
  if (!mExecutor->IsCancelled()) {
    mExecutor->ScheduleDispatch();
  }
  return true;
}

void nsGlobalWindowInner::ScheduleIdleRequestDispatch() {
  AssertIsOnMainThread();

  if (!mIdleRequestExecutor) {
    mIdleRequestExecutor = new IdleRequestExecutor(this);
  }

  mIdleRequestExecutor->MaybeDispatch();
}

void nsGlobalWindowInner::SuspendIdleRequests() {
  if (mIdleRequestExecutor) {
    mIdleRequestExecutor->Cancel();
    mIdleRequestExecutor = nullptr;
  }
}

void nsGlobalWindowInner::ResumeIdleRequests() {
  MOZ_ASSERT(!mIdleRequestExecutor);

  ScheduleIdleRequestDispatch();
}

void nsGlobalWindowInner::RemoveIdleCallback(
    mozilla::dom::IdleRequest* aRequest) {
  AssertIsOnMainThread();

  if (aRequest->HasTimeout()) {
    mTimeoutManager->ClearTimeout(aRequest->GetTimeoutHandle(),
                                  Timeout::Reason::eIdleCallbackTimeout);
  }

  aRequest->removeFrom(mIdleRequestCallbacks);
}

void nsGlobalWindowInner::RunIdleRequest(IdleRequest* aRequest,
                                         DOMHighResTimeStamp aDeadline,
                                         bool aDidTimeout) {
  AssertIsOnMainThread();
  // XXXbz Do we still need this RefPtr?  MOZ_CAN_RUN_SCRIPT should
  // guarantee that caller is holding a strong ref on the stack.
  RefPtr<IdleRequest> request(aRequest);
  RemoveIdleCallback(request);
  request->IdleRun(this, aDeadline, aDidTimeout);
}

void nsGlobalWindowInner::ExecuteIdleRequest(TimeStamp aDeadline) {
  AssertIsOnMainThread();
  RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst();

  if (!request) {
    // There are no more idle requests, so stop scheduling idle
    // request callbacks.
    return;
  }

  // If the request that we're trying to execute has been queued
  // during the current idle period, then dispatch it again at the end
  // of the idle period.
  if (mIdleRequestExecutor->IneligibleForCurrentIdlePeriod(request)) {
    mIdleRequestExecutor->MaybeDispatch(aDeadline);
    return;
  }

  DOMHighResTimeStamp deadline = 0.0;

  if (Performance* perf = GetPerformance()) {
    deadline = perf->GetDOMTiming()->TimeStampToDOMHighRes(aDeadline);
  }

  mIdleRequestExecutor->MaybeUpdateIdlePeriodLimit();
  RunIdleRequest(request, deadline, false);

  // Running the idle callback could've suspended the window, in which
  // case mIdleRequestExecutor will be null.
  if (mIdleRequestExecutor) {
    mIdleRequestExecutor->MaybeDispatch();
  }
}

class IdleRequestTimeoutHandler final : public TimeoutHandler {
 public:
  IdleRequestTimeoutHandler(JSContext* aCx, IdleRequest* aIdleRequest,
                            nsPIDOMWindowInner* aWindow)
      : TimeoutHandler(aCx), mIdleRequest(aIdleRequest), mWindow(aWindow) {}

  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  NS_DECL_CYCLE_COLLECTION_CLASS(IdleRequestTimeoutHandler)

  MOZ_CAN_RUN_SCRIPT bool Call(const char/* unused */) override {
    RefPtr<nsGlobalWindowInner> window(nsGlobalWindowInner::Cast(mWindow));
    RefPtr<IdleRequest> request(mIdleRequest);
    window->RunIdleRequest(request, 0.0, true);
    return true;
  }

 private:
  ~IdleRequestTimeoutHandler() override = default;

  RefPtr<IdleRequest> mIdleRequest;
  nsCOMPtr<nsPIDOMWindowInner> mWindow;
};

NS_IMPL_CYCLE_COLLECTION(IdleRequestTimeoutHandler, mIdleRequest, mWindow)

NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestTimeoutHandler)
NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestTimeoutHandler)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestTimeoutHandler)
  NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

uint32_t nsGlobalWindowInner::RequestIdleCallback(
    JSContext* aCx, IdleRequestCallback& aCallback,
    const IdleRequestOptions& aOptions, ErrorResult& aError) {
  AssertIsOnMainThread();

  if (IsDying()) {
    return 0;
  }

  uint32_t handle = mIdleRequestCallbackCounter++;

  RefPtr<IdleRequest> request = new IdleRequest(&aCallback, handle);

  if (aOptions.mTimeout.WasPassed()) {
    int32_t timeoutHandle;
    RefPtr<TimeoutHandler> handler(
        new IdleRequestTimeoutHandler(aCx, request, this));

    nsresult rv = mTimeoutManager->SetTimeout(
        handler, aOptions.mTimeout.Value(), false,
        Timeout::Reason::eIdleCallbackTimeout, &timeoutHandle);

    if (NS_WARN_IF(NS_FAILED(rv))) {
      return 0;
    }

    request->SetTimeoutHandle(timeoutHandle);
  }

  mIdleRequestCallbacks.insertBack(request);

  if (!IsSuspended()) {
    ScheduleIdleRequestDispatch();
  }

  return handle;
}

void nsGlobalWindowInner::CancelIdleCallback(uint32_t aHandle) {
  for (IdleRequest* r : mIdleRequestCallbacks) {
    if (r->Handle() == aHandle) {
      RemoveIdleCallback(r);
      break;
    }
  }
}

void nsGlobalWindowInner::DisableIdleCallbackRequests() {
  if (mIdleRequestExecutor) {
    mIdleRequestExecutor->Cancel();
    mIdleRequestExecutor = nullptr;
  }

  while (!mIdleRequestCallbacks.isEmpty()) {
    RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst();
    RemoveIdleCallback(request);
  }
}

bool nsGlobalWindowInner::IsBackgroundInternal() const {
  return !mOuterWindow || mOuterWindow->IsBackground();
}

class PromiseDocumentFlushedResolver final {
 public:
  PromiseDocumentFlushedResolver(Promise* aPromise,
                                 PromiseDocumentFlushedCallback& aCallback)
      : mPromise(aPromise), mCallback(&aCallback) {}

  virtual ~PromiseDocumentFlushedResolver() = default;

  void Call() {
    nsMutationGuard guard;
    ErrorResult error;
    JS::Rooted<JS::Value> returnVal(RootingCx());
    mCallback->Call(&returnVal, error);

    if (error.Failed()) {
      mPromise->MaybeReject(std::move(error));
    } else if (guard.Mutated(0)) {
      // Something within the callback mutated the DOM.
      mPromise->MaybeRejectWithNoModificationAllowedError(
          "DOM mutated from promiseDocumentFlushed callbacks");
    } else {
      mPromise->MaybeResolve(returnVal);
    }
  }

  RefPtr<Promise> mPromise;
  RefPtr<PromiseDocumentFlushedCallback> mCallback;
};

//*****************************************************************************
//***    nsGlobalWindowInner: Object Management
//*****************************************************************************

nsGlobalWindowInner::nsGlobalWindowInner(nsGlobalWindowOuter* aOuterWindow,
                                         WindowGlobalChild* aActor)
    : nsPIDOMWindowInner(aOuterWindow, aActor),
      mHasOrientationChangeListeners(false),
      mWasOffline(false),
      mHasHadSlowScript(false),
      mIsChrome(false),
      mCleanMessageManager(false),
      mNeedsFocus(true),
      mHasFocus(false),
      mFocusByKeyOccurred(false),
      mDidFireDocElemInserted(false),
      mHasGamepad(false),
      mHasXRSession(false),
      mHasVRDisplayActivateEvents(false),
      mXRRuntimeDetectionInFlight(false),
      mXRPermissionRequestInFlight(false),
      mXRPermissionGranted(false),
      mWasCurrentInnerWindow(false),
      mHasSeenGamepadInput(false),
      mHintedWasLoading(false),
      mHasOpenedExternalProtocolFrame(false),
      mScrollMarksOnHScrollbar(false),
      mStorageAllowedReasonCache(0),
      mSuspendDepth(0),
      mFreezeDepth(0),
#ifdef DEBUG
      mSerial(0),
#endif
      mFocusMethod(0),
      mIdleRequestCallbackCounter(1),
      mIdleRequestExecutor(nullptr),
      mObservingRefresh(false),
      mIteratingDocumentFlushedResolvers(false),
      mCanSkipCCGeneration(0) {
  mIsInnerWindow = true;

  AssertIsOnMainThread();
  SetIsOnMainThread();
  nsLayoutStatics::AddRef();

  // Initialize the PRCList (this).
  PR_INIT_CLIST(this);

  // add this inner window to the outer window list of inners.
  PR_INSERT_AFTER(this, aOuterWindow);

  mTimeoutManager = MakeUnique<dom::TimeoutManager>(
      *this, StaticPrefs::dom_timeout_max_idle_defer_ms(),
      static_cast<nsISerialEventTarget*>(nsPIDOMWindowInner::From(this)
                                             ->GetBrowsingContextGroup()
                                             ->GetTimerEventQueue()));

  mObserver = new nsGlobalWindowObserver(this);
  if (nsCOMPtr<nsIObserverService> os = services::GetObserverService()) {
    // Watch for online/offline status changes so we can fire events. Use
    // a strong reference.
    os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC, false);
    os->AddObserver(mObserver, MEMORY_PRESSURE_OBSERVER_TOPIC, false);
    os->AddObserver(mObserver, PERMISSION_CHANGED_TOPIC, false);
    os->AddObserver(mObserver, "screen-information-changed"false);
  }

  Preferences::AddStrongObserver(mObserver, "intl.accept_languages");

  // Watch for storage notifications so we can fire storage events.
  RefPtr<StorageNotifierService> sns = StorageNotifierService::GetOrCreate();
  if (sns) {
    sns->Register(mObserver);
  }

  if (XRE_IsContentProcess()) {
    nsCOMPtr<nsIDocShell> docShell = GetDocShell();
    if (docShell) {
      mBrowserChild = docShell->GetBrowserChild();
    }
  }

  if (gDumpFile == nullptr) {
    nsAutoCString fname;
    Preferences::GetCString("browser.dom.window.dump.file", fname);
    if (!fname.IsEmpty()) {
      // If this fails to open, Dump() knows to just go to stdout on null.
      gDumpFile = fopen(fname.get(), "wb+");
    } else {
      gDumpFile = stdout;
    }
  }

#ifdef DEBUG
  mSerial = nsContentUtils::InnerOrOuterWindowCreated();

  MOZ_LOG(gDocShellAndDOMWindowLeakLogging, LogLevel::Info,
          ("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n",
           nsContentUtils::GetCurrentInnerOrOuterWindowCount(),
           static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial,
           static_cast<void*>(ToCanonicalSupports(aOuterWindow))));
#endif

  MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
          ("DOMWINDOW %p created outer=%p"this, aOuterWindow));

  // Add ourselves to the inner windows list.
  MOZ_ASSERT(sInnerWindowsById, "Inner Windows hash table must be created!");
  MOZ_ASSERT(!sInnerWindowsById->Contains(mWindowID),
             "This window shouldn't be in the hash table yet!");
  // We seem to see crashes in release builds because of null
  // |sInnerWindowsById|.
  if (sInnerWindowsById) {
    sInnerWindowsById->InsertOrUpdate(mWindowID, this);
  }
}

#ifdef DEBUG

/* static */
void nsGlobalWindowInner::AssertIsOnMainThread() {
  MOZ_ASSERT(NS_IsMainThread());
}

#endif  // DEBUG

/* static */
void nsGlobalWindowInner::Init() {
  AssertIsOnMainThread();

  NS_ASSERTION(gDOMLeakPRLogInner,
               "gDOMLeakPRLogInner should have been initialized!");

  sInnerWindowsById = new InnerWindowByIdTable();
}

nsGlobalWindowInner::~nsGlobalWindowInner() {
  AssertIsOnMainThread();
  MOZ_ASSERT(!mHintedWasLoading);

  if (IsChromeWindow()) {
    MOZ_ASSERT(mCleanMessageManager,
               "chrome windows may always disconnect the msg manager");

    DisconnectAndClearGroupMessageManagers();

    if (mChromeFields.mMessageManager) {
      static_cast<nsFrameMessageManager*>(mChromeFields.mMessageManager.get())
          ->Disconnect();
    }

    mCleanMessageManager = false;
  }

  // In most cases this should already have been called, but call it again
  // here to catch any corner cases.
  FreeInnerObjects();

  if (sInnerWindowsById) {
    sInnerWindowsById->Remove(mWindowID);
  }

  nsContentUtils::InnerOrOuterWindowDestroyed();

#ifdef DEBUG
  if (MOZ_LOG_TEST(gDocShellAndDOMWindowLeakLogging, LogLevel::Info)) {
    nsAutoCString url;
    if (mLastOpenedURI) {
      url = mLastOpenedURI->GetSpecOrDefault();

      // Data URLs can be very long, so truncate to avoid flooding the log.
      const uint32_t maxURLLength = 1000;
      if (url.Length() > maxURLLength) {
        url.Truncate(maxURLLength);
      }
    }

    nsGlobalWindowOuter* outer = nsGlobalWindowOuter::Cast(mOuterWindow);
    MOZ_LOG(
        gDocShellAndDOMWindowLeakLogging, LogLevel::Info,
        ("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
         "%s]\n",
         nsContentUtils::GetCurrentInnerOrOuterWindowCount(),
         static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial,
         static_cast<void*>(ToCanonicalSupports(outer)), url.get()));
  }
#endif
  MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
          ("DOMWINDOW %p destroyed"this));

  Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
                        mMutationBits ? 1 : 0);

  // An inner window is destroyed, pull it out of the outer window's
  // list if inner windows.

  PR_REMOVE_LINK(this);

  // If our outer window's inner window is this window, null out the
  // outer window's reference to this window that's being deleted.
  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
  if (outer) {
    outer->MaybeClearInnerWindow(this);
  }

  // We don't have to leave the tab group if we are an inner window.

  nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
  if (ac) ac->RemoveWindowAsListener(this);

  nsLayoutStatics::Release();
}

// static
void nsGlobalWindowInner::ShutDown() {
  AssertIsOnMainThread();

  if (gDumpFile && gDumpFile != stdout) {
    fclose(gDumpFile);
  }
  gDumpFile = nullptr;

  delete sInnerWindowsById;
  sInnerWindowsById = nullptr;
}

void nsGlobalWindowInner::FreeInnerObjects() {
  if (IsDying()) {
    return;
  }
  StartDying();

  if (mDoc && mDoc->GetWindowContext()) {
    // The document is about to lose its window, so this is a good time to send
    // our page use counters.
    //
    // (We also do this in Document::SetScriptGlobalObject(nullptr), which
    // catches most cases of documents losing their window, but not all.)
    mDoc->SendPageUseCounters();
  }

  // Make sure that this is called before we null out the document and
  // other members that the window destroyed observers could
  // re-create.
  if (auto* reporter = nsWindowMemoryReporter::Get()) {
    reporter->ObserveDOMWindowDetached(this);
  }

  // Kill all of the workers for this window.
  CancelWorkersForWindow(*this);

  for (RefPtr<mozilla::dom::SharedWorker> pinnedWorker :
       mSharedWorkers.ForwardRange()) {
    pinnedWorker->Close();
  }

  if (mTimeoutManager) {
    mTimeoutManager->ClearAllTimeouts();
  }

  DisableIdleCallbackRequests();

  mChromeEventHandler = nullptr;

  if (mListenerManager) {
    mListenerManager->RemoveAllListeners();
    mListenerManager->Disconnect();
    mListenerManager = nullptr;
  }

  mHistory = nullptr;

  if (mNavigator) {
    mNavigator->OnNavigation();
    mNavigator->Invalidate();
    mNavigator = nullptr;
  }

  mScreen = nullptr;

  if (mDoc) {
    // Remember the document's principal, URI, and CSP.
    mDocumentPrincipal = mDoc->NodePrincipal();
    mDocumentCookiePrincipal = mDoc->EffectiveCookiePrincipal();
    mDocumentStoragePrincipal = mDoc->EffectiveStoragePrincipal();
    mDocumentPartitionedPrincipal = mDoc->PartitionedPrincipal();
    mDocumentURI = mDoc->GetDocumentURI();
    mDocBaseURI = mDoc->GetDocBaseURI();
    mDocumentCsp = mDoc->GetCsp();

    while (mDoc->EventHandlingSuppressed()) {
      mDoc->UnsuppressEventHandlingAndFireEvents(false);
    }
  }

  // Remove our reference to the document and the document principal.
  mFocusedElement = nullptr;

  nsIGlobalObject::UnlinkObjectsInGlobal();

  NotifyWindowIDDestroyed("inner-window-destroyed");

  for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
    mAudioContexts[i]->OnWindowDestroy();
  }
  mAudioContexts.Clear();

  for (MediaKeys* mediaKeys : mMediaKeysInstances) {
    mediaKeys->OnInnerWindowDestroy();
  }
  mMediaKeysInstances.Clear();

  DisableGamepadUpdates();
  mHasGamepad = false;
  mGamepads.Clear();
  DisableVRUpdates();
  mHasXRSession = false;
  mHasVRDisplayActivateEvents = false;
  mXRRuntimeDetectionInFlight = false;
  mXRPermissionRequestInFlight = false;
  mXRPermissionGranted = false;
  mVRDisplays.Clear();

  // This breaks a cycle between the window and the ClientSource object.
  mClientSource.reset();

  if (mWindowGlobalChild) {
    // Remove any remaining listeners.
    int64_t nListeners = mWindowGlobalChild->BeforeUnloadListeners();
    for (int64_t i = 0; i < nListeners; ++i) {
      mWindowGlobalChild->BeforeUnloadRemoved();
    }
    MOZ_ASSERT(mWindowGlobalChild->BeforeUnloadListeners() == 0);
  }

  // If we have any promiseDocumentFlushed callbacks, fire them now so
  // that the Promises can resolve.
  CallDocumentFlushedResolvers(/* aUntilExhaustion = */ true);

  DisconnectGlobalTeardownObservers();

#ifdef MOZ_WIDGET_ANDROID
  DisableOrientationChangeListener();
#endif

  if (mObserver) {
    if (nsCOMPtr<nsIObserverService> os = services::GetObserverService()) {
      os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
      os->RemoveObserver(mObserver, MEMORY_PRESSURE_OBSERVER_TOPIC);
      os->RemoveObserver(mObserver, PERMISSION_CHANGED_TOPIC);
      os->RemoveObserver(mObserver, "screen-information-changed");
    }

    RefPtr<StorageNotifierService> sns = StorageNotifierService::GetOrCreate();
    if (sns) {
      sns->Unregister(mObserver);
    }

    Preferences::RemoveObserver(mObserver, "intl.accept_languages");

    // Drop its reference to this dying window, in case for some bogus reason
    // the object stays around.
    mObserver->Forget();
  }

  mMenubar = nullptr;
  mToolbar = nullptr;
  mLocationbar = nullptr;
  mPersonalbar = nullptr;
  mStatusbar = nullptr;
  mScrollbars = nullptr;

  mConsole = nullptr;
  mCookieStore = nullptr;

  mPaintWorklet = nullptr;

  mExternal = nullptr;
  mInstallTrigger = nullptr;

  if (mLocalStorage) {
    mLocalStorage->Disconnect();
    mLocalStorage = nullptr;
  }
  mSessionStorage = nullptr;
  if (mPerformance) {
    // Since window is dying, nothing is going to be painted
    // with meaningful sizes, so these temp data for LCP is
    // no longer needed.
    static_cast<PerformanceMainThread*>(mPerformance.get())
        ->ClearGeneratedTempDataForLCP();
  }
  mPerformance = nullptr;

  mContentMediaController = nullptr;

  if (mWebTaskScheduler) {
    mWebTaskScheduler->Disconnect();
    mWebTaskScheduler = nullptr;
  }

  mTrustedTypePolicyFactory = nullptr;

  mSharedWorkers.Clear();

#ifdef MOZ_WEBSPEECH
  mSpeechSynthesis = nullptr;
#endif

  mGlean = nullptr;
  mGleanPings = nullptr;

  mParentTarget = nullptr;

  if (mCleanMessageManager) {
    MOZ_ASSERT(mIsChrome, "only chrome should have msg manager cleaned");
    if (mChromeFields.mMessageManager) {
      mChromeFields.mMessageManager->Disconnect();
    }
  }

  if (mWindowGlobalChild && !mWindowGlobalChild->IsClosed()) {
    mWindowGlobalChild->Destroy();
  }

  mIntlUtils = nullptr;

  HintIsLoading(false);
}

//*****************************************************************************
// nsGlobalWindowInner::nsISupports
//*****************************************************************************

// QueryInterface implementation for nsGlobalWindowInner
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindowInner)
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget)
  NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
  NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
  NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
  NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
  NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
  NS_INTERFACE_MAP_ENTRY(nsPIDOMWindowInner)
  NS_INTERFACE_MAP_ENTRY(mozIDOMWindow)
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_END

NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindowInner)

NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindowInner)
  if (tmp->IsBlackForCC(false)) {
    if (nsCCUncollectableMarker::InGeneration(tmp->mCanSkipCCGeneration)) {
      return true;
    }
    tmp->mCanSkipCCGeneration = nsCCUncollectableMarker::sGeneration;
    if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
      elm->MarkForCC();
    }
    if (tmp->mTimeoutManager) {
      tmp->mTimeoutManager->UnmarkGrayTimers();
    }
    return true;
  }
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END

NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindowInner)
  return tmp->IsBlackForCC(true);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END

NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindowInner)
  return tmp->IsBlackForCC(false);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END

NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindowInner)

NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner)
  if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
    char name[512];
    nsAutoCString uri;
    if (tmp->mDoc && tmp->mDoc->GetDocumentURI()) {
      uri = tmp->mDoc->GetDocumentURI()->GetSpecOrDefault();
    }
    SprintfLiteral(name, "nsGlobalWindowInner # %" PRIu64 " inner %s",
                   tmp->mWindowID, uri.get());
    cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
  } else {
    NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindowInner, tmp->mRefCnt.get())
  }

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebTaskScheduler)

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTrustedTypePolicyFactory)

#ifdef MOZ_WEBSPEECH
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis)
#endif

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlean)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGleanPings)

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOuterWindow)

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTopInnerWindow)

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)

  if (tmp->mTimeoutManager) {
    tmp->mTimeoutManager->ForEachUnorderedTimeout([&cb](Timeout* timeout) {
      cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(Timeout));
    });
  }

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistory)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigation)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomElements)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedWorkers)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentCookiePrincipal)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentStoragePrincipal)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPartitionedPrincipal)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentCsp)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChild)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor)
  for (IdleRequest* request : tmp->mIdleRequestCallbacks) {
    cb.NoteNativeChild(request, NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest));
  }

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClientSource)

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepads)

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRDisplays)

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDebuggerNotificationManager)

  // Traverse stuff from nsPIDOMWindow
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedElement)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindowGlobalChild)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCloseWatcherManager)

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMenubar)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCookieStore)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPaintWorklet)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInstallTrigger)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntlUtils)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVisualViewport)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentPasteDataTransfer)

  tmp->TraverseObjectsInGlobal(cb);

  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mMessageManager)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mGroupMessageManagers)

  for (size_t i = 0; i < tmp->mDocumentFlushedResolvers.Length(); i++) {
    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentFlushedResolvers[i]->mPromise);
    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentFlushedResolvers[i]->mCallback);
  }

NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
  NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
  if (sInnerWindowsById) {
    sInnerWindowsById->Remove(tmp->mWindowID);
  }

  JSObject* wrapper = tmp->GetWrapperPreserveColor();
  if (wrapper) {
    // Mark our realm as dead, so the JS engine won't hand out our
    // global after this point.
    JS::SetRealmNonLive(js::GetNonCCWObjectRealm(wrapper));
  }

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)

  if (tmp->mWebTaskScheduler) {
    tmp->mWebTaskScheduler->Disconnect();
    NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebTaskScheduler)
  }

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mTrustedTypePolicyFactory)

#ifdef MOZ_WEBSPEECH
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis)
#endif

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlean)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGleanPings)

  if (tmp->mOuterWindow) {
    nsGlobalWindowOuter::Cast(tmp->mOuterWindow)->MaybeClearInnerWindow(tmp);
    NS_IMPL_CYCLE_COLLECTION_UNLINK(mOuterWindow)
  }

  if (tmp->mListenerManager) {
    tmp->mListenerManager->Disconnect();
    NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
  }

  // Here the Timeouts list would've been unlinked, but we rely on
  // that Timeout objects have been traced and will remove themselves
  // while unlinking.

  tmp->UpdateTopInnerWindow();
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mTopInnerWindow)

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistory)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigation)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomElements)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSharedWorkers)
  if (tmp->mLocalStorage) {
    tmp->mLocalStorage->Disconnect();
    NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
  }
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentCookiePrincipal)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentStoragePrincipal)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPartitionedPrincipal)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentCsp)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChild)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads)

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mVRDisplays)

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDebuggerNotificationManager)

  // Unlink stuff from nsPIDOMWindow
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedElement)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)

  MOZ_DIAGNOSTIC_ASSERT(
      !tmp->mWindowGlobalChild || tmp->mWindowGlobalChild->IsClosed(),
      "How are we unlinking a window before its actor has been destroyed?");
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindowGlobalChild)

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mMenubar)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCookieStore)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPaintWorklet)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mInstallTrigger)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntlUtils)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mVisualViewport)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCurrentPasteDataTransfer)

  tmp->UnlinkObjectsInGlobal();

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleRequestExecutor)

  // Here the IdleRequest list would've been unlinked, but we rely on
  // that IdleRequest objects have been traced and will remove
  // themselves while unlinking.

  NS_IMPL_CYCLE_COLLECTION_UNLINK(mClientSource)

  if (tmp->IsChromeWindow()) {
    if (tmp->mChromeFields.mMessageManager) {
      static_cast<nsFrameMessageManager*>(
          tmp->mChromeFields.mMessageManager.get())
          ->Disconnect();
      NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mMessageManager)
    }
    tmp->DisconnectAndClearGroupMessageManagers();
    NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mGroupMessageManagers)
  }

  for (size_t i = 0; i < tmp->mDocumentFlushedResolvers.Length(); i++) {
    NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentFlushedResolvers[i]->mPromise);
    NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentFlushedResolvers[i]->mCallback);
  }
  tmp->mDocumentFlushedResolvers.Clear();

  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

#ifdef DEBUG
void nsGlobalWindowInner::RiskyUnlink() {
  NS_CYCLE_COLLECTION_INNERNAME.Unlink(this);
}
#endif

NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindowInner)
  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_END

bool nsGlobalWindowInner::IsBlackForCC(bool aTracingNeeded) {
  if (!nsCCUncollectableMarker::sGeneration) {
    return false;
  }

  return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
          HasKnownLiveWrapper()) &&
         (!aTracingNeeded || HasNothingToTrace(ToSupports(this)));
}

//*****************************************************************************
// nsGlobalWindowInner::nsIScriptGlobalObject
//*****************************************************************************

bool nsGlobalWindowInner::ShouldResistFingerprinting(RFPTarget aTarget) const {
  if (mDoc) {
    return mDoc->ShouldResistFingerprinting(aTarget);
  }
  return nsContentUtils::ShouldResistFingerprinting(
      "If we do not have a document then we do not have any context"
      "to make an informed RFP choice, so we fall back to the global pref",
      aTarget);
}

OriginTrials nsGlobalWindowInner::Trials() const {
  return OriginTrials::FromWindow(this);
}

FontFaceSet* nsGlobalWindowInner::GetFonts() {
  if (mDoc) {
    return mDoc->Fonts();
  }
  return nullptr;
}

mozilla::Result<mozilla::ipc::PrincipalInfo, nsresult>
nsGlobalWindowInner::GetStorageKey() {
  MOZ_ASSERT(NS_IsMainThread());

  nsIPrincipal* principal = GetEffectiveStoragePrincipal();
  if (!principal) {
    return mozilla::Err(NS_ERROR_FAILURE);
  }

  mozilla::ipc::PrincipalInfo principalInfo;
  nsresult rv = PrincipalToPrincipalInfo(principal, &principalInfo);
  if (NS_FAILED(rv)) {
    return mozilla::Err(rv);
  }

  // Block expanded and null principals, let content and system through.
  if (principalInfo.type() !=
          mozilla::ipc::PrincipalInfo::TContentPrincipalInfo &&
      principalInfo.type() !=
          mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo) {
    return Err(NS_ERROR_DOM_SECURITY_ERR);
  }

  return std::move(principalInfo);
}

mozilla::dom::StorageManager* nsGlobalWindowInner::GetStorageManager() {
  return Navigator()->Storage();
}

// https://html.spec.whatwg.org/multipage/web-messaging.html#eligible-for-messaging
// * a Window object whose associated Document is fully active
bool nsGlobalWindowInner::IsEligibleForMessaging() { return IsFullyActive(); }

void nsGlobalWindowInner::ReportToConsole(
    uint32_t aErrorFlags, const nsCString& aCategory,
    nsContentUtils::PropertiesFile aFile, const nsCString& aMessageName,
    const nsTArray<nsString>& aParams,
    const mozilla::SourceLocation& aLocation) {
  nsContentUtils::ReportToConsole(aErrorFlags, aCategory, mDoc, aFile,
                                  aMessageName.get(), aParams, aLocation);
}

nsresult nsGlobalWindowInner::EnsureScriptEnvironment() {
  // NOTE: We can't use FORWARD_TO_OUTER here because we don't want to fail if
  // we're called on an inactive inner window.
  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
  if (!outer) {
    NS_WARNING("No outer window available!");
    return NS_ERROR_FAILURE;
  }
  return outer->EnsureScriptEnvironment();
}

nsIScriptContext* nsGlobalWindowInner::GetScriptContext() {
  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
  if (!outer) {
    return nullptr;
  }
  return outer->GetScriptContext();
}

void nsGlobalWindowInner::TraceGlobalJSObject(JSTracer* aTrc) {
  TraceWrapper(aTrc, "active window global");
}

void nsGlobalWindowInner::UpdateAutoplayPermission() {
  if (!GetWindowContext()) {
    return;
  }
  uint32_t perm =
      media::AutoplayPolicy::GetSiteAutoplayPermission(GetPrincipal());
  if (GetWindowContext()->GetAutoplayPermission() == perm) {
    return;
  }

  // Setting autoplay permission on a discarded context has no effect.
  Unused << GetWindowContext()->SetAutoplayPermission(perm);
}

void nsGlobalWindowInner::UpdateShortcutsPermission() {
  if (!GetWindowContext() ||
      !GetWindowContext()->GetBrowsingContext()->IsTop()) {
    // We only cache the shortcuts permission on top-level WindowContexts
    // since we always check the top-level principal for the permission.
    return;
  }

  uint32_t perm = GetShortcutsPermission(GetPrincipal());

  if (GetWindowContext()->GetShortcutsPermission() == perm) {
    return;
  }

  // If the WindowContext is discarded this has no effect.
  Unused << GetWindowContext()->SetShortcutsPermission(perm);
}

/* static */
uint32_t nsGlobalWindowInner::GetShortcutsPermission(nsIPrincipal* aPrincipal) {
  uint32_t perm = nsIPermissionManager::DENY_ACTION;
  nsCOMPtr<nsIPermissionManager> permMgr =
      mozilla::components::PermissionManager::Service();
  if (aPrincipal && permMgr) {
    permMgr->TestExactPermissionFromPrincipal(aPrincipal, "shortcuts"_ns,
                                              &perm);
  }
  return perm;
}

void nsGlobalWindowInner::UpdatePopupPermission() {
  if (!GetWindowContext()) {
    return;
  }

  uint32_t perm = PopupBlocker::GetPopupPermission(GetPrincipal());
  if (GetWindowContext()->GetPopupPermission() == perm) {
    return;
  }

  // If the WindowContext is discarded this has no effect.
  Unused << GetWindowContext()->SetPopupPermission(perm);
}

void nsGlobalWindowInner::UpdatePermissions() {
  if (!GetWindowContext()) {
    return;
  }

  nsCOMPtr<nsIPrincipal> principal = GetPrincipal();
  RefPtr<WindowContext> windowContext = GetWindowContext();

  WindowContext::Transaction txn;
  txn.SetAutoplayPermission(
      media::AutoplayPolicy::GetSiteAutoplayPermission(principal));
  txn.SetPopupPermission(PopupBlocker::GetPopupPermission(principal));

  if (windowContext->IsTop()) {
    txn.SetShortcutsPermission(GetShortcutsPermission(principal));
  }

  // Setting permissions on a discarded WindowContext has no effect
  Unused << txn.Commit(windowContext);
}

void nsGlobalWindowInner::InitDocumentDependentState(JSContext* aCx) {
  MOZ_ASSERT(mDoc);

  if (MOZ_LOG_TEST(gDOMLeakPRLogInner, LogLevel::Debug)) {
    nsIURI* uri = mDoc->GetDocumentURI();
    MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
            ("DOMWINDOW %p SetNewDocument %s"this,
             uri ? uri->GetSpecOrDefault().get() : ""));
  }

  mFocusedElement = nullptr;
  mLocalStorage = nullptr;
  mSessionStorage = nullptr;
  mPerformance = nullptr;
  if (mWebTaskScheduler) {
    mWebTaskScheduler->Disconnect();
    mWebTaskScheduler = nullptr;
  }

  // This must be called after nullifying the internal objects because here we
  // could recreate them, calling the getter methods, and store them into the JS
  // slots. If we nullify them after, the slot values and the objects will be
  // out of sync.
  ClearDocumentDependentSlots(aCx);

  if (!mWindowGlobalChild) {
    mWindowGlobalChild = WindowGlobalChild::Create(this);
  }
  MOZ_ASSERT(!GetWindowContext()->HasBeenUserGestureActivated(),
             "WindowContext should always not have user gesture activation at "
             "this point.");

  UpdatePermissions();

  RefPtr<PermissionDelegateHandler> permDelegateHandler =
      mDoc->GetPermissionDelegateHandler();

  if (permDelegateHandler) {
    permDelegateHandler->PopulateAllDelegatedPermissions();
  }

#if defined(MOZ_WIDGET_ANDROID)
  // When we insert the new document to the window in the top-level browsing
  // context, we should reset the status of the request which is used for the
  // previous document.
  if (mWindowGlobalChild && GetBrowsingContext() &&
      !GetBrowsingContext()->GetParent()) {
    // Return value of setting synced field should be checked. See bug 1656492.
    Unused << GetBrowsingContext()->ResetGVAutoplayRequestStatus();
  }
#endif

#ifdef DEBUG
  mLastOpenedURI = mDoc->GetDocumentURI();
#endif

  Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
                        mMutationBits ? 1 : 0);

  // Clear our mutation bitfield.
  mMutationBits = 0;
}

nsresult nsGlobalWindowInner::EnsureClientSource() {
  MOZ_DIAGNOSTIC_ASSERT(mDoc);

  bool newClientSource = false;

  // Get the load info for the document if we performed a load.  Be careful not
  // to look at local URLs, though. Local URLs are those that have a scheme of:
  //  * about:
  //  * data:
  //  * blob:
  // We also do an additional check here so that we only treat about:blank
  // and about:srcdoc as local URLs.  Other internal firefox about: URLs should
  // not be treated this way.
  nsCOMPtr<nsILoadInfo> loadInfo;
  nsCOMPtr<nsIChannel> channel = mDoc->GetChannel();
  if (channel) {
    nsCOMPtr<nsIURI> uri;
    Unused << channel->GetURI(getter_AddRefs(uri));

    bool ignoreLoadInfo = false;

    if (uri->SchemeIs("about")) {
      ignoreLoadInfo =
          NS_IsAboutBlankAllowQueryAndFragment(uri) || NS_IsAboutSrcdoc(uri);
    } else {
      // Its not an about: URL, so now check for our other URL types.
      ignoreLoadInfo = uri->SchemeIs("data") || uri->SchemeIs("blob");
    }

    if (!ignoreLoadInfo) {
      loadInfo = channel->LoadInfo();
    }
  }

  // Take the initial client source from the docshell immediately.  Even if we
  // don't end up using it here we should consume it.
  UniquePtr<ClientSource> initialClientSource;
  nsIDocShell* docshell = GetDocShell();
  if (docshell) {
    initialClientSource = docshell->TakeInitialClientSource();
  }

  // Try to get the reserved client from the LoadInfo.  A Client is
  // reserved at the start of the channel load if there is not an
  // initial about:blank document that will be reused.  It is also
  // created if the channel load encounters a cross-origin redirect.
  if (loadInfo) {
    UniquePtr<ClientSource> reservedClient =
        loadInfo->TakeReservedClientSource();
    if (reservedClient) {
      mClientSource.reset();
      mClientSource = std::move(reservedClient);
      newClientSource = true;
    }
  }

  // We don't have a LoadInfo reserved client, but maybe we should
  // be inheriting an initial one from the docshell.  This means
  // that the docshell started the channel load before creating the
  // initial about:blank document.  This is an optimization, though,
  // and it created an initial Client as a placeholder for the document.
  // In this case we want to inherit this placeholder Client here.
  if (!mClientSource) {
    mClientSource = std::move(initialClientSource);
    if (mClientSource) {
      newClientSource = true;
    }
  }

  nsCOMPtr<nsIPrincipal> foreignPartitionedPrincipal;

  nsresult rv = StoragePrincipalHelper::GetPrincipal(
      this,
      StaticPrefs::privacy_partition_serviceWorkers()
          ? StoragePrincipalHelper::eForeignPartitionedPrincipal
          : StoragePrincipalHelper::eRegularPrincipal,
      getter_AddRefs(foreignPartitionedPrincipal));
  NS_ENSURE_SUCCESS(rv, rv);

  // Verify the final ClientSource principal matches the final document
  // principal.  The ClientChannelHelper handles things like network
  // redirects, but there are other ways the document principal can change.
  // For example, if something sets the nsIChannel.owner property, then
  // the final channel principal can be anything.  Unfortunately there is
  // no good way to detect this until after the channel completes loading.
  //
  // For now we handle this just by reseting the ClientSource.  This will
  // result in a new ClientSource with the correct principal being created.
  // To APIs like ServiceWorker and Clients API it will look like there was
  // an initial content page created that was then immediately replaced.
  // This is pretty close to what we are actually doing.
  if (mClientSource) {
    auto principalOrErr = mClientSource->Info().GetPrincipal();
    nsCOMPtr<nsIPrincipal> clientPrincipal =
        principalOrErr.isOk() ? principalOrErr.unwrap() : nullptr;
    if (!clientPrincipal ||
        !clientPrincipal->Equals(foreignPartitionedPrincipal)) {
      mClientSource.reset();
    }
  }

  // If we don't have a reserved client or an initial client, then create
  // one now.  This can happen in certain cases where we avoid preallocating
  // the client in the docshell.  This mainly occurs in situations where
  // the principal is not clearly inherited from the parent; e.g. sandboxed
  // iframes, window.open(), etc.
  //
--> --------------------

--> maximum size reached

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

96%


¤ Dauer der Verarbeitung: 0.67 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Anfrage:

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.